From e5bdcfc8e584d2867d0ad7995d18bd30c7874d1b Mon Sep 17 00:00:00 2001 From: tobigun Date: Fri, 28 Dec 2007 11:46:04 +0000 Subject: New class-structure seperates decoders/input and playback. The files aren't used in usdx until they are stable so they will not conflict with the old structure. The older files (UAudio_Bass etc.) will be replaced then. git-svn-id: svn://svn.code.sf.net/p/ultrastardx/svn/trunk@752 b956fd51-792f-4845-bead-9b4dfca2ff2c --- Game/Code/Classes/UAudioPlayback_Portaudio.pas | 664 +++++++++++++++++++++++++ 1 file changed, 664 insertions(+) create mode 100644 Game/Code/Classes/UAudioPlayback_Portaudio.pas (limited to 'Game/Code/Classes/UAudioPlayback_Portaudio.pas') diff --git a/Game/Code/Classes/UAudioPlayback_Portaudio.pas b/Game/Code/Classes/UAudioPlayback_Portaudio.pas new file mode 100644 index 00000000..36bebc8a --- /dev/null +++ b/Game/Code/Classes/UAudioPlayback_Portaudio.pas @@ -0,0 +1,664 @@ +unit UAudioPlayback_Portaudio; + +interface + +{$IFDEF FPC} + {$MODE Delphi} +{$ENDIF} + +{$I switches.inc} + + +uses Classes, + SysUtils, + UMusic; + +implementation + +uses + {$IFDEF LAZARUS} + lclintf, + {$ifndef win32} + libc, + {$endif} + {$ENDIF} + portaudio, + ULog, + UIni, + UMain; + +type + TPortaudioPlaybackStream = class(TAudioPlaybackStream) + private + status: TStreamStatus; + Loaded: boolean; + Loop: boolean; + public + decodeStream: TAudioDecodeStream; + + constructor Create(decodeStream: TAudioDecodeStream); + 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 ReadData(Buffer: PChar; BufSize: integer): integer; + + function IsLoaded(): boolean; + end; + +type + TAudioMixerStream = class + private + activeStreams: TList; + public + constructor Create(); + destructor Destroy(); override; + procedure AddStream(stream: TAudioPlaybackStream); + procedure RemoveStream(stream: TAudioPlaybackStream); + function ReadData(Buffer: PChar; BufSize: integer): integer; + end; + +type + TAudioPlayback_Portaudio = class( TInterfacedObject, IAudioPlayback ) + 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; + paStream: PPaStream; + public + FrameSize: integer; + + function GetName: String; + + function InitializePortaudio(): boolean; + function StartPortaudioStream(): boolean; + + procedure InitializePlayback(); + 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; + 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; + + //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; + + +function AudioCallback(input: Pointer; output: Pointer; frameCount: Longword; + timeInfo: PPaStreamCallbackTimeInfo; statusFlags: TPaStreamCallbackFlags; + userData: Pointer): Integer; cdecl; forward; + +var + singleton_AudioPlaybackPortaudio : IAudioPlayback; + + +{ TAudioMixerStream } + +constructor TAudioMixerStream.Create(); +begin + activeStreams := TList.Create; +end; + +destructor TAudioMixerStream.Destroy(); +begin + activeStreams.Free; +end; + +procedure TAudioMixerStream.AddStream(stream: TAudioPlaybackStream); +begin + // check if stream is already in list to avoid duplicates + if (activeStreams.IndexOf(Pointer(stream)) = -1) then + activeStreams.Add(Pointer(stream)); +end; + +procedure TAudioMixerStream.RemoveStream(stream: TAudioPlaybackStream); +begin + activeStreams.Remove(Pointer(stream)); +end; + +function TAudioMixerStream.ReadData(Buffer: PChar; BufSize: integer): integer; +var + i: integer; + stream: TPortaudioPlaybackStream; + dataAvailable: boolean; +begin + dataAvailable := false; + + // search for playing stream + if (activeStreams.Count > 0) then + begin + for i := 0 to activeStreams.Count-1 do + begin + stream := TPortaudioPlaybackStream(activeStreams[i]); + if (stream.getStatus = sPlaying) then + begin + dataAvailable := true; + break; + end; + end; + + // fetch data from current stream + if (dataAvailable) then + begin + result := stream.ReadData(Buffer, BufSize); + end; + end; + + // return silence + if ((not dataAvailable) or (result = -1)) then + begin + FillChar(Buffer^, BufSize, 0); + result := BufSize; + end; +end; + + +{ TPortaudioPlaybackStream } + +constructor TPortaudioPlaybackStream.Create(decodeStream: TAudioDecodeStream); +begin + inherited Create(); + status := sStopped; + if (decodeStream <> nil) then + begin + Self.decodeStream := decodeStream; + Loaded := true; + end; +end; + +procedure TPortaudioPlaybackStream.Play(); +begin + status := sPlaying; +end; + +procedure TPortaudioPlaybackStream.Pause(); +begin + status := sPaused; +end; + +procedure TPortaudioPlaybackStream.Stop(); +begin + status := sStopped; +end; + +procedure TPortaudioPlaybackStream.Close(); +begin + Stop(); +end; + +function TPortaudioPlaybackStream.IsLoaded(): boolean; +begin + result := Loaded; +end; + +function TPortaudioPlaybackStream.GetLoop(): boolean; +begin + result := Loop; +end; + +procedure TPortaudioPlaybackStream.SetLoop(Enabled: boolean); +begin + Loop := Enabled; +end; + +function TPortaudioPlaybackStream.GetLength(): real; +begin + result := decodeStream.Length; +end; + +function TPortaudioPlaybackStream.GetStatus(): TStreamStatus; +begin + result := status; +end; + +function TPortaudioPlaybackStream.ReadData(Buffer: PChar; BufSize: integer): integer; +begin + result := decodeStream.ReadData(Buffer, BufSize); + // end-of-stream reached -> stop playback + if (decodeStream.EOS) then + begin + status := sStopped; + end; +end; + + +{ TAudioPlayback_Portaudio } + +function AudioCallback(input: Pointer; output: Pointer; frameCount: Longword; + timeInfo: PPaStreamCallbackTimeInfo; statusFlags: TPaStreamCallbackFlags; + userData: Pointer): Integer; cdecl; +var + playback : TAudioPlayback_Portaudio; + playbackStream : TPortaudioPlaybackStream; + decodeStream : TAudioDecodeStream; +begin + playback := TAudioPlayback_Portaudio(userData); + with playback do + begin + mixerStream.ReadData(output, frameCount * FrameSize); + end; + result := paContinue; +end; + + +function TAudioPlayback_Portaudio.GetName: String; +begin + result := 'Portaudio_Playback'; +end; + +function TAudioPlayback_Portaudio.InitializePortaudio(): boolean; +var + paApi : TPaHostApiIndex; + paApiInfo : PPaHostApiInfo; + paOutParams : TPaStreamParameters; + paOutDevice : TPaDeviceIndex; + paOutDeviceInfo : PPaDeviceInfo; + err : TPaError; +begin + result := false; + + Pa_Initialize(); + + // FIXME: determine automatically + {$IFDEF WIN32} + paApi := Pa_HostApiTypeIdToHostApiIndex(paDirectSound); + {$ELSE} + paApi := Pa_HostApiTypeIdToHostApiIndex(paALSA); + {$ENDIF} + if (paApi < 0) then + begin + Log.LogStatus('Pa_HostApiTypeIdToHostApiIndex: '+Pa_GetErrorText(paApi), 'UAudioPlayback_Portaudio'); + exit; + end; + + paApiInfo := Pa_GetHostApiInfo(paApi); + paOutDevice := paApiInfo^.defaultOutputDevice; + paOutDeviceInfo := Pa_GetDeviceInfo(paOutDevice); + + with paOutParams do begin + device := paOutDevice; + channelCount := 2; + sampleFormat := paInt16; + suggestedLatency := paOutDeviceInfo^.defaultLowOutputLatency; + hostApiSpecificStreamInfo := nil; + end; + + FrameSize := 2 * sizeof(Smallint); + + err := Pa_OpenStream(paStream, nil, @paOutParams, 44100, + paFramesPerBufferUnspecified, + paNoFlag, @AudioCallback, Self); + if(err <> paNoError) then begin + Log.LogStatus('Pa_OpenStream: '+Pa_GetErrorText(err), 'UAudioPlayback_Portaudio'); + exit; + end; + + Log.LogStatus('Opened audio device', 'UAudioPlayback_Portaudio'); + + result := true; +end; + +function TAudioPlayback_Portaudio.StartPortaudioStream(): boolean; +var + err: TPaError; +begin + result := false; + + err := Pa_StartStream(paStream); + if(err <> paNoError) then + begin + Log.LogStatus('Pa_StartStream: '+Pa_GetErrorText(err), 'UAudioPlayback_Portaudio'); + exit; + end; + + result := true; +end; + +procedure TAudioPlayback_Portaudio.InitializePlayback; +begin + Log.LogStatus('InitializePlayback', 'UAudioPlayback_Portaudio'); + + InitializePortaudio(); + mixerStream := TAudioMixerStream.Create; + + 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'); + +// DrumSoundStream := Load(SoundPath + 'bassdrumhard076b.mp3'); +// HihatSoundStream := Load(SoundPath + 'hihatclosed068b.mp3'); +// ClapSoundStream := Load(SoundPath + 'claps050b.mp3'); + +// ShuffleSoundStream := Load(SoundPath + 'Shuffle.mp3'); + + StartPortaudioStream(); +end; + + +procedure TAudioPlayback_Portaudio.SetVolume(Volume: integer); +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); +*) +end; + +procedure TAudioPlayback_Portaudio.SetMusicVolume(Volume: Integer); +begin + //Max Volume Prevention + if Volume > 100 then + Volume := 100; + + if Volume < 0 then + Volume := 0; + + //Set Volume +// BASS_ChannelSetAttributes (Bass, -1, Volume, -101); +end; + +procedure TAudioPlayback_Portaudio.SetLoop(Enabled: boolean); +begin + MusicStream.SetLoop(Enabled); +end; + +function TAudioPlayback_Portaudio.Open(Filename: string): boolean; +var + decodeStream: TAudioDecodeStream; +begin + decodeStream := AudioDecoder.Open(Filename); + MusicStream := TPortaudioPlaybackStream.Create(decodeStream); + + if(MusicStream.IsLoaded()) then + begin + //Set Max Volume + SetMusicVolume(100); + end; + + Result := MusicStream.IsLoaded(); +end; + +procedure TAudioPlayback_Portaudio.Rewind; +begin + SetPosition(0); +end; + +procedure TAudioPlayback_Portaudio.SetPosition(Time: real); +var + bytes: integer; +begin + if (MusicStream.IsLoaded) then + begin + MusicStream.SetPosition(Time); + end; +end; + +procedure TAudioPlayback_Portaudio.Play; +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; +end; + +procedure TAudioPlayback_Portaudio.Pause; //Pause Mod +begin + if (MusicStream <> nil) then + if (MusicStream.IsLoaded()) then begin + MusicStream.Pause(); // Pauses Song + end; +end; + +procedure TAudioPlayback_Portaudio.Stop; +begin + if MusicStream <> nil then + MusicStream.Stop(); +end; + +procedure TAudioPlayback_Portaudio.Close; +begin + if MusicStream <> nil then + MusicStream.Close(); +end; + +function TAudioPlayback_Portaudio.Length: real; +begin + Result := 0; + if assigned( MusicStream ) then + begin + Result := MusicStream.GetLength(); + end; +end; + +function TAudioPlayback_Portaudio.getPosition: real; +var + bytes: integer; +begin + Result := 0; + +(* + bytes := BASS_ChannelGetPosition(BASS); + Result := BASS_ChannelBytes2Seconds(BASS, bytes); +*) +end; + +function TAudioPlayback_Portaudio.Finished: boolean; +begin + Result := false; + +(* + if BASS_ChannelIsActive(BASS) = BASS_ACTIVE_STOPPED then + begin + Result := true; + end; +*) +end; + +procedure TAudioPlayback_Portaudio.PlayStart; +begin + if StartSoundStream <> nil then + StartSoundStream.Play(); +end; + +procedure TAudioPlayback_Portaudio.PlayBack; +begin + if BackSoundStream <> nil then + BackSoundStream.Play(); +end; + +procedure TAudioPlayback_Portaudio.PlaySwoosh; +begin + if SwooshSoundStream <> nil then + SwooshSoundStream.Play(); +end; + +procedure TAudioPlayback_Portaudio.PlayChange; +begin + if ChangeSoundStream <> nil then + ChangeSoundStream.Play(); +end; + +procedure TAudioPlayback_Portaudio.PlayOption; +begin + if OptionSoundStream <> nil then + OptionSoundStream.Play(); +end; + +procedure TAudioPlayback_Portaudio.PlayClick; +begin + if ClickSoundStream <> nil then + ClickSoundStream.Play(); +end; + +procedure TAudioPlayback_Portaudio.PlayDrum; +begin + if DrumSoundStream <> nil then + DrumSoundStream.Play(); +end; + +procedure TAudioPlayback_Portaudio.PlayHihat; +begin + if HihatSoundStream <> nil then + HihatSoundStream.Play(); +end; + +procedure TAudioPlayback_Portaudio.PlayClap; +begin + if ClapSoundStream <> nil then + ClapSoundStream.Play(); +end; + +procedure TAudioPlayback_Portaudio.PlayShuffle; +begin + if ShuffleSoundStream <> nil then + ShuffleSoundStream.Play(); +end; + +procedure TAudioPlayback_Portaudio.StopShuffle; +begin + if ShuffleSoundStream <> nil then + ShuffleSoundStream.Stop(); +end; + +//Equalizer +function TAudioPlayback_Portaudio.GetFFTData: TFFTData; +var + data: TFFTData; +begin + //Get Channel Data Mono and 256 Values +// BASS_ChannelGetData(Bass, @Result, BASS_DATA_FFT512); + result := data; +end; + +// Interface for Visualizer +function TAudioPlayback_Portaudio.GetPCMData(var data: TPCMData): Cardinal; +begin + result := 0; +end; + +function TAudioPlayback_Portaudio.Load(Filename: string): TPortaudioPlaybackStream; +var + decodeStream : TAudioDecodeStream; + playbackStream : TPortaudioPlaybackStream; + csIndex : integer; +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); + mixerStream.AddStream(playbackStream); + + //Add CustomSound + csIndex := High(CustomSounds) + 1; + SetLength(CustomSounds, csIndex + 1); + CustomSounds[csIndex].Filename := Filename; + CustomSounds[csIndex].Stream := playbackStream; + + result := playbackStream; +end; + +function TAudioPlayback_Portaudio.LoadCustomSound(const Filename: String): Cardinal; +var + S: TAudioPlaybackStream; + 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; + + S := Load(SoundPath + Filename); + if (S <> nil) then + Result := High(CustomSounds) + else + Result := 0; +end; + +procedure TAudioPlayback_Portaudio.PlayCustomSound(const Index: Cardinal ); +begin + if (Index <= High(CustomSounds)) then + CustomSounds[Index].Stream.Play(); +end; + + + +initialization + singleton_AudioPlaybackPortaudio := TAudioPlayback_Portaudio.create(); + AudioManager.add( singleton_AudioPlaybackPortaudio ); + +finalization + AudioManager.Remove( singleton_AudioPlaybackPortaudio ); + + +end. -- cgit v1.2.3 From 4a0e50ba0cc5bd835aaf942b65149e9613aad86e Mon Sep 17 00:00:00 2001 From: tobigun Date: Fri, 28 Dec 2007 13:08:55 +0000 Subject: experimental positioning support added git-svn-id: svn://svn.code.sf.net/p/ultrastardx/svn/trunk@753 b956fd51-792f-4845-bead-9b4dfca2ff2c --- Game/Code/Classes/UAudioPlayback_Portaudio.pas | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 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 36bebc8a..c2694e6d 100644 --- a/Game/Code/Classes/UAudioPlayback_Portaudio.pas +++ b/Game/Code/Classes/UAudioPlayback_Portaudio.pas @@ -46,9 +46,12 @@ type function GetLength(): real; override; function GetStatus(): TStreamStatus; override; - function ReadData(Buffer: PChar; BufSize: integer): integer; - function IsLoaded(): boolean; + + // functions delegated to the decode stream + function GetPosition: real; + procedure SetPosition(Time: real); + function ReadData(Buffer: PChar; BufSize: integer): integer; end; type @@ -269,6 +272,16 @@ begin end; end; +function TPortaudioPlaybackStream.GetPosition: real; +begin + result := decodeStream.Position; +end; + +procedure TPortaudioPlaybackStream.SetPosition(Time: real); +begin + decodeStream.Position := Time; +end; + { TAudioPlayback_Portaudio } -- cgit v1.2.3 From d69c2a35192623e5d923f17c07d96d980d045adf Mon Sep 17 00:00:00 2001 From: tobigun Date: Thu, 10 Jan 2008 22:59:10 +0000 Subject: partial seeking and mixing support git-svn-id: svn://svn.code.sf.net/p/ultrastardx/svn/trunk@775 b956fd51-792f-4845-bead-9b4dfca2ff2c --- Game/Code/Classes/UAudioPlayback_Portaudio.pas | 123 ++++++++++++------------- 1 file changed, 59 insertions(+), 64 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 c2694e6d..c1abd0eb 100644 --- a/Game/Code/Classes/UAudioPlayback_Portaudio.pas +++ b/Game/Code/Classes/UAudioPlayback_Portaudio.pas @@ -22,6 +22,7 @@ uses libc, {$endif} {$ENDIF} + sdl, portaudio, ULog, UIni, @@ -58,6 +59,7 @@ type TAudioMixerStream = class private activeStreams: TList; + mixerBuffer: PChar; public constructor Create(); destructor Destroy(); override; @@ -104,7 +106,7 @@ type procedure Rewind; procedure SetPosition(Time: real); procedure Play; - procedure Pause; //Pause Mod + procedure Pause; procedure Stop; procedure Close; @@ -152,6 +154,8 @@ end; destructor TAudioMixerStream.Destroy(); begin + if (mixerBuffer <> nil) then + Freemem(mixerBuffer); activeStreams.Free; end; @@ -170,36 +174,33 @@ end; function TAudioMixerStream.ReadData(Buffer: PChar; BufSize: integer): integer; var i: integer; + size: integer; stream: TPortaudioPlaybackStream; - dataAvailable: boolean; begin - dataAvailable := false; + result := BufSize; - // search for playing stream - if (activeStreams.Count > 0) then + // zero target-buffer (silence) + FillChar(Buffer^, BufSize, 0); + + // resize mixer-buffer + ReallocMem(mixerBuffer, BufSize); + if (mixerBuffer = nil) then + Exit; + + writeln('Mix: ' + inttostr(activeStreams.Count)); + + for i := 0 to activeStreams.Count-1 do begin - for i := 0 to activeStreams.Count-1 do + stream := TPortaudioPlaybackStream(activeStreams[i]); + if (stream.GetStatus() = sPlaying) then begin - stream := TPortaudioPlaybackStream(activeStreams[i]); - if (stream.getStatus = sPlaying) then + // fetch data from current stream + size := stream.ReadData(mixerBuffer, BufSize); + if (size > 0) then begin - dataAvailable := true; - break; + SDL_MixAudio(PUInt8(Buffer), PUInt8(mixerBuffer), size, SDL_MIX_MAXVOLUME); end; end; - - // fetch data from current stream - if (dataAvailable) then - begin - result := stream.ReadData(Buffer, BufSize); - end; - end; - - // return silence - if ((not dataAvailable) or (result = -1)) then - begin - FillChar(Buffer^, BufSize, 0); - result := BufSize; end; end; @@ -219,7 +220,13 @@ end; procedure TPortaudioPlaybackStream.Play(); begin + if (status <> sPaused) then + begin + // rewind + decodeStream.Position := 0; + end; status := sPlaying; + mixerStream.AddStream(Self); end; procedure TPortaudioPlaybackStream.Pause(); @@ -234,7 +241,9 @@ end; procedure TPortaudioPlaybackStream.Close(); begin - Stop(); + status := sStopped; + Loaded := false; + // TODO: cleanup decode-stream end; function TPortaudioPlaybackStream.IsLoaded(): boolean; @@ -265,8 +274,8 @@ end; function TPortaudioPlaybackStream.ReadData(Buffer: PChar; BufSize: integer): integer; begin result := decodeStream.ReadData(Buffer, BufSize); - // end-of-stream reached -> stop playback - if (decodeStream.EOS) then + // end-of-file reached -> stop playback + if (decodeStream.EOF) then begin status := sStopped; end; @@ -424,7 +433,9 @@ end; procedure TAudioPlayback_Portaudio.SetLoop(Enabled: boolean); begin - MusicStream.SetLoop(Enabled); + if (MusicStream <> nil) then + if (MusicStream.IsLoaded) then + MusicStream.SetLoop(Enabled); end; function TAudioPlayback_Portaudio.Open(Filename: string): boolean; @@ -449,8 +460,6 @@ begin end; procedure TAudioPlayback_Portaudio.SetPosition(Time: real); -var - bytes: integer; begin if (MusicStream.IsLoaded) then begin @@ -458,10 +467,26 @@ begin end; end; +function TAudioPlayback_Portaudio.GetPosition: real; +begin + if (MusicStream.IsLoaded) then + Result := MusicStream.GetPosition(); +end; + +function TAudioPlayback_Portaudio.Length: real; +begin + Result := 0; + if assigned( MusicStream ) then + if (MusicStream.IsLoaded) then + begin + Result := MusicStream.GetLength(); + end; +end; + procedure TAudioPlayback_Portaudio.Play; begin if (MusicStream <> nil) then - if (MusicStream.IsLoaded()) then + if (MusicStream.IsLoaded) then begin if (MusicStream.GetLoop()) then begin @@ -472,12 +497,10 @@ begin end; end; -procedure TAudioPlayback_Portaudio.Pause; //Pause Mod +procedure TAudioPlayback_Portaudio.Pause; begin if (MusicStream <> nil) then - if (MusicStream.IsLoaded()) then begin - MusicStream.Pause(); // Pauses Song - end; + MusicStream.Pause(); end; procedure TAudioPlayback_Portaudio.Stop; @@ -492,37 +515,10 @@ begin MusicStream.Close(); end; -function TAudioPlayback_Portaudio.Length: real; -begin - Result := 0; - if assigned( MusicStream ) then - begin - Result := MusicStream.GetLength(); - end; -end; - -function TAudioPlayback_Portaudio.getPosition: real; -var - bytes: integer; -begin - Result := 0; - -(* - bytes := BASS_ChannelGetPosition(BASS); - Result := BASS_ChannelBytes2Seconds(BASS, bytes); -*) -end; - function TAudioPlayback_Portaudio.Finished: boolean; begin - Result := false; - -(* - if BASS_ChannelIsActive(BASS) = BASS_ACTIVE_STOPPED then - begin - Result := true; - end; -*) + if MusicStream <> nil then + Result := (MusicStream.GetStatus() = sStopped); end; procedure TAudioPlayback_Portaudio.PlayStart; @@ -623,7 +619,6 @@ begin end; playbackStream := TPortaudioPlaybackStream.Create(decodeStream); - mixerStream.AddStream(playbackStream); //Add CustomSound csIndex := High(CustomSounds) + 1; -- cgit v1.2.3 From c1a89635c888f21203db62021cb30333d5d80a47 Mon Sep 17 00:00:00 2001 From: tobigun Date: Fri, 11 Jan 2008 03:27:40 +0000 Subject: some minor changes git-svn-id: svn://svn.code.sf.net/p/ultrastardx/svn/trunk@780 b956fd51-792f-4845-bead-9b4dfca2ff2c --- Game/Code/Classes/UAudioPlayback_Portaudio.pas | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (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 c1abd0eb..5f4a8cde 100644 --- a/Game/Code/Classes/UAudioPlayback_Portaudio.pas +++ b/Game/Code/Classes/UAudioPlayback_Portaudio.pas @@ -226,7 +226,7 @@ begin decodeStream.Position := 0; end; status := sPlaying; - mixerStream.AddStream(Self); + //mixerStream.AddStream(Self); end; procedure TPortaudioPlaybackStream.Pause(); @@ -444,6 +444,8 @@ var begin decodeStream := AudioDecoder.Open(Filename); MusicStream := TPortaudioPlaybackStream.Create(decodeStream); + // FIXME: remove this line + mixerStream.AddStream(MusicStream); if(MusicStream.IsLoaded()) then begin @@ -619,6 +621,8 @@ begin end; playbackStream := TPortaudioPlaybackStream.Create(decodeStream); + // FIXME: remove this line + mixerStream.AddStream(playbackStream); //Add CustomSound csIndex := High(CustomSounds) + 1; -- cgit v1.2.3 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 From 51a8b92b1696c8ff27523de753a7c6a743a817de Mon Sep 17 00:00:00 2001 From: tobigun Date: Thu, 7 Feb 2008 18:38:51 +0000 Subject: Audio output working again git-svn-id: svn://svn.code.sf.net/p/ultrastardx/svn/trunk@838 b956fd51-792f-4845-bead-9b4dfca2ff2c --- Game/Code/Classes/UAudioPlayback_Portaudio.pas | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (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 2743fa86..59571d3d 100644 --- a/Game/Code/Classes/UAudioPlayback_Portaudio.pas +++ b/Game/Code/Classes/UAudioPlayback_Portaudio.pas @@ -411,7 +411,7 @@ begin playback := TAudioPlayback_Portaudio(userdata); with playback do begin - //MixerStream.ReadData(stream, len); + MixerStream.ReadData(stream, len); end; end; -- cgit v1.2.3