unit UAudioPlayback_Bass;
interface
{$IFDEF FPC}
{$MODE Delphi}
{$ENDIF}
{$I switches.inc}
uses
Classes,
SysUtils,
UMusic;
implementation
uses
UIni,
UMain,
ULog,
UAudioCore_Bass,
bass;
type
TBassPlaybackStream = class(TAudioPlaybackStream)
private
Handle: HSTREAM;
Loop: boolean;
public
constructor Create(); overload;
constructor Create(stream: HSTREAM); overload;
procedure Reset();
procedure Play(); override;
procedure Pause(); override;
procedure Stop(); override;
procedure Close(); override;
function GetLoop(): boolean; override;
procedure SetLoop(Enabled: boolean); override;
function GetLength(): real; override;
function GetStatus(): TStreamStatus; override;
function GetVolume(): integer; override;
procedure SetVolume(volume: integer); override;
function GetPosition: real;
procedure SetPosition(Time: real);
function IsLoaded(): boolean;
end;
type
TAudioPlayback_Bass = class( TInterfacedObject, IAudioPlayback)
private
MusicStream: TBassPlaybackStream;
function Load(const Filename: string): TBassPlaybackStream;
public
function GetName: String;
{IAudioOutput interface}
function InitializePlayback(): boolean;
procedure SetVolume(Volume: integer);
procedure SetMusicVolume(Volume: integer);
procedure SetLoop(Enabled: boolean);
function Open(const Filename: string): boolean; // true if succeed
procedure Rewind;
procedure Play;
procedure Pause; //Pause Mod
procedure Stop;
procedure Close;
function Finished: boolean;
function Length: real;
function GetPosition: real;
procedure SetPosition(Time: real);
//Equalizer
procedure GetFFTData(var data: TFFTData);
// Interface for Visualizer
function GetPCMData(var data: TPCMData): Cardinal;
// Sounds
function OpenSound(const Filename: String): TAudioPlaybackStream;
procedure PlaySound(stream: TAudioPlaybackStream);
procedure StopSound(stream: TAudioPlaybackStream);
end;
var
singleton_AudioPlaybackBass : IAudioPlayback;
constructor TBassPlaybackStream.Create();
begin
inherited;
Reset();
end;
constructor TBassPlaybackStream.Create(stream: HSTREAM);
begin
Create();
Handle := stream;
end;
procedure TBassPlaybackStream.Reset();
begin
Loop := false;
if (Handle <> 0) then
Bass_StreamFree(Handle);
Handle := 0;
end;
procedure TBassPlaybackStream.Play();
begin
BASS_ChannelPlay(Handle, Loop);
end;
procedure TBassPlaybackStream.Pause();
begin
BASS_ChannelPause(Handle);
end;
procedure TBassPlaybackStream.Stop();
begin
BASS_ChannelStop(Handle);
end;
procedure TBassPlaybackStream.Close();
begin
Reset();
end;
function TBassPlaybackStream.GetVolume(): integer;
begin
Result := 0;
BASS_ChannelSetAttributes(Handle, PInteger(nil)^, Result, PInteger(nil)^);
end;
procedure TBassPlaybackStream.SetVolume(volume: integer);
begin
// clamp volume
if volume < 0 then
volume := 0;
if volume > 100 then
volume := 100;
// set volume
BASS_ChannelSetAttributes(Handle, -1, volume, -101);
end;
function TBassPlaybackStream.GetPosition: real;
var
bytes: integer;
begin
bytes := BASS_ChannelGetPosition(Handle);
Result := BASS_ChannelBytes2Seconds(Handle, bytes);
end;
procedure TBassPlaybackStream.SetPosition(Time: real);
var
bytes: integer;
begin
bytes := BASS_ChannelSeconds2Bytes(Handle, Time);
BASS_ChannelSetPosition(Handle, bytes);
end;
function TBassPlaybackStream.GetLoop(): boolean;
begin
result := Loop;
end;
procedure TBassPlaybackStream.SetLoop(Enabled: boolean);
begin
Loop := Enabled;
end;
function TBassPlaybackStream.GetLength(): real;
var
bytes: integer;
begin
bytes := BASS_ChannelGetLength(Handle);
Result := BASS_ChannelBytes2Seconds(Handle, bytes);
end;
function TBassPlaybackStream.GetStatus(): TStreamStatus;
var
state: DWORD;
begin
state := BASS_ChannelIsActive(Handle);
case state of
BASS_ACTIVE_PLAYING:
result := ssPlaying;
BASS_ACTIVE_PAUSED:
result := ssPaused;
BASS_ACTIVE_STALLED:
result := ssBlocked;
BASS_ACTIVE_STOPPED:
result := ssStopped;
else
result := ssUnknown;
end;
end;
function TBassPlaybackStream.IsLoaded(): boolean;
begin
Result := (Handle <> 0);
end;
function TAudioPlayback_Bass.GetName: String;
begin
result := 'BASS_Playback';
end;
function TAudioPlayback_Bass.InitializePlayback(): boolean;
var
Pet: integer;
S: integer;
begin
result := false;
//Log.BenchmarkStart(4);
//Log.LogStatus('Initializing Playback Subsystem', 'Music Initialize');
if not BASS_Init(1, 44100, 0, 0, nil) then
begin
Log.LogError('Could not initialize BASS', 'Error');
Exit;
end;
//Log.BenchmarkEnd(4); Log.LogBenchmark('--> Bass Init', 4);
// config playing buffer
//BASS_SetConfig(BASS_CONFIG_UPDATEPERIOD, 10);
//BASS_SetConfig(BASS_CONFIG_BUFFER, 100);
result := true;
end;
function TAudioPlayback_Bass.Load(const Filename: string): TBassPlaybackStream;
var
L: Integer;
stream: HSTREAM;
begin
Result := nil;
//Log.LogStatus('Loading Sound: "' + Filename + '"', 'LoadSoundFromFile');
stream := BASS_StreamCreateFile(False, pchar(Filename), 0, 0, 0);
if (stream = 0) then
begin
Log.LogError('Failed to open "' + Filename + '", ' +
TAudioCore_Bass.ErrorGetString(BASS_ErrorGetCode()), 'TAudioPlayback_Bass.Load');
Exit;
end;
Result := TBassPlaybackStream.Create(stream);
end;
procedure TAudioPlayback_Bass.SetVolume(Volume: integer);
begin
//Old Sets Wave Volume
//BASS_SetVolume(Volume);
//New: Sets Volume only for this Application
BASS_SetConfig(BASS_CONFIG_GVOL_SAMPLE, Volume);
BASS_SetConfig(BASS_CONFIG_GVOL_STREAM, Volume);
BASS_SetConfig(BASS_CONFIG_GVOL_MUSIC, Volume);
end;
procedure TAudioPlayback_Bass.SetMusicVolume(Volume: Integer);
begin
if assigned(MusicStream) then
MusicStream.SetVolume(Volume);
end;
procedure TAudioPlayback_Bass.SetLoop(Enabled: boolean);
begin
if assigned(MusicStream) then
MusicStream.Loop := Enabled;
end;
function TAudioPlayback_Bass.Open(const Filename: string): boolean;
var
stream: HSTREAM;
begin
Result := false;
// free old MusicStream
if assigned(MusicStream) then
MusicStream.Free;
MusicStream := Load(Filename);
if not assigned(MusicStream) then
Exit;
//Set Max Volume
SetMusicVolume(100);
Result := true;
end;
procedure TAudioPlayback_Bass.Rewind;
begin
SetPosition(0);
end;
procedure TAudioPlayback_Bass.Play;
begin
if assigned(MusicStream) then
MusicStream.Play();
end;
procedure TAudioPlayback_Bass.Pause;
begin
if assigned(MusicStream) then
MusicStream.Pause();
end;
procedure TAudioPlayback_Bass.Stop;
begin
if assigned(MusicStream) then
MusicStream.Stop();
end;
procedure TAudioPlayback_Bass.Close;
begin
if assigned(MusicStream) then
MusicStream.Close();
end;
function TAudioPlayback_Bass.Length: real;
var
bytes: integer;
begin
if assigned(MusicStream) then
Result := MusicStream.GetLength()
else
Result := -1;
end;
function TAudioPlayback_Bass.GetPosition: real;
begin
if assigned(MusicStream) then
Result := MusicStream.GetPosition()
else
Result := -1;
end;
procedure TAudioPlayback_Bass.SetPosition(Time: real);
begin
if assigned(MusicStream) then
MusicStream.SetPosition(Time);
end;
function TAudioPlayback_Bass.Finished: boolean;
begin
if assigned(MusicStream) then
Result := (MusicStream.GetStatus() = ssStopped)
else
Result := true;
end;
// Equalizer
procedure TAudioPlayback_Bass.GetFFTData(var data: TFFTData);
begin
// Get Channel Data Mono and 256 Values
BASS_ChannelGetData(MusicStream.Handle, @data, BASS_DATA_FFT512);
end;
{*
* Copies interleaved PCM 16bit uint (maybe fake) stereo samples into data.
* Returns the number of frames (= stereo/mono sample)
*}
function TAudioPlayback_Bass.GetPCMData(var data: TPCMData): Cardinal;
var
info: BASS_CHANNELINFO;
nBytes: DWORD;
begin
Result := 0;
// Get Channel Data Mono and 256 Values
BASS_ChannelGetInfo(MusicStream.Handle, info);
FillChar(data, sizeof(TPCMData), 0);
// no support for non-stereo files at the moment
if (info.chans <> 2) then
Exit;
nBytes := BASS_ChannelGetData(MusicStream.Handle, @data, sizeof(TPCMData));
if(nBytes <= 0) then
result := 0
else
result := nBytes div sizeof(TPCMStereoSample);
end;
function TAudioPlayback_Bass.OpenSound(const Filename: string): TAudioPlaybackStream;
begin
result := Load(Filename);
end;
procedure TAudioPlayback_Bass.PlaySound(stream: TAudioPlaybackStream);
begin
if assigned(stream) then
stream.Play();
end;
procedure TAudioPlayback_Bass.StopSound(stream: TAudioPlaybackStream);
begin
if assigned(stream) then
stream.Stop();
end;
initialization
singleton_AudioPlaybackBass := TAudioPlayback_Bass.create();
AudioManager.add( singleton_AudioPlaybackBass );
finalization
AudioManager.Remove( singleton_AudioPlaybackBass );
end.