2

I'm using NAudio and trying to record what's being played on my pc with the WasapiLoopbackCapture. The problem that I have is that I need the recorded data as PCM 16bit 44100khz Mono. For that I have constructed this:

using System;
using System.Diagnostics;

using NAudio.Wave;
using NAudio.CoreAudioApi;

namespace soundtest
{
    class Program {

        static void Main(string[] args) {
            try {
                var deviceToRecord = (new MMDeviceEnumerator().EnumerateAudioEndPoints(DataFlow.All, DeviceState.Active))[0];

                var recorder = new CustomWasapiLoopbackCapture(deviceToRecord, false, 1000 / 5);
                recorder.ShareMode = AudioClientShareMode.Shared;
                recorder.DataAvailable += recorderDataAvailable;

                var inprov = new WaveInProvider(recorder);
                var fto16prov = new WaveFloatTo16Provider(inprov);
                var stomprov = new StereoToMonoProvider16(fto16prov);

                Console.WriteLine("Press something to stop recording.");
                recorder.StartRecording();
                Console.ReadKey();
                recorder.StopRecording();

            } catch (Exception e) {
                Console.WriteLine("!!! EXCEPTION !!!" + 
                    "\nMessage:\n   " + e.Message + 
                    "\nSource:\n   " + e.Source + 
                    "\nStack:\n" + e.StackTrace);
            }

            Console.WriteLine("Press something to close.");
            Console.ReadKey();
        }

        static void recorderDataAvailable(object sender, WaveInEventArgs args) {
            // how do I access PCM 16bit here?
            // It's not args.Buffer, or am I wrong?
            // additional calculation is done here with the PCM data
        }
    }


    class CustomWasapiLoopbackCapture : WasapiCapture
    {
        public CustomWasapiLoopbackCapture() 
            : this(GetDefaultLoopbackCaptureDevice()){ }
        public CustomWasapiLoopbackCapture(MMDevice captureDevice)
            : this(captureDevice, false){ }
        public CustomWasapiLoopbackCapture(MMDevice captureDevice, bool useEventSync)
            : this(captureDevice, useEventSync, 100){ }
        public CustomWasapiLoopbackCapture(MMDevice captureDevice, bool useEventSync, int audioBufferMillisecondsLength)
            : base(captureDevice, useEventSync, audioBufferMillisecondsLength){ }

        public static MMDevice GetDefaultLoopbackCaptureDevice() {
            MMDeviceEnumerator devices = new MMDeviceEnumerator();
            return devices.GetDefaultAudioEndpoint(DataFlow.Render, Role.Multimedia);
        }

        public override WaveFormat WaveFormat
        {
            get { return base.WaveFormat; }
            set { throw new InvalidOperationException("WaveFormat cannot be set for WASAPI Loopback Capture"); }
        }

        protected override AudioClientStreamFlags GetAudioClientStreamFlags() {
            return AudioClientStreamFlags.Loopback;
        }
    }
}

How can I access the converted recording? I thought that by adding those providers I could get the data for further calculations. My assumption that args.Buffer does not deliver the expected PCM 16bit 44100 kHz Mono data comes from unrealistic results of the additional processing that I'm doing in the recorderDataAvailable method. I tested this with a simple WaveInEvent on another input from my mixer board with which I looped the playing sound back in.

hansOlaf
  • 23
  • 2
  • 5

1 Answers1

3

WASAPI always records audio as IEEE floating point samples. So in the recorded buffer you get in the callback, every 4 bytes is a float. A simple way to access individual samples is with BitConverter.ToSingle. That will give you a value in the range +/- 1.0. So multiply by 32767 and then cast to an Int16 to turn it into a 16 bit sample value.

Mark Heath
  • 48,273
  • 29
  • 137
  • 194
  • 1
    Can you elaborate? I'm trying to copy the recorded buffer to a System.IO.Stream so I can pass it to a SpeechRecognitionEngine.SetInputToAudioStream(). I've tried AcmStream to resample, but I feel like that may not even be necessary. The SRE only accepts 8 or 16bit samples. Basically trying to do [this](https://stackoverflow.com/questions/1682902/streaming-input-to-system-speech-recognition-speechrecognitionengine) but with a WasapiLoopbackCapture(). – javon27 Jan 29 '18 at 21:17