web-dev-qa-db-ja.com

C#で.wavファイルを作成する

C#を学ぶための言い訳として、私は単純なプロジェクト、つまりオーディオファイルの作成をコーディングしようとしています。まず、WAVE形式に適合するファイルを書き込めることを確認したいと思います。オンラインでフォーマットを調べましたが(たとえば、 ここ )、ファイルを再生しようとすると、正しく開かれません。これが私のコードです。何かが足りない、または間違っていますか?

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));
}
14
user2034752

主な問題は:

BinaryWriter.Write(string)BinaryReaderが読み取るために、の前に長さが付いた文字列を書き込みますそれを取り戻します。それはあなたの場合のように使用されることを意図していません。 BinaryWriter.Write(string)を使用する代わりに、バイトを直接書き込む必要があります。

あなたがすべきこと:

文字列をバイトに変換してから、バイトを直接書き込みます。

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

または1行にします:

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

あなたが書いている整数が必要と同じサイズでないかもしれないなど、他の問題もあるかもしれません。注意深くチェックする必要があります。

エンディアンについては、データがリトルエンディアンであり、BinaryWriterがリトルエンディアンを使用していることを示すリンクがあるため、これは問題にはなりません。

9
Alvin Wong

可能な限り最も簡単な方法で、次のように変更できます。

wr.Write("RIFF");

に:

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

バイナリファイルに文字列を書き込むと、後で文字列に逆シリアル化できるように、文字列の長さが含まれます。この場合、4バイトを4バイトとして書き込むだけで、char配列に変換するだけでそれが可能になります。

2
Dave Cousineau

適切な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");
1
Jason

@ Alvin-wongの答えは完璧に機能します。さらにいくつかの行がありますが、別の提案を追加したかっただけです。

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