NAudio 效果不工作并且在不同的声卡上表现不同
NAudio effect not working and behaving differently on different sound cards
我正在使用 NAudio 和 WasapiLoopbackCapture 结合 WaveOut 以便创建一个全局的回声效果,即影响当前的音频输出。
然而,我的实施对我来说似乎很差,根本不能正常工作。在每台机器上听起来都不一样,有时甚至会崩溃。
这是我想出的代码。它记录音频输出,每 75 毫秒使用 WaveOut 播放记录的流。
我哪里做错了,如何改进?
private static void CreateReverb()
{
MemoryStream loopbackWave = new MemoryStream();
DateTime lastEcho = DateTime.Now;
WasapiLoopbackCapture waveIn = new WasapiLoopbackCapture();
waveIn.StartRecording();
waveIn.DataAvailable += delegate(object sender, WaveInEventArgs e)
{
loopbackWave.Write(e.Buffer, 0, e.BytesRecorded);
if ((DateTime.Now - lastEcho).TotalMilliseconds > 75)
{
lastEcho = DateTime.Now;
byte[] loopbackBytes = loopbackWave.ToArray();
loopbackWave.Dispose();
loopbackWave = new MemoryStream();
using (MemoryStream waveStream = new MemoryStream())
{
using (WaveFileWriter waveFileWriter = new WaveFileWriter(waveStream, waveIn.WaveFormat))
{
waveFileWriter.Write(loopbackBytes, 0, loopbackBytes.Length);
}
loopbackBytes = waveStream.ToArray();
}
for (int i = 0; i < 3; i++)
{
ThreadPool.QueueUserWorkItem(delegate
{
try
{
WaveOut waveOut = new WaveOut();
waveOut.Init(new WaveFileReader(new MemoryStream(loopbackBytes)));
waveOut.Volume = ReverbIntensity * .5f;
waveOut.Play();
Thread.Sleep(200);
waveOut.Dispose();
}
catch { }
});
}
}
};
}
编辑:第二次尝试:
这一次,我尝试按照 Mark 的建议使用 BufferedWaveProvider
。问题是播放没有延迟,因此产生了反馈循环而不是回声。输出的音量必须约为 .5f
,并且必须有大约 75 毫秒的延迟才能使其正常工作。
private static void CreateReverb()
{
DateTime lastEcho = DateTime.Now;
WasapiLoopbackCapture waveIn = new WasapiLoopbackCapture();
BufferedWaveProvider bufferedWaveProvider = new BufferedWaveProvider(waveIn.WaveFormat);
WasapiOut wasapiOut = new WasapiOut(AudioClientShareMode.Shared, 0);
bufferedWaveProvider.DiscardOnBufferOverflow = true;
wasapiOut.Init(bufferedWaveProvider);
wasapiOut.Play();
waveIn.StartRecording();
waveIn.DataAvailable += delegate(object sender, WaveInEventArgs e)
{
bufferedWaveProvider.AddSamples(e.Buffer, 0, e.BytesRecorded);
};
}
不要一直打开 WaveOut
的数百个实例。您应该只有一个 WaveOut
实例,即从以录制的音频开始的自定义流播放(BufferedWaveProvider
将是一个很好的起点),然后将其传递给您的效果。执行此操作的最佳方法是创建 ISampleProvider
的实现,在其 Read
方法中从源提供程序读取,然后执行效果。
最后,您正在使用环回音频捕获声音,然后从同一设备播放它,这本身可能会产生令人讨厌的反馈循环。
我正在使用 NAudio 和 WasapiLoopbackCapture 结合 WaveOut 以便创建一个全局的回声效果,即影响当前的音频输出。
然而,我的实施对我来说似乎很差,根本不能正常工作。在每台机器上听起来都不一样,有时甚至会崩溃。
这是我想出的代码。它记录音频输出,每 75 毫秒使用 WaveOut 播放记录的流。
我哪里做错了,如何改进?
private static void CreateReverb()
{
MemoryStream loopbackWave = new MemoryStream();
DateTime lastEcho = DateTime.Now;
WasapiLoopbackCapture waveIn = new WasapiLoopbackCapture();
waveIn.StartRecording();
waveIn.DataAvailable += delegate(object sender, WaveInEventArgs e)
{
loopbackWave.Write(e.Buffer, 0, e.BytesRecorded);
if ((DateTime.Now - lastEcho).TotalMilliseconds > 75)
{
lastEcho = DateTime.Now;
byte[] loopbackBytes = loopbackWave.ToArray();
loopbackWave.Dispose();
loopbackWave = new MemoryStream();
using (MemoryStream waveStream = new MemoryStream())
{
using (WaveFileWriter waveFileWriter = new WaveFileWriter(waveStream, waveIn.WaveFormat))
{
waveFileWriter.Write(loopbackBytes, 0, loopbackBytes.Length);
}
loopbackBytes = waveStream.ToArray();
}
for (int i = 0; i < 3; i++)
{
ThreadPool.QueueUserWorkItem(delegate
{
try
{
WaveOut waveOut = new WaveOut();
waveOut.Init(new WaveFileReader(new MemoryStream(loopbackBytes)));
waveOut.Volume = ReverbIntensity * .5f;
waveOut.Play();
Thread.Sleep(200);
waveOut.Dispose();
}
catch { }
});
}
}
};
}
编辑:第二次尝试:
这一次,我尝试按照 Mark 的建议使用 BufferedWaveProvider
。问题是播放没有延迟,因此产生了反馈循环而不是回声。输出的音量必须约为 .5f
,并且必须有大约 75 毫秒的延迟才能使其正常工作。
private static void CreateReverb()
{
DateTime lastEcho = DateTime.Now;
WasapiLoopbackCapture waveIn = new WasapiLoopbackCapture();
BufferedWaveProvider bufferedWaveProvider = new BufferedWaveProvider(waveIn.WaveFormat);
WasapiOut wasapiOut = new WasapiOut(AudioClientShareMode.Shared, 0);
bufferedWaveProvider.DiscardOnBufferOverflow = true;
wasapiOut.Init(bufferedWaveProvider);
wasapiOut.Play();
waveIn.StartRecording();
waveIn.DataAvailable += delegate(object sender, WaveInEventArgs e)
{
bufferedWaveProvider.AddSamples(e.Buffer, 0, e.BytesRecorded);
};
}
不要一直打开 WaveOut
的数百个实例。您应该只有一个 WaveOut
实例,即从以录制的音频开始的自定义流播放(BufferedWaveProvider
将是一个很好的起点),然后将其传递给您的效果。执行此操作的最佳方法是创建 ISampleProvider
的实现,在其 Read
方法中从源提供程序读取,然后执行效果。
最后,您正在使用环回音频捕获声音,然后从同一设备播放它,这本身可能会产生令人讨厌的反馈循环。