如何使用 NAudio 正确地将淡出写入 WAV 文件?
How to properly write a fade-out to a WAV file using NAudio?
我正在使用 NAudio 转换 & trim 一些音频文件,我正在尝试在每个文件的最后几秒添加淡出效果。
我已经检查过 this question, , and this,但所有答案都在谈论使用淡入淡出播放 wav 文件,而我需要实际将淡入淡出写入输出文件。
那么,有什么方法可以使用 NAudio 做到这一点吗?如果没有,我愿意接受其他建议。
编辑: 这是我试过的:
private void PerformFadeOut(string inputPath, string outputPath)
{
WaveFileReader waveSource = new WaveFileReader(inputPath);
ISampleProvider sampleSource = waveSource.ToSampleProvider();
OffsetSampleProvider fadeOutSource = new OffsetSampleProvider(sampleSource);
// Assume the length of the audio file is 122 seconds.
fadeOutSource.SkipOver = TimeSpan.FromSeconds(120); // Hard-coded values for brevity
// Two seconds fade
var fadeOut = new FadeInOutSampleProvider(fadeOutSource);
fadeOut.BeginFadeOut(2000);
Player = new WaveOut();
Player.Init(fadeOut);
Player.Play();
}
当我使用 Player.Play()
- 应用淡入淡出后播放音频时,如上述方法所示 -,它按预期完美运行,我可以听到褪色。现在,我想将此结果导出到输出 WAV 文件。
我尝试通过添加以下行来做到这一点:
WaveFileWriter.CreateWaveFile(outputPath, waveSource);
但是,输出文件没有应用任何淡入淡出。那么,我在这里缺少什么?
好的,让我们总结一下,以防将来有人遇到同样的问题:
在@yms 的大力帮助下,我设法使用以下方法将淡入淡出写入文件:
WaveFileWriter.CreateWaveFile(outputPath, new SampleToWaveProvider(fadeOut));
但这导致 wave writer 只写最后两秒 这很有意义 ,所以我尝试使用 DelayFadeOutSampleProvider
class 而不是 FadeInOutSampleProvider
。这样我就可以写入整个文件,但最终导致淡入淡出的位置错误(保存时更明显。播放时不是 ).
我用Audacity生成了一个10秒的wav文件,用下面的方法测试:
private static void PerformFadeOut(string inputPath, string outputPath, bool playNoSave = false)
{
WaveFileReader waveSource = new WaveFileReader(inputPath);
ISampleProvider sampleSource = waveSource.ToSampleProvider();
// Two seconds fade
var fadeOut = new DelayFadeOutSampleProvider(sampleSource);
fadeOut.BeginFadeOut(8000, 2000);
if(playNoSave)
{
// Here the fade is played exactly where expected (@00:08)
var player = new WaveOut();
player.Init(fadeOut);
player.Play();
}
else
{
// But when saving, the fade is applied @00:04!
WaveFileWriter.CreateWaveFile(outputPath, new SampleToWaveProvider(fadeOut));
}
}
这是写入淡出之前和之后的文件:
如上所示,淡出没有从正确的位置开始。
在DelayFadeOutSampleProvider
里查了一下,发现Read
方法有bug,所以修改成这样:
public int Read(float[] buffer, int offset, int count)
{
int sourceSamplesRead = source.Read(buffer, offset, count);
lock (lockObject)
{
if (fadeOutDelaySamples > 0)
{
int oldFadeOutDelayPos = fadeOutDelayPosition;
fadeOutDelayPosition += sourceSamplesRead / WaveFormat.Channels;
if (fadeOutDelayPosition > fadeOutDelaySamples)
{
int normalSamples = (fadeOutDelaySamples - oldFadeOutDelayPos) * WaveFormat.Channels;
int fadeOutSamples = (fadeOutDelayPosition - fadeOutDelaySamples) * WaveFormat.Channels;
// apply the fade-out only to the samples after fadeOutDelayPosition
FadeOut(buffer, offset + normalSamples, fadeOutSamples);
fadeOutDelaySamples = 0;
fadeState = FadeState.FadingOut;
return sourceSamplesRead;
}
}
if (fadeState == FadeState.FadingIn)
{
FadeIn(buffer, offset, sourceSamplesRead);
}
else if (fadeState == FadeState.FadingOut)
{
FadeOut(buffer, offset, sourceSamplesRead);
}
else if (fadeState == FadeState.Silence)
{
ClearBuffer(buffer, offset, count);
}
}
return sourceSamplesRead;
}
现在一切正常。
Here's my fork 整个 class 如果有人感兴趣,我已经要求作者 (@mark-heath) 使用此修复程序更新原始要点。
您的原始代码使用原始 waveSource
作为输入,这就是您没有淡入淡出的原因。
以下备选方案使用 fadeOut
对象:
WaveFileWriter.CreateWaveFile16(outputPath, fadeOut);
CreateWaveFile16
的签名为:
public static void CreateWaveFile16(string filename, ISampleProvider sourceProvider)
这可以在source code of the class WaveFileWriter.
中看到
另一种选择是使用 class SampleToWaveProvider 并将您的 fadeOut
对象转换为 IWaveProvider
,这样您就可以使用常规的 CreateWaveFile
方法。
WaveFileWriter.CreateWaveFile(outputPath, new SampleToWaveProvider(fadeOut))
如您所知,在所有情况下,您的输出文件将只包含与淡出相对应的最后 k 秒,如果您想要整个文件 with[=,则需要不同的 class 34=] 淡出。
我正在使用 NAudio 转换 & trim 一些音频文件,我正在尝试在每个文件的最后几秒添加淡出效果。
我已经检查过 this question,
那么,有什么方法可以使用 NAudio 做到这一点吗?如果没有,我愿意接受其他建议。
编辑: 这是我试过的:
private void PerformFadeOut(string inputPath, string outputPath)
{
WaveFileReader waveSource = new WaveFileReader(inputPath);
ISampleProvider sampleSource = waveSource.ToSampleProvider();
OffsetSampleProvider fadeOutSource = new OffsetSampleProvider(sampleSource);
// Assume the length of the audio file is 122 seconds.
fadeOutSource.SkipOver = TimeSpan.FromSeconds(120); // Hard-coded values for brevity
// Two seconds fade
var fadeOut = new FadeInOutSampleProvider(fadeOutSource);
fadeOut.BeginFadeOut(2000);
Player = new WaveOut();
Player.Init(fadeOut);
Player.Play();
}
当我使用 Player.Play()
- 应用淡入淡出后播放音频时,如上述方法所示 -,它按预期完美运行,我可以听到褪色。现在,我想将此结果导出到输出 WAV 文件。
我尝试通过添加以下行来做到这一点:
WaveFileWriter.CreateWaveFile(outputPath, waveSource);
但是,输出文件没有应用任何淡入淡出。那么,我在这里缺少什么?
好的,让我们总结一下,以防将来有人遇到同样的问题:
在@yms 的大力帮助下,我设法使用以下方法将淡入淡出写入文件:
WaveFileWriter.CreateWaveFile(outputPath, new SampleToWaveProvider(fadeOut));
但这导致 wave writer 只写最后两秒 这很有意义 ,所以我尝试使用 DelayFadeOutSampleProvider
class 而不是 FadeInOutSampleProvider
。这样我就可以写入整个文件,但最终导致淡入淡出的位置错误(保存时更明显。播放时不是 ).
我用Audacity生成了一个10秒的wav文件,用下面的方法测试:
private static void PerformFadeOut(string inputPath, string outputPath, bool playNoSave = false)
{
WaveFileReader waveSource = new WaveFileReader(inputPath);
ISampleProvider sampleSource = waveSource.ToSampleProvider();
// Two seconds fade
var fadeOut = new DelayFadeOutSampleProvider(sampleSource);
fadeOut.BeginFadeOut(8000, 2000);
if(playNoSave)
{
// Here the fade is played exactly where expected (@00:08)
var player = new WaveOut();
player.Init(fadeOut);
player.Play();
}
else
{
// But when saving, the fade is applied @00:04!
WaveFileWriter.CreateWaveFile(outputPath, new SampleToWaveProvider(fadeOut));
}
}
这是写入淡出之前和之后的文件:
如上所示,淡出没有从正确的位置开始。
在DelayFadeOutSampleProvider
里查了一下,发现Read
方法有bug,所以修改成这样:
public int Read(float[] buffer, int offset, int count)
{
int sourceSamplesRead = source.Read(buffer, offset, count);
lock (lockObject)
{
if (fadeOutDelaySamples > 0)
{
int oldFadeOutDelayPos = fadeOutDelayPosition;
fadeOutDelayPosition += sourceSamplesRead / WaveFormat.Channels;
if (fadeOutDelayPosition > fadeOutDelaySamples)
{
int normalSamples = (fadeOutDelaySamples - oldFadeOutDelayPos) * WaveFormat.Channels;
int fadeOutSamples = (fadeOutDelayPosition - fadeOutDelaySamples) * WaveFormat.Channels;
// apply the fade-out only to the samples after fadeOutDelayPosition
FadeOut(buffer, offset + normalSamples, fadeOutSamples);
fadeOutDelaySamples = 0;
fadeState = FadeState.FadingOut;
return sourceSamplesRead;
}
}
if (fadeState == FadeState.FadingIn)
{
FadeIn(buffer, offset, sourceSamplesRead);
}
else if (fadeState == FadeState.FadingOut)
{
FadeOut(buffer, offset, sourceSamplesRead);
}
else if (fadeState == FadeState.Silence)
{
ClearBuffer(buffer, offset, count);
}
}
return sourceSamplesRead;
}
现在一切正常。
Here's my fork 整个 class 如果有人感兴趣,我已经要求作者 (@mark-heath) 使用此修复程序更新原始要点。
您的原始代码使用原始 waveSource
作为输入,这就是您没有淡入淡出的原因。
以下备选方案使用 fadeOut
对象:
WaveFileWriter.CreateWaveFile16(outputPath, fadeOut);
CreateWaveFile16
的签名为:
public static void CreateWaveFile16(string filename, ISampleProvider sourceProvider)
这可以在source code of the class WaveFileWriter.
中看到另一种选择是使用 class SampleToWaveProvider 并将您的 fadeOut
对象转换为 IWaveProvider
,这样您就可以使用常规的 CreateWaveFile
方法。
WaveFileWriter.CreateWaveFile(outputPath, new SampleToWaveProvider(fadeOut))
如您所知,在所有情况下,您的输出文件将只包含与淡出相对应的最后 k 秒,如果您想要整个文件 with[=,则需要不同的 class 34=] 淡出。