aboutsummaryrefslogtreecommitdiffstats
path: root/Game/Code/Classes/UAudioPlayback_Portaudio.pas
diff options
context:
space:
mode:
authortobigun <tobigun@b956fd51-792f-4845-bead-9b4dfca2ff2c>2007-12-28 11:46:04 +0000
committertobigun <tobigun@b956fd51-792f-4845-bead-9b4dfca2ff2c>2007-12-28 11:46:04 +0000
commite5bdcfc8e584d2867d0ad7995d18bd30c7874d1b (patch)
treeb29112594215be695cfbc45094e8ef2dce19c4e4 /Game/Code/Classes/UAudioPlayback_Portaudio.pas
parente4c30499349a0cc5b75fce7e59dc0a4abfa0a10e (diff)
downloadusdx-e5bdcfc8e584d2867d0ad7995d18bd30c7874d1b.tar.gz
usdx-e5bdcfc8e584d2867d0ad7995d18bd30c7874d1b.tar.xz
usdx-e5bdcfc8e584d2867d0ad7995d18bd30c7874d1b.zip
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
Diffstat (limited to '')
-rw-r--r--Game/Code/Classes/UAudioPlayback_Portaudio.pas664
1 files changed, 664 insertions, 0 deletions
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.