20 TBasicSound
= class (TObject
)
22 FChannel
: FMOD_CHANNEL
;
30 function RawPlay(Pan
: Single; Volume
: Single; aPos
: DWORD
): Boolean;
34 destructor Destroy(); override;
35 procedure SetID(ID
: DWORD
);
36 procedure FreeSound();
37 function IsPlaying(): Boolean;
39 function IsPaused(): Boolean;
40 procedure Pause(Enable
: Boolean);
41 function GetVolume(): Single;
42 procedure SetVolume(Volume
: Single);
43 function GetPan(): Single;
44 procedure SetPan(Pan
: Single);
45 function IsMuted(): Boolean;
46 procedure Mute(Enable
: Boolean);
47 function GetPosition(): DWORD
;
48 procedure SetPosition(aPos
: DWORD
);
49 procedure SetPriority(priority
: Integer);
53 NO_SOUND_ID
= DWORD(-1);
55 function e_InitSoundSystem(Freq
: Integer; forceNoSound
: Boolean): Boolean;
57 function e_LoadSound(FileName
: string; var ID
: DWORD
; bLoop
: Boolean): Boolean;
58 function e_LoadSoundMem(pData
: Pointer; Length
: Integer; var ID
: DWORD
; bLoop
: Boolean): Boolean;
60 function e_PlaySound(ID
: DWORD
): Boolean;
61 function e_PlaySoundPan(ID
: DWORD
; Pan
: Single): Boolean;
62 function e_PlaySoundVolume(ID
: DWORD
; Volume
: Single): Boolean;
63 function e_PlaySoundPanVolume(ID
: DWORD
; Pan
, Volume
: Single): Boolean;
65 procedure e_ModifyChannelsVolumes(SoundMod
: Single; setMode
: Boolean);
66 procedure e_MuteChannels(Enable
: Boolean);
67 procedure e_StopChannels();
69 procedure e_DeleteSound(ID
: DWORD
);
70 procedure e_RemoveAllSounds();
71 procedure e_ReleaseSoundSystem();
72 procedure e_SoundUpdate();
75 e_SoundsArray
: array of TSoundRec
= nil;
80 g_window
, g_options
, BinEditor
;
86 F_System
: FMOD_SYSTEM
= nil;
87 SoundMuted
: Boolean = False;
90 function Channel_Callback(channel
: FMOD_CHANNEL
; callbacktype
: FMOD_CHANNEL_CALLBACKTYPE
;
91 commanddata1
: Pointer; commanddata2
: Pointer): FMOD_RESULT
; {$IFDEF WIN32} stdcall; {$ELSE} cdecl; {$ENDIF}
101 if callbacktype
= FMOD_CHANNEL_CALLBACKTYPE_END
then
103 res
:= FMOD_Channel_GetCurrentSound(channel
, sound
);
104 if res
= FMOD_OK
then
106 res
:= FMOD_Sound_GetUserData(sound
, ud
);
107 if res
= FMOD_OK
then
110 if id
< DWORD(Length(e_SoundsArray
)) then
111 if e_SoundsArray
[id
].nRefs
> 0 then
112 Dec(e_SoundsArray
[id
].nRefs
);
120 function TryInitWithOutput(Output
: FMOD_OUTPUTTYPE
; OutputName
: String): FMOD_RESULT
;
122 e_WriteLog('Trying with ' + OutputName
+ '...', MSG_WARNING
);
123 Result
:= FMOD_System_SetOutput(F_System
, Output
);
124 if Result
<> FMOD_OK
then
126 e_WriteLog('Error setting FMOD output to ' + OutputName
+ '!', MSG_WARNING
);
127 e_WriteLog(FMOD_ErrorString(Result
), MSG_WARNING
);
130 Result
:= FMOD_System_Init(F_System
, N_CHANNELS
, FMOD_INIT_NORMAL
, nil);
131 if Result
<> FMOD_OK
then
133 e_WriteLog('Error initializing FMOD system!', MSG_WARNING
);
134 e_WriteLog(FMOD_ErrorString(Result
), MSG_WARNING
);
139 function e_InitSoundSystem(Freq
: Integer; forceNoSound
: Boolean): Boolean;
143 output
: FMOD_OUTPUTTYPE
;
149 res
:= FMOD_System_Create(F_System
);
150 if res
<> FMOD_OK
then
152 e_WriteLog('Error creating FMOD system:', MSG_FATALERROR
);
153 e_WriteLog(FMOD_ErrorString(res
), MSG_FATALERROR
);
157 res
:= FMOD_System_GetVersion(F_System
, ver
);
158 if res
<> FMOD_OK
then
160 e_WriteLog('Error getting FMOD version:', MSG_FATALERROR
);
161 e_WriteLog(FMOD_ErrorString(res
), MSG_FATALERROR
);
165 if ver
< FMOD_VERSION
then
167 e_WriteLog('FMOD library version is too old! Need '+IntToStr(FMOD_VERSION
), MSG_FATALERROR
);
171 res
:= FMOD_System_SetSoftwareFormat(F_System
, Freq
,
172 FMOD_SOUND_FORMAT_PCM16
, 0, 0, FMOD_DSP_RESAMPLER_LINEAR
);
173 if res
<> FMOD_OK
then
175 e_WriteLog('Error setting FMOD software format!', MSG_FATALERROR
);
176 e_WriteLog(FMOD_ErrorString(res
), MSG_FATALERROR
);
180 res
:= FMOD_System_Init(F_System
, N_CHANNELS
, FMOD_INIT_NORMAL
, nil);
181 if res
<> FMOD_OK
then
183 e_WriteLog('Error initializing FMOD system!', MSG_WARNING
);
184 e_WriteLog(FMOD_ErrorString(res
), MSG_WARNING
);
187 res
:= TryInitWithOutput(FMOD_OUTPUTTYPE_ALSA
, 'OUTPUTTYPE_ALSA');
188 if res
<> FMOD_OK
then
189 res
:= TryInitWithOutput(FMOD_OUTPUTTYPE_OSS
, 'OUTPUTTYPE_OSS');
191 if not forceNoSound
then Exit
;
192 if res
<> FMOD_OK
then
193 res
:= TryInitWithOutput(FMOD_OUTPUTTYPE_NOSOUND
, 'OUTPUTTYPE_NOSOUND');
194 if res
<> FMOD_OK
then
196 e_WriteLog('FMOD: Giving up, can''t init any output.', MSG_FATALERROR
);
201 res
:= FMOD_System_GetOutput(F_System
, output
);
202 if res
<> FMOD_OK
then
203 e_WriteLog('Error getting FMOD output!', MSG_WARNING
)
206 FMOD_OUTPUTTYPE_NOSOUND
: e_WriteLog('FMOD Output Method: NOSOUND', MSG_NOTIFY
);
207 FMOD_OUTPUTTYPE_NOSOUND_NRT
: e_WriteLog('FMOD Output Method: NOSOUND_NRT', MSG_NOTIFY
);
208 FMOD_OUTPUTTYPE_DSOUND
: e_WriteLog('FMOD Output Method: DSOUND', MSG_NOTIFY
);
209 FMOD_OUTPUTTYPE_WINMM
: e_WriteLog('FMOD Output Method: WINMM', MSG_NOTIFY
);
210 FMOD_OUTPUTTYPE_OPENAL
: e_WriteLog('FMOD Output Method: OPENAL', MSG_NOTIFY
);
211 FMOD_OUTPUTTYPE_WASAPI
: e_WriteLog('FMOD Output Method: WASAPI', MSG_NOTIFY
);
212 FMOD_OUTPUTTYPE_ASIO
: e_WriteLog('FMOD Output Method: ASIO', MSG_NOTIFY
);
213 FMOD_OUTPUTTYPE_OSS
: e_WriteLog('FMOD Output Method: OSS', MSG_NOTIFY
);
214 FMOD_OUTPUTTYPE_ALSA
: e_Writelog('FMOD Output Method: ALSA', MSG_NOTIFY
);
215 else e_WriteLog('FMOD Output Method: Unknown', MSG_NOTIFY
);
218 res
:= FMOD_System_GetDriver(F_System
, drv
);
219 if res
<> FMOD_OK
then
220 e_WriteLog('Error getting FMOD driver!', MSG_WARNING
)
222 e_WriteLog('FMOD driver id: '+IntToStr(drv
), MSG_NOTIFY
);
227 function FindESound(): DWORD
;
232 if e_SoundsArray
<> nil then
233 for i
:= 0 to High(e_SoundsArray
) do
234 if e_SoundsArray
[i
].Sound
= nil then
240 if e_SoundsArray
= nil then
242 SetLength(e_SoundsArray
, 16);
247 Result
:= High(e_SoundsArray
) + 1;
248 SetLength(e_SoundsArray
, Length(e_SoundsArray
) + 16);
252 function e_LoadSound(FileName
: String; var ID
: DWORD
; bLoop
: Boolean): Boolean;
262 e_WriteLog('Loading sound '+FileName
+'...', MSG_NOTIFY
);
264 find_id
:= FindESound();
267 bt
:= FMOD_LOOP_NORMAL
272 res
:= FMOD_System_CreateSound(F_System
, PAnsiChar(FileName
),
273 bt
+ FMOD_2D
+ FMOD_HARDWARE
,
274 nil, e_SoundsArray
[find_id
].Sound
)
276 res
:= FMOD_System_CreateStream(F_System
, PAnsiChar(FileName
),
277 bt
+ FMOD_2D
+ FMOD_HARDWARE
,
278 nil, e_SoundsArray
[find_id
].Sound
);
279 if res
<> FMOD_OK
then
281 e_SoundsArray
[find_id
].Sound
:= nil;
285 GetMem(ud
, SizeOf(DWORD
));
286 DWORD(ud
^) := find_id
;
287 res
:= FMOD_Sound_SetUserData(e_SoundsArray
[find_id
].Sound
, ud
);
288 if res
<> FMOD_OK
then
290 e_SoundsArray
[find_id
].Sound
:= nil;
294 e_SoundsArray
[find_id
].Data
:= nil;
295 e_SoundsArray
[find_id
].Loop
:= bLoop
;
296 e_SoundsArray
[find_id
].nRefs
:= 0;
303 function e_LoadSoundMem(pData
: Pointer; Length
: Integer; var ID
: DWORD
; bLoop
: Boolean): Boolean;
309 soundExInfo
: FMOD_CREATESOUNDEXINFO
;
315 find_id
:= FindESound();
317 sz
:= SizeOf(FMOD_CREATESOUNDEXINFO
);
318 FillMemory(@soundExInfo
, sz
, 0);
319 soundExInfo
.cbsize
:= sz
;
320 soundExInfo
.length
:= Length
;
323 bt
:= FMOD_LOOP_NORMAL
328 res
:= FMOD_System_CreateSound(F_System
, pData
,
329 bt
+ FMOD_2D
+ FMOD_HARDWARE
+ FMOD_OPENMEMORY
,
330 @soundExInfo
, e_SoundsArray
[find_id
].Sound
)
332 res
:= FMOD_System_CreateStream(F_System
, pData
,
333 bt
+ FMOD_2D
+ FMOD_HARDWARE
+ FMOD_OPENMEMORY
,
334 @soundExInfo
, e_SoundsArray
[find_id
].Sound
);
335 if res
<> FMOD_OK
then
337 e_SoundsArray
[find_id
].Sound
:= nil;
341 GetMem(ud
, SizeOf(DWORD
));
342 DWORD(ud
^) := find_id
;
343 res
:= FMOD_Sound_SetUserData(e_SoundsArray
[find_id
].Sound
, ud
);
344 if res
<> FMOD_OK
then
346 e_SoundsArray
[find_id
].Sound
:= nil;
350 e_SoundsArray
[find_id
].Data
:= pData
;
351 e_SoundsArray
[find_id
].Loop
:= bLoop
;
352 e_SoundsArray
[find_id
].nRefs
:= 0;
359 function e_PlaySound(ID
: DWORD
): Boolean;
365 if e_SoundsArray
[ID
].nRefs
>= gMaxSimSounds
then
373 res
:= FMOD_System_PlaySound(F_System
, FMOD_CHANNEL_FREE
,
374 e_SoundsArray
[ID
].Sound
, False, Chan
);
375 if res
<> FMOD_OK
then
380 res
:= FMOD_Channel_SetCallback(Chan
, Channel_Callback
);
381 if res
<> FMOD_OK
then
387 res
:= FMOD_Channel_SetMute(Chan
, True);
388 if res
<> FMOD_OK
then
393 Inc(e_SoundsArray
[ID
].nRefs
);
397 function e_PlaySoundPan(ID
: DWORD
; Pan
: Single): Boolean;
403 if e_SoundsArray
[ID
].nRefs
>= gMaxSimSounds
then
411 res
:= FMOD_System_PlaySound(F_System
, FMOD_CHANNEL_FREE
,
412 e_SoundsArray
[ID
].Sound
, False, Chan
);
413 if res
<> FMOD_OK
then
418 res
:= FMOD_Channel_SetPan(Chan
, Pan
);
419 if res
<> FMOD_OK
then
423 res
:= FMOD_Channel_SetCallback(Chan
, Channel_Callback
);
424 if res
<> FMOD_OK
then
430 res
:= FMOD_Channel_SetMute(Chan
, True);
431 if res
<> FMOD_OK
then
436 Inc(e_SoundsArray
[ID
].nRefs
);
440 function e_PlaySoundVolume(ID
: DWORD
; Volume
: Single): Boolean;
446 if e_SoundsArray
[ID
].nRefs
>= gMaxSimSounds
then
454 res
:= FMOD_System_PlaySound(F_System
, FMOD_CHANNEL_FREE
,
455 e_SoundsArray
[ID
].Sound
, False, Chan
);
456 if res
<> FMOD_OK
then
461 res
:= FMOD_Channel_SetVolume(Chan
, Volume
);
462 if res
<> FMOD_OK
then
466 res
:= FMOD_Channel_SetCallback(Chan
, Channel_Callback
);
467 if res
<> FMOD_OK
then
473 res
:= FMOD_Channel_SetMute(Chan
, True);
474 if res
<> FMOD_OK
then
479 Inc(e_SoundsArray
[ID
].nRefs
);
483 function e_PlaySoundPanVolume(ID
: DWORD
; Pan
, Volume
: Single): Boolean;
489 if e_SoundsArray
[ID
].nRefs
>= gMaxSimSounds
then
497 res
:= FMOD_System_PlaySound(F_System
, FMOD_CHANNEL_FREE
,
498 e_SoundsArray
[ID
].Sound
, False, Chan
);
499 if res
<> FMOD_OK
then
504 res
:= FMOD_Channel_SetPan(Chan
, Pan
);
505 if res
<> FMOD_OK
then
509 res
:= FMOD_Channel_SetVolume(Chan
, Volume
);
510 if res
<> FMOD_OK
then
514 res
:= FMOD_Channel_SetCallback(Chan
, Channel_Callback
);
515 if res
<> FMOD_OK
then
521 res
:= FMOD_Channel_SetMute(Chan
, True);
522 if res
<> FMOD_OK
then
527 Inc(e_SoundsArray
[ID
].nRefs
);
531 procedure e_DeleteSound(ID
: DWORD
);
537 if e_SoundsArray
[ID
].Sound
= nil then
540 if e_SoundsArray
[ID
].Data
<> nil then
541 FreeMem(e_SoundsArray
[ID
].Data
);
543 res
:= FMOD_Sound_GetUserData(e_SoundsArray
[ID
].Sound
, ud
);
544 if res
= FMOD_OK
then
549 res
:= FMOD_Sound_Release(e_SoundsArray
[ID
].Sound
);
550 if res
<> FMOD_OK
then
552 e_WriteLog('Error releasing sound:', MSG_WARNING
);
553 e_WriteLog(FMOD_ErrorString(res
), MSG_WARNING
);
556 e_SoundsArray
[ID
].Sound
:= nil;
557 e_SoundsArray
[ID
].Data
:= nil;
560 procedure e_ModifyChannelsVolumes(SoundMod
: Single; setMode
: Boolean);
568 for i
:= 0 to N_CHANNELS
-1 do
571 res
:= FMOD_System_GetChannel(F_System
, i
, Chan
);
573 if (res
= FMOD_OK
) and (Chan
<> nil) then
575 res
:= FMOD_Channel_GetVolume(Chan
, vol
);
577 if res
= FMOD_OK
then
582 vol
:= vol
* SoundMod
;
584 res
:= FMOD_Channel_SetVolume(Chan
, vol
);
586 if res
<> FMOD_OK
then
594 procedure e_MuteChannels(Enable
: Boolean);
601 if Enable
= SoundMuted
then
604 SoundMuted
:= Enable
;
606 for i
:= 0 to N_CHANNELS
-1 do
609 res
:= FMOD_System_GetChannel(F_System
, i
, Chan
);
611 if (res
= FMOD_OK
) and (Chan
<> nil) then
613 res
:= FMOD_Channel_SetMute(Chan
, Enable
);
615 if res
<> FMOD_OK
then
622 procedure e_StopChannels();
629 for i
:= 0 to N_CHANNELS
-1 do
632 res
:= FMOD_System_GetChannel(F_System
, i
, Chan
);
634 if (res
= FMOD_OK
) and (Chan
<> nil) then
636 res
:= FMOD_Channel_Stop(Chan
);
638 if res
<> FMOD_OK
then
645 procedure e_RemoveAllSounds();
650 for i
:= 0 to High(e_SoundsArray
) do
651 if e_SoundsArray
[i
].Sound
<> nil then
654 SetLength(e_SoundsArray
, 0);
655 e_SoundsArray
:= nil;
658 procedure e_ReleaseSoundSystem();
665 res
:= FMOD_System_Close(F_System
);
666 if res
<> FMOD_OK
then
668 e_WriteLog('Error closing FMOD system!', MSG_FATALERROR
);
669 e_WriteLog(FMOD_ErrorString(res
), MSG_FATALERROR
);
673 res
:= FMOD_System_Release(F_System
);
674 if res
<> FMOD_OK
then
676 e_WriteLog('Error releasing FMOD system!', MSG_FATALERROR
);
677 e_WriteLog(FMOD_ErrorString(res
), MSG_FATALERROR
);
681 procedure e_SoundUpdate();
683 FMOD_System_Update(F_System
);
688 constructor TBasicSound
.Create();
697 destructor TBasicSound
.Destroy();
703 procedure TBasicSound
.FreeSound();
705 if FID
= NO_SOUND_ID
then
714 function TBasicSound
.RawPlay(Pan
: Single; Volume
: Single; aPos
: DWORD
): Boolean;
719 if e_SoundsArray
[FID
].nRefs
>= gMaxSimSounds
then
727 if FID
= NO_SOUND_ID
then
730 res
:= FMOD_System_PlaySound(F_System
, FMOD_CHANNEL_FREE
,
731 e_SoundsArray
[FID
].Sound
, False, FChannel
);
732 if res
<> FMOD_OK
then
738 res
:= FMOD_Channel_SetPosition(FChannel
, aPos
, FMOD_TIMEUNIT_MS
);
739 if res
<> FMOD_OK
then
746 res
:= FMOD_Channel_SetPan(FChannel
, Pan
);
747 if res
<> FMOD_OK
then
751 res
:= FMOD_Channel_SetVolume(FChannel
, Volume
);
752 if res
<> FMOD_OK
then
756 res
:= FMOD_Channel_SetCallback(FChannel
, Channel_Callback
);
757 if res
<> FMOD_OK
then
763 res
:= FMOD_Channel_SetMute(FChannel
, True);
764 if res
<> FMOD_OK
then
769 Inc(e_SoundsArray
[FID
].nRefs
);
773 procedure TBasicSound
.SetID(ID
: DWORD
);
777 FLoop
:= e_SoundsArray
[ID
].Loop
;
780 function TBasicSound
.IsPlaying(): Boolean;
788 if FChannel
= nil then
791 res
:= FMOD_Channel_IsPlaying(FChannel
, b
);
792 if res
<> FMOD_OK
then
800 procedure TBasicSound
.Stop();
805 if FChannel
= nil then
810 res
:= FMOD_Channel_Stop(FChannel
);
811 if res
<> FMOD_OK
then
818 function TBasicSound
.IsPaused(): Boolean;
826 if FChannel
= nil then
829 res
:= FMOD_Channel_GetPaused(FChannel
, b
);
830 if res
<> FMOD_OK
then
838 procedure TBasicSound
.Pause(Enable
: Boolean);
843 if FChannel
= nil then
846 res
:= FMOD_Channel_SetPaused(FChannel
, Enable
);
847 if res
<> FMOD_OK
then
853 res
:= FMOD_Channel_GetPosition(FChannel
, FPosition
, FMOD_TIMEUNIT_MS
);
854 if res
<> FMOD_OK
then
860 function TBasicSound
.GetVolume(): Single;
868 if FChannel
= nil then
871 res
:= FMOD_Channel_GetVolume(FChannel
, vol
);
872 if res
<> FMOD_OK
then
880 procedure TBasicSound
.SetVolume(Volume
: Single);
885 if FChannel
= nil then
888 res
:= FMOD_Channel_SetVolume(FChannel
, Volume
);
889 if res
<> FMOD_OK
then
894 function TBasicSound
.GetPan(): Single;
902 if FChannel
= nil then
905 res
:= FMOD_Channel_GetPan(FChannel
, pan
);
906 if res
<> FMOD_OK
then
914 procedure TBasicSound
.SetPan(Pan
: Single);
919 if FChannel
= nil then
922 res
:= FMOD_Channel_SetPan(FChannel
, Pan
);
923 if res
<> FMOD_OK
then
928 function TBasicSound
.IsMuted(): Boolean;
936 if FChannel
= nil then
939 res
:= FMOD_Channel_GetMute(FChannel
, b
);
940 if res
<> FMOD_OK
then
948 procedure TBasicSound
.Mute(Enable
: Boolean);
953 if FChannel
= nil then
956 res
:= FMOD_Channel_SetMute(FChannel
, Enable
);
957 if res
<> FMOD_OK
then
962 function TBasicSound
.GetPosition(): DWORD
;
969 if FChannel
= nil then
972 res
:= FMOD_Channel_GetPosition(FChannel
, FPosition
, FMOD_TIMEUNIT_MS
);
973 if res
<> FMOD_OK
then
981 procedure TBasicSound
.SetPosition(aPos
: DWORD
);
988 if FChannel
= nil then
991 res
:= FMOD_Channel_SetPosition(FChannel
, FPosition
, FMOD_TIMEUNIT_MS
);
992 if res
<> FMOD_OK
then
997 procedure TBasicSound
.SetPriority(priority
: Integer);
1002 if (FChannel
<> nil) and (FPriority
<> priority
) and
1003 (priority
>= 0) and (priority
<= 256) then
1005 FPriority
:= priority
;
1006 res
:= FMOD_Channel_SetPriority(FChannel
, priority
);
1007 if res
<> FMOD_OK
then