約 1 年前、私は生成された WAV ファイルを扱っていましたが、数千の WAV ファイルがありました。それらにタグを付け、フォルダーに分類し、メタデータを作成しようとしました。その過程で、私はいくつかの曲を聴いたが、残念なことに、それらはすべてかなり長い沈黙から始まることが判明した.一連のファイルを連続して聴いていて、次のファイルを再生する前に一時停止を繰り返しているときは特に、非常に面倒でした。素晴らしい、つまり、あなたもそれについて何かをしなければならないことを意味します。
ファイルから沈黙を取り除く解決策を探すのに、私はすでにしばらく時間を費やしていたのですが、突然それが私に気付いたのです。通常、WAV ファイルのデータは PCM オーディオです。つまり、ファイル内の各値は、ある時点でのサウンドの振幅を指定します。したがって、ホワイト ノイズではなく、実際に完全な無音がある場合、ファイル内のこの無音にソリッド ゼロが対応している必要があります。
$ xxd testfile1.wav | head -n 100
00000000: 5249 4646 64b9 0e00 5741 5645 666d 7420 RIFFd...WAVEfmt
00000010: 1000 0000 0100 0200 44ac 0000 10b1 0200 ........D.......
00000020: 0400 1000 6461 7461 40b9 0e00 0000 0000 ....data@.......
00000030: 0000 0000 0000 0000 0000 0000 0000 0000 ................
00000040: 0000 0000 0000 0000 0000 0000 0000 0000 ................
00000050: 0000 0000 0000 0000 0000 0000 0000 0000 ................
00000060: 0000 0000 0000 0000 0000 0000 0000 0000 ................
00000070: 0000 0000 0000 0000 0000 0000 0000 0000 ................
00000080: 0000 0000 0000 0000 0000 0000 0000 0000 ................
# ... and a lot more zeros below
そこには。つまり、見た目よりも簡単です。ファイルを読み取り、これらのゼロが終わる場所を見つけて、対応するフラグメントを削除するだけで十分です。
WAV ファイルの読み方
まず、そのようなファイルを操作し、ファイル内のデータを管理する方法を理解するために、WAV 形式に慣れる必要がありました。私はいくつかのソースを収集しました。最も有用なものの 1 つは、stanford.eduの古いページであることが判明しました (サイトは現在利用できませんが、幸いなことに、Wayback Machine には残っています)。非常に明確な図がありました。
したがって、WAV ファイルの構造は非常に単純であるように見えます。最初は 44 バイトのヘッダー、次に実際のデータです。この情報により、コードを開始することはすでに可能でした。最初の 44 バイトをスキップし、データ セクションの先頭にある一連のゼロを削除し、他のすべてを送信して元の形式で再生するだけで済みました。別のソースでそれを追加せずにはいられませんが 、次の情報を見つけました。
一部のプログラムは、ヘッダーのプリアンブルが常に正確に 44 バイトであり (上記の表に記載されているように)、ファイルの残りの部分はオーディオ データのみであると想定しています (これは非常に単純です)。そのような仮定をするのは安全ではありません。」
私は C でプログラムを書いたので、セキュリティについてあまり心配する必要はありませんでした。
コード
コードは単純で、100 行未満でした。実際、彼は最初の 44 を除いてファイル全体を 1 バイトずつ調べ、連続するゼロを数えました。ゼロではないものに遭遇すると、プログラムはすぐに停止し、適切なインデックスを保存して、ファイルを最初から読み取り始めます。今回は、インデックスより前のすべてをスキップし (ヘッダーはカウントしません)、他のすべてのバイトを標準の方法で出力しました。
コード全体を引用する必要はありませんが、ここに興味のある部分があります。
// index was calculated above to be the index of
// the last consecutive zero byte
FILE *f = fopen(argv[1], "rb");
int ind = 0;
int current_byte;
while ((current_byte = fgetc(f)) != EOF) {
if (ind < 44 || ind >= index) {
fputc(current_byte, stdout);
}
ind += 1;
}
fclose(f);
すべてがクールで、すべてがシンプルです。テストする時が来ました。私は、ファイルの 1 つでプログラムを特に長い一時停止で実行しました。
./strip_audio testfile1.wav > testfile1.nosilence.wav
xxd が testfile1.nosilence.wav に対して生成するものを確認しました。先行ゼロなし。それでうまくいきました。念のため、オーディオ プレーヤーでファイルをすばやく開きます。
ソース
すぐに、これまでの人生で聞いた中で最も強力な静的ノイズが耳に届きました。私は椅子から転げ落ちそうになり、必死にヘッドフォンを外そうとしました。真夜中だったのを覚えていますが、犬が私の様子を確認しに走ってきました。
どこで私は間違えましたか?
私の耳はまだ鳴り響いており、私は座って自分の無頓着な決定を理解しようとしました。
- 間違いその1:音を小さくする必要があった。
- 間違いその 2: ヘッドホンをつけるべきではなかった.
- 間違い 3: 未記録のユニット。
上記のコードの 3 番目のエラーに気付いたでしょうか。ヒント: コメントを見てください。ゼロを表す最後のバイトのインデックスとして変数インデックスを計算しました。これは、ヘッダーの 44 バイトを差し引いたものであり、インデックスに続くもの、またはインデックスと重複するものだけを再現することを意味します。 index はシリーズの最後のゼロです。つまり、データ セクションに 1 つの余分なゼロ バイトが含まれます。
これは次のように修正できます。
// replaced >= with just >
if (ind < 44 || ind > index) {
fputc(current_byte, stdout);
}
これで、出力に余分なゼロがなくなり、ファイルを再生しても何も起こりません。私はすべてを修正しました...しかし、やめてください。
WAV ファイルには PCM オーディオがあり、この種のオーディオ データのゼロは完全な無音に対応します。では、この余分なバイトは完全に沈黙すべきではありませんか? どうしてあんなに騒がしくて静かだったの?
まず、通常のオーディオ ファイルを Audacity で作成したモンスターと比較してみましょう。
モンスターはどこにいると思いますか?はい、振幅がほぼ最大に安定して出ているものです。何故ですか?
オーディオサンプルの読み方
私は選択したソースに戻って、1 つのユニットのエラーがどのようにしてそのような振幅の爆発につながるのかを理解しようとしました。私のファイルにはサンプルに 16 ビットが含まれており、2 つのチャンネル (ステレオ) があることがわかっていたので、適切な情報を探し始めました。 16 ビット ステレオ PCM オーディオのセクションで私が言ったことは次のとおりです。
「各サンプルは整数 i に含まれています。これは、指定されたサンプル サイズを格納するのに十分な最小バイト数を表します。最下位バイトが最初にストアに配置されます。」
「指定されたサイズを格納するのに十分な最小バイト数」 - 言い回しが不必要に混乱しています。 i は、サンプルに含まれるビット数に対応します。私たちの場合、それらは16個あります。したがって、長さが 16 ビットの特定の値がある場合、もちろん 2 バイトで格納されます。そして重要な点: 最下位のバイトが最初にストレージに配置されます。ここにあります。
このような強い信号の原因を示すために作成したグラフを見てください。
上の部分は私のモンスター ファイルを示しています。このファイルには、誤って 1 バイトをゼロで残してしまいました。3 つのサンプル (s1、s2、および s3) にはそれぞれ 2 バイトが含まれており、2 番目のサンプルはより重要です。したがって、これらのバイトのペアを 10 進数に変換すると、非常に高い振幅が得られます。
同時に、下部では、ゼロバイトを削除すると、サンプルが正常に読み取られ、オーディオファイルの値が妥当な範囲内にあることがわかります。
私が 8 ビットのオーディオを使用している場合、余分なバイトが欠落していても問題は発生しないことがわかりました。しかし、これは 16 ビットだったので、シーケンス全体をサンプル単位でシフトしたので、最下位バイトが最上位バイトとして読み取られました。
結論
- 最大音量で再生する前に、オーディオ ファイルのサウンド ウェーブを確認する
- ( )
- ,