From dee94f5dae9e6b5ae6c7b54a12a567745abc8dc3 Mon Sep 17 00:00:00 2001 From: tobigun Date: Tue, 5 Feb 2008 20:36:19 +0000 Subject: General: - cleanup and adaption of SingDrawOscilloscope Portaudio/SDL audio output: - stuttering in portaudio output has been fixed (SDL_MixBuffers cannot be used without initializing the SDL audio stuff first, so it is not usable with portaudio. Now SDL is used for audio-output instead of portaudio (although the file-name is UAudioPlayback_Portaudio.pas at the moment). - cleaner file closing - volume adjustment UMusic: - cleanup of the audio-interfaces - introduced TNoteType = (ntFreestyle, ntNormal, ntGolden) - some bug-fixes - introduced TSoundLibrary. This is library for all in-game sounds used by USDX. Instead of calling AudioPlayer.PlaySwoosh you should call AudioPlayer.PlaySound(SoundLib.Swoosh) now. You might call SoundLib.Swoosh.Play too, but this is not recommended at the moment because SoundLib.Swoosh could be nil if the file was not found. The SoundLibrary approach is much cleaner than the previous one. The AudioPlayer does not have to specify a Play... and Stop... method for every available sound anymore. In addition it is not an AudioPlayers responsibility to init the in-game sounds. URecord: - polish to english translation of some variables - CaptureSoundLeft/Right is CaptureChannel[0/1] now - TSoundCardInput -> TAudioInputDeviceSource - TGenericSoundCard.Input -> TGenericSoundCard.Source - autocorrelation algorithm more readable now - Clean-up of the audio-input interface - moved cloned code of the input-classes to one base class (TAudioInputBase) - Cleaner finalization - Start-/StopCapture will not crash anymore in the recording-options menu - Fixed several bugs in the autocorrelation stuff (e.g. wrong usage of $10000) - SzczytJest (now ToneValid) was not used correctly. ToneValid is set to true if a valid tone was found (= the sound was louder than the threshold -> no background noise). If i remember correctly the sound was accepted although the tone was invalid. So the old data was used although noone was singing. This resulted in some sort of ghost-singer effect. UIni: - moved TIni.Card to TScreenOptionsRecord.Card because it is not stored in the ini-file and will not be in the future. - TIni.CardList ist now TIni.InputDeviceConfig. The name cardlist was misleading because it just specifies input- but no output-devices. In addition a soundcard can have multiple input-devices (at least in linux). - bugfix on InputDeviceConfig (formerly CardList) usage. USDX expected that the indices of the corresponding elements in TIni.InputDeviceConfig[] and TAudioInputProcessor.Device[] were the same. This is wrong. If device 2 was defined at first place in the ini and device 1 at the second, the indices of the two arrays didn't match (they were swapped) erroneously. To fix this and to support the item listed below the index to TIni.InputDeviceConfig[] is now stored in TAudioInputDevice.CfgIndex. NOTE: InputDeviceConfig[] contains configurations of non-available (unplugged) devices. Iterate over TAudioInputProcessor.Device[] for available devices. - configurations of external devices that are not plugged in will not be deleted anymore. - multiple definitions of one device in the ini-file will not crash USDX anymore - CardList[I].ChannelL/R now are InputDeviceConfig[I].ChannelToPlayerMap[0/1]. I think the new name is more intuitive because it maps a channel to a player number. Now the both vars are joint to one array. Now it is possible to use loops to process them and we might support more than two input channels on one device in the future (if such devices exist) git-svn-id: svn://svn.code.sf.net/p/ultrastardx/svn/trunk@827 b956fd51-792f-4845-bead-9b4dfca2ff2c --- Game/Code/Classes/UAudioPlayback_Portaudio.pas | 608 ++++++++++++++----------- 1 file changed, 330 insertions(+), 278 deletions(-) (limited to 'Game/Code/Classes/UAudioPlayback_Portaudio.pas') diff --git a/Game/Code/Classes/UAudioPlayback_Portaudio.pas b/Game/Code/Classes/UAudioPlayback_Portaudio.pas index 5f4a8cde..2743fa86 100644 --- a/Game/Code/Classes/UAudioPlayback_Portaudio.pas +++ b/Game/Code/Classes/UAudioPlayback_Portaudio.pas @@ -9,35 +9,40 @@ interface {$I switches.inc} -uses Classes, - SysUtils, - UMusic; +uses + Classes, + SysUtils, + UMusic; implementation uses - {$IFDEF LAZARUS} - lclintf, - {$ifndef win32} - libc, - {$endif} - {$ENDIF} - sdl, - portaudio, - ULog, - UIni, - UMain; + {$IFNDEF Win32} + libc, + {$ENDIF} + sdl, + portaudio, + ULog, + UIni, + UMain; type TPortaudioPlaybackStream = class(TAudioPlaybackStream) private - status: TStreamStatus; - Loaded: boolean; + Status: TStreamStatus; Loop: boolean; + + _volume: integer; + + procedure Reset(); public - decodeStream: TAudioDecodeStream; + DecodeStream: TAudioDecodeStream; + + constructor Create(); + destructor Destroy(); override; + + function SetDecodeStream(decodeStream: TAudioDecodeStream): boolean; - constructor Create(decodeStream: TAudioDecodeStream); procedure Play(); override; procedure Pause(); override; procedure Stop(); override; @@ -49,6 +54,9 @@ type function IsLoaded(): boolean; + function GetVolume(): integer; override; + procedure SetVolume(volume: integer); override; + // functions delegated to the decode stream function GetPosition: real; procedure SetPosition(Time: real); @@ -60,12 +68,23 @@ type private activeStreams: TList; mixerBuffer: PChar; + internalLock: PSDL_Mutex; + + _volume: integer; + + procedure Lock(); inline; + procedure Unlock(); inline; + + function GetVolume(): integer; + procedure SetVolume(volume: integer); public constructor Create(); destructor Destroy(); override; procedure AddStream(stream: TAudioPlaybackStream); procedure RemoveStream(stream: TAudioPlaybackStream); function ReadData(Buffer: PChar; BufSize: integer): integer; + + property Volume: integer READ GetVolume WRITE SetVolume; end; type @@ -73,36 +92,29 @@ type private MusicStream: TPortaudioPlaybackStream; - StartSoundStream: TPortaudioPlaybackStream; - BackSoundStream: TPortaudioPlaybackStream; - SwooshSoundStream: TPortaudioPlaybackStream; - ChangeSoundStream: TPortaudioPlaybackStream; - OptionSoundStream: TPortaudioPlaybackStream; - ClickSoundStream: TPortaudioPlaybackStream; - DrumSoundStream: TPortaudioPlaybackStream; - HihatSoundStream: TPortaudioPlaybackStream; - ClapSoundStream: TPortaudioPlaybackStream; - ShuffleSoundStream: TPortaudioPlaybackStream; - - //Custom Sounds - CustomSounds: array of TCustomSoundEntry; - - mixerStream: TAudioMixerStream; + MixerStream: TAudioMixerStream; paStream: PPaStream; - public - FrameSize: integer; - function GetName: String; + FrameSize: integer; function InitializePortaudio(): boolean; function StartPortaudioStream(): boolean; - procedure InitializePlayback(); + function InitializeSDLAudio(): boolean; + function StartSDLAudioStream(): boolean; + procedure StopSDLAudioStream(); + public + function GetName: String; + + function InitializePlayback(): boolean; + destructor Destroy; override; + + function Load(const Filename: String): TPortaudioPlaybackStream; + procedure SetVolume(Volume: integer); procedure SetMusicVolume(Volume: integer); procedure SetLoop(Enabled: boolean); function Open(Filename: string): boolean; // true if succeed - function Load(Filename: string): TPortaudioPlaybackStream; procedure Rewind; procedure SetPosition(Time: real); procedure Play; @@ -113,27 +125,17 @@ type 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; - - //Equalizer - function GetFFTData: TFFTData; + + // Equalizer + procedure GetFFTData(var data: TFFTData); // Interface for Visualizer function GetPCMData(var data: TPCMData): Cardinal; - //Custom Sounds - function LoadCustomSound(const Filename: String): Cardinal; - procedure PlayCustomSound(const Index: Cardinal ); + // Sounds + function OpenSound(const Filename: String): TAudioPlaybackStream; + procedure PlaySound(stream: TAudioPlaybackStream); + procedure StopSound(stream: TAudioPlaybackStream); end; @@ -150,25 +152,59 @@ var constructor TAudioMixerStream.Create(); begin activeStreams := TList.Create; + internalLock := SDL_CreateMutex(); + _volume := 100; end; destructor TAudioMixerStream.Destroy(); begin - if (mixerBuffer <> nil) then + if assigned(mixerBuffer) then Freemem(mixerBuffer); activeStreams.Free; + SDL_DestroyMutex(internalLock); +end; + +procedure TAudioMixerStream.Lock(); +begin + SDL_mutexP(internalLock); +end; + +procedure TAudioMixerStream.Unlock(); +begin + SDL_mutexV(internalLock); +end; + +function TAudioMixerStream.GetVolume(): integer; +begin + Lock(); + result := _volume; + Unlock(); +end; + +procedure TAudioMixerStream.SetVolume(volume: integer); +begin + Lock(); + _volume := volume; + Unlock(); end; procedure TAudioMixerStream.AddStream(stream: TAudioPlaybackStream); begin + if not assigned(stream) then + Exit; + + Lock(); // check if stream is already in list to avoid duplicates if (activeStreams.IndexOf(Pointer(stream)) = -1) then activeStreams.Add(Pointer(stream)); + Unlock(); end; procedure TAudioMixerStream.RemoveStream(stream: TAudioPlaybackStream); begin + Lock(); activeStreams.Remove(Pointer(stream)); + Unlock(); end; function TAudioMixerStream.ReadData(Buffer: PChar; BufSize: integer): integer; @@ -176,79 +212,111 @@ var i: integer; size: integer; stream: TPortaudioPlaybackStream; + appVolume: single; begin result := BufSize; // zero target-buffer (silence) FillChar(Buffer^, BufSize, 0); - // resize mixer-buffer + // resize mixer-buffer if necessary ReallocMem(mixerBuffer, BufSize); - if (mixerBuffer = nil) then + if not assigned(mixerBuffer) then Exit; - writeln('Mix: ' + inttostr(activeStreams.Count)); + Lock(); + + //writeln('Mix: ' + inttostr(activeStreams.Count)); + + // use _volume instead of Volume to prevent recursive locking + appVolume := _volume / 100 * SDL_MIX_MAXVOLUME; for i := 0 to activeStreams.Count-1 do begin stream := TPortaudioPlaybackStream(activeStreams[i]); - if (stream.GetStatus() = sPlaying) then + if (stream.GetStatus() = ssPlaying) then begin // fetch data from current stream size := stream.ReadData(mixerBuffer, BufSize); if (size > 0) then begin - SDL_MixAudio(PUInt8(Buffer), PUInt8(mixerBuffer), size, SDL_MIX_MAXVOLUME); + SDL_MixAudio(PUInt8(Buffer), PUInt8(mixerBuffer), size, + Trunc(appVolume * stream.Volume / 100)); end; end; end; + + Unlock(); end; { TPortaudioPlaybackStream } -constructor TPortaudioPlaybackStream.Create(decodeStream: TAudioDecodeStream); +constructor TPortaudioPlaybackStream.Create(); begin inherited Create(); - status := sStopped; - if (decodeStream <> nil) then - begin - Self.decodeStream := decodeStream; - Loaded := true; - end; + Reset(); +end; + +destructor TPortaudioPlaybackStream.Destroy(); +begin + Close(); + inherited Destroy(); +end; + +procedure TPortaudioPlaybackStream.Reset(); +begin + Status := ssStopped; + Loop := false; + DecodeStream := nil; + _volume := 0; +end; + +function TPortaudioPlaybackStream.SetDecodeStream(decodeStream: TAudioDecodeStream): boolean; +begin + result := false; + + Reset(); + + if not assigned(decodeStream) then + Exit; + Self.DecodeStream := decodeStream; + + _volume := 100; + + result := true; +end; + +procedure TPortaudioPlaybackStream.Close(); +begin + Reset(); end; procedure TPortaudioPlaybackStream.Play(); begin - if (status <> sPaused) then + if (status <> ssPaused) then begin // rewind - decodeStream.Position := 0; + if assigned(DecodeStream) then + DecodeStream.Position := 0; end; - status := sPlaying; - //mixerStream.AddStream(Self); + status := ssPlaying; + //MixerStream.AddStream(Self); end; procedure TPortaudioPlaybackStream.Pause(); begin - status := sPaused; + status := ssPaused; end; procedure TPortaudioPlaybackStream.Stop(); begin - status := sStopped; -end; - -procedure TPortaudioPlaybackStream.Close(); -begin - status := sStopped; - Loaded := false; - // TODO: cleanup decode-stream + status := ssStopped; end; function TPortaudioPlaybackStream.IsLoaded(): boolean; begin - result := Loaded; + result := assigned(DecodeStream); end; function TPortaudioPlaybackStream.GetLoop(): boolean; @@ -263,7 +331,10 @@ end; function TPortaudioPlaybackStream.GetLength(): real; begin - result := decodeStream.Length; + if assigned(DecodeStream) then + result := DecodeStream.Length + else + result := -1; end; function TPortaudioPlaybackStream.GetStatus(): TStreamStatus; @@ -273,22 +344,47 @@ end; function TPortaudioPlaybackStream.ReadData(Buffer: PChar; BufSize: integer): integer; begin - result := decodeStream.ReadData(Buffer, BufSize); + if not assigned(DecodeStream) then + begin + result := -1; + Exit; + end; + result := DecodeStream.ReadData(Buffer, BufSize); // end-of-file reached -> stop playback - if (decodeStream.EOF) then + if (DecodeStream.EOF) then begin - status := sStopped; + status := ssStopped; end; end; function TPortaudioPlaybackStream.GetPosition: real; begin - result := decodeStream.Position; + if assigned(DecodeStream) then + result := DecodeStream.Position + else + result := -1; end; procedure TPortaudioPlaybackStream.SetPosition(Time: real); begin - decodeStream.Position := Time; + if assigned(DecodeStream) then + DecodeStream.Position := Time; +end; + +function TPortaudioPlaybackStream.GetVolume(): integer; +begin + result := _volume; +end; + +procedure TPortaudioPlaybackStream.SetVolume(volume: integer); +begin + // clamp volume + if (volume > 100) then + _volume := 100 + else if (volume < 0) then + _volume := 0 + else + _volume := volume; end; @@ -298,18 +394,26 @@ function AudioCallback(input: Pointer; output: Pointer; frameCount: Longword; timeInfo: PPaStreamCallbackTimeInfo; statusFlags: TPaStreamCallbackFlags; userData: Pointer): Integer; cdecl; var - playback : TAudioPlayback_Portaudio; - playbackStream : TPortaudioPlaybackStream; - decodeStream : TAudioDecodeStream; + playback: TAudioPlayback_Portaudio; begin playback := TAudioPlayback_Portaudio(userData); with playback do begin - mixerStream.ReadData(output, frameCount * FrameSize); + MixerStream.ReadData(output, frameCount * FrameSize); end; result := paContinue; end; +procedure SDLAudioCallback(userdata: Pointer; stream: PChar; len: integer); cdecl; +var + playback: TAudioPlayback_Portaudio; +begin + playback := TAudioPlayback_Portaudio(userdata); + with playback do + begin + //MixerStream.ReadData(stream, len); + end; +end; function TAudioPlayback_Portaudio.GetName: String; begin @@ -349,10 +453,11 @@ begin device := paOutDevice; channelCount := 2; sampleFormat := paInt16; - suggestedLatency := paOutDeviceInfo^.defaultLowOutputLatency; + suggestedLatency := paOutDeviceInfo^.defaultHighOutputLatency; hostApiSpecificStreamInfo := nil; end; + // set the size of one audio frame (2channel 16bit uint sample) FrameSize := 2 * sizeof(Smallint); err := Pa_OpenStream(paStream, nil, @paOutParams, 44100, @@ -384,219 +489,208 @@ begin result := true; end; -procedure TAudioPlayback_Portaudio.InitializePlayback; +function TAudioPlayback_Portaudio.InitializeSDLAudio(): boolean; +var + desiredAudioSpec, obtainedAudioSpec: TSDL_AudioSpec; + err: integer; begin - Log.LogStatus('InitializePlayback', 'UAudioPlayback_Portaudio'); + result := false; - InitializePortaudio(); - mixerStream := TAudioMixerStream.Create; + SDL_InitSubSystem(SDL_INIT_AUDIO); - StartSoundStream := Load(SoundPath + 'Common start.mp3'); - BackSoundStream := Load(SoundPath + 'Common back.mp3'); - SwooshSoundStream := Load(SoundPath + 'menu swoosh.mp3'); - ChangeSoundStream := Load(SoundPath + 'select music change music 50.mp3'); - OptionSoundStream := Load(SoundPath + 'option change col.mp3'); - ClickSoundStream := Load(SoundPath + 'rimshot022b.mp3'); + FillChar(desiredAudioSpec, sizeof(desiredAudioSpec), 0); + with desiredAudioSpec do + begin + freq := 44100; + format := AUDIO_S16SYS; + channels := 2; + samples := 1024; // latency: 23 ms + callback := @SDLAudioCallback; + userdata := Self; + end; -// DrumSoundStream := Load(SoundPath + 'bassdrumhard076b.mp3'); -// HihatSoundStream := Load(SoundPath + 'hihatclosed068b.mp3'); -// ClapSoundStream := Load(SoundPath + 'claps050b.mp3'); + // set the size of one audio frame (2channel 16bit uint sample) + FrameSize := 2 * sizeof(Smallint); + + if(SDL_OpenAudio(@desiredAudioSpec, @obtainedAudioSpec) = -1) then + begin + Log.LogStatus('SDL_OpenAudio: ' + SDL_GetError(), 'UAudioPlayback_SDL'); + exit; + end; -// ShuffleSoundStream := Load(SoundPath + 'Shuffle.mp3'); + Log.LogStatus('Opened audio device', 'UAudioPlayback_SDL'); - StartPortaudioStream(); + result := true; end; +function TAudioPlayback_Portaudio.StartSDLAudioStream(): boolean; +begin + SDL_PauseAudio(0); + result := true; +end; -procedure TAudioPlayback_Portaudio.SetVolume(Volume: integer); +procedure TAudioPlayback_Portaudio.StopSDLAudioStream(); begin - //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); -*) + SDL_CloseAudio(); end; -procedure TAudioPlayback_Portaudio.SetMusicVolume(Volume: Integer); +function TAudioPlayback_Portaudio.InitializePlayback: boolean; begin - //Max Volume Prevention - if Volume > 100 then - Volume := 100; + result := false; - if Volume < 0 then - Volume := 0; + //Log.LogStatus('InitializePlayback', 'UAudioPlayback_Portaudio'); - //Set Volume -// BASS_ChannelSetAttributes (Bass, -1, Volume, -101); + //if(not InitializePortaudio()) then + if(not InitializeSDLAudio()) then + Exit; + + MixerStream := TAudioMixerStream.Create; + + //if(not StartPortaudioStream()) then; + if(not StartSDLAudioStream()) then + Exit; + + result := true; end; -procedure TAudioPlayback_Portaudio.SetLoop(Enabled: boolean); +destructor TAudioPlayback_Portaudio.Destroy; begin - if (MusicStream <> nil) then - if (MusicStream.IsLoaded) then - MusicStream.SetLoop(Enabled); + StopSDLAudioStream(); + + MixerStream.Free(); + MusicStream.Free(); + + inherited Destroy(); end; -function TAudioPlayback_Portaudio.Open(Filename: string): boolean; +function TAudioPlayback_Portaudio.Load(const Filename: String): TPortaudioPlaybackStream; var decodeStream: TAudioDecodeStream; + playbackStream: TPortaudioPlaybackStream; begin - decodeStream := AudioDecoder.Open(Filename); - MusicStream := TPortaudioPlaybackStream.Create(decodeStream); - // FIXME: remove this line - mixerStream.AddStream(MusicStream); + Result := nil; - if(MusicStream.IsLoaded()) then + decodeStream := AudioDecoder.Open(Filename); + if not assigned(decodeStream) then begin - //Set Max Volume - SetMusicVolume(100); + Log.LogStatus('LoadSoundFromFile: Sound not found "' + Filename + '"', 'UAudioPlayback_Portaudio'); + Exit; end; - Result := MusicStream.IsLoaded(); -end; - -procedure TAudioPlayback_Portaudio.Rewind; -begin - SetPosition(0); -end; + playbackStream := TPortaudioPlaybackStream.Create(); + if (not playbackStream.SetDecodeStream(decodeStream)) then + Exit; -procedure TAudioPlayback_Portaudio.SetPosition(Time: real); -begin - if (MusicStream.IsLoaded) then - begin - MusicStream.SetPosition(Time); - end; -end; + // FIXME: remove this line + MixerStream.AddStream(playbackStream); -function TAudioPlayback_Portaudio.GetPosition: real; -begin - if (MusicStream.IsLoaded) then - Result := MusicStream.GetPosition(); + result := playbackStream; end; -function TAudioPlayback_Portaudio.Length: real; +procedure TAudioPlayback_Portaudio.SetVolume(Volume: integer); begin - Result := 0; - if assigned( MusicStream ) then - if (MusicStream.IsLoaded) then - begin - Result := MusicStream.GetLength(); - end; + // sets volume only for this application + MixerStream.Volume := Volume; end; -procedure TAudioPlayback_Portaudio.Play; +procedure TAudioPlayback_Portaudio.SetMusicVolume(Volume: Integer); begin - if (MusicStream <> nil) then - if (MusicStream.IsLoaded) then - begin - if (MusicStream.GetLoop()) then - begin - end; - // start from beginning... - // actually bass itself does not loop, nor does this TAudio_FFMpeg Class - MusicStream.Play(); - end; + if assigned(MusicStream) then + MusicStream.Volume := Volume; end; -procedure TAudioPlayback_Portaudio.Pause; +procedure TAudioPlayback_Portaudio.SetLoop(Enabled: boolean); begin - if (MusicStream <> nil) then - MusicStream.Pause(); + if assigned(MusicStream) then + MusicStream.SetLoop(Enabled); end; -procedure TAudioPlayback_Portaudio.Stop; +function TAudioPlayback_Portaudio.Open(Filename: string): boolean; +var + decodeStream: TAudioDecodeStream; begin - if MusicStream <> nil then - MusicStream.Stop(); -end; + Result := false; -procedure TAudioPlayback_Portaudio.Close; -begin - if MusicStream <> nil then - MusicStream.Close(); -end; + // free old MusicStream + MusicStream.Free(); -function TAudioPlayback_Portaudio.Finished: boolean; -begin - if MusicStream <> nil then - Result := (MusicStream.GetStatus() = sStopped); -end; + MusicStream := Load(Filename); + if not assigned(MusicStream) then + Exit; -procedure TAudioPlayback_Portaudio.PlayStart; -begin - if StartSoundStream <> nil then - StartSoundStream.Play(); -end; + //Set Max Volume + SetMusicVolume(100); -procedure TAudioPlayback_Portaudio.PlayBack; -begin - if BackSoundStream <> nil then - BackSoundStream.Play(); + Result := true; end; -procedure TAudioPlayback_Portaudio.PlaySwoosh; +procedure TAudioPlayback_Portaudio.Rewind; begin - if SwooshSoundStream <> nil then - SwooshSoundStream.Play(); + SetPosition(0); end; -procedure TAudioPlayback_Portaudio.PlayChange; +procedure TAudioPlayback_Portaudio.SetPosition(Time: real); begin - if ChangeSoundStream <> nil then - ChangeSoundStream.Play(); + if assigned(MusicStream) then + MusicStream.SetPosition(Time); end; -procedure TAudioPlayback_Portaudio.PlayOption; +function TAudioPlayback_Portaudio.GetPosition: real; begin - if OptionSoundStream <> nil then - OptionSoundStream.Play(); + if assigned(MusicStream) then + Result := MusicStream.GetPosition() + else + Result := -1; end; -procedure TAudioPlayback_Portaudio.PlayClick; +function TAudioPlayback_Portaudio.Length: real; begin - if ClickSoundStream <> nil then - ClickSoundStream.Play(); + if assigned(MusicStream) then + Result := MusicStream.GetLength() + else + Result := -1; end; -procedure TAudioPlayback_Portaudio.PlayDrum; +procedure TAudioPlayback_Portaudio.Play; begin - if DrumSoundStream <> nil then - DrumSoundStream.Play(); + if assigned(MusicStream) then + MusicStream.Play(); end; -procedure TAudioPlayback_Portaudio.PlayHihat; +procedure TAudioPlayback_Portaudio.Pause; begin - if HihatSoundStream <> nil then - HihatSoundStream.Play(); + if assigned(MusicStream) then + MusicStream.Pause(); end; -procedure TAudioPlayback_Portaudio.PlayClap; +procedure TAudioPlayback_Portaudio.Stop; begin - if ClapSoundStream <> nil then - ClapSoundStream.Play(); + if assigned(MusicStream) then + MusicStream.Stop(); end; -procedure TAudioPlayback_Portaudio.PlayShuffle; +procedure TAudioPlayback_Portaudio.Close; begin - if ShuffleSoundStream <> nil then - ShuffleSoundStream.Play(); + if assigned(MusicStream) then + begin + MixerStream.RemoveStream(MusicStream); + MusicStream.Close(); + end; end; -procedure TAudioPlayback_Portaudio.StopShuffle; +function TAudioPlayback_Portaudio.Finished: boolean; begin - if ShuffleSoundStream <> nil then - ShuffleSoundStream.Stop(); + if assigned(MusicStream) then + Result := (MusicStream.GetStatus() = ssStopped) + else + Result := true; end; //Equalizer -function TAudioPlayback_Portaudio.GetFFTData: TFFTData; -var - data: TFFTData; +procedure TAudioPlayback_Portaudio.GetFFTData(var data: TFFTData); begin //Get Channel Data Mono and 256 Values // BASS_ChannelGetData(Bass, @Result, BASS_DATA_FFT512); - result := data; end; // Interface for Visualizer @@ -605,66 +699,24 @@ begin result := 0; end; -function TAudioPlayback_Portaudio.Load(Filename: string): TPortaudioPlaybackStream; -var - decodeStream : TAudioDecodeStream; - playbackStream : TPortaudioPlaybackStream; - csIndex : integer; +function TAudioPlayback_Portaudio.OpenSound(const Filename: String): TAudioPlaybackStream; begin - result := nil; - - decodeStream := AudioDecoder.Open(Filename); - if (decodeStream = nil) then - begin - Log.LogStatus('LoadSoundFromFile: Sound not found "' + Filename + '"', 'UAudioPlayback_Portaudio'); - exit; - end; - - playbackStream := TPortaudioPlaybackStream.Create(decodeStream); - // FIXME: remove this line - mixerStream.AddStream(playbackStream); - - //Add CustomSound - csIndex := High(CustomSounds) + 1; - SetLength(CustomSounds, csIndex + 1); - CustomSounds[csIndex].Filename := Filename; - CustomSounds[csIndex].Stream := playbackStream; - - result := playbackStream; + result := Load(Filename); end; -function TAudioPlayback_Portaudio.LoadCustomSound(const Filename: String): Cardinal; -var - S: TAudioPlaybackStream; - I: Integer; - F: String; +procedure TAudioPlayback_Portaudio.PlaySound(stream: TAudioPlaybackStream); 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; - - S := Load(SoundPath + Filename); - if (S <> nil) then - Result := High(CustomSounds) - else - Result := 0; + if assigned(stream) then + stream.Play(); end; -procedure TAudioPlayback_Portaudio.PlayCustomSound(const Index: Cardinal ); +procedure TAudioPlayback_Portaudio.StopSound(stream: TAudioPlaybackStream); begin - if (Index <= High(CustomSounds)) then - CustomSounds[Index].Stream.Play(); + if assigned(stream) then + stream.Stop(); end; - initialization singleton_AudioPlaybackPortaudio := TAudioPlayback_Portaudio.create(); AudioManager.add( singleton_AudioPlaybackPortaudio ); -- cgit v1.2.3