【问题标题】:How to record and playback with NAudio using AsioOut如何使用 AsioOut 使用 NAudio 进行录制和播放
【发布时间】:2014-04-24 18:13:34
【问题描述】:

我正在尝试获取声音输入直接发送输出,使用 C# 可能会减少延迟。

我正在使用支持 ASIO 的库 NAudio 以获得更好的延迟。

特别是,我使用 AsioOut 对象进行录制,另一个用于播放,并使用 BufferedWaveProvider 进行初始化,该对象填充了一个回调函数:OnAudioAvailable,它允许我使用 ASIO 缓冲区。

问题是我听到的声音有各种毛刺有点延迟。我认为问题出在函数 OnAudioAvailable 中,其中缓冲区填充了从声卡输入的数据。

声明:

NAudio.Wave.AsioOut playAsio;
NAudio.Wave.AsioOut recAsio;
NAudio.Wave.BufferedWaveProvider buffer;

播放过程:

if (sourceList.SelectedItems.Count == 0) return;

int deviceNumber = sourceList.SelectedItems[0].Index;

recAsio = new NAudio.Wave.AsioOut(deviceNumber);
recAsio.InitRecordAndPlayback(null, 2, 44100); //rec channel = 1

NAudio.Wave.WaveFormat formato = new NAudio.Wave.WaveFormat();
buffer = new NAudio.Wave.BufferedWaveProvider(formato);

recAsio.AudioAvailable += new EventHandler<NAudio.Wave.AsioAudioAvailableEventArgs>(OnAudioAvailable);

//Collego l'output col buffer
playAsio = new NAudio.Wave.AsioOut(deviceNumber);
playAsio.Init(buffer);

//Registro
recAsio.Play();
//Playback
playAsio.Play();

OnAudioAvailable():

//Callback
private unsafe void OnAudioAvailable(object sender, NAudio.Wave.AsioAudioAvailableEventArgs e)
{
    //Copio tutti gli elementi di InputBuffers in buf e li aggiungo in coda al buffer
    byte[] buf = new byte[e.SamplesPerBuffer];
    for (int i = 0; i < e.InputBuffers.Length; i++)
    {
        Marshal.Copy(e.InputBuffers[i], buf, 0, e.SamplesPerBuffer);
        //Aggiungo in coda al buffer
        buffer.AddSamples(buf, 0, buf.Length);
    }
}

AsioAudioAvailableEventArgs 定义:

public AsioAudioAvailableEventArgs(IntPtr[] inputBuffers, int samplesPerBuffer, AsioSampleType asioSampleType);
public float[] GetAsInterleavedSamples();

有人知道怎么解决吗? 谢谢大家。

【问题讨论】:

    标签: c# audio-recording playback naudio asio


    【解决方案1】:

    您不应为同一设备使用两个AsioOut 实例。我很惊讶这完全有效。只需使用InitRecordAndPlayback

    对于直通监控的绝对最小延迟,在AudioAvailableEvent 中,直接复制到OutputBuffers,并设置WrittenToOutputBuffers = true。这意味着您不需要BufferedWaveProvider

    还请记住,任何故障都只是由于您未能足够快地处理 AudioAvailable 事件。当您使用 ASIO 时,您的延迟可能非常低(例如低于 10 毫秒),并且可以处理大量数据(例如 96kHz 采样率、8 个输入和输出通道)。所以你需要在很短的时间窗口内做大量的数据移动。对于 .NET,您必须考虑一个不幸的事实,即垃圾收集器可能随时启动并导致您不时错过缓冲区。

    【讨论】:

    • 我明白你说的,事实上这正是我想做的,但仍然不明白如何..我找不到任何 OutputBuffers 并且在 AsioAudioAvailableEventArgs 这两个参数不存在。你能告诉我在哪里可以找到它或者给我看一些代码吗?非常感谢。
    • 您使用的是最新版本的 NAudio 吗?
    • 感谢您让我注意到我使用的是旧版本。但我还是不能按照你说的做,因为 OutputBuffers 总是有 length=0 不像 InputBufferslength=2。因此,如果我尝试在它们之间复制数据,我就会超出范围。我该怎么办?可能我忘记了一些重要的事情。
    • 啊,是的,像这样工作有点麻烦(需要为将来的版本清理大量 API)。将缓冲的波形提供程序传递给 InitRecordAndPlayback,它将用于确定您想要的输出通道数,即使您实际上不会从中读取任何内容。
    • 我试着照你说的做,但我什么也没听到。然而,我还检查了调试器,它执行所有指令都没有错误。我做错了什么? OnAudioAvailable: for (int i = 0; i &lt; e.InputBuffers.Length; i++) e.OutputBuffers[i] = e.InputBuffers[i]; e.WrittenToOutputBuffers = true;
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-01-30
    相关资源
    最近更新 更多