unit UAudioPlayback_Portaudio;
interface
{$IFDEF FPC}
{$MODE Delphi}
{$ENDIF}
{$I switches.inc}
uses
Classes,
SysUtils,
UMusic;
implementation
uses
portaudio,
UAudioCore_Portaudio,
UAudioPlayback_SoftMixer,
ULog,
UIni,
UMain;
type
TAudioPlayback_Portaudio = class(TAudioPlayback_SoftMixer)
private
paStream: PPaStream;
protected
function InitializeAudioPlaybackEngine(): boolean; override;
function StartAudioPlaybackEngine(): boolean; override;
procedure StopAudioPlaybackEngine(); override;
public
function GetName: String; override;
end;
var
singleton_AudioPlaybackPortaudio : IAudioPlayback;
{ TAudioPlayback_Portaudio }
function PortaudioAudioCallback(input: Pointer; output: Pointer; frameCount: Longword;
timeInfo: PPaStreamCallbackTimeInfo; statusFlags: TPaStreamCallbackFlags;
userData: Pointer): Integer; cdecl;
var
engine: TAudioPlayback_Portaudio;
begin
engine := TAudioPlayback_Portaudio(userData);
engine.AudioCallback(output, frameCount * engine.FormatInfo.FrameSize);
result := paContinue;
end;
function TAudioPlayback_Portaudio.GetName: String;
begin
result := 'Portaudio_Playback';
end;
function TAudioPlayback_Portaudio.InitializeAudioPlaybackEngine(): boolean;
var
paApiIndex : TPaHostApiIndex;
paApiInfo : PPaHostApiInfo;
paOutParams : TPaStreamParameters;
paOutDevice : TPaDeviceIndex;
paOutDeviceInfo : PPaDeviceInfo;
err : TPaError;
sampleRate : integer;
begin
result := false;
Pa_Initialize();
paApiIndex := TAudioCore_Portaudio.GetPreferredApiIndex();
if(paApiIndex = -1) then
begin
Log.LogError('No working Audio-API found', 'TAudioPlayback_Portaudio.InitializeAudioPlaybackEngine');
Exit;
end;
paApiInfo := Pa_GetHostApiInfo(paApiIndex);
paOutDevice := paApiInfo^.defaultOutputDevice;
paOutDeviceInfo := Pa_GetDeviceInfo(paOutDevice);
if (paOutDeviceInfo^.defaultSampleRate > 0) then
sampleRate := Trunc(paOutDeviceInfo^.defaultSampleRate)
else
sampleRate := 44100;
with paOutParams do begin
device := paOutDevice;
channelCount := 2;
sampleFormat := paInt16;
suggestedLatency := paOutDeviceInfo^.defaultLowOutputLatency;
hostApiSpecificStreamInfo := nil;
end;
err := Pa_OpenStream(paStream, nil, @paOutParams, sampleRate,
paFramesPerBufferUnspecified,
paNoFlag, @PortaudioAudioCallback, Self);
if(err <> paNoError) then begin
Log.LogStatus('Pa_OpenStream: '+Pa_GetErrorText(err), 'UAudioPlayback_Portaudio');
exit;
end;
FormatInfo := TAudioFormatInfo.Create(
paOutParams.channelCount,
sampleRate,
asfS16 // FIXME: is paInt16 system-dependant or -independant?
);
Log.LogStatus('Opened audio device', 'UAudioPlayback_Portaudio');
result := true;
end;
function TAudioPlayback_Portaudio.StartAudioPlaybackEngine(): boolean;
var
err: TPaError;
begin
result := false;
if (paStream = nil) then
Exit;
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.StopAudioPlaybackEngine();
begin
if (paStream <> nil) then
Pa_StopStream(paStream);
end;
initialization
singleton_AudioPlaybackPortaudio := TAudioPlayback_Portaudio.create();
AudioManager.add( singleton_AudioPlaybackPortaudio );
finalization
AudioManager.Remove( singleton_AudioPlaybackPortaudio );
end.