NAudio Wasapi 录音和转换

Posted

技术标签:

【中文标题】NAudio Wasapi 录音和转换【英文标题】:NAudio Wasapi recording and conversion 【发布时间】:2017-08-06 19:13:15 【问题描述】:

我正在使用 NAudio 并尝试使用 WasapiLoopbackCapture 记录我的电脑上正在播放的内容。我遇到的问题是我需要记录的数据为 PCM 16bit 44100khz Mono。 为此,我构建了这个:

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;
        
    

如何访问转换后的录音?我认为通过添加这些提供程序,我可以获得数据以进行进一步计算。我认为 args.Buffer 没有提供预期的 PCM 16 位 44100 kHz 单声道数据的假设来自我在 recorderDataAvailable 方法中进行的额外处理的不切实际结果。我在混音板的另一个输入上使用简单的 WaveInEvent 对此进行了测试,我用它循环播放的声音。

【问题讨论】:

【参考方案1】:

WASAPI 始终将音频记录为 IEEE 浮点样本。因此,在回调中记录的缓冲区中,每 4 个字节是一个float。访问单个样本的一种简单方法是使用BitConverter.ToSingle。这将为您提供 +/- 1.0 范围内的值。所以乘以 32767,然后转换为 Int16 以将其转换为 16 位样本值。

【讨论】:

您能详细说明一下吗?我正在尝试将录制的缓冲区复制到 System.IO.Stream,以便可以将其传递给 SpeechRecognitionEngine.SetInputToAudiostream()。我尝试过 AcmStream 重新采样,但我觉得这甚至可能没有必要。 SRE 仅接受 8 位或 16 位样本。基本上尝试做this,但使用WasapiLoopbackCapture()。

以上是关于NAudio Wasapi 录音和转换的主要内容,如果未能解决你的问题,请参考以下文章

NAudio录音输出流

枚举 NAudio 中的录音设备

c# Naudio 音频电平捕获和显示,仅在打开录音属性时有效

WPF使用NAudio录音

NAudio 录音中不需要的静音部分

将nAudio录音存储在变量而不是c#中的文件中