unit UAudioPlayback_Bass;
interface
{$IFDEF FPC}
{$MODE Delphi}
{$ENDIF}
{$I switches.inc}
uses Classes,
{$IFDEF win32}
windows,
{$ENDIF}
SysUtils,
bass,
ULog,
UMusic;
implementation
uses
{$IFDEF LAZARUS}
lclintf,
{$ENDIF}
URecord,
UIni,
UMain,
UCommon,
UThemes;
type
TBassOutputStream = class(TAudioPlaybackStream)
private
Handle: HSTREAM;
public
constructor Create(); overload;
constructor Create(stream: HSTREAM); overload;
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;
end;
type
TAudioPlayback_Bass = class( TInterfacedObject, IAudioPlayback)
private
MusicStream: HSTREAM;
StartSoundStream: HSTREAM;
BackSoundStream: HSTREAM;
SwooshSoundStream: HSTREAM;
ChangeSoundStream: HSTREAM;
OptionSoundStream: HSTREAM;
ClickSoundStream: HSTREAM;
DrumSoundStream: HSTREAM;
HihatSoundStream: HSTREAM;
ClapSoundStream: HSTREAM;
ShuffleSoundStream: HSTREAM;
//Custom Sounds
CustomSounds: array of TCustomSoundEntry;
Loaded: boolean;
Loop: boolean;
public
function GetName: String;
{IAudioOutput interface}
procedure InitializePlayback;
procedure SetVolume(Volume: integer);
procedure SetMusicVolume(Volume: integer);
procedure SetLoop(Enabled: boolean);
function Open(Name: 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);
procedure PlayStart;
procedure PlayBack;
procedure PlaySwoosh;
procedure PlayChange;
procedure PlayOption;
procedure PlayClick;
procedure PlayDrum;
procedure PlayHihat;
procedure PlayClap;
procedure PlayShuffle;
procedure StopShuffle;
function LoadSoundFromFile(var stream: HSTREAM; Name: string): boolean;
//Equalizer
function GetFFTData: TFFTData;
// Interface for Visualizer
function GetPCMData(var data: TPCMData): Cardinal;
//Custom Sounds
function LoadCustomSound(const Filename: String): Cardinal;
procedure PlayCustomSound(const Index: Cardinal );
end;
var
singleton_AudioPlaybackBass : IAudioPlayback;
constructor TBassOutputStream.Create();
begin
inherited;
end;
constructor TBassOutputStream.Create(stream: HSTREAM);
begin
Create();
Handle := stream;
end;
procedure TBassOutputStream.Play();
begin
BASS_ChannelPlay(Handle, True);
end;
procedure TBassOutputStream.Pause();
begin
//if (Loaded) then
BASS_ChannelPause(Handle);
end;
procedure TBassOutputStream.Stop();
begin
BASS_ChannelStop(Handle);
end;
procedure TBassOutputStream.Close();
begin
Bass_StreamFree(Handle);
end;
function TBassOutputStream.GetLoop(): boolean;
begin
// TODO
result := false;
end;
procedure TBassOutputStream.SetLoop(Enabled: boolean);
begin
// TODO
end;
function TBassOutputStream.GetLength(): real;
var
bytes: integer;
begin
bytes := BASS_ChannelGetLength(Handle);
Result := BASS_ChannelBytes2Seconds(Handle, bytes);
end;
function TBassOutputStream.GetStatus(): TStreamStatus;
var
state: DWORD;
begin
state := BASS_ChannelIsActive(Handle);
case state of
BASS_ACTIVE_PLAYING:
result := sPlaying;
BASS_ACTIVE_PAUSED:
result := sPaused;
else
result := sStopped;
end;
end;
function TAudioPlayback_Bass.GetName: String;
begin
result := 'BASS_Playback';
end;
procedure TAudioPlayback_Bass.InitializePlayback;
var
Pet: integer;
S: integer;
begin
// Log.BenchmarkStart(4);
// Log.LogStatus('Initializing Playback Subsystem', 'Music Initialize');
Loaded := false;
Loop := false;
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);
// Log.LogStatus('Loading Sounds', 'Music Initialize');
// Log.BenchmarkStart(4);
LoadSoundFromFile(StartSoundStream, SoundPath + 'Common Start.mp3');
LoadSoundFromFile(BackSoundStream, SoundPath + 'Common Back.mp3');
LoadSoundFromFile(SwooshSoundStream, SoundPath + 'menu swoosh.mp3');
LoadSoundFromFile(ChangeSoundStream, SoundPath + 'select music change music 50.mp3');
LoadSoundFromFile(OptionSoundStream, SoundPath + 'option change col.mp3');
LoadSoundFromFile(ClickSoundStream, SoundPath + 'rimshot022b.mp3');
// LoadSoundFromFile(DrumSoundStream, SoundPath + 'bassdrumhard076b.mp3');
// LoadSoundFromFile(HihatSoundStream, SoundPath + 'hihatclosed068b.mp3');
// LoadSoundFromFile(ClapSoundStream, SoundPath + 'claps050b.mp3');
// LoadSoundFromFile(ShuffleSoundStream, SoundPath + 'Shuffle.mp3');
// Log.BenchmarkEnd(4);
// Log.LogBenchmark('--> Loading Sounds', 4);
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
//Max Volume Prevention
if Volume > 100 then
Volume := 100;
if Volume < 0 then
Volume := 0;
//Set Volume
BASS_ChannelSetAttributes (MusicStream, -1, Volume, -101);
end;
procedure TAudioPlayback_Bass.SetLoop(Enabled: boolean);
begin
Loop := Enabled;
end;
function TAudioPlayback_Bass.Open(Name: string): boolean;
begin
Loaded := false;
if FileExists(Name) then
begin
MusicStream := Bass_StreamCreateFile(false, pchar(Name), 0, 0, 0);
Loaded := true;
//Set Max Volume
SetMusicVolume (100);
end;
Result := Loaded;
end;
procedure TAudioPlayback_Bass.Rewind;
begin
if Loaded then begin
end;
end;
procedure TAudioPlayback_Bass.SetPosition(Time: real);
var
bytes: integer;
begin
bytes := BASS_ChannelSeconds2Bytes(MusicStream, Time);
BASS_ChannelSetPosition(MusicStream, bytes);
end;
procedure TAudioPlayback_Bass.Play;
begin
if Loaded then
begin
if Loop then
BASS_ChannelPlay(MusicStream, True); // start from beginning... actually bass itself does not loop, nor does this TAudio_bass Class
BASS_ChannelPlay(MusicStream, False); // for setting position before playing
end;
end;
procedure TAudioPlayback_Bass.Pause; //Pause Mod
begin
if Loaded then begin
BASS_ChannelPause(MusicStream); // Pauses Song
end;
end;
procedure TAudioPlayback_Bass.Stop;
begin
Bass_ChannelStop(MusicStream);
end;
procedure TAudioPlayback_Bass.Close;
begin
Bass_StreamFree(MusicStream);
end;
function TAudioPlayback_Bass.Length: real;
var
bytes: integer;
begin
bytes := BASS_ChannelGetLength(MusicStream);
Result := BASS_ChannelBytes2Seconds(MusicStream, bytes);
end;
function TAudioPlayback_Bass.getPosition: real;
var
bytes: integer;
begin
bytes := BASS_ChannelGetPosition(MusicStream);
Result := BASS_ChannelBytes2Seconds(MusicStream, bytes);
end;
function TAudioPlayback_Bass.Finished: boolean;
begin
Result := false;
if BASS_ChannelIsActive(MusicStream) = BASS_ACTIVE_STOPPED then
begin
Result := true;
end;
end;
procedure TAudioPlayback_Bass.PlayStart;
begin
BASS_ChannelPlay(StartSoundStream, True);
end;
procedure TAudioPlayback_Bass.PlayBack;
begin
BASS_ChannelPlay(BackSoundStream, True);// then
end;
procedure TAudioPlayback_Bass.PlaySwoosh;
begin
BASS_ChannelPlay(SwooshSoundStream, True);
end;
procedure TAudioPlayback_Bass.PlayChange;
begin
BASS_ChannelPlay(ChangeSoundStream, True);
end;
procedure TAudioPlayback_Bass.PlayOption;
begin
BASS_ChannelPlay(OptionSoundStream, True);
end;
procedure TAudioPlayback_Bass.PlayClick;
begin
BASS_ChannelPlay(ClickSoundStream, True);
end;
procedure TAudioPlayback_Bass.PlayDrum;
begin
BASS_ChannelPlay(DrumSoundStream, True);
end;
procedure TAudioPlayback_Bass.PlayHihat;
begin
BASS_ChannelPlay(HihatSoundStream, True);
end;
procedure TAudioPlayback_Bass.PlayClap;
begin
BASS_ChannelPlay(ClapSoundStream, True);
end;
procedure TAudioPlayback_Bass.PlayShuffle;
begin
BASS_ChannelPlay(ShuffleSoundStream, True);
end;
procedure TAudioPlayback_Bass.StopShuffle;
begin
BASS_ChannelStop(ShuffleSoundStream);
end;
function TAudioPlayback_Bass.LoadSoundFromFile(var stream: HSTREAM; Name: string): boolean;
var
L: Integer;
begin
if FileExists(Name) then
begin
Log.LogStatus('Loading Sound: "' + Name + '"', 'LoadSoundFromFile');
try
stream := BASS_StreamCreateFile(False, pchar(Name), 0, 0, 0);
//Add CustomSound
L := High(CustomSounds) + 1;
SetLength (CustomSounds, L + 1);
CustomSounds[L].Filename := Name;
CustomSounds[L].Stream := TBassOutputStream.Create(stream);
except
Log.LogError('Failed to open using BASS', 'LoadSoundFromFile');
end;
end
else
begin
Log.LogError('Sound not found: "' + Name + '"', 'LoadSoundFromFile');
exit;
end;
end;
//Equalizer
function TAudioPlayback_Bass.GetFFTData: TFFTData;
var
Data: TFFTData;
begin
//Get Channel Data Mono and 256 Values
BASS_ChannelGetData(MusicStream, @Result, 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
//Get Channel Data Mono and 256 Values
BASS_ChannelGetInfo(MusicStream, info);
ZeroMemory(@data, sizeof(TPCMData));
if (info.chans = 1) then
begin
// mono file -> add stereo channel
{
nBytes := BASS_ChannelGetData(Bass, @data[0], samples*sizeof(Smallint));
// interleave data
//CopyMemory(@data[1], @data[0], samples*sizeof(Smallint));
}
result := 0;
end
else
begin
// stereo file
nBytes := BASS_ChannelGetData(MusicStream, @data, sizeof(TPCMData));
end;
if(nBytes <= 0) then
result := 0
else
result := nBytes div sizeof(TPCMStereoSample);
end;
function TAudioPlayback_Bass.LoadCustomSound(const Filename: String): Cardinal;
var
S: hStream;
I: Integer;
F: String;
begin
//Search for Sound in already loaded Sounds
F := UpperCase(SoundPath + FileName);
For I := 0 to High(CustomSounds) do
begin
if (UpperCase(CustomSounds[I].Filename) = F) then
begin
Result := I;
Exit;
end;
end;
if LoadSoundFromFile(S, SoundPath + Filename) then
Result := High(CustomSounds)
else
Result := 0;
end;
procedure TAudioPlayback_Bass.PlayCustomSound(const Index: Cardinal );
begin
if Index <= High(CustomSounds) then
with CustomSounds[Index].Stream as TBassOutputStream do
begin
BASS_ChannelPlay(Handle, True);
end;
end;
initialization
singleton_AudioPlaybackBass := TAudioPlayback_Bass.create();
AudioManager.add( singleton_AudioPlaybackBass );
finalization
AudioManager.Remove( singleton_AudioPlaybackBass );
end.