aboutsummaryrefslogblamecommitdiffstats
path: root/Game/Code/Classes/UAudioInput_Bass.pas
blob: 6d6612581b1f270eb68519011ceaa46a22587f71 (plain) (tree)










































































































































































































                                                                                                    
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.