GLSM.BASS.pas 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340
  1. //
  2. // This unit is part of the GLScene Engine, http://glscene.org
  3. //
  4. unit GLSM.BASS;
  5. (*
  6. BASS based sound-manager (http://www.un4seen.com/music/, free for freeware).
  7. Unsupported feature(s) :
  8. sound source velocity
  9. looping (sounds are played either once or forever)
  10. source priorities (not relevant, channels are not limited)
  11. *)
  12. interface
  13. {$I GLScene.inc}
  14. uses
  15. System.Classes,
  16. System.SysUtils,
  17. Vcl.Forms,
  18. GLSound,
  19. GLScene,
  20. GLVectorTypes,
  21. GLVectorGeometry,
  22. Import.BASS;
  23. type
  24. TBASS3DAlgorithm = (algDefault, algOff, algFull, algLight);
  25. TGLSMBASS = class(TGLSoundManager)
  26. private
  27. FActivated: Boolean;
  28. FAlgorithm3D: TBASS3DAlgorithm;
  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;
  39. paused: Boolean); override;
  40. function GetDefaultFrequency(aSource: TGLBaseSoundSource): Integer;
  41. public
  42. constructor Create(AOwner: TComponent); override;
  43. destructor Destroy; override;
  44. procedure UpdateSources; override;
  45. function CPUUsagePercent: Single; override;
  46. function EAXSupported: Boolean; override;
  47. published
  48. property Algorithm3D: TBASS3DAlgorithm read FAlgorithm3D write FAlgorithm3D
  49. default algDefault;
  50. end;
  51. // ---------------------------------------------------------------------
  52. implementation
  53. // ---------------------------------------------------------------------
  54. type
  55. TBASSInfo = record
  56. channel: HCHANNEL;
  57. sample: HSAMPLE;
  58. end;
  59. PBASSInfo = ^TBASSInfo;
  60. procedure VectorToBASSVector(const aVector: TVector;
  61. var aBASSVector: BASS_3DVECTOR);
  62. begin
  63. aBASSVector.x := aVector.x;
  64. aBASSVector.y := aVector.y;
  65. aBASSVector.z := -aVector.z;
  66. end;
  67. // ------------------
  68. // ------------------ TGLSMBASS ------------------
  69. // ------------------
  70. constructor TGLSMBASS.Create(AOwner: TComponent);
  71. begin
  72. inherited Create(AOwner);
  73. BASS_Load(bassdll);
  74. MaxChannels := 32;
  75. end;
  76. destructor TGLSMBASS.Destroy;
  77. begin
  78. inherited Destroy;
  79. BASS_UnLoad;
  80. end;
  81. function TGLSMBASS.DoActivate: Boolean;
  82. const
  83. c3DAlgo: array [algDefault .. algLight] of Integer = (BASS_3DALG_DEFAULT,
  84. BASS_3DALG_OFF, BASS_3DALG_FULL, BASS_3DALG_LIGHT);
  85. begin
  86. Assert(bass_isloaded, 'BASS DLL is not present');
  87. if not BASS_Init(1, OutputFrequency, BASS_DEVICE_3D, Application.Handle, nil)
  88. then
  89. begin
  90. Result := False;
  91. Exit;
  92. end;
  93. if not BASS_Start then
  94. begin
  95. Result := False;
  96. Exit;
  97. end;
  98. FActivated := True;
  99. BASS_SetConfig(BASS_CONFIG_3DALGORITHM, c3DAlgo[FAlgorithm3D]);
  100. NotifyMasterVolumeChange;
  101. Notify3DFactorsChanged;
  102. if Environment <> seDefault then
  103. NotifyEnvironmentChanged;
  104. Result := True;
  105. end;
  106. procedure TGLSMBASS.DoDeActivate;
  107. begin
  108. FActivated := False;
  109. BASS_Stop;
  110. BASS_Free;
  111. end;
  112. procedure TGLSMBASS.NotifyMasterVolumeChange;
  113. begin
  114. if FActivated then
  115. BASS_SetVolume(Round(MasterVolume * 100));
  116. end;
  117. procedure TGLSMBASS.Notify3DFactorsChanged;
  118. begin
  119. if FActivated then
  120. BASS_Set3DFactors(DistanceFactor, RollOffFactor, DopplerFactor);
  121. end;
  122. procedure TGLSMBASS.NotifyEnvironmentChanged;
  123. const
  124. cEnvironmentToBASSConstant: array [seDefault .. sePsychotic] of Integer =
  125. (EAX_ENVIRONMENT_GENERIC, EAX_ENVIRONMENT_PADDEDCELL, EAX_ENVIRONMENT_ROOM,
  126. EAX_ENVIRONMENT_BATHROOM, EAX_ENVIRONMENT_LIVINGROOM,
  127. EAX_ENVIRONMENT_STONEROOM, EAX_ENVIRONMENT_AUDITORIUM,
  128. EAX_ENVIRONMENT_CONCERTHALL, EAX_ENVIRONMENT_CAVE, EAX_ENVIRONMENT_ARENA,
  129. EAX_ENVIRONMENT_HANGAR, EAX_ENVIRONMENT_CARPETEDHALLWAY,
  130. EAX_ENVIRONMENT_HALLWAY, EAX_ENVIRONMENT_STONECORRIDOR,
  131. EAX_ENVIRONMENT_ALLEY, EAX_ENVIRONMENT_FOREST, EAX_ENVIRONMENT_CITY,
  132. EAX_ENVIRONMENT_MOUNTAINS, EAX_ENVIRONMENT_QUARRY, EAX_ENVIRONMENT_PLAIN,
  133. EAX_ENVIRONMENT_PARKINGLOT, EAX_ENVIRONMENT_SEWERPIPE,
  134. EAX_ENVIRONMENT_UNDERWATER, EAX_ENVIRONMENT_DRUGGED, EAX_ENVIRONMENT_DIZZY,
  135. EAX_ENVIRONMENT_PSYCHOTIC);
  136. begin
  137. if FActivated and EAXSupported then
  138. BASS_SetEAXParameters(cEnvironmentToBASSConstant[Environment], -1, -1, -1);
  139. end;
  140. procedure TGLSMBASS.KillSource(aSource: TGLBaseSoundSource);
  141. var
  142. p: PBASSInfo;
  143. begin
  144. if aSource.ManagerTag <> 0 then
  145. begin
  146. p := PBASSInfo(aSource.ManagerTag);
  147. if p.channel <> 0 then
  148. if not BASS_ChannelStop(p.channel) then
  149. Assert(False);
  150. BASS_SampleFree(p.sample);
  151. FreeMem(p);
  152. aSource.ManagerTag := 0;
  153. end;
  154. end;
  155. procedure TGLSMBASS.UpdateSource(aSource: TGLBaseSoundSource);
  156. var
  157. i: Integer;
  158. p: PBASSInfo;
  159. objPos, objOri, objVel: TVector;
  160. position, orientation, velocity: BASS_3DVECTOR;
  161. res: Boolean;
  162. begin
  163. if (sscSample in aSource.Changes) then
  164. begin
  165. KillSource(aSource);
  166. end;
  167. if (aSource.sample = nil) or (aSource.sample.Data = nil) or
  168. (aSource.sample.Data.WAVDataSize = 0) then
  169. Exit;
  170. if aSource.ManagerTag <> 0 then
  171. begin
  172. p := PBASSInfo(aSource.ManagerTag);
  173. if BASS_ChannelIsActive(p.channel) = 0 then
  174. begin
  175. p.channel := 0;
  176. aSource.Free;
  177. Exit;
  178. end;
  179. end
  180. else
  181. begin
  182. p := AllocMem(SizeOf(TBASSInfo));
  183. p.channel := 0;
  184. i := BASS_SAMPLE_VAM + BASS_SAMPLE_3D + BASS_SAMPLE_OVER_DIST;
  185. if aSource.NbLoops > 1 then
  186. i := i + BASS_SAMPLE_LOOP;
  187. p.sample := BASS_SampleLoad(True, aSource.sample.Data.WAVData, 0,
  188. aSource.sample.Data.WAVDataSize, MaxChannels, i);
  189. Assert(p.sample <> 0, 'BASS Error ' + IntToStr(Integer(BASS_ErrorGetCode)));
  190. aSource.ManagerTag := Integer(p);
  191. if aSource.Frequency <= 0 then
  192. aSource.Frequency := -1;
  193. end;
  194. if aSource.Origin <> nil then
  195. begin
  196. objPos := aSource.Origin.AbsolutePosition;
  197. objOri := aSource.Origin.AbsoluteZVector;
  198. objVel := NullHmgVector;
  199. end
  200. else
  201. begin
  202. objPos := NullHmgPoint;
  203. objOri := ZHmgVector;
  204. objVel := NullHmgVector;
  205. end;
  206. VectorToBASSVector(objPos, position);
  207. VectorToBASSVector(objVel, velocity);
  208. VectorToBASSVector(objOri, orientation);
  209. if p.channel = 0 then
  210. begin
  211. p.channel := BASS_SampleGetChannel(p.sample, False);
  212. Assert(p.channel <> 0);
  213. BASS_ChannelSet3DPosition(p.channel, position, orientation, velocity);
  214. BASS_ChannelSet3DAttributes(p.channel, BASS_3DMODE_NORMAL,
  215. aSource.MinDistance, aSource.MaxDistance, Round(aSource.InsideConeAngle),
  216. Round(aSource.OutsideConeAngle), Round(aSource.ConeOutsideVolume * 100));
  217. if not aSource.Pause then
  218. BASS_ChannelPlay(p.channel, True);
  219. end
  220. else
  221. BASS_ChannelSet3DPosition(p.channel, position, orientation, velocity);
  222. if p.channel <> 0 then
  223. begin
  224. res := BASS_ChannelSetAttribute(p.channel, BASS_ATTRIB_FREQ, 0);
  225. Assert(res);
  226. if aSource.Mute then
  227. res := BASS_ChannelSetAttribute(p.channel, BASS_ATTRIB_VOL, 0)
  228. else
  229. res := BASS_ChannelSetAttribute(p.channel, BASS_ATTRIB_VOL,
  230. aSource.Volume);
  231. Assert(res);
  232. end
  233. else
  234. aSource.Free;
  235. inherited UpdateSource(aSource);
  236. end;
  237. procedure TGLSMBASS.MuteSource(aSource: TGLBaseSoundSource; muted: Boolean);
  238. var
  239. p: PBASSInfo;
  240. res: Boolean;
  241. begin
  242. if aSource.ManagerTag <> 0 then
  243. begin
  244. p := PBASSInfo(aSource.ManagerTag);
  245. if muted then
  246. res := BASS_ChannelSetAttribute(p.channel, BASS_ATTRIB_VOL, 0)
  247. else
  248. res := BASS_ChannelSetAttribute(p.channel, BASS_ATTRIB_VOL,
  249. aSource.Volume);
  250. Assert(res);
  251. end;
  252. end;
  253. procedure TGLSMBASS.PauseSource(aSource: TGLBaseSoundSource; paused: Boolean);
  254. var
  255. p: PBASSInfo;
  256. begin
  257. if aSource.ManagerTag <> 0 then
  258. begin
  259. p := PBASSInfo(aSource.ManagerTag);
  260. if paused then
  261. BASS_ChannelPause(p.channel)
  262. else
  263. BASS_ChannelPlay(p.channel, False);
  264. end;
  265. end;
  266. procedure TGLSMBASS.UpdateSources;
  267. var
  268. objPos, objVel, objDir, objUp: TVector;
  269. position, velocity, fwd, top: BASS_3DVECTOR;
  270. begin
  271. // update listener
  272. ListenerCoordinates(objPos, objVel, objDir, objUp);
  273. VectorToBASSVector(objPos, position);
  274. VectorToBASSVector(objVel, velocity);
  275. VectorToBASSVector(objDir, fwd);
  276. VectorToBASSVector(objUp, top);
  277. if not BASS_Set3DPosition(position, velocity, fwd, top) then
  278. Assert(False);
  279. // update sources
  280. inherited;
  281. { if not } BASS_Apply3D; { then Assert(False); }
  282. end;
  283. function TGLSMBASS.CPUUsagePercent: Single;
  284. begin
  285. Result := BASS_GetCPU * 100;
  286. end;
  287. function TGLSMBASS.EAXSupported: Boolean;
  288. var
  289. c: Cardinal;
  290. s: Single;
  291. begin
  292. Result := BASS_GetEAXParameters(c, s, s, s);
  293. end;
  294. function TGLSMBASS.GetDefaultFrequency(aSource: TGLBaseSoundSource): Integer;
  295. var
  296. p: PBASSInfo;
  297. sampleInfo: BASS_Sample;
  298. begin
  299. try
  300. p := PBASSInfo(aSource.ManagerTag);
  301. BASS_SampleGetInfo(p.sample, sampleInfo);
  302. Result := sampleInfo.freq;
  303. except
  304. Result := -1;
  305. end;
  306. end;
  307. end.