我在ISampleProvider模型中编码了一些DSP效果。为了应用一种效果,我这样做,它工作正常。
string filename = "C:\myaudio.mp3";
MediaFoundationReader mediaFileReader = new MediaFoundationReader(filename);
ISampleProvider sampProvider = mediaFileReader.ToSampleProvider();
ReverbSampleProvider reverbSamplr = new ReverbSampleProvider(sampProvider);
IWavePlayer waveOutDevice.Init(reverbSamplr);
waveOutDevice.Play();
如何同时将多个效果应用于同一个输入文件? 例如,如果我有一个混响效果和失真效果提供器,我如何将它们链接在一起以同时将它们应用到一个输入文件?
答案 0 :(得分:1)
效果可以通过传递一个作为下一个的“源”来链接在一起。因此,如果您希望音频首先通过混响,然后失真,您可能会执行类似这样的操作,将原始音频传递到混响效果,将混响输出传递到失真效果,然后将失真发送到waveOut设备
var reverb = new ReverbSampleProvider(sampProvider);
var distortion = new DistortionSampleProvider(reverb);
waveOutDevice.Init(distortion);
(n.b.NAudio没有内置的混响/失真效果 - 您必须自己制作或从其他地方获取它们)
答案 1 :(得分:1)
Mark的答案是正确的,但是如果您以不同的顺序复制和粘贴内容,这种方法会很痛苦,因为您必须更改要传递的变量。
例如,如果您以以下内容开头:
var lpf = new LowPassEffectStream(input);
var reverb = new ReverbEffectStream(lpf);
var stereo = new StereoEffectStream(reverb);
var vol = new VolumeSampleProvider(stereo);
waveOutDevice.Init(vol);
您想交换混响和立体声,快速复制粘贴将输入变量倒退:
var lpf = new LowPassEffectStream(input);
var stereo = new StereoEffectStream(reverb); // <--
var reverb = new ReverbEffectStream(lpf); // <--
var vol = new VolumeSampleProvider(stereo);
waveOutDevice.Init(vol);
这也使固定参数变得容易,但是却忘记了修改另一个参数,例如修复stereo
效果以将lpf
作为其输入,但是却忘记修复reverb
效果。当效果似乎不起作用时,这通常会导致效果链中跳过效果,导致调试受挫。
为使效果堆叠在一起并对其重新排序时,使事情变得更容易且不易出错,我创建了以下帮助程序类:
class EffectChain : ISampleProvider
{
public EffectChain(ISampleProvider source)
{
this._sourceStream = source;
}
private readonly ISampleProvider _sourceStream;
private readonly List<ISampleProvider> _chain = new List<ISampleProvider>();
public ISampleProvider Head
{
get
{
return _chain.LastOrDefault() ?? _sourceStream;
}
}
public WaveFormat WaveFormat
{
get
{
return Head.WaveFormat;
}
}
public void AddEffect(ISampleProvider effect)
{
_chain.Add(effect);
}
public int Read(float[] buffer, int offset, int count)
{
return Head.Read(buffer, offset, count);
}
}
您可以像这样使用它:
var effectChain = new EffectChain(input);
var lpf = new LowPassEffectStream(effectChain.Head);
effectChain.AddEffect(lpf);
var stereo = new StereoEffectStream(effectChain.Head);
effectChain.AddEffect(stereo);
var reverb = new ReverbEffectStream(effectChain.Head);
effectChain.AddEffect(reverb);
var vol = new VolumeSampleProvider(effectChain.Head);
effectChain.AddEffect(vol);
waveOutDevice.Init(effectChain);
这使您可以快速重新排列链中的效果,因为每个效果都以效果链的头部为输入。如果您不添加任何效果,则仅作为传递。如果愿意,您可以轻松地扩展此类,以具有更多方法来管理所包含的效果,但就目前而言,它工作得很干净。