GLS.Sounds.FMOD.pas 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339
  1. //
  2. // The graphics engine GLXEngine. The unit of GLScene for Delphi
  3. //
  4. unit GLS.Sounds.FMOD;
  5. (*
  6. FMOD based sound-manager (http://www.fmod.org/, free for freeware).
  7. Unsupported feature(s) :
  8. sound source velocity
  9. looping (sounds are played either once or forever)
  10. sound cones
  11. *)
  12. interface
  13. {$I Stage.Defines.inc}
  14. uses
  15. System.Classes,
  16. System.SysUtils,
  17. GLS.SoundManager,
  18. GLS.Scene,
  19. Stage.VectorTypes,
  20. Stage.VectorGeometry,
  21. FMOD.Import,
  22. FMOD.Types,
  23. FMOD.Presets;
  24. type
  25. TGLSMFMOD = class(TGLSoundManager)
  26. private
  27. FActivated: Boolean;
  28. FEAXCapable: Boolean; // not persistent
  29. protected
  30. function DoActivate: Boolean; override;
  31. procedure DoDeActivate; override;
  32. procedure NotifyMasterVolumeChange; override;
  33. procedure Notify3DFactorsChanged; override;
  34. procedure NotifyEnvironmentChanged; override;
  35. procedure KillSource(aSource: TGLBaseSoundSource); override;
  36. procedure UpdateSource(aSource: TGLBaseSoundSource); override;
  37. procedure MuteSource(aSource: TGLBaseSoundSource; muted: Boolean); override;
  38. procedure PauseSource(aSource: TGLBaseSoundSource; paused: Boolean); override;
  39. function GetDefaultFrequency(aSource: TGLBaseSoundSource): Integer;
  40. public
  41. constructor Create(AOwner: TComponent); override;
  42. destructor Destroy; override;
  43. procedure UpdateSources; override;
  44. function CPUUsagePercent: Single; override;
  45. function EAXSupported: Boolean; override;
  46. published
  47. property MaxChannels default 32;
  48. end;
  49. // ---------------------------------------------------------------------
  50. implementation
  51. // ---------------------------------------------------------------------
  52. type
  53. TFMODInfo = record
  54. channel: Integer;
  55. pfs: PFSoundSample;
  56. end;
  57. PFMODInfo = ^TFMODInfo;
  58. procedure VectorToFMODVector(const aVector: TGLVector; var aFMODVector: TFSoundVector);
  59. begin
  60. aFMODVector.X := aVector.X;
  61. aFMODVector.Y := aVector.Y;
  62. aFMODVector.Z := -aVector.Z;
  63. end;
  64. // ------------------
  65. // ------------------ TGLSMFMOD ------------------
  66. // ------------------
  67. constructor TGLSMFMOD.Create(AOwner: TComponent);
  68. begin
  69. inherited Create(AOwner);
  70. MaxChannels := 32;
  71. end;
  72. destructor TGLSMFMOD.Destroy;
  73. begin
  74. inherited Destroy;
  75. end;
  76. function TGLSMFMOD.DoActivate: Boolean;
  77. var
  78. cap: Cardinal;
  79. begin
  80. FMOD_Load(nil);
  81. {$IFDEF MSWINDOWS}
  82. if not FSOUND_SetOutput(FSOUND_OUTPUT_DSOUND) then
  83. begin
  84. Result := False;
  85. Exit;
  86. end;
  87. {$ENDIF}
  88. {$IFDEF LINUX}
  89. if not FSOUND_SetOutput(FSOUND_OUTPUT_ALSA) then
  90. begin
  91. Result := False;
  92. Exit;
  93. end;
  94. {$ENDIF}
  95. if not FSOUND_SetDriver(0) then
  96. begin
  97. Result := False;
  98. Exit;
  99. end;
  100. cap := 0;
  101. if FSOUND_GetDriverCaps(0, cap) then
  102. FEAXCapable := ((cap and (FSOUND_CAPS_EAX2 or FSOUND_CAPS_EAX3)) > 0)
  103. else
  104. Assert(False, 'Failed to retrieve driver Caps.');
  105. if not FSOUND_Init(OutputFrequency, MaxChannels, 0) then
  106. Assert(False, 'FSOUND_Init failed.');
  107. FActivated := True;
  108. NotifyMasterVolumeChange;
  109. Notify3DFactorsChanged;
  110. if Environment <> seDefault then
  111. NotifyEnvironmentChanged;
  112. Result := True;
  113. end;
  114. procedure TGLSMFMOD.DoDeActivate;
  115. begin
  116. FSOUND_StopSound(FSOUND_ALL);
  117. FSOUND_Close;
  118. FMOD_Unload;
  119. FEAXCapable := False;
  120. end;
  121. procedure TGLSMFMOD.NotifyMasterVolumeChange;
  122. begin
  123. if FActivated then
  124. FSOUND_SetSFXMasterVolume(Round(MasterVolume * 255));
  125. end;
  126. procedure TGLSMFMOD.Notify3DFactorsChanged;
  127. begin
  128. if FActivated then
  129. begin
  130. FSOUND_3D_SetDistanceFactor(DistanceFactor);
  131. FSOUND_3D_SetRolloffFactor(RollOffFactor);
  132. FSOUND_3D_SetDopplerFactor(DopplerFactor);
  133. end;
  134. end;
  135. procedure TGLSMFMOD.NotifyEnvironmentChanged;
  136. var
  137. SoundRevProps: TFSoundReverbProperties;
  138. begin
  139. if FActivated and EAXSupported then
  140. begin
  141. case Environment of
  142. seDefault : SoundRevProps := FSOUND_PRESET_GENERIC;
  143. sePaddedCell : SoundRevProps := FSOUND_PRESET_PADDEDCELL;
  144. seRoom : SoundRevProps := FSOUND_PRESET_ROOM;
  145. seBathroom : SoundRevProps := FSOUND_PRESET_BATHROOM;
  146. seLivingRoom : SoundRevProps := FSOUND_PRESET_LIVINGROOM;
  147. seStoneroom : SoundRevProps := FSOUND_PRESET_STONEROOM;
  148. seAuditorium : SoundRevProps := FSOUND_PRESET_AUDITORIUM;
  149. seConcertHall : SoundRevProps := FSOUND_PRESET_CONCERTHALL;
  150. seCave : SoundRevProps := FSOUND_PRESET_CAVE;
  151. seArena : SoundRevProps := FSOUND_PRESET_ARENA;
  152. seHangar : SoundRevProps := FSOUND_PRESET_HANGAR;
  153. seCarpetedHallway : SoundRevProps := FSOUND_PRESET_CARPETTEDHALLWAY;
  154. seHallway : SoundRevProps := FSOUND_PRESET_HALLWAY;
  155. seStoneCorridor : SoundRevProps := FSOUND_PRESET_STONECORRIDOR;
  156. seAlley : SoundRevProps := FSOUND_PRESET_ALLEY;
  157. seForest : SoundRevProps := FSOUND_PRESET_FOREST;
  158. seCity : SoundRevProps := FSOUND_PRESET_CITY;
  159. seMountains : SoundRevProps := FSOUND_PRESET_MOUNTAINS;
  160. seQuarry : SoundRevProps := FSOUND_PRESET_QUARRY;
  161. sePlain : SoundRevProps := FSOUND_PRESET_PLAIN;
  162. seParkingLot : SoundRevProps := FSOUND_PRESET_PARKINGLOT;
  163. seSewerPipe : SoundRevProps := FSOUND_PRESET_SEWERPIPE;
  164. seUnderWater : SoundRevProps := FSOUND_PRESET_UNDERWATER;
  165. seDrugged : SoundRevProps := FSOUND_PRESET_DRUGGED;
  166. seDizzy : SoundRevProps := FSOUND_PRESET_DIZZY;
  167. sePsychotic : SoundRevProps := FSOUND_PRESET_PSYCHOTIC;
  168. else
  169. Assert(False);
  170. end;
  171. FSOUND_Reverb_SetProperties(SoundRevProps);
  172. end;
  173. end;
  174. procedure TGLSMFMOD.KillSource(aSource: TGLBaseSoundSource);
  175. var
  176. p: PFMODInfo;
  177. begin
  178. if aSource.ManagerTag <> 0 then
  179. begin
  180. p := PFMODInfo(aSource.ManagerTag);
  181. aSource.ManagerTag := 0;
  182. if p.channel <> -1 then
  183. if not FSOUND_StopSound(p.channel) then
  184. Assert(False, IntToStr(Integer(p)));
  185. FSOUND_Sample_Free(p.pfs);
  186. FreeMem(p);
  187. end;
  188. end;
  189. procedure TGLSMFMOD.UpdateSource(aSource: TGLBaseSoundSource);
  190. var
  191. p: PFMODInfo;
  192. objPos, objVel: TGLVector;
  193. position, velocity: TFSoundVector;
  194. begin
  195. if (sscSample in aSource.Changes) then
  196. begin
  197. KillSource(aSource);
  198. end;
  199. if (aSource.Sample = nil) or (aSource.Sample.Data = nil) or (aSource.Sample.Data.WAVDataSize = 0) then
  200. Exit;
  201. if aSource.ManagerTag <> 0 then
  202. begin
  203. p := PFMODInfo(aSource.ManagerTag);
  204. if not FSOUND_IsPlaying(p.channel) then
  205. begin
  206. p.channel := -1;
  207. aSource.Free;
  208. Exit;
  209. end;
  210. end
  211. else
  212. begin
  213. p := AllocMem(SizeOf(TFMODInfo));
  214. p.channel := -1;
  215. p.pfs := FSOUND_Sample_Load(FSOUND_FREE, aSource.Sample.Data.WAVData, FSOUND_HW3D + FSOUND_LOOP_OFF + FSOUND_LOADMEMORY, 0,
  216. aSource.Sample.Data.WAVDataSize);
  217. if aSource.NbLoops > 1 then
  218. FSOUND_Sample_SetMode(p.pfs, FSOUND_LOOP_NORMAL);
  219. FSOUND_Sample_SetMinMaxDistance(p.pfs, aSource.MinDistance, aSource.MaxDistance);
  220. aSource.ManagerTag := Integer(p);
  221. end;
  222. if aSource.Origin <> nil then
  223. begin
  224. objPos := aSource.Origin.AbsolutePosition;
  225. objVel := NullHmgVector;
  226. end
  227. else
  228. begin
  229. objPos := NullHmgPoint;
  230. objVel := NullHmgVector;
  231. end;
  232. VectorToFMODVector(objPos, position);
  233. VectorToFMODVector(objVel, velocity);
  234. if p.channel = -1 then
  235. p.channel := FSOUND_PlaySound(FSOUND_FREE, p.pfs);
  236. if p.channel <> -1 then
  237. begin
  238. FSOUND_3D_SetAttributes(p.channel, @position, @velocity);
  239. FSOUND_SetVolume(p.channel, Round(aSource.Volume * 255));
  240. FSOUND_SetMute(p.channel, aSource.Mute);
  241. FSOUND_SetPaused(p.channel, aSource.Pause);
  242. FSOUND_SetPriority(p.channel, aSource.Priority);
  243. if aSource.Frequency > 0 then
  244. FSOUND_SetFrequency(p.channel, aSource.Frequency);
  245. end
  246. else
  247. aSource.Free;
  248. inherited UpdateSource(aSource);
  249. end;
  250. procedure TGLSMFMOD.MuteSource(aSource: TGLBaseSoundSource; muted: Boolean);
  251. var
  252. p: PFMODInfo;
  253. begin
  254. if aSource.ManagerTag <> 0 then
  255. begin
  256. p := PFMODInfo(aSource.ManagerTag);
  257. FSOUND_SetMute(p.channel, muted);
  258. end;
  259. end;
  260. procedure TGLSMFMOD.PauseSource(aSource: TGLBaseSoundSource; paused: Boolean);
  261. var
  262. p: PFMODInfo;
  263. begin
  264. if aSource.ManagerTag <> 0 then
  265. begin
  266. p := PFMODInfo(aSource.ManagerTag);
  267. FSOUND_SetPaused(p.channel, paused);
  268. end;
  269. end;
  270. procedure TGLSMFMOD.UpdateSources;
  271. var
  272. objPos, objVel, objDir, objUp: TGLVector;
  273. position, velocity, fwd, top: TFSoundVector;
  274. begin
  275. // update listener
  276. ListenerCoordinates(objPos, objVel, objDir, objUp);
  277. VectorToFMODVector(objPos, position);
  278. VectorToFMODVector(objVel, velocity);
  279. VectorToFMODVector(objDir, fwd);
  280. VectorToFMODVector(objUp, top);
  281. FSOUND_3D_Listener_SetAttributes(@position, @velocity, fwd.x, fwd.y, fwd.z, top.x, top.y, top.z);
  282. // update sources
  283. inherited;
  284. FSOUND_Update;
  285. end;
  286. function TGLSMFMOD.CPUUsagePercent: Single;
  287. begin
  288. Result := FSOUND_GetCPUUsage;
  289. end;
  290. function TGLSMFMOD.EAXSupported: Boolean;
  291. begin
  292. Result := FEAXCapable;
  293. end;
  294. function TGLSMFMOD.GetDefaultFrequency(aSource: TGLBaseSoundSource): Integer;
  295. var
  296. p: PFMODInfo;
  297. dfreq, dVol, dPan, dPri: Integer;
  298. begin
  299. try
  300. p:=PFMODInfo(aSource.ManagerTag);
  301. FSOUND_Sample_GetDefaults(p.pfs, dFreq, dVol, dPan, dPri);
  302. Result:=dFreq;
  303. except
  304. Result:=-1;
  305. end;
  306. end;
  307. end.