aboutsummaryrefslogtreecommitdiffstats
path: root/Game/Code/Classes/UAudioInput_Portaudio.pas
diff options
context:
space:
mode:
Diffstat (limited to 'Game/Code/Classes/UAudioInput_Portaudio.pas')
-rw-r--r--Game/Code/Classes/UAudioInput_Portaudio.pas347
1 files changed, 0 insertions, 347 deletions
diff --git a/Game/Code/Classes/UAudioInput_Portaudio.pas b/Game/Code/Classes/UAudioInput_Portaudio.pas
deleted file mode 100644
index 753c69f6..00000000
--- a/Game/Code/Classes/UAudioInput_Portaudio.pas
+++ /dev/null
@@ -1,347 +0,0 @@
-unit UAudioInput_Portaudio;
-
-interface
-
-{$IFDEF FPC}
- {$MODE Delphi}
-{$ENDIF}
-
-{$I ../switches.inc}
-
-
-uses
- Classes,
- SysUtils,
- UMusic;
-
-implementation
-
-uses
- URecord,
- UIni,
- ULog,
- UMain,
- {$IFDEF UsePortmixer}
- portmixer,
- {$ENDIF}
- portaudio;
-
-type
- TAudioInput_Portaudio = class(TAudioInputBase)
- private
- function GetPreferredApiIndex(): TPaHostApiIndex;
- public
- function GetName: String; override;
- function InitializeRecord: boolean; override;
- destructor Destroy; override;
- end;
-
- TPortaudioInputDevice = class(TAudioInputDevice)
- public
- RecordStream: PPaStream;
- PaDeviceIndex: TPaDeviceIndex;
-
- procedure Start(); override;
- procedure Stop(); override;
- end;
-
-function MicrophoneCallback(input: Pointer; output: Pointer; frameCount: Longword;
- timeInfo: PPaStreamCallbackTimeInfo; statusFlags: TPaStreamCallbackFlags;
- inputDevice: Pointer): Integer; cdecl; forward;
-
-var
- singleton_AudioInputPortaudio : IAudioInput;
-
-{* the default API used by Portaudio is the least common denominator
- * and might lack efficiency. ApiPreferenceOrder defines the order of
- * preferred APIs to use. The first API-type in the list is tried first. If it's
- * not available the next is tried, ...
- * If none of the preferred APIs was found the default API is used.
- * Pascal doesn't permit zero-length static arrays, so you can use paDefaultApi
- * as an array's only member if you do not have any preferences.
- * paDefaultApi also terminates a preferences list but this is optional.
- *}
-const
- paDefaultApi = -1;
-var
- ApiPreferenceOrder:
-{$IF Defined(WIN32)}
- // Note1: Portmixer has no mixer support for paASIO and paWASAPI at the moment
- // Note2: Windows Default-API is MME
- //array[0..0] of TPaHostApiTypeId = ( paDirectSound, paMME );
- array[0..0] of TPaHostApiTypeId = ( paDirectSound );
-{$ELSEIF Defined(LINUX)}
- // Note1: Portmixer has no mixer support for paJACK at the moment
- // Note2: Not tested, but ALSA might be better than OSS.
- array[0..1] of TPaHostApiTypeId = ( paALSA, paOSS );
-{$ELSEIF Defined(DARWIN)}
- // Note: Not tested.
- //array[0..0] of TPaHostApiTypeId = ( paCoreAudio );
- array[0..0] of TPaHostApiTypeId = ( paDefaultApi );
-{$ELSE}
- array[0..0] of TPaHostApiTypeId = ( paDefaultApi );
-{$IFEND}
-
-
-{ TPortaudioInputDevice }
-
-procedure TPortaudioInputDevice.Start();
-var
- Error: TPaError;
- ErrorMsg: string;
- inputParams: TPaStreamParameters;
- deviceInfo: PPaDeviceInfo;
-begin
- // get input latency info
- deviceInfo := Pa_GetDeviceInfo(PaDeviceIndex);
-
- // set input stream parameters
- with inputParams do begin
- device := PaDeviceIndex;
- channelCount := 2;
- sampleFormat := paInt16;
- suggestedLatency := deviceInfo^.defaultLowInputLatency;
- hostApiSpecificStreamInfo := nil;
- end;
-
- Log.LogStatus(inttostr(PaDeviceIndex), 'Portaudio');
- Log.LogStatus(floattostr(deviceInfo^.defaultLowInputLatency), 'Portaudio');
-
- // open input stream
- Error := Pa_OpenStream(RecordStream, @inputParams, nil, SampleRate,
- paFramesPerBufferUnspecified, paNoFlag,
- @MicrophoneCallback, Pointer(Self));
- if(Error <> paNoError) then begin
- ErrorMsg := Pa_GetErrorText(Error);
- Log.CriticalError('TPortaudioInputDevice.Start(): Error opening stream: ' + ErrorMsg);
- //Halt;
- end;
-
- // start capture
- Error := Pa_StartStream(RecordStream);
- if(Error <> paNoError) then begin
- Pa_CloseStream(RecordStream);
- ErrorMsg := Pa_GetErrorText(Error);
- Log.CriticalError('TPortaudioInputDevice.Start(): Error starting stream: ' + ErrorMsg);
- //Halt;
- end;
-end;
-
-procedure TPortaudioInputDevice.Stop();
-begin
- if assigned(RecordStream) then begin
- Pa_StopStream(RecordStream);
- Pa_CloseStream(RecordStream);
- end;
-end;
-
-
-{ TAudioInput_Portaudio }
-
-function TAudioInput_Portaudio.GetName: String;
-begin
- result := 'Portaudio';
-end;
-
-function TAudioInput_Portaudio.GetPreferredApiIndex(): TPaHostApiIndex;
-var
- i: integer;
-begin
- result := -1;
-
- // select preferred sound-API
- for i:= 0 to High(ApiPreferenceOrder) do
- begin
- if(ApiPreferenceOrder[i] <> paDefaultApi) then begin
- // check if API is available
- result := Pa_HostApiTypeIdToHostApiIndex(ApiPreferenceOrder[i]);
- if(result >= 0) then
- break;
- end;
- end;
-
- // None of the preferred APIs is available -> use default
- if(result < 0) then begin
- result := Pa_GetDefaultHostApi();
- end;
-end;
-
-function TAudioInput_Portaudio.InitializeRecord(): boolean;
-var
- i: integer;
- apiIndex: TPaHostApiIndex;
- apiInfo: PPaHostApiInfo;
- deviceName: string;
- deviceIndex: TPaDeviceIndex;
- deviceInfo: PPaDeviceInfo;
- sourceCnt: integer;
- sourceName: string;
- SC: integer; // soundcard
- SCI: integer; // soundcard source
- err: TPaError;
- errMsg: string;
- paDevice: TPortaudioInputDevice;
- inputParams: TPaStreamParameters;
- stream: PPaStream;
- {$IFDEF UsePortmixer}
- mixer: PPxMixer;
- {$ENDIF}
-const
- captureFreq = 44100;
-begin
- result := false;
-
- err := Pa_Initialize();
- if(err <> paNoError) then begin
- Log.LogError('Portaudio.InitializeRecord: ' + Pa_GetErrorText(err));
- Exit;
- end;
- apiIndex := GetPreferredApiIndex();
- apiInfo := Pa_GetHostApiInfo(apiIndex);
-
- SC := 0;
-
- // init array-size to max. input-devices count
- SetLength(AudioInputProcessor.Device, apiInfo^.deviceCount);
- for i:= 0 to High(AudioInputProcessor.Device) do
- begin
- // convert API-specific device-index to global index
- deviceIndex := Pa_HostApiDeviceIndexToDeviceIndex(apiIndex, i);
- deviceInfo := Pa_GetDeviceInfo(deviceIndex);
-
- // current device is no input device -> skip
- if(deviceInfo^.maxInputChannels <= 0) then
- continue;
-
- paDevice := TPortaudioInputDevice.Create();
- AudioInputProcessor.Device[SC] := paDevice;
-
- // retrieve device-name
- deviceName := deviceInfo^.name;
- paDevice.Description := deviceName;
- paDevice.PaDeviceIndex := deviceIndex;
-
- // setup desired input parameters
- with inputParams do begin
- device := deviceIndex;
- channelCount := 2;
- sampleFormat := paInt16;
- suggestedLatency := deviceInfo^.defaultLowInputLatency;
- hostApiSpecificStreamInfo := nil;
- end;
-
- paDevice.SampleRate := captureFreq;
-
- // check if device supports our input-format
- err := Pa_IsFormatSupported(@inputParams, nil, paDevice.SampleRate);
- if(err <> 0) then begin
- // format not supported -> skip
- errMsg := Pa_GetErrorText(err);
- Log.LogError('Portaudio.InitializeRecord, device: "'+ deviceName +'" '
- + '('+ errMsg +')');
- paDevice.Free();
- continue;
- end;
-
- // TODO: retry with mono if stereo is not supported
- // TODO: retry with input-latency set to 20ms (defaultLowInputLatency might
- // not be set correctly in OSS)
- // use TPaDeviceInfo.defaultSampleRate
-
- err := Pa_OpenStream(stream, @inputParams, nil, paDevice.SampleRate,
- paFramesPerBufferUnspecified, paNoFlag, @MicrophoneCallback, nil);
- if(err <> paNoError) then begin
- // unable to open device -> skip
- errMsg := Pa_GetErrorText(err);
- Log.LogError('Portaudio.InitializeRecord, device: "'+ deviceName +'" '
- + '('+ errMsg +')');
- paDevice.Free();
- continue;
- end;
-
-
- {$IFDEF UsePortmixer}
-
- // use default mixer
- mixer := Px_OpenMixer(stream, 0);
-
- // get input count
- sourceCnt := Px_GetNumInputSources(mixer);
- SetLength(paDevice.Source, sourceCnt);
-
- // get input names
- for SCI := 0 to sourceCnt-1 do
- begin
- sourceName := Px_GetInputSourceName(mixer, SCI);
- paDevice.Source[SCI].Name := sourceName;
- end;
-
- Px_CloseMixer(mixer);
-
- {$ELSE} // !UsePortmixer
-
- //Pa_StartStream(stream);
- // TODO: check if callback was called (this problem may occur on some devices)
- //Pa_StopStream(stream);
-
- // create a standard input source
- SetLength(paDevice.Source, 1);
- paDevice.Source[0].Name := 'Standard';
-
- {$ENDIF}
-
- // close test-stream
- Pa_CloseStream(stream);
-
- // use default input source
- paDevice.SourceSelected := 0;
-
- Inc(SC);
- end;
-
- // adjust size to actual input-device count
- SetLength(AudioInputProcessor.Device, SC);
-
- Log.LogStatus('#Soundcards: ' + inttostr(SC), 'Portaudio');
-
- {
- SoundCard[SC].InputSelected := Mic[Device];
- }
- result := true;
-end;
-
-destructor TAudioInput_Portaudio.Destroy;
-var
- i: integer;
- paSoundCard: TPortaudioInputDevice;
-begin
- Pa_Terminate();
- for i := 0 to High(AudioInputProcessor.Device) do
- begin
- AudioInputProcessor.Device[i].Free();
- end;
- AudioInputProcessor.Device := nil;
-
- inherited Destroy;
-end;
-
-{*
- * Portaudio input capture callback.
- *}
-function MicrophoneCallback(input: Pointer; output: Pointer; frameCount: Longword;
- timeInfo: PPaStreamCallbackTimeInfo; statusFlags: TPaStreamCallbackFlags;
- inputDevice: Pointer): Integer; cdecl;
-begin
- AudioInputProcessor.HandleMicrophoneData(input, frameCount*4, inputDevice);
- result := paContinue;
-end;
-
-
-initialization
- singleton_AudioInputPortaudio := TAudioInput_Portaudio.create();
- AudioManager.add( singleton_AudioInputPortaudio );
-
-finalization
- AudioManager.Remove( singleton_AudioInputPortaudio );
-
-end.