Author Topic: WASAPI Microphone capture problem  (Read 282 times)

WASAPI Microphone capture problem
« on: 30 Oct '18 - 02:26 »
Hi,

I am trying to capture Microphone or Speaker sound with using WASAPI and I found the best example but the recorded sound is very fast and strange when I record with "Mikrofon Dizisi (A4 TECH PC Camera Audio)" but when I record the speaker sound, everything is okay.

I've been trying to solve this problem for hours, but I haven't reached a conclusion.

I downloaded RecTestDelphi.zip from: http://www.un4seen.com/forum/?topic=13752.msg96862#msg96862

I updated the project to the latest Bass/BassEnc/BassMix/BassWasapi version with using Delphi 10.2

How do I solve this problem?

Thank you.

Code: [Select]
unit RecTestDelphi;
....

procedure TForm1.StartRecording;
var
  StrFlag: dWord;
  encFlag: dWord;
begin
  if CBoxInputDevice.ItemIndex < 0 then
    Exit;
  StrFlag := BASS_SAMPLE_FLOAT or BASS_STREAM_DECODE;
  Channel_Stream := BASS_StreamCreate(WasapiInfo.freq, WasapiInfo.chans, StrFlag, STREAMPROC_PUSH, nil);
  if (Channel_Stream = 0) then
  begin
    BassError('Error setting Channel Stream: ');
    exit;
  end;

  BASS_WASAPI_Stop(TRUE);
  BASS_StreamFree(Channel_Mixer);
  Channel_Mixer := BASS_Mixer_StreamCreate(sampleRate, 2, BASS_STREAM_DECODE);
  BASS_Mixer_StreamAddChannel(Channel_Mixer, Channel_Stream, 0);

  encFlag := BASS_ENCODE_PAUSE or BASS_ENCODE_PCM or BASS_UNICODE;

  if FileExists(tempFilename) then
    DeleteFile(tempFilename);
  Channel_Encoder := BASS_Encode_Start(Channel_Mixer, PChar(tempFilename), encFlag, nil, nil);

  if not (BASS_WASAPI_Start()) then
  begin
    BassError('Error starting WASAPI: ');
    exit;
  end;

  BASS_Encode_SetPaused(Channel_Encoder, False);

  IsRecording := True;
  BtnRecord.Caption := 'Stop';
  BtnPlay.Enabled := False;
end;

// WASAPI input processing function
function Input_Wasapi_Proc(buffer: Pointer; length: DWORD; user: Pointer): DWORD; stdcall;
var
  Buff: array[0..50000] of Byte;
  Data: DWORD;
begin
  BASS_StreamPutData(Channel_Stream, buffer, length);
  Data := BASS_ChannelGetData(Channel_Mixer, @Buff, SizeOf(Buff));
  if Data = DW_ERROR then
    Data := 0;
  Result := Data
end;

procedure InitInputDevice;
var
  Volume: Real;
  typeStr: string;
begin
  InputDev := StrToInt(Form1.CBoxInputDeviceNr.Items[Form1.CBoxInputDevice.ItemIndex]);

  if not BASS_WASAPI_Init(InputDev, 0, 0, 0, 1, 0, @Input_Wasapi_Proc, NIL) then
    case BASS_ErrorGetCode of
      14:
        ;  //skip Error message
    else
      Form1.BassError('Error initialising BASS WASAPI: ');
    end; // of case

  // update level slider
  Volume := BASS_WASAPI_GetVolume(BASS_WASAPI_VOL_SESSION);
  if (Volume < 0) then
    Form1.TBarVol.Position := 100 // failed to get level -> just display 100%
  else
    Form1.TBarVol.Position := round(Volume * 100);

// update device type display
  BASS_WASAPI_GetDeviceInfo(InputDev, WasapiDevInfo);
  case WasapiDevInfo.&Type of
    BASS_WASAPI_TYPE_NETWORKDEVICE:
      typeStr := 'Remote Network Device';
    BASS_WASAPI_TYPE_SPEAKERS:
      typeStr := 'Speakers';
    BASS_WASAPI_TYPE_LINELEVEL:
      typeStr := 'Line In';
    BASS_WASAPI_TYPE_HEADPHONES:
      typeStr := 'Headphones';
    BASS_WASAPI_TYPE_MICROPHONE:
      typeStr := 'Microphone';
    BASS_WASAPI_TYPE_HEADSET:
      typeStr := 'Headset';
    BASS_WASAPI_TYPE_HANDSET:
      typeStr := 'Handset';
    BASS_WASAPI_TYPE_DIGITAL:
      typeStr := 'Digital';
    BASS_WASAPI_TYPE_SPDIF:
      typeStr := 'SPDIF';
    BASS_WASAPI_TYPE_HDMI:
      typeStr := 'HDMI';
  else
    typeStr := 'Undefined';
  end; //of case

  if (WasapiDevInfo.flags and BASS_DEVICE_LOOPBACK > 1) then
    typeStr := typeStr + ' (loopback)';

  Form1.lTypeDescription.Caption := typeStr
end;


procedure TForm1.BtnPlayClick(Sender: TObject);
var
  len: QWord;
begin
  if IsPlaying then
  begin
    IsPlaying := False;
    BtnPlay.Caption := 'Start';
    BtnRecord.Enabled := True;
    TimerPlay.Enabled := False;
    BASS_ChannelStop(PlayerStream);
  end
  else
  begin
    if fNameSave = '' then
    begin
      MessageBox(Handle, PChar('Save a recording first!'), nil, 0);
      exit;
    end;
    IsPlaying := True;
    BtnPlay.Caption := 'Stop';
    BtnRecord.Enabled := False;

           //Load the last recorded sample
    BASS_StreamFree(PlayerStream);
    PlayerStream := BASS_StreamCreateFile(FALSE, PChar(fNameSave), 0, 0, 0{$IFDEF UNICODE}                                             or BASS_UNICODE {$ENDIF});
    BASS_ChannelStop(PlayerStream);
    BASS_ChannelPlay(PlayerStream, True);
    len := BASS_ChannelGetLength(PlayerStream, BASS_POS_BYTE);                // length in bytes
    TimerPlay.Interval := Round(1000 * BASS_ChannelBytes2Seconds(PlayerStream, len)); // Start Timer with channels playing duration (in Milliseconds)
    TimerPlay.Enabled := True;                                                     // Start the Timer (it will stop the Playback once the channel was played completely)
  end;
end;


procedure TForm1.CBoxInputDeviceChange(Sender: TObject);
begin
  InitInputDevice(); // initialize selected device
end;

procedure TForm1.cBoxSampleRateChange(Sender: TObject);
begin
  sampleRate := StrToInt(cBoxSampleRate.Text);
end;

end.

Re: WASAPI Microphone capture problem
« Reply #1 on: 30 Oct '18 - 15:27 »
Why is this problem caused? The sound recorded from the microphone turns scratchy. What should I do to fix this problem?

Please help me.

Ian @ un4seen

  • Administrator
  • Posts: 21537
Re: WASAPI Microphone capture problem
« Reply #2 on: 30 Oct '18 - 17:06 »
Where are the "WasapiInfo" values being set? If the recording is the wrong speed then that may be where the problem is, ie. they don't reflect the active device's sample format.

Re: WASAPI Microphone capture problem
« Reply #3 on: 30 Oct '18 - 21:27 »
thank you, the problem was solved by itself in a way I didn't understand.