21 TBasicSound
= class (TObject
)
23 FChannel
: FMOD_CHANNEL
;
31 function RawPlay(Pan
: Single; Volume
: Single; aPos
: DWORD
): Boolean;
35 destructor Destroy(); override;
36 procedure SetID(ID
: DWORD
);
37 procedure FreeSound();
38 function IsPlaying(): Boolean;
40 function IsPaused(): Boolean;
41 procedure Pause(Enable
: Boolean);
42 function GetVolume(): Single;
43 procedure SetVolume(Volume
: Single);
44 function GetPan(): Single;
45 procedure SetPan(Pan
: Single);
46 function IsMuted(): Boolean;
47 procedure Mute(Enable
: Boolean);
48 function GetPosition(): DWORD
;
49 procedure SetPosition(aPos
: DWORD
);
50 procedure SetPriority(priority
: Integer);
54 NO_SOUND_ID
= DWORD(-1);
56 function e_InitSoundSystem(Freq
: Integer): Boolean;
58 function e_LoadSound(FileName
: string; var ID
: DWORD
; bLoop
: Boolean): Boolean;
59 function e_LoadSoundMem(pData
: Pointer; Length
: Integer; var ID
: DWORD
; bLoop
: Boolean): Boolean;
61 function e_PlaySound(ID
: DWORD
): Boolean;
62 function e_PlaySoundPan(ID
: DWORD
; Pan
: Single): Boolean;
63 function e_PlaySoundVolume(ID
: DWORD
; Volume
: Single): Boolean;
64 function e_PlaySoundPanVolume(ID
: DWORD
; Pan
, Volume
: Single): Boolean;
66 procedure e_ModifyChannelsVolumes(SoundMod
: Single; setMode
: Boolean);
67 procedure e_MuteChannels(Enable
: Boolean);
68 procedure e_StopChannels();
70 procedure e_DeleteSound(ID
: DWORD
);
71 procedure e_RemoveAllSounds();
72 procedure e_ReleaseSoundSystem();
73 procedure e_SoundUpdate();
76 e_SoundsArray
: array of TSoundRec
= nil;
87 F_System
: FMOD_SYSTEM
= nil;
88 SoundMuted
: Boolean = False;
91 function Channel_Callback(channel
: FMOD_CHANNEL
; callbacktype
: FMOD_CHANNEL_CALLBACKTYPE
;
92 commanddata1
: Pointer; commanddata2
: Pointer): FMOD_RESULT
; stdcall;
102 if callbacktype
= FMOD_CHANNEL_CALLBACKTYPE_END
then
104 res
:= FMOD_Channel_GetCurrentSound(channel
, sound
);
105 if res
= FMOD_OK
then
107 res
:= FMOD_Sound_GetUserData(sound
, ud
);
108 if res
= FMOD_OK
then
111 if id
< DWORD(Length(e_SoundsArray
)) then
112 if e_SoundsArray
[id
].nRefs
> 0 then
113 Dec(e_SoundsArray
[id
].nRefs
);
121 function e_InitSoundSystem(Freq
: Integer): Boolean;
125 output
: FMOD_OUTPUTTYPE
;
131 res
:= FMOD_System_Create(F_System
);
132 if res
<> FMOD_OK
then
134 e_WriteLog('Error creating FMOD system:', MSG_FATALERROR
);
135 e_WriteLog(FMOD_ErrorString(res
), MSG_FATALERROR
);
139 res
:= FMOD_System_GetVersion(F_System
, ver
);
140 if res
<> FMOD_OK
then
142 e_WriteLog('Error getting FMOD version:', MSG_FATALERROR
);
143 e_WriteLog(FMOD_ErrorString(res
), MSG_FATALERROR
);
147 if ver
< FMOD_VERSION
then
149 e_WriteLog('FMOD DLL version is too old! Need '+IntToStr(FMOD_VERSION
), MSG_FATALERROR
);
153 res
:= FMOD_System_SetSoftwareFormat(F_System
, Freq
,
154 FMOD_SOUND_FORMAT_PCM16
, 0, 0, FMOD_DSP_RESAMPLER_LINEAR
);
155 if res
<> FMOD_OK
then
157 e_WriteLog('Error setting FMOD software format!', MSG_FATALERROR
);
158 e_WriteLog(FMOD_ErrorString(res
), MSG_FATALERROR
);
162 res
:= FMOD_System_Init(F_System
, N_CHANNELS
, FMOD_INIT_NORMAL
, nil);
163 if res
<> FMOD_OK
then
165 e_WriteLog('Error initializing FMOD system!', MSG_WARNING
);
166 e_WriteLog(FMOD_ErrorString(res
), MSG_WARNING
);
167 e_WriteLog('Trying with OUTPUTTYPE_NOSOUND...', MSG_WARNING
);
168 res
:= FMOD_System_SetOutput(F_System
, FMOD_OUTPUTTYPE_NOSOUND
);
169 if res
<> FMOD_OK
then
171 e_WriteLog('Error setting FMOD output to NOSOUND!', MSG_FATALERROR
);
172 e_WriteLog(FMOD_ErrorString(res
), MSG_FATALERROR
);
175 res
:= FMOD_System_Init(F_System
, N_CHANNELS
, FMOD_INIT_NORMAL
, nil);
176 if res
<> FMOD_OK
then
178 e_WriteLog('Error initializing FMOD system!', MSG_FATALERROR
);
179 e_WriteLog(FMOD_ErrorString(res
), MSG_FATALERROR
);
184 res
:= FMOD_System_GetOutput(F_System
, output
);
185 if res
<> FMOD_OK
then
186 e_WriteLog('Error getting FMOD output!', MSG_WARNING
)
189 FMOD_OUTPUTTYPE_NOSOUND
: e_WriteLog('FMOD Output Method: NOSOUND', MSG_NOTIFY
);
190 FMOD_OUTPUTTYPE_NOSOUND_NRT
: e_WriteLog('FMOD Output Method: NOSOUND_NRT', MSG_NOTIFY
);
191 FMOD_OUTPUTTYPE_DSOUND
: e_WriteLog('FMOD Output Method: DSOUND', MSG_NOTIFY
);
192 FMOD_OUTPUTTYPE_WINMM
: e_WriteLog('FMOD Output Method: WINMM', MSG_NOTIFY
);
193 FMOD_OUTPUTTYPE_OPENAL
: e_WriteLog('FMOD Output Method: OPENAL', MSG_NOTIFY
);
194 FMOD_OUTPUTTYPE_WASAPI
: e_WriteLog('FMOD Output Method: WASAPI', MSG_NOTIFY
);
195 FMOD_OUTPUTTYPE_ASIO
: e_WriteLog('FMOD Output Method: ASIO', MSG_NOTIFY
);
196 else e_WriteLog('FMOD Output Method: Unknown', MSG_NOTIFY
);
199 res
:= FMOD_System_GetDriver(F_System
, drv
);
200 if res
<> FMOD_OK
then
201 e_WriteLog('Error getting FMOD driver!', MSG_WARNING
)
204 {res := FMOD_System_GetDriverName(F_System, drv, str, 64);
205 if res <> FMOD_OK then
206 e_WriteLog('Error getting FMOD driver name!', MSG_WARNING)
208 e_WriteLog('FMOD driver id: '+IntToStr(drv
), MSG_NOTIFY
);
214 function FindESound(): DWORD
;
219 if e_SoundsArray
<> nil then
220 for i
:= 0 to High(e_SoundsArray
) do
221 if e_SoundsArray
[i
].Sound
= nil then
227 if e_SoundsArray
= nil then
229 SetLength(e_SoundsArray
, 16);
234 Result
:= High(e_SoundsArray
) + 1;
235 SetLength(e_SoundsArray
, Length(e_SoundsArray
) + 16);
239 function e_LoadSound(FileName
: String; var ID
: DWORD
; bLoop
: Boolean): Boolean;
249 e_WriteLog('Loading sound '+FileName
+'...', MSG_NOTIFY
);
251 find_id
:= FindESound();
254 bt
:= FMOD_LOOP_NORMAL
259 res
:= FMOD_System_CreateSound(F_System
, PAnsiChar(FileName
),
260 bt
+ FMOD_2D
+ FMOD_HARDWARE
,
261 nil, e_SoundsArray
[find_id
].Sound
)
263 res
:= FMOD_System_CreateStream(F_System
, PAnsiChar(FileName
),
264 bt
+ FMOD_2D
+ FMOD_HARDWARE
,
265 nil, e_SoundsArray
[find_id
].Sound
);
266 if res
<> FMOD_OK
then
268 e_SoundsArray
[find_id
].Sound
:= nil;
272 GetMem(ud
, SizeOf(DWORD
));
273 DWORD(ud
^) := find_id
;
274 res
:= FMOD_Sound_SetUserData(e_SoundsArray
[find_id
].Sound
, ud
);
275 if res
<> FMOD_OK
then
277 e_SoundsArray
[find_id
].Sound
:= nil;
281 e_SoundsArray
[find_id
].Data
:= nil;
282 e_SoundsArray
[find_id
].Loop
:= bLoop
;
283 e_SoundsArray
[find_id
].nRefs
:= 0;
290 function e_LoadSoundMem(pData
: Pointer; Length
: Integer; var ID
: DWORD
; bLoop
: Boolean): Boolean;
296 soundExInfo
: FMOD_CREATESOUNDEXINFO
;
302 find_id
:= FindESound();
304 sz
:= SizeOf(FMOD_CREATESOUNDEXINFO
);
305 FillMemory(@soundExInfo
, sz
, 0);
306 soundExInfo
.cbsize
:= sz
;
307 soundExInfo
.length
:= Length
;
310 bt
:= FMOD_LOOP_NORMAL
315 res
:= FMOD_System_CreateSound(F_System
, pData
,
316 bt
+ FMOD_2D
+ FMOD_HARDWARE
+ FMOD_OPENMEMORY
,
317 @soundExInfo
, e_SoundsArray
[find_id
].Sound
)
319 res
:= FMOD_System_CreateStream(F_System
, pData
,
320 bt
+ FMOD_2D
+ FMOD_HARDWARE
+ FMOD_OPENMEMORY
,
321 @soundExInfo
, e_SoundsArray
[find_id
].Sound
);
322 if res
<> FMOD_OK
then
324 e_SoundsArray
[find_id
].Sound
:= nil;
328 GetMem(ud
, SizeOf(DWORD
));
329 DWORD(ud
^) := find_id
;
330 res
:= FMOD_Sound_SetUserData(e_SoundsArray
[find_id
].Sound
, ud
);
331 if res
<> FMOD_OK
then
333 e_SoundsArray
[find_id
].Sound
:= nil;
337 e_SoundsArray
[find_id
].Data
:= pData
;
338 e_SoundsArray
[find_id
].Loop
:= bLoop
;
339 e_SoundsArray
[find_id
].nRefs
:= 0;
346 function e_PlaySound(ID
: DWORD
): Boolean;
352 if e_SoundsArray
[ID
].nRefs
>= gMaxSimSounds
then
360 res
:= FMOD_System_PlaySound(F_System
, FMOD_CHANNEL_FREE
,
361 e_SoundsArray
[ID
].Sound
, False, Chan
);
362 if res
<> FMOD_OK
then
367 res
:= FMOD_Channel_SetCallback(Chan
, Channel_Callback
);
368 if res
<> FMOD_OK
then
374 res
:= FMOD_Channel_SetMute(Chan
, True);
375 if res
<> FMOD_OK
then
380 Inc(e_SoundsArray
[ID
].nRefs
);
384 function e_PlaySoundPan(ID
: DWORD
; Pan
: Single): Boolean;
390 if e_SoundsArray
[ID
].nRefs
>= gMaxSimSounds
then
398 res
:= FMOD_System_PlaySound(F_System
, FMOD_CHANNEL_FREE
,
399 e_SoundsArray
[ID
].Sound
, False, Chan
);
400 if res
<> FMOD_OK
then
405 res
:= FMOD_Channel_SetPan(Chan
, Pan
);
406 if res
<> FMOD_OK
then
410 res
:= FMOD_Channel_SetCallback(Chan
, Channel_Callback
);
411 if res
<> FMOD_OK
then
417 res
:= FMOD_Channel_SetMute(Chan
, True);
418 if res
<> FMOD_OK
then
423 Inc(e_SoundsArray
[ID
].nRefs
);
427 function e_PlaySoundVolume(ID
: DWORD
; Volume
: Single): Boolean;
433 if e_SoundsArray
[ID
].nRefs
>= gMaxSimSounds
then
441 res
:= FMOD_System_PlaySound(F_System
, FMOD_CHANNEL_FREE
,
442 e_SoundsArray
[ID
].Sound
, False, Chan
);
443 if res
<> FMOD_OK
then
448 res
:= FMOD_Channel_SetVolume(Chan
, Volume
);
449 if res
<> FMOD_OK
then
453 res
:= FMOD_Channel_SetCallback(Chan
, Channel_Callback
);
454 if res
<> FMOD_OK
then
460 res
:= FMOD_Channel_SetMute(Chan
, True);
461 if res
<> FMOD_OK
then
466 Inc(e_SoundsArray
[ID
].nRefs
);
470 function e_PlaySoundPanVolume(ID
: DWORD
; Pan
, Volume
: Single): Boolean;
476 if e_SoundsArray
[ID
].nRefs
>= gMaxSimSounds
then
484 res
:= FMOD_System_PlaySound(F_System
, FMOD_CHANNEL_FREE
,
485 e_SoundsArray
[ID
].Sound
, False, Chan
);
486 if res
<> FMOD_OK
then
491 res
:= FMOD_Channel_SetPan(Chan
, Pan
);
492 if res
<> FMOD_OK
then
496 res
:= FMOD_Channel_SetVolume(Chan
, Volume
);
497 if res
<> FMOD_OK
then
501 res
:= FMOD_Channel_SetCallback(Chan
, Channel_Callback
);
502 if res
<> FMOD_OK
then
508 res
:= FMOD_Channel_SetMute(Chan
, True);
509 if res
<> FMOD_OK
then
514 Inc(e_SoundsArray
[ID
].nRefs
);
518 procedure e_DeleteSound(ID
: DWORD
);
524 if e_SoundsArray
[ID
].Sound
= nil then
527 if e_SoundsArray
[ID
].Data
<> nil then
528 FreeMem(e_SoundsArray
[ID
].Data
);
530 res
:= FMOD_Sound_GetUserData(e_SoundsArray
[ID
].Sound
, ud
);
531 if res
= FMOD_OK
then
536 res
:= FMOD_Sound_Release(e_SoundsArray
[ID
].Sound
);
537 if res
<> FMOD_OK
then
539 e_WriteLog('Error releasing sound:', MSG_WARNING
);
540 e_WriteLog(FMOD_ErrorString(res
), MSG_WARNING
);
543 e_SoundsArray
[ID
].Sound
:= nil;
544 e_SoundsArray
[ID
].Data
:= nil;
547 procedure e_ModifyChannelsVolumes(SoundMod
: Single; setMode
: Boolean);
555 for i
:= 0 to N_CHANNELS
-1 do
558 res
:= FMOD_System_GetChannel(F_System
, i
, Chan
);
560 if (res
= FMOD_OK
) and (Chan
<> nil) then
562 res
:= FMOD_Channel_GetVolume(Chan
, vol
);
564 if res
= FMOD_OK
then
569 vol
:= vol
* SoundMod
;
571 res
:= FMOD_Channel_SetVolume(Chan
, vol
);
573 if res
<> FMOD_OK
then
581 procedure e_MuteChannels(Enable
: Boolean);
588 if Enable
= SoundMuted
then
591 SoundMuted
:= Enable
;
593 for i
:= 0 to N_CHANNELS
-1 do
596 res
:= FMOD_System_GetChannel(F_System
, i
, Chan
);
598 if (res
= FMOD_OK
) and (Chan
<> nil) then
600 res
:= FMOD_Channel_SetMute(Chan
, Enable
);
602 if res
<> FMOD_OK
then
609 procedure e_StopChannels();
616 for i
:= 0 to N_CHANNELS
-1 do
619 res
:= FMOD_System_GetChannel(F_System
, i
, Chan
);
621 if (res
= FMOD_OK
) and (Chan
<> nil) then
623 res
:= FMOD_Channel_Stop(Chan
);
625 if res
<> FMOD_OK
then
632 procedure e_RemoveAllSounds();
637 for i
:= 0 to High(e_SoundsArray
) do
638 if e_SoundsArray
[i
].Sound
<> nil then
641 SetLength(e_SoundsArray
, 0);
642 e_SoundsArray
:= nil;
645 procedure e_ReleaseSoundSystem();
652 res
:= FMOD_System_Close(F_System
);
653 if res
<> FMOD_OK
then
655 e_WriteLog('Error closing FMOD system!', MSG_FATALERROR
);
656 e_WriteLog(FMOD_ErrorString(res
), MSG_FATALERROR
);
660 res
:= FMOD_System_Release(F_System
);
661 if res
<> FMOD_OK
then
663 e_WriteLog('Error releasing FMOD system!', MSG_FATALERROR
);
664 e_WriteLog(FMOD_ErrorString(res
), MSG_FATALERROR
);
668 procedure e_SoundUpdate();
670 FMOD_System_Update(F_System
);
675 constructor TBasicSound
.Create();
684 destructor TBasicSound
.Destroy();
690 procedure TBasicSound
.FreeSound();
692 if FID
= NO_SOUND_ID
then
701 function TBasicSound
.RawPlay(Pan
: Single; Volume
: Single; aPos
: DWORD
): Boolean;
706 if e_SoundsArray
[FID
].nRefs
>= gMaxSimSounds
then
714 if FID
= NO_SOUND_ID
then
717 res
:= FMOD_System_PlaySound(F_System
, FMOD_CHANNEL_FREE
,
718 e_SoundsArray
[FID
].Sound
, False, FChannel
);
719 if res
<> FMOD_OK
then
725 res
:= FMOD_Channel_SetPosition(FChannel
, aPos
, FMOD_TIMEUNIT_MS
);
726 if res
<> FMOD_OK
then
733 res
:= FMOD_Channel_SetPan(FChannel
, Pan
);
734 if res
<> FMOD_OK
then
738 res
:= FMOD_Channel_SetVolume(FChannel
, Volume
);
739 if res
<> FMOD_OK
then
743 res
:= FMOD_Channel_SetCallback(FChannel
, Channel_Callback
);
744 if res
<> FMOD_OK
then
750 res
:= FMOD_Channel_SetMute(FChannel
, True);
751 if res
<> FMOD_OK
then
756 Inc(e_SoundsArray
[FID
].nRefs
);
760 procedure TBasicSound
.SetID(ID
: DWORD
);
764 FLoop
:= e_SoundsArray
[ID
].Loop
;
767 function TBasicSound
.IsPlaying(): Boolean;
775 if FChannel
= nil then
778 res
:= FMOD_Channel_IsPlaying(FChannel
, b
);
779 if res
<> FMOD_OK
then
787 procedure TBasicSound
.Stop();
792 if FChannel
= nil then
797 res
:= FMOD_Channel_Stop(FChannel
);
798 if res
<> FMOD_OK
then
805 function TBasicSound
.IsPaused(): Boolean;
813 if FChannel
= nil then
816 res
:= FMOD_Channel_GetPaused(FChannel
, b
);
817 if res
<> FMOD_OK
then
825 procedure TBasicSound
.Pause(Enable
: Boolean);
830 if FChannel
= nil then
833 res
:= FMOD_Channel_SetPaused(FChannel
, Enable
);
834 if res
<> FMOD_OK
then
840 res
:= FMOD_Channel_GetPosition(FChannel
, FPosition
, FMOD_TIMEUNIT_MS
);
841 if res
<> FMOD_OK
then
847 function TBasicSound
.GetVolume(): Single;
855 if FChannel
= nil then
858 res
:= FMOD_Channel_GetVolume(FChannel
, vol
);
859 if res
<> FMOD_OK
then
867 procedure TBasicSound
.SetVolume(Volume
: Single);
872 if FChannel
= nil then
875 res
:= FMOD_Channel_SetVolume(FChannel
, Volume
);
876 if res
<> FMOD_OK
then
881 function TBasicSound
.GetPan(): Single;
889 if FChannel
= nil then
892 res
:= FMOD_Channel_GetPan(FChannel
, pan
);
893 if res
<> FMOD_OK
then
901 procedure TBasicSound
.SetPan(Pan
: Single);
906 if FChannel
= nil then
909 res
:= FMOD_Channel_SetPan(FChannel
, Pan
);
910 if res
<> FMOD_OK
then
915 function TBasicSound
.IsMuted(): Boolean;
923 if FChannel
= nil then
926 res
:= FMOD_Channel_GetMute(FChannel
, b
);
927 if res
<> FMOD_OK
then
935 procedure TBasicSound
.Mute(Enable
: Boolean);
940 if FChannel
= nil then
943 res
:= FMOD_Channel_SetMute(FChannel
, Enable
);
944 if res
<> FMOD_OK
then
949 function TBasicSound
.GetPosition(): DWORD
;
956 if FChannel
= nil then
959 res
:= FMOD_Channel_GetPosition(FChannel
, FPosition
, FMOD_TIMEUNIT_MS
);
960 if res
<> FMOD_OK
then
968 procedure TBasicSound
.SetPosition(aPos
: DWORD
);
975 if FChannel
= nil then
978 res
:= FMOD_Channel_SetPosition(FChannel
, FPosition
, FMOD_TIMEUNIT_MS
);
979 if res
<> FMOD_OK
then
984 procedure TBasicSound
.SetPriority(priority
: Integer);
989 if (FChannel
<> nil) and (FPriority
<> priority
) and
990 (priority
>= 0) and (priority
<= 256) then
992 FPriority
:= priority
;
993 res
:= FMOD_Channel_SetPriority(FChannel
, priority
);
994 if res
<> FMOD_OK
then