如何在 C# 中使用 NAudio 将 3 个 wav 文件合并为具有 3 个通道的单个文件?

发布于 2024-11-28 16:42:59 字数 439 浏览 7 评论 0原文

使用 C# 和 NAudio,我有三个波形文件,我想将其加入到具有三个通道的单个波形文件中,每个通道对应于三个输入文件之一。此外,我希望每个波形文件中的音频剪辑在最终流中的不同点开始。例如,如果三个波形文件的长度分别为3秒、5秒。和 2 秒,分别,输出波形文件将是 10 秒长并且...

  • 通道 1 包含来自文件 1 的 3 秒声音,后跟 7 静音秒数。

  • 频道 2 包含 3 秒的静音,然后是 5 秒的静音 来自文件 2 的声音,然后是 2 秒的静音。

  • 频道 3 包含 8 秒的静音,然后是 2 秒的静音 来自文件 3 的声音。

我一直在尝试为每个文件创建一个 WaveChannel32 实例,然后使用 WaveOffsetStream 类,但我对这类事情很陌生,而且没有取得太大成功。

有人有什么建议吗?

Using C# and NAudio, I have have three wave files I would like to join into a single wave file having three channels, each corresponding to one of the three input files. Furthermore, I would like the audio clip from each wave file to begin at a different point in the final stream. For example, if the lengths of the three wave files are 3 sec., 5 sec. and 2 sec., respectively, the output wave file would be 10 seconds long and...

  • channel 1 contains the 3 seconds of sound from file 1 followed by 7
    seconds of silence.

  • channel 2 contains 3 seconds of silence followed by the 5 seconds of
    sound from file 2 followed by 2 seconds of silence.

  • channel 3 contains 8 seconds of silence followed by the 2 seconds of
    sound from file 3.

I have been experimenting by creating a WaveChannel32 instance for each file and then using the WaveOffsetStream class, but I'm new to this sort of thing and I'm not having much success.

Anyone have any suggestions?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

冷…雨湿花 2024-12-05 16:42:59

您可以通过编写自己的自定义 IWaveProvider/WaveStream 来实现此目的,其输出 WaveFormat 具有三个通道。它包含对三个输入文件中每一个的引用。
然后,在 Read 方法中,它计算出请求的样本数量,并从每个源文件中读取适当的数量。然后需要对样本进行交错 - 一个来自第一个文件,一个来自第二个文件,一个来自第三个文件。要延迟,您只需将零放入即可。

这里有一些未经测试的示例代码,它们来自各种源文件(必须具有相同的位深度和采样率),它们有望为您指明正确的方向:

int Read(byte[] buffer, int offset, int bytesRequired)
{
    int bytesPerSample = this.WaveFormat.BitsPerSample / 8;
    int samplesRequired = bytesRequired / bytesPerSample;
    int channels = this.WaveFormat.Channels; // 3
    int samplesPerChannel = samplesRequired / channels;
    byte[] readBuffer = new byte[samplesPerChannel * bytesPerSample];
    for (int channel = 0; channel < channels; channel++)
    {
        int read = inputs[channel].Read(readBuffer, 0, samplesPerChannel * bytesPerSample);
        int outOffset = offset + channel * bytesPerSample;
        for (int i = 0; i < read; i += bytesPerSample)
        {
             Array.Copy(readBuffer, i, buffer, outOffset, bytesPerSample);
             outOffset += channels * bytesPerSample;
        } 
    }
}

为了防止代码变得过于复杂,您可以通过创建另一个派生的 IWaveProvider / WaveStream 来插入静音,其 Read 方法返回适当数量的静音,然后再从输入文件返回实际数据。然后可以将其用作交错 WaveStream 的输入。

You would do this by writing your own custom IWaveProvider/WaveStream whose output WaveFormat has three channels. It holds a reference to each of your three input files.
Then, in the Read method, it works out the number of samples requested, and reads the appropriate number from each source file. The samples then need to be interleaved - one from first file, one from second, one from third. To delay you simply put zeroes in.

Here's some untested example code that interleaves from various source files (must all be of same bit depth and sample rate) which will hopefully point you in the right direction:

int Read(byte[] buffer, int offset, int bytesRequired)
{
    int bytesPerSample = this.WaveFormat.BitsPerSample / 8;
    int samplesRequired = bytesRequired / bytesPerSample;
    int channels = this.WaveFormat.Channels; // 3
    int samplesPerChannel = samplesRequired / channels;
    byte[] readBuffer = new byte[samplesPerChannel * bytesPerSample];
    for (int channel = 0; channel < channels; channel++)
    {
        int read = inputs[channel].Read(readBuffer, 0, samplesPerChannel * bytesPerSample);
        int outOffset = offset + channel * bytesPerSample;
        for (int i = 0; i < read; i += bytesPerSample)
        {
             Array.Copy(readBuffer, i, buffer, outOffset, bytesPerSample);
             outOffset += channels * bytesPerSample;
        } 
    }
}

To keep the code from becoming overly complicated, you could do your silence insertion by creating another derived IWaveProvider / WaveStream, whose Read method returned the appropriate amount of silence, before then returning the real data from the input file. This can then be used as an input to your interleaving WaveStream.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文