15

作为学习 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));
}
4

4 回答 4

13

主要问题是:

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使用小端,所以这应该不是问题。

于 2013-02-02T08:44:10.920 回答
4

最简单的方法,您可以简单地更改:

wr.Write("RIFF");

到:

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

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

于 2015-04-07T17:37:56.917 回答
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");
于 2013-02-02T08:31:35.717 回答
1

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

binaryWriter.Write('R');
binaryWriter.Write('I');
binaryWriter.Write('F');
binaryWriter.Write('F'); 
于 2018-05-15T17:09:09.007 回答