From 21e5e8cec6f253ec24b5116b4020dc62bb2a80b1 Mon Sep 17 00:00:00 2001 From: tobigun Date: Wed, 5 Dec 2007 21:48:59 +0000 Subject: - Moved initialization from URecord to UAudio_bass. - Removed duplicate registration at AudioManager - separated input an output functions so input-functionality can be switched on and off with the UseBASSInput define - Removed HWND Windows stuff git-svn-id: svn://svn.code.sf.net/p/ultrastardx/svn/trunk@669 b956fd51-792f-4845-bead-9b4dfca2ff2c --- Game/Code/Classes/UAudio_bass.pas | 1297 ++++++++++++++++++------------------- 1 file changed, 648 insertions(+), 649 deletions(-) (limited to 'Game/Code') diff --git a/Game/Code/Classes/UAudio_bass.pas b/Game/Code/Classes/UAudio_bass.pas index 9ef3b789..bcf01f92 100644 --- a/Game/Code/Classes/UAudio_bass.pas +++ b/Game/Code/Classes/UAudio_bass.pas @@ -1,649 +1,648 @@ -unit UAudio_bass; - -interface - -{$IFDEF FPC} - {$MODE Delphi} -{$ENDIF} - -{$I switches.inc} - - -uses Classes, - {$IFDEF win32} - windows, - {$ENDIF} - Messages, - SysUtils, - {$IFNDEF FPC} - Forms, - {$ENDIF} - - bass, - ULog, - UMusic; - -implementation - -uses - {$IFDEF LAZARUS} - lclintf, - {$ENDIF} - URecord, - UIni, - UMain, - UCommon, - UThemes; - -const - RecordSystem = 1; - -type - TMPModes = (mpNotReady, mpStopped, mpPlaying, mpRecording, mpSeeking, - mpPaused, mpOpen); - -const - ModeStr: array[TMPModes] of string = ('Not ready', 'Stopped', 'Playing', 'Recording', 'Seeking', 'Paused', 'Open'); - -type - TAudio_bass = class( TInterfacedObject, IAudioPlayback, IAudioInput ) - private - BassStart: hStream; // Wait, I've replaced this with BASS - BassBack: hStream; // It has almost all features we need - BassSwoosh: hStream; - BassChange: hStream; // Almost? It aleady has them all :) - BassOption: hStream; - BassClick: hStream; - BassDrum: hStream; - BassHihat: hStream; - BassClap: hStream; - BassShuffle: hStream; - - //Custom Sounds - CustomSounds: array of TCustomSoundEntry; - Loaded: boolean; - Loop: boolean; - fHWND: THandle; - - public - Bass: hStream; - function GetName: String; - procedure InitializePlayback; - procedure InitializeRecord; - procedure SetVolume(Volume: integer); - procedure SetMusicVolume(Volume: integer); - procedure SetLoop(Enabled: boolean); - function Open(Name: string): boolean; // true if succeed - procedure Rewind; - procedure MoveTo(Time: real); - procedure Play; - procedure Pause; //Pause Mod - procedure Stop; - procedure Close; - function Finished: boolean; - function Length: real; - function getPosition: real; - procedure PlayStart; - procedure PlayBack; - procedure PlaySwoosh; - procedure PlayChange; - procedure PlayOption; - procedure PlayClick; - procedure PlayDrum; - procedure PlayHihat; - procedure PlayClap; - procedure PlayShuffle; - procedure StopShuffle; - procedure CaptureStart; - procedure CaptureStop; - procedure CaptureCard(RecordI, PlayerLeft, PlayerRight: byte); - procedure StopCard(Card: byte); - function LoadSoundFromFile(var hStream: hStream; Name: string): boolean; - - //Equalizer - function GetFFTData: TFFTData; - - //Custom Sounds - function LoadCustomSound(const Filename: String): Cardinal; - procedure PlayCustomSound(const Index: Cardinal ); -end; - -var - singleton_MusicBass : IAudioPlayback; - -function TAudio_bass.GetName: String; -begin - result := 'BASS'; -end; - -procedure TAudio_bass.InitializePlayback; -var - Pet: integer; - S: integer; -begin - writeln( 'TAudio_bass.InitializePlayback' ); -// Log.BenchmarkStart(4); -// Log.LogStatus('Initializing Playback Subsystem', 'Music Initialize'); - - Loaded := false; - Loop := false; - - - writeln( 'TAudio_bass AllocateHWND' ); - {$ifdef win32} - // TODO : JB_Linux ... is this needed ? :) - fHWND := AllocateHWND( nil); // TODO : JB_lazarus - can we do something different here ?? lazarus didnt like this function - {$ENDIF} - - - writeln( 'TAudio_bass BASS_Init' ); - // TODO : jb_linux replace with something other than bass - if not BASS_Init(1, 44100, 0, fHWND, nil) then - begin - {$IFNDEF FPC} - // TODO : JB_linux find a way to do this nice.. - Application.MessageBox ('Could not initialize BASS', 'Error'); - {$ENDIF} - 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'); - - writeln( 'TAudio_bass LoadSoundFromFile' ); -// Log.BenchmarkStart(4); - LoadSoundFromFile(BassStart, SoundPath + 'Common Start.mp3'); - LoadSoundFromFile(BassBack, SoundPath + 'Common Back.mp3'); - LoadSoundFromFile(BassSwoosh, SoundPath + 'menu swoosh.mp3'); - LoadSoundFromFile(BassChange, SoundPath + 'select music change music 50.mp3'); - LoadSoundFromFile(BassOption, SoundPath + 'option change col.mp3'); - LoadSoundFromFile(BassClick, SoundPath + 'rimshot022b.mp3'); - -// LoadSoundFromFile(BassDrum, SoundPath + 'bassdrumhard076b.mp3'); -// LoadSoundFromFile(BassHihat, SoundPath + 'hihatclosed068b.mp3'); -// LoadSoundFromFile(BassClap, SoundPath + 'claps050b.mp3'); - -// LoadSoundFromFile(BassShuffle, SoundPath + 'Shuffle.mp3'); - -// Log.BenchmarkEnd(4); -// Log.LogBenchmark('--> Loading Sounds', 4); -end; - -procedure TAudio_bass.InitializeRecord; -var - S: integer; - device: integer; - descr: string; - input: integer; - input2: integer; - flags: integer; - mic: array[0..15] of integer; - SC: integer; // soundcard - SCI: integer; // soundcard input -begin - if RecordSystem = 1 then begin - SetLength(Sound, 6 {max players});//Ini.Players+1); - for S := 0 to High(Sound) do begin //Ini.Players do begin - Sound[S] := TSound.Create; - Sound[S].Num := S; - Sound[S].BufferNew := TMemoryStream.Create; - SetLength(Sound[S].BufferLong, 1); - Sound[S].BufferLong[0] := TMemoryStream.Create; - Sound[S].n := 4*1024; - end; - - - // check for recording devices; - {device := 0; - descr := BASS_RecordGetDeviceDescription(device); - - SetLength(SoundCard, 0); - while (descr <> '') do begin - SC := High(SoundCard) + 1; - SetLength(SoundCard, SC+1); - - Log.LogAnalyze('Device #'+IntToStr(device)+': '+ descr); - SoundCard[SC].Description := Descr; - - // check for recording inputs - mic[device] := -1; // default to no change - input := 0; - BASS_RecordInit(device); - Log.LogAnalyze('Input #' + IntToStr(Input) + ': ' + BASS_RecordGetInputName(input)); - flags := BASS_RecordGetInput(input); - - SetLength(SoundCard[SC].Input, 0); - while (flags <> -1) do begin - SCI := High(SoundCard[SC].Input) + 1; - SetLength(SoundCard[SC].Input, SCI+1); - - Log.LogAnalyze('Input #' + IntToStr(Input) + ': ' + BASS_RecordGetInputName(input)); - SoundCard[SC].Input[SCI].Name := BASS_RecordGetInputName(Input); - - if (flags and BASS_INPUT_TYPE_MASK) = BASS_INPUT_TYPE_MIC then begin - mic[device] := input; // auto set microphone - end; - Inc(Input); - flags := BASS_RecordGetInput(input); - end; - - if mic[device] <> -1 then begin - Log.LogAnalyze('Found the mic at input ' + IntToStr(Mic[device])) - end else begin - Log.LogAnalyze('Mic not found'); - mic[device] := 0; // setting to the first one (for kxproject) - end; - SoundCard[SC].InputSeleceted := Mic[Device]; - - - BASS_RecordFree; - - inc(Device); - descr := BASS_RecordGetDeviceDescription(Device); - end; // while} - end; // if -end; - -procedure TAudio_bass.SetVolume(Volume: integer); -begin - //Old Sets Wave Volume - //BASS_SetVolume(Volume); - //New: Sets Volume only for this Application - - - // TODO : jb_linux replace with something other than bass - BASS_SetConfig(BASS_CONFIG_GVOL_SAMPLE, Volume); - BASS_SetConfig(BASS_CONFIG_GVOL_STREAM, Volume); - BASS_SetConfig(BASS_CONFIG_GVOL_MUSIC, Volume); -end; - -procedure TAudio_bass.SetMusicVolume(Volume: Integer); -begin - //Max Volume Prevention - if Volume > 100 then - Volume := 100; - - if Volume < 0 then - Volume := 0; - - - //Set Volume - // TODO : jb_linux replace with something other than bass - BASS_ChannelSetAttributes (Bass, -1, Volume, -101); -end; - -procedure TAudio_bass.SetLoop(Enabled: boolean); -begin - Loop := Enabled; -end; - -function TAudio_bass.Open(Name: string): boolean; -begin - Loaded := false; - if FileExists(Name) then - begin - // TODO : jb_linux replace with something other than bass - Bass := Bass_StreamCreateFile(false, pchar(Name), 0, 0, 0); - - Loaded := true; - //Set Max Volume - SetMusicVolume (100); - end; - - Result := Loaded; -end; - -procedure TAudio_bass.Rewind; -begin - if Loaded then begin - end; -end; - -procedure TAudio_bass.MoveTo(Time: real); -var - bytes: integer; -begin - // TODO : jb_linux replace with something other than bass - bytes := BASS_ChannelSeconds2Bytes(Bass, Time); - BASS_ChannelSetPosition(Bass, bytes); -end; - -procedure TAudio_bass.Play; -begin - // TODO : jb_linux replace with something other than bass - if Loaded then - begin - if Loop then - BASS_ChannelPlay(Bass, True); // start from beginning... actually bass itself does not loop, nor does this TAudio_bass Class - - BASS_ChannelPlay(Bass, False); // for setting position before playing - end; -end; - -procedure TAudio_bass.Pause; //Pause Mod -begin - // TODO : jb_linux replace with something other than bass - if Loaded then begin - BASS_ChannelPause(Bass); // Pauses Song - end; -end; - -procedure TAudio_bass.Stop; -begin - // TODO : jb_linux replace with something other than bass - Bass_ChannelStop(Bass); -end; - -procedure TAudio_bass.Close; -begin - // TODO : jb_linux replace with something other than bass - Bass_StreamFree(Bass); -end; - -function TAudio_bass.Length: real; -var - bytes: integer; -begin - Result := 60; - - // TODO : jb_linux replace with something other than bass - bytes := BASS_ChannelGetLength(Bass); - Result := BASS_ChannelBytes2Seconds(Bass, bytes); -end; - -function TAudio_bass.getPosition: real; -var - bytes: integer; -begin - Result := 0; - - // TODO : jb_linux replace with something other than bass - bytes := BASS_ChannelGetPosition(BASS); - Result := BASS_ChannelBytes2Seconds(BASS, bytes); -end; - -function TAudio_bass.Finished: boolean; -begin - Result := false; - - // TODO : jb_linux replace with something other than bass - if BASS_ChannelIsActive(BASS) = BASS_ACTIVE_STOPPED then - begin - Result := true; - end; -end; - -procedure TAudio_bass.PlayStart; -begin - // TODO : jb_linux replace with something other than bass - BASS_ChannelPlay(BassStart, True); -end; - -procedure TAudio_bass.PlayBack; -begin - // TODO : jb_linux replace with something other than bass - BASS_ChannelPlay(BassBack, True);// then -end; - -procedure TAudio_bass.PlaySwoosh; -begin - // TODO : jb_linux replace with something other than bass - BASS_ChannelPlay(BassSwoosh, True); -end; - -procedure TAudio_bass.PlayChange; -begin - // TODO : jb_linux replace with something other than bass - BASS_ChannelPlay(BassChange, True); -end; - -procedure TAudio_bass.PlayOption; -begin - // TODO : jb_linux replace with something other than bass - BASS_ChannelPlay(BassOption, True); -end; - -procedure TAudio_bass.PlayClick; -begin - // TODO : jb_linux replace with something other than bass - BASS_ChannelPlay(BassClick, True); -end; - -procedure TAudio_bass.PlayDrum; -begin - // TODO : jb_linux replace with something other than bass - BASS_ChannelPlay(BassDrum, True); -end; - -procedure TAudio_bass.PlayHihat; -begin - // TODO : jb_linux replace with something other than bass - BASS_ChannelPlay(BassHihat, True); -end; - -procedure TAudio_bass.PlayClap; -begin - // TODO : jb_linux replace with something other than bass - BASS_ChannelPlay(BassClap, True); -end; - -procedure TAudio_bass.PlayShuffle; -begin - // TODO : jb_linux replace with something other than bass - BASS_ChannelPlay(BassShuffle, True); -end; - -procedure TAudio_bass.StopShuffle; -begin - // TODO : jb_linux replace with something other than bass - BASS_ChannelStop(BassShuffle); -end; - -procedure TAudio_bass.CaptureStart; -var - S: integer; - SC: integer; - P1: integer; - P2: integer; -begin - for S := 0 to High(Sound) do - Sound[S].BufferLong[0].Clear; - - for SC := 0 to High(Ini.CardList) do begin - P1 := Ini.CardList[SC].ChannelL; - P2 := Ini.CardList[SC].ChannelR; - if P1 > PlayersPlay then P1 := 0; - if P2 > PlayersPlay then P2 := 0; - if (P1 > 0) or (P2 > 0) then - CaptureCard(SC, P1, P2); - end; -end; - -procedure TAudio_bass.CaptureStop; -var - SC: integer; - P1: integer; - P2: integer; -begin - - for SC := 0 to High(Ini.CardList) do begin - P1 := Ini.CardList[SC].ChannelL; - P2 := Ini.CardList[SC].ChannelR; - if P1 > PlayersPlay then P1 := 0; - if P2 > PlayersPlay then P2 := 0; - if (P1 > 0) or (P2 > 0) then StopCard(SC); - end; - -end; - -//procedure TAudio_bass.CaptureCard(RecordI, SoundNum, PlayerLeft, PlayerRight: byte); -procedure TAudio_bass.CaptureCard(RecordI, PlayerLeft, PlayerRight: byte); -var - Error: integer; - ErrorMsg: string; -begin - if not BASS_RecordInit(RecordI) then - begin - Error := BASS_ErrorGetCode; - - ErrorMsg := IntToStr(Error); - if Error = BASS_ERROR_DX then ErrorMsg := 'No DX5'; - if Error = BASS_ERROR_ALREADY then ErrorMsg := 'The device has already been initialized'; - if Error = BASS_ERROR_DEVICE then ErrorMsg := 'The device number specified is invalid'; - if Error = BASS_ERROR_DRIVER then ErrorMsg := 'There is no available device driver'; - - {Log.LogAnalyze('Error initializing record [' + IntToStr(RecordI) + ', ' - + IntToStr(PlayerLeft) + ', '+ IntToStr(PlayerRight) + ']: ' - + ErrorMsg);} - Log.LogError('Error initializing record [' + IntToStr(RecordI) + ', ' - + IntToStr(PlayerLeft) + ', '+ IntToStr(PlayerRight) + ']: ' - + ErrorMsg); - Log.LogError('Music -> CaptureCard: Error initializing record: ' + ErrorMsg); - - - end - else - begin - Recording.SoundCard[RecordI].BassRecordStream := BASS_RecordStart(44100, 2, MakeLong(0, 20) , @GetMicrophone, PlayerLeft + PlayerRight*256); - end; -end; - -procedure TAudio_bass.StopCard(Card: byte); -begin - // TODO : jb_linux replace with something other than bass - BASS_RecordSetDevice(Card); - BASS_RecordFree; -end; - -function TAudio_bass.LoadSoundFromFile(var hStream: hStream; Name: string): boolean; -var - L: Integer; -begin - if FileExists(Name) then - begin - Log.LogStatus('Loading Sound: "' + Name + '"', 'LoadSoundFromFile'); - try - // TODO : jb_linux replace with something other than bass - hStream := BASS_StreamCreateFile(False, pchar(Name), 0, 0, 0); - - //Add CustomSound - L := High(CustomSounds) + 1; - SetLength (CustomSounds, L + 1); - CustomSounds[L].Filename := Name; - CustomSounds[L].Handle := hStream; - 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 TAudio_bass.GetFFTData: TFFTData; -var - Data: TFFTData; -begin - //Get Channel Data Mono and 256 Values - BASS_ChannelGetData(Bass, @Result, BASS_DATA_FFT512); -end; - -function TAudio_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 TAudio_bass.PlayCustomSound(const Index: Cardinal ); -begin - if Index <= High(CustomSounds) then - BASS_ChannelPlay(CustomSounds[Index].Handle, True); -end; - - -{* - -Sorry guys... this is my mess :( -Im going to try and get ffmpeg to handle audio playback ( at least for linux ) -and Im going to implement it nicly along side BASS, in TAudio_bass ( where I can ) - -http://www.dranger.com/ffmpeg/ffmpeg.html -http://www.dranger.com/ffmpeg/ffmpegtutorial_all.html - -http://www.inb.uni-luebeck.de/~boehme/using_libavcodec.html - -*} -{* -function TAudio_bass.FFMPeg_StreamCreateFile(abool : boolean; aFileName : pchar ): THandle; -var - lFormatCtx : PAVFormatContext; -begin - -(* - if(SDL_OpenAudio(&wanted_spec, &spec) < 0) - begin - fprintf(stderr, "SDL_OpenAudio: %s\n", SDL_GetError()); - writeln( 'SDL_OpenAudio' ); - exit; - end; -*) - -(* - if ( av_open_input_file( lFormatCtx, aFileName, NULL, 0, NULL ) <> 0 ) - begin - writeln( 'Unable to open file '+ aFileName ); - exit; - end; - - // Retrieve stream information - if ( av_find_stream_info(pFormatCtx) < 0 ) - begin - writeln( 'Unable to Retrieve stream information' ); - exit; - end; -*) - -end; *} - -initialization - singleton_MusicBass := TAudio_bass.create(); - - writeln( 'UAudio_Bass - Register Playback' ); - AudioManager.add( IAudioPlayback( singleton_MusicBass ) ); - - writeln( 'UAudio_Bass - Register Input' ); - AudioManager.add( IAudioInput( singleton_MusicBass ) ); - -finalization - writeln( 'UAudio_Bass - UnRegister Playback' ); - AudioManager.Remove( IAudioPlayback( singleton_MusicBass ) ); - - writeln( 'UAudio_Bass - UnRegister Input' ); - AudioManager.Remove( IAudioInput( singleton_MusicBass ) ); - -end. +unit UAudio_bass; + +interface + +{$IFDEF FPC} + {$MODE Delphi} +{$ENDIF} + +{$I switches.inc} + + +uses Classes, + {$IFDEF win32} + windows, + {$ENDIF} + Messages, + SysUtils, + {$IFNDEF FPC} + Forms, + {$ENDIF} + bass, + ULog, + UMusic; + +implementation + +uses + {$IFDEF LAZARUS} + lclintf, + {$ENDIF} + URecord, + UIni, + UMain, + UCommon, + UThemes; + +type + TMPModes = (mpNotReady, mpStopped, mpPlaying, mpRecording, mpSeeking, + mpPaused, mpOpen); + +const + ModeStr: array[TMPModes] of string = ('Not ready', 'Stopped', 'Playing', 'Recording', 'Seeking', 'Paused', 'Open'); + +type +{$IFDEF UseBASSInput} + TAudio_bass = class( TInterfacedObject, IAudioPlayback, IAudioInput) +{$ELSE} + TAudio_bass = class( TInterfacedObject, IAudioPlayback) +{$ENDIF} + private + BassStart: hStream; // Wait, I've replaced this with BASS + BassBack: hStream; // It has almost all features we need + BassSwoosh: hStream; + BassChange: hStream; // Almost? It aleady has them all :) + BassOption: hStream; + BassClick: hStream; + BassDrum: hStream; + BassHihat: hStream; + BassClap: hStream; + BassShuffle: hStream; + + //Custom Sounds + CustomSounds: array of TCustomSoundEntry; + Loaded: boolean; + Loop: boolean; + + public + Bass: hStream; + 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 MoveTo(Time: real); + procedure Play; + procedure Pause; //Pause Mod + procedure Stop; + procedure Close; + function Finished: boolean; + function Length: real; + function getPosition: 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 hStream: hStream; Name: string): boolean; + + //Equalizer + function GetFFTData: TFFTData; + + //Custom Sounds + function LoadCustomSound(const Filename: String): Cardinal; + procedure PlayCustomSound(const Index: Cardinal ); + + {IAudioInput interface} + {$IFDEF UseBASSInput} + procedure InitializeRecord; + + procedure CaptureStart; + procedure CaptureStop; + procedure CaptureCard(Card: byte; CaptureSoundLeft, CaptureSoundRight: TSound); + procedure StopCard(Card: byte); + {$ENDIF} + end; + +{$IFDEF UseBASSInput} + TBassSoundCard = class(TGenericSoundCard) + RecordStream: HSTREAM; + end; +{$ENDIF} + + +var + singleton_MusicBass : IAudioPlayback; + +function TAudio_bass.GetName: String; +begin + result := 'BASS'; +end; + +procedure TAudio_bass.InitializePlayback; +var + Pet: integer; + S: integer; +begin + writeln( 'TAudio_bass.InitializePlayback' ); +// Log.BenchmarkStart(4); +// Log.LogStatus('Initializing Playback Subsystem', 'Music Initialize'); + + Loaded := false; + Loop := false; + + writeln( 'TAudio_bass BASS_Init' ); + 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'); + + writeln( 'TAudio_bass LoadSoundFromFile' ); +// Log.BenchmarkStart(4); + LoadSoundFromFile(BassStart, SoundPath + 'Common Start.mp3'); + LoadSoundFromFile(BassBack, SoundPath + 'Common Back.mp3'); + LoadSoundFromFile(BassSwoosh, SoundPath + 'menu swoosh.mp3'); + LoadSoundFromFile(BassChange, SoundPath + 'select music change music 50.mp3'); + LoadSoundFromFile(BassOption, SoundPath + 'option change col.mp3'); + LoadSoundFromFile(BassClick, SoundPath + 'rimshot022b.mp3'); + +// LoadSoundFromFile(BassDrum, SoundPath + 'bassdrumhard076b.mp3'); +// LoadSoundFromFile(BassHihat, SoundPath + 'hihatclosed068b.mp3'); +// LoadSoundFromFile(BassClap, SoundPath + 'claps050b.mp3'); + +// LoadSoundFromFile(BassShuffle, SoundPath + 'Shuffle.mp3'); + +// Log.BenchmarkEnd(4); +// Log.LogBenchmark('--> Loading Sounds', 4); +end; + +procedure TAudio_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 TAudio_bass.SetMusicVolume(Volume: Integer); +begin + //Max Volume Prevention + if Volume > 100 then + Volume := 100; + + if Volume < 0 then + Volume := 0; + + + //Set Volume + // TODO : jb_linux replace with something other than bass + BASS_ChannelSetAttributes (Bass, -1, Volume, -101); +end; + +procedure TAudio_bass.SetLoop(Enabled: boolean); +begin + Loop := Enabled; +end; + +function TAudio_bass.Open(Name: string): boolean; +begin + Loaded := false; + if FileExists(Name) then + begin + Bass := Bass_StreamCreateFile(false, pchar(Name), 0, 0, 0); + + Loaded := true; + //Set Max Volume + SetMusicVolume (100); + end; + + Result := Loaded; +end; + +procedure TAudio_bass.Rewind; +begin + if Loaded then begin + end; +end; + +procedure TAudio_bass.MoveTo(Time: real); +var + bytes: integer; +begin + bytes := BASS_ChannelSeconds2Bytes(Bass, Time); + BASS_ChannelSetPosition(Bass, bytes); +end; + +procedure TAudio_bass.Play; +begin + if Loaded then + begin + if Loop then + BASS_ChannelPlay(Bass, True); // start from beginning... actually bass itself does not loop, nor does this TAudio_bass Class + + BASS_ChannelPlay(Bass, False); // for setting position before playing + end; +end; + +procedure TAudio_bass.Pause; //Pause Mod +begin + if Loaded then begin + BASS_ChannelPause(Bass); // Pauses Song + end; +end; + +procedure TAudio_bass.Stop; +begin + Bass_ChannelStop(Bass); +end; + +procedure TAudio_bass.Close; +begin + Bass_StreamFree(Bass); +end; + +function TAudio_bass.Length: real; +var + bytes: integer; +begin + Result := 60; + + bytes := BASS_ChannelGetLength(Bass); + Result := BASS_ChannelBytes2Seconds(Bass, bytes); +end; + +function TAudio_bass.getPosition: real; +var + bytes: integer; +begin + Result := 0; + + bytes := BASS_ChannelGetPosition(BASS); + Result := BASS_ChannelBytes2Seconds(BASS, bytes); +end; + +function TAudio_bass.Finished: boolean; +begin + Result := false; + + if BASS_ChannelIsActive(BASS) = BASS_ACTIVE_STOPPED then + begin + Result := true; + end; +end; + +procedure TAudio_bass.PlayStart; +begin + BASS_ChannelPlay(BassStart, True); +end; + +procedure TAudio_bass.PlayBack; +begin + BASS_ChannelPlay(BassBack, True);// then +end; + +procedure TAudio_bass.PlaySwoosh; +begin + BASS_ChannelPlay(BassSwoosh, True); +end; + +procedure TAudio_bass.PlayChange; +begin + BASS_ChannelPlay(BassChange, True); +end; + +procedure TAudio_bass.PlayOption; +begin + BASS_ChannelPlay(BassOption, True); +end; + +procedure TAudio_bass.PlayClick; +begin + BASS_ChannelPlay(BassClick, True); +end; + +procedure TAudio_bass.PlayDrum; +begin + BASS_ChannelPlay(BassDrum, True); +end; + +procedure TAudio_bass.PlayHihat; +begin + BASS_ChannelPlay(BassHihat, True); +end; + +procedure TAudio_bass.PlayClap; +begin + BASS_ChannelPlay(BassClap, True); +end; + +procedure TAudio_bass.PlayShuffle; +begin + BASS_ChannelPlay(BassShuffle, True); +end; + +procedure TAudio_bass.StopShuffle; +begin + BASS_ChannelStop(BassShuffle); +end; + +function TAudio_bass.LoadSoundFromFile(var hStream: hStream; Name: string): boolean; +var + L: Integer; +begin + if FileExists(Name) then + begin + Log.LogStatus('Loading Sound: "' + Name + '"', 'LoadSoundFromFile'); + try + hStream := BASS_StreamCreateFile(False, pchar(Name), 0, 0, 0); + + //Add CustomSound + L := High(CustomSounds) + 1; + SetLength (CustomSounds, L + 1); + CustomSounds[L].Filename := Name; + CustomSounds[L].Handle := hStream; + 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 TAudio_bass.GetFFTData: TFFTData; +var + Data: TFFTData; +begin + //Get Channel Data Mono and 256 Values + BASS_ChannelGetData(Bass, @Result, BASS_DATA_FFT512); +end; + +function TAudio_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 TAudio_bass.PlayCustomSound(const Index: Cardinal ); +begin + if Index <= High(CustomSounds) then + BASS_ChannelPlay(CustomSounds[Index].Handle, True); +end; + +{$IFDEF UseBASSInput} + +procedure TAudio_bass.InitializeRecord; +var + device: integer; + Descr: string; + input: integer; + input2: integer; + InputName: PChar; + Flags: integer; + mic: array[0..15] of integer; + SC: integer; // soundcard + SCI: integer; // soundcard input + No: integer; + +function isDuplicate(Desc: String): Boolean; +var + I: Integer; +begin + Result := False; + //Check for Soundcard with same Description + For I := 0 to SC-1 do + begin + if (Recording.SoundCard[I].Description = Desc) then + begin + Result := True; + Break; + end; + end; +end; + +begin + with Recording do + begin + // checks for recording devices and puts them into an array + SetLength(SoundCard, 0); + + SC := 0; + Descr := BASS_RecordGetDeviceDescription(SC); + + while (Descr <> '') do + begin + //If there is another SoundCard with the Same ID, Search an available Name + if (IsDuplicate(Descr)) then + begin + No:= 1; //Count of SoundCards with same Name + Repeat + Inc(No) + Until not IsDuplicate(Descr + ' (' + InttoStr(No) + ')'); + + //Set Description + Descr := Descr + ' (' + InttoStr(No) + ')'; + end; + + SetLength(SoundCard, SC+1); + + // TODO: free object on termination + SoundCard[SC] := TBassSoundCard.Create(); + SoundCard[SC].Description := Descr; + + //Get Recording Inputs + SCI := 0; + BASS_RecordInit(SC); + + InputName := BASS_RecordGetInputName(SCI); + + {$IFDEF DARWIN} + // Under MacOSX the SingStar Mics have an empty + // InputName. So, we have to add a hard coded + // Workaround for this problem + if (InputName = nil) and (Pos( 'USBMIC Serial#', Descr) > 0) then + begin + InputName := 'Microphone'; + end; + {$ENDIF} + + SetLength(SoundCard[SC].Input, 1); + SoundCard[SC].Input[SCI].Name := InputName; + + // process each input + while (InputName <> nil) do + begin + Flags := BASS_RecordGetInput(SCI); + if (SCI >= 1) {AND (Flags AND BASS_INPUT_OFF = 0)} then + begin + SetLength(SoundCard[SC].Input, SCI+1); + SoundCard[SC].Input[SCI].Name := InputName; + end; + + //Set Mic Index + if ((Flags and BASS_INPUT_TYPE_MIC) = 1) then + SoundCard[SC].MicInput := SCI; + + Inc(SCI); + InputName := BASS_RecordGetInputName(SCI); + end; + + BASS_RecordFree; + + Inc(SC); + Descr := BASS_RecordGetDeviceDescription(SC); + end; // while + end; // with Recording +end; + +// TODO: code is used by all IAudioInput implementors +// -> move to a common superclass (TAudioInput_Generic?) +procedure TAudio_bass.CaptureStart; +var + S: integer; + SC: integer; + PlayerLeft, PlayerRight: integer; + CaptureSoundLeft, CaptureSoundRight: TSound; +begin + for S := 0 to High(Recording.Sound) do + Recording.Sound[S].BufferLong[0].Clear; + + for SC := 0 to High(Ini.CardList) do begin + PlayerLeft := Ini.CardList[SC].ChannelL-1; + PlayerRight := Ini.CardList[SC].ChannelR-1; + if PlayerLeft >= PlayersPlay then PlayerLeft := -1; + if PlayerRight >= PlayersPlay then PlayerRight := -1; + if (PlayerLeft > -1) or (PlayerRight > -1) then begin + if (PlayerLeft > -1) then + CaptureSoundLeft := Recording.Sound[PlayerLeft] + else + CaptureSoundLeft := nil; + if (PlayerRight > -1) then + CaptureSoundRight := Recording.Sound[PlayerRight] + else + CaptureSoundRight := nil; + + CaptureCard(SC, CaptureSoundLeft, CaptureSoundRight); + end; + end; +end; + +// TODO: code is used by all IAudioInput implementors +// -> move to a common superclass (TAudioInput_Generic?) +procedure TAudio_bass.CaptureStop; +var + SC: integer; + PlayerLeft: integer; + PlayerRight: integer; +begin + + for SC := 0 to High(Ini.CardList) do begin + PlayerLeft := Ini.CardList[SC].ChannelL-1; + PlayerRight := Ini.CardList[SC].ChannelR-1; + if PlayerLeft >= PlayersPlay then PlayerLeft := -1; + if PlayerRight >= PlayersPlay then PlayerRight := -1; + if (PlayerLeft > -1) or (PlayerRight > -1) then + StopCard(SC); + end; + +end; + +{* + * Bass input capture callback. + * Params: + * stream - BASS input stream + * buffer - buffer of captured samples + * len - size of buffer in bytes + * user - players associated with left/right channels + *} +function MicrophoneCallback(stream: HSTREAM; buffer: Pointer; + len: Cardinal; Card: Cardinal): boolean; stdcall; +begin + Recording.HandleMicrophoneData(buffer, len, Recording.SoundCard[Card]); + Result := true; +end; + +{* + * Start input-capturing on Soundcard specified by Card. + * Params: + * Card - soundcard index in Recording.SoundCard array + * CaptureSoundLeft - sound(-buffer) used for left channel capture data + * CaptureSoundRight - sound(-buffer) used for right channel capture data + *} +procedure TAudio_bass.CaptureCard(Card: byte; CaptureSoundLeft, CaptureSoundRight: TSound); +var + Error: integer; + ErrorMsg: string; + bassSoundCard: TBassSoundCard; +begin + if not BASS_RecordInit(Card) then + begin + Error := BASS_ErrorGetCode; + ErrorMsg := IntToStr(Error); + if Error = BASS_ERROR_DX then ErrorMsg := 'No DX5'; + if Error = BASS_ERROR_ALREADY then ErrorMsg := 'The device has already been initialized'; + if Error = BASS_ERROR_DEVICE then ErrorMsg := 'The device number specified is invalid'; + if Error = BASS_ERROR_DRIVER then ErrorMsg := 'There is no available device driver'; + Log.LogError('Error initializing record [' + IntToStr(Card) + ']'); + Log.LogError('TAudio_bass.CaptureCard: Error initializing record: ' + ErrorMsg); + end + else + begin + bassSoundCard := TBassSoundCard(Recording.SoundCard[Card]); + bassSoundCard.CaptureSoundLeft := CaptureSoundLeft; + bassSoundCard.CaptureSoundRight := CaptureSoundRight; + + // capture in 44.1kHz/stereo/16bit and a 20ms callback period + bassSoundCard.RecordStream := + BASS_RecordStart(44100, 2, MakeLong(0, 20) , @MicrophoneCallback, Card); + end; +end; + +{* + * Stop input-capturing on Soundcard specified by Card. + * Params: + * Card - soundcard index in Recording.SoundCard array + *} +procedure TAudio_bass.StopCard(Card: byte); +begin + BASS_RecordSetDevice(Card); + BASS_RecordFree; +end; + +{$ENDIF} + + +initialization + singleton_MusicBass := TAudio_bass.create(); + + writeln( 'UAudio_Bass - Register' ); + AudioManager.add( singleton_MusicBass ); + +finalization + writeln( 'UAudio_Bass - UnRegister' ); + AudioManager.Remove( singleton_MusicBass ); + +end. -- cgit v1.2.3