unit UAudioInput_Bass;
interface
{$IFDEF FPC}
{$MODE Delphi}
{$ENDIF}
{$I switches.inc}
uses
Classes,
SysUtils,
URecord,
UMusic;
implementation
uses
UMain,
UIni,
ULog,
UAudioCore_Bass,
Windows,
bass;
type
TAudioInput_Bass = class(TAudioInputBase)
public
function GetName: String; override;
function InitializeRecord: boolean; override;
destructor Destroy; override;
end;
TBassInputDevice = class(TAudioInputDevice)
public
DeviceIndex: integer; // index in TAudioInputProcessor.Device[]
BassDeviceID: integer; // DeviceID used by BASS
RecordStream: HSTREAM;
procedure Start(); override;
procedure Stop(); override;
end;
var
singleton_AudioInputBass : IAudioInput;
{ Global }
{*
* Bass input capture callback.
* Params:
* stream - BASS input stream
* buffer - buffer of captured samples
* len - size of buffer in bytes
* user - players associated with left/right channels
*}
function MicrophoneCallback(stream: HSTREAM; buffer: Pointer;
len: Cardinal; Card: Cardinal): boolean; stdcall;
begin
AudioInputProcessor.HandleMicrophoneData(buffer, len,
AudioInputProcessor.Device[Card]);
Result := true;
end;
{ TBassInputDevice }
{*
* Start input-capturing on this device.
* TODO: call BASS_RecordInit only once
*}
procedure TBassInputDevice.Start();
const
captureFreq = 44100;
begin
// recording already started -> stop first
if (RecordStream <> 0) then
Stop();
// TODO: Call once. Otherwise it's to slow
if not BASS_RecordInit(BassDeviceID) then
begin
Log.LogError('TBassInputDevice.Start: Error initializing device['+IntToStr(DeviceIndex)+']: ' +
TAudioCore_Bass.ErrorGetString());
Exit;
end;
SampleRate := captureFreq;
// capture in 44.1kHz/stereo/16bit and a 20ms callback period
RecordStream := BASS_RecordStart(captureFreq, 2, MakeLong(0, 20),
@MicrophoneCallback, DeviceIndex);
if (RecordStream = 0) then
begin
BASS_RecordFree;
Exit;
end;
end;
{*
* Stop input-capturing on this device.
*}
procedure TBassInputDevice.Stop();
begin
if (RecordStream = 0) then
Exit;
// TODO: Don't free the device. Do this on close
if (BASS_RecordSetDevice(BassDeviceID)) then
BASS_RecordFree;
RecordStream := 0;
end;
{ TAudioInput_Bass }
function TAudioInput_Bass.GetName: String;
begin
result := 'BASS_Input';
end;
function TAudioInput_Bass.InitializeRecord(): boolean;
var
Descr: PChar;
SourceName: PChar;
Flags: integer;
BassDeviceID: integer;
BassDevice: TBassInputDevice;
DeviceIndex: integer;
SourceIndex: integer;
begin
result := false;
DeviceIndex := 0;
BassDeviceID := 0;
SetLength(AudioInputProcessor.Device, 0);
// checks for recording devices and puts them into an array
while true do
begin
Descr := BASS_RecordGetDeviceDescription(BassDeviceID);
if (Descr = nil) then
break;
SetLength(AudioInputProcessor.Device, DeviceIndex+1);
// TODO: free object on termination
BassDevice := TBassInputDevice.Create();
AudioInputProcessor.Device[DeviceIndex] := BassDevice;
BassDevice.DeviceIndex := DeviceIndex;
BassDevice.BassDeviceID := BassDeviceID;
BassDevice.Description := UnifyDeviceName(Descr, DeviceIndex);
// get input sources
SourceIndex := 0;
BASS_RecordInit(BassDeviceID);
BassDevice.MicInput := 0;
// process each input
while true do
begin
SourceName := BASS_RecordGetInputName(SourceIndex);
if (SourceName = nil) then
break;
SetLength(BassDevice.Source, SourceIndex+1);
BassDevice.Source[SourceIndex].Name :=
UnifyDeviceSourceName(SourceName, BassDevice.Description);
// set mic index
Flags := BASS_RecordGetInput(SourceIndex);
if ((Flags and BASS_INPUT_TYPE_MIC) <> 0) then
BassDevice.MicInput := SourceIndex;
Inc(SourceIndex);
end;
BASS_RecordFree;
Inc(DeviceIndex);
Inc(BassDeviceID);
end;
result := true;
end;
destructor TAudioInput_Bass.Destroy;
begin
inherited;
end;
initialization
singleton_AudioInputBass := TAudioInput_Bass.create();
AudioManager.add( singleton_AudioInputBass );
finalization
AudioManager.Remove( singleton_AudioInputBass );
end.