123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340 |
- //
- // The graphics engine GLXEngine. The unit of GXScene for Delphi
- //
- unit GXS.Sounds.BASS;
- (*
- BASS based sound-manager (http://www.un4seen.com/music/, free for freeware).
- Unsupported feature(s) :
- sound source velocity
- looping (sounds are played either once or forever)
- source priorities (not relevant, channels are not limited)
- *)
- interface
- uses
- Winapi.Windows,
- System.Classes,
- System.SysUtils,
- FMX.Forms,
- Stage.VectorTypes,
- GXS.SoundManager,
- GXS.Scene,
- Stage.VectorGeometry,
- BASS.Import;
- type
- TBASS3DAlgorithm = (algDefault, algOff, algFull, algLight);
- TgxSMBASS = class(TgxSoundManager)
- private
- FActivated: Boolean;
- FAlgorithm3D: TBASS3DAlgorithm;
- protected
- function DoActivate: Boolean; override;
- procedure DoDeActivate; override;
- procedure NotifyMasterVolumeChange; override;
- procedure Notify3DFactorsChanged; override;
- procedure NotifyEnvironmentChanged; override;
- procedure KillSource(aSource: TgxBaseSoundSource); override;
- procedure UpdateSource(aSource: TgxBaseSoundSource); override;
- procedure MuteSource(aSource: TgxBaseSoundSource; muted: Boolean); override;
- procedure PauseSource(aSource: TgxBaseSoundSource;
- paused: Boolean); override;
- function GetDefaultFrequency(aSource: TgxBaseSoundSource): Integer;
- public
- constructor Create(AOwner: TComponent); override;
- destructor Destroy; override;
- procedure UpdateSources; override;
- function CPUUsagePercent: Single; override;
- function EAXSupported: Boolean; override;
- published
- property Algorithm3D: TBASS3DAlgorithm read FAlgorithm3D write FAlgorithm3D
- default algDefault;
- end;
- // ---------------------------------------------------------------------
- implementation
- // ---------------------------------------------------------------------
- type
- TBASSInfo = record
- channel: HCHANNEL;
- sample: HSAMPLE;
- end;
- PBASSInfo = ^TBASSInfo;
- // VectorToBASSVector
- //
- procedure VectorToBASSVector(const aVector: TVector4f;
- var aBASSVector: BASS_3DVECTOR);
- begin
- aBASSVector.x := aVector.x;
- aBASSVector.y := aVector.y;
- aBASSVector.z := -aVector.z;
- end;
- // ------------------
- // ------------------ TgxSMBASS ------------------
- // ------------------
- constructor TgxSMBASS.Create(AOwner: TComponent);
- begin
- inherited Create(AOwner);
- BASS_Load(bassdll);
- MaxChannels := 32;
- end;
- destructor TgxSMBASS.Destroy;
- begin
- inherited Destroy;
- BASS_UnLoad;
- end;
- function TgxSMBASS.DoActivate: Boolean;
- const
- c3DAlgo: array [algDefault .. algLight] of Integer = (BASS_3DALG_DEFAULT,
- BASS_3DALG_OFF, BASS_3DALG_FULL, BASS_3DALG_LIGHT);
- var
- AHWND: HWND;
- begin
- Assert(bass_isloaded, 'BASS DLL is not present');
- if not BASS_Init(1, OutputFrequency, BASS_DEVICE_3D, AHWND, nil) then
- begin
- Result := False;
- Exit;
- end;
- if not BASS_Start then
- begin
- Result := False;
- Exit;
- end;
- FActivated := True;
- BASS_SetConfig(BASS_CONFIG_3DALGORITHM, c3DAlgo[FAlgorithm3D]);
- NotifyMasterVolumeChange;
- Notify3DFactorsChanged;
- if Environment <> seDefault then
- NotifyEnvironmentChanged;
- Result := True;
- end;
- procedure TgxSMBASS.DoDeActivate;
- begin
- FActivated := False;
- BASS_Stop;
- BASS_Free;
- end;
- procedure TgxSMBASS.NotifyMasterVolumeChange;
- begin
- if FActivated then
- BASS_SetVolume(Round(MasterVolume * 100));
- end;
- procedure TgxSMBASS.Notify3DFactorsChanged;
- begin
- if FActivated then
- BASS_Set3DFactors(DistanceFactor, RollOffFactor, DopplerFactor);
- end;
- procedure TgxSMBASS.NotifyEnvironmentChanged;
- const
- cEnvironmentToBASSConstant: array [seDefault .. sePsychotic] of Integer =
- (EAX_ENVIRONMENT_GENERIC, EAX_ENVIRONMENT_PADDEDCELL, EAX_ENVIRONMENT_ROOM,
- EAX_ENVIRONMENT_BATHROOM, EAX_ENVIRONMENT_LIVINGROOM,
- EAX_ENVIRONMENT_STONEROOM, EAX_ENVIRONMENT_AUDITORIUM,
- EAX_ENVIRONMENT_CONCERTHALL, EAX_ENVIRONMENT_CAVE, EAX_ENVIRONMENT_ARENA,
- EAX_ENVIRONMENT_HANGAR, EAX_ENVIRONMENT_CARPETEDHALLWAY,
- EAX_ENVIRONMENT_HALLWAY, EAX_ENVIRONMENT_STONECORRIDOR,
- EAX_ENVIRONMENT_ALLEY, EAX_ENVIRONMENT_FOREST, EAX_ENVIRONMENT_CITY,
- EAX_ENVIRONMENT_MOUNTAINS, EAX_ENVIRONMENT_QUARRY, EAX_ENVIRONMENT_PLAIN,
- EAX_ENVIRONMENT_PARKINGLOT, EAX_ENVIRONMENT_SEWERPIPE,
- EAX_ENVIRONMENT_UNDERWATER, EAX_ENVIRONMENT_DRUGGED, EAX_ENVIRONMENT_DIZZY,
- EAX_ENVIRONMENT_PSYCHOTIC);
- begin
- if FActivated and EAXSupported then
- BASS_SetEAXParameters(cEnvironmentToBASSConstant[Environment], -1, -1, -1);
- end;
- procedure TgxSMBASS.KillSource(aSource: TgxBaseSoundSource);
- var
- p: PBASSInfo;
- begin
- if aSource.ManagerTag <> 0 then
- begin
- p := PBASSInfo(aSource.ManagerTag);
- if p.channel <> 0 then
- if not BASS_ChannelStop(p.channel) then
- Assert(False);
- BASS_SampleFree(p.sample);
- FreeMem(p);
- aSource.ManagerTag := 0;
- end;
- end;
- procedure TgxSMBASS.UpdateSource(aSource: TgxBaseSoundSource);
- var
- i: Integer;
- p: PBASSInfo;
- objPos, objOri, objVel: TVector4f;
- position, orientation, velocity: BASS_3DVECTOR;
- res: Boolean;
- begin
- if (sscSample in aSource.Changes) then
- begin
- KillSource(aSource);
- end;
- if (aSource.sample = nil) or (aSource.sample.Data = nil) or
- (aSource.sample.Data.WAVDataSize = 0) then
- Exit;
- if aSource.ManagerTag <> 0 then
- begin
- p := PBASSInfo(aSource.ManagerTag);
- if BASS_ChannelIsActive(p.channel) = 0 then
- begin
- p.channel := 0;
- aSource.Free;
- Exit;
- end;
- end
- else
- begin
- p := AllocMem(SizeOf(TBASSInfo));
- p.channel := 0;
- i := BASS_SAMPLE_VAM + BASS_SAMPLE_3D + BASS_SAMPLE_OVER_DIST;
- if aSource.NbLoops > 1 then
- i := i + BASS_SAMPLE_LOOP;
- p.sample := BASS_SampleLoad(True, aSource.sample.Data.WAVData, 0,
- aSource.sample.Data.WAVDataSize, MaxChannels, i);
- Assert(p.sample <> 0, 'BASS Error ' + IntToStr(Integer(BASS_ErrorGetCode)));
- aSource.ManagerTag := Integer(p);
- if aSource.Frequency <= 0 then
- aSource.Frequency := -1;
- end;
- if aSource.Origin <> nil then
- begin
- objPos := aSource.Origin.AbsolutePosition;
- objOri := aSource.Origin.AbsoluteZVector;
- objVel := NullHmgVector;
- end
- else
- begin
- objPos := NullHmgPoint;
- objOri := ZHmgVector;
- objVel := NullHmgVector;
- end;
- VectorToBASSVector(objPos, position);
- VectorToBASSVector(objVel, velocity);
- VectorToBASSVector(objOri, orientation);
- if p.channel = 0 then
- begin
- p.channel := BASS_SampleGetChannel(p.sample, False);
- Assert(p.channel <> 0);
- BASS_ChannelSet3DPosition(p.channel, position, orientation, velocity);
- BASS_ChannelSet3DAttributes(p.channel, BASS_3DMODE_NORMAL,
- aSource.MinDistance, aSource.MaxDistance, Round(aSource.InsideConeAngle),
- Round(aSource.OutsideConeAngle), Round(aSource.ConeOutsideVolume * 100));
- if not aSource.Pause then
- BASS_ChannelPlay(p.channel, True);
- end
- else
- BASS_ChannelSet3DPosition(p.channel, position, orientation, velocity);
- if p.channel <> 0 then
- begin
- res := BASS_ChannelSetAttribute(p.channel, BASS_ATTRIB_FREQ, 0);
- Assert(res);
- if aSource.Mute then
- res := BASS_ChannelSetAttribute(p.channel, BASS_ATTRIB_VOL, 0)
- else
- res := BASS_ChannelSetAttribute(p.channel, BASS_ATTRIB_VOL,
- aSource.Volume);
- Assert(res);
- end
- else
- aSource.Free;
- inherited UpdateSource(aSource);
- end;
- procedure TgxSMBASS.MuteSource(aSource: TgxBaseSoundSource; muted: Boolean);
- var
- p: PBASSInfo;
- res: Boolean;
- begin
- if aSource.ManagerTag <> 0 then
- begin
- p := PBASSInfo(aSource.ManagerTag);
- if muted then
- res := BASS_ChannelSetAttribute(p.channel, BASS_ATTRIB_VOL, 0)
- else
- res := BASS_ChannelSetAttribute(p.channel, BASS_ATTRIB_VOL,
- aSource.Volume);
- Assert(res);
- end;
- end;
- procedure TgxSMBASS.PauseSource(aSource: TgxBaseSoundSource; paused: Boolean);
- var
- p: PBASSInfo;
- begin
- if aSource.ManagerTag <> 0 then
- begin
- p := PBASSInfo(aSource.ManagerTag);
- if paused then
- BASS_ChannelPause(p.channel)
- else
- BASS_ChannelPlay(p.channel, False);
- end;
- end;
- procedure TgxSMBASS.UpdateSources;
- var
- objPos, objVel, objDir, objUp: TVector4f;
- position, velocity, fwd, top: BASS_3DVECTOR;
- begin
- // update listener
- ListenerCoordinates(objPos, objVel, objDir, objUp);
- VectorToBASSVector(objPos, position);
- VectorToBASSVector(objVel, velocity);
- VectorToBASSVector(objDir, fwd);
- VectorToBASSVector(objUp, top);
- if not BASS_Set3DPosition(position, velocity, fwd, top) then
- Assert(False);
- // update sources
- inherited;
- { if not } BASS_Apply3D; { then Assert(False); }
- end;
- function TgxSMBASS.CPUUsagePercent: Single;
- begin
- Result := BASS_GetCPU * 100;
- end;
- function TgxSMBASS.EAXSupported: Boolean;
- var
- c: Cardinal;
- s: Single;
- begin
- Result := BASS_GetEAXParameters(c, s, s, s);
- end;
- function TgxSMBASS.GetDefaultFrequency(aSource: TgxBaseSoundSource): Integer;
- var
- p: PBASSInfo;
- sampleInfo: BASS_Sample;
- begin
- try
- p := PBASSInfo(aSource.ManagerTag);
- BASS_SampleGetInfo(p.sample, sampleInfo);
- Result := sampleInfo.freq;
- except
- Result := -1;
- end;
- end;
- end.
|