如何使用NAudio正确地将淡出写入WAV文件?

时间:2017-08-26 06:22:10

标签: c# .net audio wav naudio

我使用NAudio转换&修剪一些音频文件,我试图在每个文件的最后几秒添加淡出。

我已经检查了thisthis和{{3}},但所有的答案都在讨论用淡入淡出来播放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);

但是,输出文件没有应用任何淡入淡出。那么,我在这里错过了什么?

2 个答案:

答案 0 :(得分:1)

好的,让我们把所有事情都包起来以防将来有人遇到同样的问题:

在@yms的帮助下,我设法使用以下方法将淡入淡出写入文件:

WaveFileWriter.CreateWaveFile(outputPath, new SampleToWaveProvider(fadeOut));

但是这导致wave writer只写了最后两秒,这是有意义的,所以我尝试使用DelayFadeOutSampleProvider类而不是FadeInOutSampleProvider。有了这个,我就能写出整个文件,但最终导致褪色开始处于错误的位置(在保存时更明显。播放时< / em>的)。

我用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));
    }
}

这里是文件,之前&amp;写完淡出后:

Before & after writing the fade-out

如上所示,淡出不会从正确的位置开始。

DelayFadeOutSampleProvider进行一些调查后,我在Read方法中发现了一个错误,因此我对其进行了修改:

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;
}

现在一切正常。

全班的{p> Here's my fork,如果有人感兴趣,我已经要求作者(@ mark-heath)用这个修补程序更新原始要点。

答案 1 :(得分:1)

原始代码使用原始waveSource作为输入,这就是您没有淡入淡出的原因。

以下替代方法使用fadeOut对象:

WaveFileWriter.CreateWaveFile16(outputPath, fadeOut);

CreateWaveFile16的签名是:

public static void CreateWaveFile16(string filename, ISampleProvider sourceProvider)

这可以在source code of the class WaveFileWriter

中看到

另一种方法是使用类SampleToWaveProvider并将fadeOut对象转换为IWaveProvider,这样您就可以使用常规的CreateWaveFile方法。

WaveFileWriter.CreateWaveFile(outputPath, new SampleToWaveProvider(fadeOut))

如您所知,在所有情况下,您的输出文件将仅包含与淡出对应的最后k秒,如果您希望整个文件 为淡出,则需要不同的类。