DEADSOFTWARE

saves: fix incorrect map load after failed state load
[d2df-sdl.git] / src / engine / e_sound_fmod.inc
1 (* Copyright (C) Doom 2D: Forever Developers
2 *
3 * This program is free software: you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation, version 3 of the License ONLY.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 *
12 * You should have received a copy of the GNU General Public License
13 * along with this program. If not, see <http://www.gnu.org/licenses/>.
14 *)
15 interface
17 uses
18 fmod,
19 fmodtypes,
20 fmoderrors,
21 {$IFDEF USE_MEMPOOL}mempool,{$ENDIF}
22 e_log,
23 SysUtils;
25 type
26 TSoundRec = record
27 Data: Pointer;
28 Sound: FMOD_SOUND;
29 isMusic: Boolean;
30 nRefs: Integer;
31 end;
33 TBasicSound = class{$IFDEF USE_MEMPOOL}(TPoolObject){$ENDIF}
34 private
35 FChannel: FMOD_CHANNEL;
37 protected
38 FID: DWORD;
39 FMusic: Boolean;
40 FPosition: DWORD;
41 FPriority: Integer;
43 function RawPlay(Pan: Single; Volume: Single; aPos: DWORD): Boolean;
45 public
46 constructor Create();
47 destructor Destroy(); override;
48 procedure SetID(ID: DWORD);
49 procedure FreeSound();
50 function IsPlaying(): Boolean;
51 procedure Stop();
52 function IsPaused(): Boolean;
53 procedure Pause(Enable: Boolean);
54 function GetVolume(): Single;
55 procedure SetVolume(Volume: Single);
56 function GetPan(): Single;
57 procedure SetPan(Pan: Single);
58 function IsMuted(): Boolean;
59 procedure Mute(Enable: Boolean);
60 function GetPosition(): DWORD;
61 procedure SetPosition(aPos: DWORD);
62 procedure SetPriority(priority: Integer);
63 end;
65 const
66 NO_SOUND_ID = DWORD(-1);
68 function e_InitSoundSystem(NoOutput: Boolean = False): Boolean;
70 function e_LoadSound(FileName: string; var ID: DWORD; isMusic: Boolean; ForceNoLoop: Boolean = False): Boolean;
71 function e_LoadSoundMem(pData: Pointer; Length: Integer; var ID: DWORD; isMusic: Boolean; ForceNoLoop: Boolean = False): Boolean;
73 function e_PlaySound(ID: DWORD): Integer;
74 function e_PlaySoundPan(ID: DWORD; Pan: Single): Integer;
75 function e_PlaySoundVolume(ID: DWORD; Volume: Single): Integer;
76 function e_PlaySoundPanVolume(ID: DWORD; Pan, Volume: Single): Integer;
78 procedure e_ModifyChannelsVolumes(SoundMod: Single; setMode: Boolean);
79 procedure e_MuteChannels(Enable: Boolean);
80 procedure e_StopChannels();
82 procedure e_DeleteSound(ID: DWORD);
83 procedure e_RemoveAllSounds();
84 procedure e_ReleaseSoundSystem();
85 procedure e_SoundUpdate();
87 var
88 e_SoundsArray: array of TSoundRec = nil;
90 implementation
92 uses
93 g_window, g_options, utils;
95 const
96 N_CHANNELS = 512;
98 var
99 F_System: FMOD_SYSTEM = nil;
100 SoundMuted: Boolean = False;
103 function Channel_Callback(channel: FMOD_CHANNEL; callbacktype: FMOD_CHANNEL_CALLBACKTYPE;
104 commanddata1: Pointer; commanddata2: Pointer): FMOD_RESULT; {$IFDEF WIN32} stdcall; {$ELSE} cdecl; {$ENDIF}
105 var
106 res: FMOD_RESULT;
107 sound: FMOD_SOUND;
108 ud: Pointer;
109 id: DWORD;
111 begin
112 res := FMOD_OK;
114 if callbacktype = FMOD_CHANNEL_CALLBACKTYPE_END then
115 begin
116 res := FMOD_Channel_GetCurrentSound(channel, sound);
117 if res = FMOD_OK then
118 begin
119 res := FMOD_Sound_GetUserData(sound, ud);
120 if res = FMOD_OK then
121 begin
122 id := DWORD(ud^);
123 if id < DWORD(Length(e_SoundsArray)) then
124 if e_SoundsArray[id].nRefs > 0 then
125 Dec(e_SoundsArray[id].nRefs);
126 end;
127 end;
128 end;
130 Result := res;
131 end;
133 function TryInitWithOutput(Output: FMOD_OUTPUTTYPE; OutputName: String): FMOD_RESULT;
134 begin
135 e_WriteLog('Trying with ' + OutputName + '...', TMsgType.Warning);
136 Result := FMOD_System_SetOutput(F_System, Output);
137 if Result <> FMOD_OK then
138 begin
139 e_WriteLog('Error setting FMOD output to ' + OutputName + '!', TMsgType.Warning);
140 e_WriteLog(FMOD_ErrorString(Result), TMsgType.Warning);
141 Exit;
142 end;
143 Result := FMOD_System_Init(F_System, N_CHANNELS, FMOD_INIT_NORMAL, nil);
144 if Result <> FMOD_OK then
145 begin
146 e_WriteLog('Error initializing FMOD system!', TMsgType.Warning);
147 e_WriteLog(FMOD_ErrorString(Result), TMsgType.Warning);
148 Exit;
149 end;
150 end;
152 function e_TrySS (Freq: Integer; forceNoSound: Integer): Boolean;
153 var
154 res: FMOD_RESULT;
155 ver: Cardinal;
156 output: FMOD_OUTPUTTYPE;
157 drv: Integer;
159 begin
160 Result := False;
161 e_WriteLog(Format('Trying to initialize FMOD with %d', [Freq]), TMsgType.Notify);
163 res := FMOD_System_Create(F_System);
164 if res <> FMOD_OK then
165 begin
166 e_WriteLog('Error creating FMOD system:', TMsgType.Fatal);
167 e_WriteLog(FMOD_ErrorString(res), TMsgType.Fatal);
168 Exit;
169 end;
171 res := FMOD_System_GetVersion(F_System, ver);
172 if res <> FMOD_OK then
173 begin
174 e_WriteLog('Error getting FMOD version:', TMsgType.Fatal);
175 e_WriteLog(FMOD_ErrorString(res), TMsgType.Fatal);
176 Exit;
177 end;
179 if ver < FMOD_VERSION then
180 begin
181 e_WriteLog('FMOD library version is too old! Need '+IntToStr(FMOD_VERSION), TMsgType.Fatal);
182 Exit;
183 end;
185 res := FMOD_System_SetSoftwareFormat(F_System, Freq, FMOD_SOUND_FORMAT_PCM16, 0, 0, FMOD_DSP_RESAMPLER_LINEAR);
186 if res <> FMOD_OK then
187 begin
188 e_WriteLog('Error setting FMOD software format!', TMsgType.Fatal);
189 e_WriteLog(FMOD_ErrorString(res), TMsgType.Fatal);
190 Exit;
191 end;
193 if forceNoSound = 2 then
194 begin
195 res := TryInitWithOutput(FMOD_OUTPUTTYPE_NOSOUND, 'OUTPUTTYPE_NOSOUND');
196 if res <> FMOD_OK then
197 begin
198 e_WriteLog('FMOD: Giving up, can''t init with NOSOUND.', TMsgType.Fatal);
199 Exit;
200 end;
201 end
202 else
203 begin
204 res := FMOD_System_Init(F_System, N_CHANNELS, FMOD_INIT_NORMAL, nil);
205 if res <> FMOD_OK then
206 begin
207 e_WriteLog('Error initializing FMOD system!', TMsgType.Warning);
208 e_WriteLog(FMOD_ErrorString(res), TMsgType.Warning);
210 {$IFDEF LINUX}
211 res := TryInitWithOutput(FMOD_OUTPUTTYPE_ALSA, 'OUTPUTTYPE_ALSA');
212 if res <> FMOD_OK then
213 res := TryInitWithOutput(FMOD_OUTPUTTYPE_OSS, 'OUTPUTTYPE_OSS');
214 {$ENDIF}
215 if (res <> FMOD_OK) and (forceNoSound <> 1) then Exit;
216 if res <> FMOD_OK then
217 res := TryInitWithOutput(FMOD_OUTPUTTYPE_NOSOUND, 'OUTPUTTYPE_NOSOUND');
218 if res <> FMOD_OK then
219 begin
220 e_WriteLog('FMOD: Giving up, can''t init any output.', TMsgType.Fatal);
221 Exit;
222 end;
223 end;
224 end;
226 res := FMOD_System_GetOutput(F_System, output);
227 if res <> FMOD_OK then
228 e_WriteLog('Error getting FMOD output!', TMsgType.Warning)
229 else
230 case output of
231 FMOD_OUTPUTTYPE_NOSOUND: e_WriteLog('FMOD Output Method: NOSOUND', TMsgType.Notify);
232 FMOD_OUTPUTTYPE_NOSOUND_NRT: e_WriteLog('FMOD Output Method: NOSOUND_NRT', TMsgType.Notify);
233 FMOD_OUTPUTTYPE_DSOUND: e_WriteLog('FMOD Output Method: DSOUND', TMsgType.Notify);
234 FMOD_OUTPUTTYPE_WINMM: e_WriteLog('FMOD Output Method: WINMM', TMsgType.Notify);
235 FMOD_OUTPUTTYPE_OPENAL: e_WriteLog('FMOD Output Method: OPENAL', TMsgType.Notify);
236 FMOD_OUTPUTTYPE_WASAPI: e_WriteLog('FMOD Output Method: WASAPI', TMsgType.Notify);
237 FMOD_OUTPUTTYPE_ASIO: e_WriteLog('FMOD Output Method: ASIO', TMsgType.Notify);
238 FMOD_OUTPUTTYPE_OSS: e_WriteLog('FMOD Output Method: OSS', TMsgType.Notify);
239 FMOD_OUTPUTTYPE_ALSA: e_Writelog('FMOD Output Method: ALSA', TMsgType.Notify);
240 else e_WriteLog('FMOD Output Method: Unknown', TMsgType.Notify);
241 end;
243 res := FMOD_System_GetDriver(F_System, drv);
244 if res <> FMOD_OK then
245 e_WriteLog('Error getting FMOD driver!', TMsgType.Warning)
246 else
247 e_WriteLog('FMOD driver id: '+IntToStr(drv), TMsgType.Notify);
249 Result := True;
250 end;
252 function e_InitSoundSystem(NoOutput: Boolean = False): Boolean;
253 begin
254 if NoOutput then
255 begin
256 Result := e_TrySS(48000, 2);
257 Exit;
258 end;
259 Result := e_TrySS(48000, 0);
260 if not Result then Result := e_TrySS(44100, 1);
261 end;
263 function FindESound(): DWORD;
264 var
265 i: Integer;
267 begin
268 if e_SoundsArray <> nil then
269 for i := 0 to High(e_SoundsArray) do
270 if e_SoundsArray[i].Sound = nil then
271 begin
272 Result := i;
273 Exit;
274 end;
276 if e_SoundsArray = nil then
277 begin
278 SetLength(e_SoundsArray, 16);
279 Result := 0;
280 end
281 else
282 begin
283 Result := High(e_SoundsArray) + 1;
284 SetLength(e_SoundsArray, Length(e_SoundsArray) + 16);
285 end;
286 end;
288 function e_LoadSound(FileName: String; var ID: DWORD; isMusic: Boolean; ForceNoLoop: Boolean = False): Boolean;
289 var
290 find_id: DWORD;
291 res: FMOD_RESULT;
292 bt: Cardinal;
293 ud: Pointer;
295 begin
296 Result := False;
298 e_WriteLog('Loading sound '+FileName+'...', TMsgType.Notify);
300 find_id := FindESound();
302 if isMusic and not ForceNoLoop then
303 bt := FMOD_LOOP_NORMAL
304 else
305 bt := FMOD_LOOP_OFF;
307 if not isMusic then
308 res := FMOD_System_CreateSound(F_System, PAnsiChar(FileName),
309 bt + FMOD_2D + FMOD_HARDWARE,
310 nil, e_SoundsArray[find_id].Sound)
311 else
312 res := FMOD_System_CreateStream(F_System, PAnsiChar(FileName),
313 bt + FMOD_2D + FMOD_HARDWARE,
314 nil, e_SoundsArray[find_id].Sound);
315 if res <> FMOD_OK then
316 begin
317 e_SoundsArray[find_id].Sound := nil;
318 Exit;
319 end;
321 GetMem(ud, SizeOf(DWORD));
322 DWORD(ud^) := find_id;
323 res := FMOD_Sound_SetUserData(e_SoundsArray[find_id].Sound, ud);
324 if res <> FMOD_OK then
325 begin
326 e_SoundsArray[find_id].Sound := nil;
327 Exit;
328 end;
330 e_SoundsArray[find_id].Data := nil;
331 e_SoundsArray[find_id].isMusic := isMusic;
332 e_SoundsArray[find_id].nRefs := 0;
334 ID := find_id;
336 Result := True;
337 end;
339 function e_LoadSoundMem(pData: Pointer; Length: Integer; var ID: DWORD; isMusic: Boolean; ForceNoLoop: Boolean = False): Boolean;
340 var
341 find_id: DWORD;
342 res: FMOD_RESULT;
343 sz: Integer;
344 bt: Cardinal;
345 soundExInfo: FMOD_CREATESOUNDEXINFO;
346 ud: Pointer;
348 begin
349 Result := False;
351 find_id := FindESound();
353 sz := SizeOf(FMOD_CREATESOUNDEXINFO);
354 FillMemory(@soundExInfo, sz, 0);
355 soundExInfo.cbsize := sz;
356 soundExInfo.length := Length;
358 if isMusic and not ForceNoLoop then
359 bt := FMOD_LOOP_NORMAL
360 else
361 bt := FMOD_LOOP_OFF;
363 if not isMusic then
364 res := FMOD_System_CreateSound(F_System, pData,
365 bt + FMOD_2D + FMOD_HARDWARE + FMOD_OPENMEMORY,
366 @soundExInfo, e_SoundsArray[find_id].Sound)
367 else
368 res := FMOD_System_CreateStream(F_System, pData,
369 bt + FMOD_2D + FMOD_HARDWARE + FMOD_OPENMEMORY,
370 @soundExInfo, e_SoundsArray[find_id].Sound);
371 if res <> FMOD_OK then
372 begin
373 e_SoundsArray[find_id].Sound := nil;
374 Exit;
375 end;
377 GetMem(ud, SizeOf(DWORD));
378 DWORD(ud^) := find_id;
379 res := FMOD_Sound_SetUserData(e_SoundsArray[find_id].Sound, ud);
380 if res <> FMOD_OK then
381 begin
382 e_SoundsArray[find_id].Sound := nil;
383 Exit;
384 end;
386 e_SoundsArray[find_id].Data := pData;
387 e_SoundsArray[find_id].isMusic := isMusic;
388 e_SoundsArray[find_id].nRefs := 0;
390 ID := find_id;
392 Result := True;
393 end;
395 function e_PlaySound(ID: DWORD): Integer;
396 var
397 res: FMOD_RESULT;
398 Chan: FMOD_CHANNEL;
400 begin
401 if e_SoundsArray[ID].nRefs >= gMaxSimSounds then
402 begin
403 Result := 0;
404 Exit;
405 end;
407 Result := -1;
409 res := FMOD_System_PlaySound(F_System, FMOD_CHANNEL_FREE,
410 e_SoundsArray[ID].Sound, False, Chan);
411 if res <> FMOD_OK then
412 begin
413 Exit;
414 end;
416 res := FMOD_Channel_SetCallback(Chan, Channel_Callback);
417 if res <> FMOD_OK then
418 begin
419 end;
421 if SoundMuted then
422 begin
423 res := FMOD_Channel_SetMute(Chan, True);
424 if res <> FMOD_OK then
425 begin
426 end;
427 end;
429 Inc(e_SoundsArray[ID].nRefs);
430 Result := 0;
431 end;
433 function e_PlaySoundPan(ID: DWORD; Pan: Single): Integer;
434 var
435 res: FMOD_RESULT;
436 Chan: FMOD_CHANNEL;
438 begin
439 if e_SoundsArray[ID].nRefs >= gMaxSimSounds then
440 begin
441 Result := 0;
442 Exit;
443 end;
445 Result := -1;
447 res := FMOD_System_PlaySound(F_System, FMOD_CHANNEL_FREE,
448 e_SoundsArray[ID].Sound, False, Chan);
449 if res <> FMOD_OK then
450 begin
451 Exit;
452 end;
454 res := FMOD_Channel_SetPan(Chan, Pan);
455 if res <> FMOD_OK then
456 begin
457 end;
459 res := FMOD_Channel_SetCallback(Chan, Channel_Callback);
460 if res <> FMOD_OK then
461 begin
462 end;
464 if SoundMuted then
465 begin
466 res := FMOD_Channel_SetMute(Chan, True);
467 if res <> FMOD_OK then
468 begin
469 end;
470 end;
472 Inc(e_SoundsArray[ID].nRefs);
473 Result := 0;
474 end;
476 function e_PlaySoundVolume(ID: DWORD; Volume: Single): Integer;
477 var
478 res: FMOD_RESULT;
479 Chan: FMOD_CHANNEL;
481 begin
482 if e_SoundsArray[ID].nRefs >= gMaxSimSounds then
483 begin
484 Result := 0;
485 Exit;
486 end;
488 Result := -1;
490 res := FMOD_System_PlaySound(F_System, FMOD_CHANNEL_FREE,
491 e_SoundsArray[ID].Sound, False, Chan);
492 if res <> FMOD_OK then
493 begin
494 Exit;
495 end;
497 res := FMOD_Channel_SetVolume(Chan, Volume);
498 if res <> FMOD_OK then
499 begin
500 end;
502 res := FMOD_Channel_SetCallback(Chan, Channel_Callback);
503 if res <> FMOD_OK then
504 begin
505 end;
507 if SoundMuted then
508 begin
509 res := FMOD_Channel_SetMute(Chan, True);
510 if res <> FMOD_OK then
511 begin
512 end;
513 end;
515 Inc(e_SoundsArray[ID].nRefs);
516 Result := 0;
517 end;
519 function e_PlaySoundPanVolume(ID: DWORD; Pan, Volume: Single): Integer;
520 var
521 res: FMOD_RESULT;
522 Chan: FMOD_CHANNEL;
524 begin
525 if e_SoundsArray[ID].nRefs >= gMaxSimSounds then
526 begin
527 Result := 0;
528 Exit;
529 end;
531 Result := -1;
533 res := FMOD_System_PlaySound(F_System, FMOD_CHANNEL_FREE,
534 e_SoundsArray[ID].Sound, False, Chan);
535 if res <> FMOD_OK then
536 begin
537 Exit;
538 end;
540 res := FMOD_Channel_SetPan(Chan, Pan);
541 if res <> FMOD_OK then
542 begin
543 end;
545 res := FMOD_Channel_SetVolume(Chan, Volume);
546 if res <> FMOD_OK then
547 begin
548 end;
550 res := FMOD_Channel_SetCallback(Chan, Channel_Callback);
551 if res <> FMOD_OK then
552 begin
553 end;
555 if SoundMuted then
556 begin
557 res := FMOD_Channel_SetMute(Chan, True);
558 if res <> FMOD_OK then
559 begin
560 end;
561 end;
563 Inc(e_SoundsArray[ID].nRefs);
564 Result := 0;
565 end;
567 procedure e_DeleteSound(ID: DWORD);
568 var
569 res: FMOD_RESULT;
570 ud: Pointer;
572 begin
573 if e_SoundsArray[ID].Sound = nil then
574 Exit;
576 if e_SoundsArray[ID].Data <> nil then
577 FreeMem(e_SoundsArray[ID].Data);
579 res := FMOD_Sound_GetUserData(e_SoundsArray[ID].Sound, ud);
580 if res = FMOD_OK then
581 begin
582 FreeMem(ud);
583 end;
585 res := FMOD_Sound_Release(e_SoundsArray[ID].Sound);
586 if res <> FMOD_OK then
587 begin
588 e_WriteLog('Error releasing sound:', TMsgType.Warning);
589 e_WriteLog(FMOD_ErrorString(res), TMsgType.Warning);
590 end;
592 e_SoundsArray[ID].Sound := nil;
593 e_SoundsArray[ID].Data := nil;
594 end;
596 procedure e_ModifyChannelsVolumes(SoundMod: Single; setMode: Boolean);
597 var
598 res: FMOD_RESULT;
599 i: Integer;
600 Chan: FMOD_CHANNEL;
601 vol: Single;
603 begin
604 for i := 0 to N_CHANNELS-1 do
605 begin
606 Chan := nil;
607 res := FMOD_System_GetChannel(F_System, i, Chan);
609 if (res = FMOD_OK) and (Chan <> nil) then
610 begin
611 res := FMOD_Channel_GetVolume(Chan, vol);
613 if res = FMOD_OK then
614 begin
615 if setMode then
616 vol := SoundMod
617 else
618 vol := vol * SoundMod;
620 res := FMOD_Channel_SetVolume(Chan, vol);
622 if res <> FMOD_OK then
623 begin
624 end;
625 end;
626 end;
627 end;
628 end;
630 procedure e_MuteChannels(Enable: Boolean);
631 var
632 res: FMOD_RESULT;
633 i: Integer;
634 Chan: FMOD_CHANNEL;
636 begin
637 if Enable = SoundMuted then
638 Exit;
640 SoundMuted := Enable;
642 for i := 0 to N_CHANNELS-1 do
643 begin
644 Chan := nil;
645 res := FMOD_System_GetChannel(F_System, i, Chan);
647 if (res = FMOD_OK) and (Chan <> nil) then
648 begin
649 res := FMOD_Channel_SetMute(Chan, Enable);
651 if res <> FMOD_OK then
652 begin
653 end;
654 end;
655 end;
656 end;
658 procedure e_StopChannels();
659 var
660 res: FMOD_RESULT;
661 i: Integer;
662 Chan: FMOD_CHANNEL;
664 begin
665 for i := 0 to N_CHANNELS-1 do
666 begin
667 Chan := nil;
668 res := FMOD_System_GetChannel(F_System, i, Chan);
670 if (res = FMOD_OK) and (Chan <> nil) then
671 begin
672 res := FMOD_Channel_Stop(Chan);
674 if res <> FMOD_OK then
675 begin
676 end;
677 end;
678 end;
679 end;
681 procedure e_RemoveAllSounds();
682 var
683 i: Integer;
685 begin
686 for i := 0 to High(e_SoundsArray) do
687 if e_SoundsArray[i].Sound <> nil then
688 e_DeleteSound(i);
690 SetLength(e_SoundsArray, 0);
691 e_SoundsArray := nil;
692 end;
694 procedure e_ReleaseSoundSystem();
695 var
696 res: FMOD_RESULT;
698 begin
699 e_RemoveAllSounds();
701 res := FMOD_System_Close(F_System);
702 if res <> FMOD_OK then
703 begin
704 e_WriteLog('Error closing FMOD system!', TMsgType.Fatal);
705 e_WriteLog(FMOD_ErrorString(res), TMsgType.Fatal);
706 Exit;
707 end;
709 res := FMOD_System_Release(F_System);
710 if res <> FMOD_OK then
711 begin
712 e_WriteLog('Error releasing FMOD system!', TMsgType.Fatal);
713 e_WriteLog(FMOD_ErrorString(res), TMsgType.Fatal);
714 end;
715 end;
717 procedure e_SoundUpdate();
718 begin
719 FMOD_System_Update(F_System);
720 end;
722 { TBasicSound: }
724 constructor TBasicSound.Create();
725 begin
726 FID := NO_SOUND_ID;
727 FMusic := False;
728 FChannel := nil;
729 FPosition := 0;
730 FPriority := 128;
731 end;
733 destructor TBasicSound.Destroy();
734 begin
735 FreeSound();
736 inherited;
737 end;
739 procedure TBasicSound.FreeSound();
740 begin
741 if FID = NO_SOUND_ID then
742 Exit;
744 Stop();
745 FID := NO_SOUND_ID;
746 FMusic := False;
747 FPosition := 0;
748 end;
750 function TBasicSound.RawPlay(Pan: Single; Volume: Single; aPos: DWORD): Boolean;
751 var
752 res: FMOD_RESULT;
754 begin
755 Result := False;
756 if FID = NO_SOUND_ID then Exit;
758 if e_SoundsArray[FID].nRefs >= gMaxSimSounds then
759 begin
760 Result := True;
761 Exit;
762 end;
764 res := FMOD_System_PlaySound(F_System, FMOD_CHANNEL_FREE,
765 e_SoundsArray[FID].Sound, False, FChannel);
766 if res <> FMOD_OK then
767 begin
768 FChannel := nil;
769 Exit;
770 end;
772 res := FMOD_Channel_SetPosition(FChannel, aPos, FMOD_TIMEUNIT_MS);
773 if res <> FMOD_OK then
774 begin
775 FPosition := 0;
776 end
777 else
778 FPosition := aPos;
780 res := FMOD_Channel_SetPan(FChannel, Pan);
781 if res <> FMOD_OK then
782 begin
783 end;
785 res := FMOD_Channel_SetVolume(FChannel, Volume);
786 if res <> FMOD_OK then
787 begin
788 end;
790 res := FMOD_Channel_SetCallback(FChannel, Channel_Callback);
791 if res <> FMOD_OK then
792 begin
793 end;
795 if SoundMuted then
796 begin
797 res := FMOD_Channel_SetMute(FChannel, True);
798 if res <> FMOD_OK then
799 begin
800 end;
801 end;
803 Inc(e_SoundsArray[FID].nRefs);
804 Result := True;
805 end;
807 procedure TBasicSound.SetID(ID: DWORD);
808 begin
809 FreeSound();
810 FID := ID;
811 FMusic := e_SoundsArray[ID].isMusic;
812 end;
814 function TBasicSound.IsPlaying(): Boolean;
815 var
816 res: FMOD_RESULT;
817 b: LongBool;
819 begin
820 Result := False;
822 if FChannel = nil then
823 Exit;
825 res := FMOD_Channel_IsPlaying(FChannel, b);
826 if res <> FMOD_OK then
827 begin
828 Exit;
829 end;
831 Result := b;
832 end;
834 procedure TBasicSound.Stop();
835 var
836 res: FMOD_RESULT;
838 begin
839 if FChannel = nil then
840 Exit;
842 GetPosition();
844 res := FMOD_Channel_Stop(FChannel);
845 if res <> FMOD_OK then
846 begin
847 end;
849 FChannel := nil;
850 end;
852 function TBasicSound.IsPaused(): Boolean;
853 var
854 res: FMOD_RESULT;
855 b: LongBool;
857 begin
858 Result := False;
860 if FChannel = nil then
861 Exit;
863 res := FMOD_Channel_GetPaused(FChannel, b);
864 if res <> FMOD_OK then
865 begin
866 Exit;
867 end;
869 Result := b;
870 end;
872 procedure TBasicSound.Pause(Enable: Boolean);
873 var
874 res: FMOD_RESULT;
876 begin
877 if FChannel = nil then
878 Exit;
880 res := FMOD_Channel_SetPaused(FChannel, Enable);
881 if res <> FMOD_OK then
882 begin
883 end;
885 if Enable then
886 begin
887 res := FMOD_Channel_GetPosition(FChannel, FPosition, FMOD_TIMEUNIT_MS);
888 if res <> FMOD_OK then
889 begin
890 end;
891 end;
892 end;
894 function TBasicSound.GetVolume(): Single;
895 var
896 res: FMOD_RESULT;
897 vol: Single;
899 begin
900 Result := 0.0;
902 if FChannel = nil then
903 Exit;
905 res := FMOD_Channel_GetVolume(FChannel, vol);
906 if res <> FMOD_OK then
907 begin
908 Exit;
909 end;
911 Result := vol;
912 end;
914 procedure TBasicSound.SetVolume(Volume: Single);
915 var
916 res: FMOD_RESULT;
918 begin
919 if FChannel = nil then
920 Exit;
922 res := FMOD_Channel_SetVolume(FChannel, Volume);
923 if res <> FMOD_OK then
924 begin
925 end;
926 end;
928 function TBasicSound.GetPan(): Single;
929 var
930 res: FMOD_RESULT;
931 pan: Single;
933 begin
934 Result := 0.0;
936 if FChannel = nil then
937 Exit;
939 res := FMOD_Channel_GetPan(FChannel, pan);
940 if res <> FMOD_OK then
941 begin
942 Exit;
943 end;
945 Result := pan;
946 end;
948 procedure TBasicSound.SetPan(Pan: Single);
949 var
950 res: FMOD_RESULT;
952 begin
953 if FChannel = nil then
954 Exit;
956 res := FMOD_Channel_SetPan(FChannel, Pan);
957 if res <> FMOD_OK then
958 begin
959 end;
960 end;
962 function TBasicSound.IsMuted(): Boolean;
963 var
964 res: FMOD_RESULT;
965 b: LongBool;
967 begin
968 Result := False;
970 if FChannel = nil then
971 Exit;
973 res := FMOD_Channel_GetMute(FChannel, b);
974 if res <> FMOD_OK then
975 begin
976 Exit;
977 end;
979 Result := b;
980 end;
982 procedure TBasicSound.Mute(Enable: Boolean);
983 var
984 res: FMOD_RESULT;
986 begin
987 if FChannel = nil then
988 Exit;
990 res := FMOD_Channel_SetMute(FChannel, Enable);
991 if res <> FMOD_OK then
992 begin
993 end;
994 end;
996 function TBasicSound.GetPosition(): DWORD;
997 var
998 res: FMOD_RESULT;
1000 begin
1001 Result := 0;
1003 if FChannel = nil then
1004 Exit;
1006 res := FMOD_Channel_GetPosition(FChannel, FPosition, FMOD_TIMEUNIT_MS);
1007 if res <> FMOD_OK then
1008 begin
1009 Exit;
1010 end;
1012 Result := FPosition;
1013 end;
1015 procedure TBasicSound.SetPosition(aPos: DWORD);
1016 var
1017 res: FMOD_RESULT;
1019 begin
1020 FPosition := aPos;
1022 if FChannel = nil then
1023 Exit;
1025 res := FMOD_Channel_SetPosition(FChannel, FPosition, FMOD_TIMEUNIT_MS);
1026 if res <> FMOD_OK then
1027 begin
1028 end;
1029 end;
1031 procedure TBasicSound.SetPriority(priority: Integer);
1032 var
1033 res: FMOD_RESULT;
1035 begin
1036 if (FChannel <> nil) and (FPriority <> priority) and
1037 (priority >= 0) and (priority <= 256) then
1038 begin
1039 FPriority := priority;
1040 res := FMOD_Channel_SetPriority(FChannel, priority);
1041 if res <> FMOD_OK then
1042 begin
1043 end;
1044 end;
1045 end;
1047 end.