【问题标题】:Creating a .wav File in C#在 C# 中创建一个 .wav 文件
【发布时间】:2013-01-17 13:19:56
【问题描述】:

作为学习 C# 的借口,我一直在尝试编写一个简单的项目:创建音频文件。首先,我想确保我可以编写符合 WAVE 格式的文件。我在网上研究过格式(例如here),但是每当我尝试播放文件时,它都无法正确打开。这是我的代码。有什么遗漏或不正确吗?

uint numsamples = 44100;
ushort numchannels = 1;
ushort samplelength = 1; // in bytes
uint samplerate = 22050;

FileStream f = new FileStream("a.wav", FileMode.Create);
BinaryWriter wr = new BinaryWriter(f);

wr.Write("RIFF");
wr.Write(36 + numsamples * numchannels * samplelength);
wr.Write("WAVEfmt ");
wr.Write(16);
wr.Write((ushort)1);
wr.Write(numchannels);
wr.Write(samplerate);
wr.Write(samplerate * samplelength * numchannels);
wr.Write(samplelength * numchannels);
wr.Write((ushort)(8 * samplelength));
wr.Write("data");
wr.Write(numsamples * samplelength);

// for now, just a square wave
Waveform a = new Waveform(440, 50);

double t = 0.0;
for (int i = 0; i < numsamples; i++, t += 1.0 / samplerate)
{
    wr.Write((byte)((a.sample(t) + (samplelength == 1 ? 128 : 0)) & 0xff));
}

【问题讨论】:

  • “无法正确打开”是什么意思?请提及确切的错误或异常。
  • 当我尝试播放时,上面的代码会产生此错误消息:“Windows Media Player 无法播放文件。播放器可能不支持文件类型或可能不支持用于压缩的编解码器文件。”但是后来我更改了文本输出以单独编写每个字符(我猜是作为字符串,他们将空终止符放入其中,这会破坏对齐方式)。经过这些更改,当我尝试播放时,会弹出一条不同的错误消息:“Windows Media Player 在播放文件时遇到问题。”
  • 这实际上是我的第二次尝试。我的第一次尝试是尝试更精确的代码(我使用字节数组并单独分配每个字节,跟踪字节顺序),然​​后将数组内容写入文件。但是这种尝试给出了我提到的第一条错误消息。
  • 在尝试播放文件之前,您是否正确关闭了流?
  • 或者你可以使用C# class that can create WAV for you

标签: c# wav


【解决方案1】:

主要问题是:

BinaryWriter.Write(string) 写入一个字符串,以它的长度为前缀,以便BinaryReader 将其读回。它不打算像您的情况一样使用。您需要直接写入字节而不是使用BinaryWriter.Write(string)

你应该做什么:

将字符串转换为字节,然后直接写入字节。

byte[] data = System.Text.Encoding.ASCII.GetBytes("RIFF");
binaryWriter.Write(data);

或者写一行:

binaryWriter.Write(System.Text.Encoding.ASCII.GetBytes("RIFF"));

还可能存在其他问题,例如您正在编写的整数可能与所需的大小不同。您应该仔细检查它们。

至于字节序,您放置的链接指出数据是小字节序,BinaryWriter 使用小字节序,所以这应该不是问题。

【讨论】:

  • 我修好了。我想我需要用 ASCII 编码它。就像我在评论中提到的那样,我最初尝试使用字节数组并单独处理每个字节(就像我在 C 中工作一样)。正是在这个设置中,我明确地处理了字节顺序(通过移动和隔离一个字节并存储在正确的索引中)。还是谢谢你。
【解决方案2】:

最简单的方法,你可以简单地改变:

wr.Write("RIFF");

到:

wr.Write("RIFF".ToArray());

在二进制文件中写入字符串,它将包含字符串的长度,以便以后可以将其反序列化回字符串。在这种情况下,您只需要将四个字节写入四个字节,然后将其转换为 char 数组即可。

【讨论】:

    【解决方案3】:

    我缺少正确的 WAV 数据,但请尝试用此代码替换生成标头的代码部分(适当替换):

    wr.Write(Encoding.ASCII.GetBytes("RIFF"));
    wr.Write(0);
    wr.Write(Encoding.ASCII.GetBytes("WAVE"));
    wr.Write(Encoding.ASCII.GetBytes("fmt "));
    wr.Write(18 + (int)(numsamples * samplelength));
    wr.Write((short)1); // Encoding
    wr.Write((short)numchannels); // Channels
    wr.Write((int)(samplerate)); // Sample rate
    wr.Write((int)(samplerate * samplelength * numchannels)); // Average bytes per second
    wr.Write((short)(samplelength * numchannels)); // block align
    wr.Write((short)(8 * samplelength)); // bits per sample
    wr.Write((short)(numsamples * samplelength)); // Extra size
    wr.Write("data");
    

    【讨论】:

    • 我得到一个错误(我上面提到的第二个)。这可能是我的数据,但我很确定写入文件的字节数是正确的,所以最坏的结果应该是噪音。我什至将最后一行更改为与其他字符串相同的格式。
    • 我重新排列了一些东西(例如,我不了解您的块大小,所以我使用了我的),结果确实有效!我不知道为什么。也许 C# 或 Visual Studio 的默认值不是 ASCII?无论如何,谢谢。
    • 是的,我正在尝试制作自己的录音机以用于 Google 的语音识别(就像一种桌面助手)。我也花了几个小时来梳理 WAV 格式的细节。很高兴你明白了。
    【解决方案4】:

    @Alvin-wong 的回答非常完美。只是想添加另一个建议,尽管还有几行是:

    binaryWriter.Write('R');
    binaryWriter.Write('I');
    binaryWriter.Write('F');
    binaryWriter.Write('F'); 
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-07-06
      • 2019-07-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多