Sekitar setahun yang lalu saya bekerja dengan file WAV yang dihasilkan, ada beberapa ribu di antaranya. Saya mencoba menandainya, mengurutkannya ke dalam folder, membuat metadata. Dalam prosesnya, saya mendengarkan beberapa bagian, dan, yang membuat saya kecewa, ternyata semuanya dimulai dengan keheningan yang agak lama. Itu sangat menjengkelkan, terutama ketika Anda mendengarkan serangkaian file berturut-turut dan terus-menerus tersandung jeda sebelum memutar setiap file berikutnya. Hebat, yang berarti Anda juga harus melakukan sesuatu.
Saya sudah menghabiskan beberapa waktu mencari solusi untuk menghilangkan keheningan dari file ketika tiba-tiba saya sadar: ini WAV! Data dalam file WAV biasanya audio PCM, yaitu, setiap nilai dalam file menentukan amplitudo suara di beberapa titik waktu. Oleh karena itu, jika kita benar-benar memiliki keheningan total di sana, dan bukan white noise, maka nol yang solid harus sesuai dengan keheningan dalam file ini, bukan?
$ 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
Dan ada. Nah, itu berarti lebih mudah dari yang terlihat. Cukup dengan membaca file, menemukan tempat di mana angka nol ini berakhir, dan menghapus fragmen yang sesuai.
Bagaimana file WAV dibaca
Pertama, saya perlu menjadi lebih akrab dengan format WAV untuk memahami cara bekerja dengan file tersebut dan mengelola data di dalamnya. Saya telah mengumpulkan beberapa sumber; salah satu yang paling berguna ternyata adalah halaman lama dari stanford.edu (situs itu tidak lagi tersedia, tetapi, untungnya, situs itu bertahan di Wayback Machine). Ada diagram yang sangat jelas:
Jadi, struktur file WAV tampaknya cukup sederhana: pertama, header 44-byte, dan kemudian data sebenarnya. Dengan informasi ini, sudah memungkinkan untuk memulai kode. Itu hanya diperlukan untuk melewati 44 byte pertama, menghapus urutan nol di awal bagian data, dan mengirim yang lainnya untuk diputar dalam bentuk aslinya. Meskipun saya tidak bisa tidak menambahkan bahwa di sumber lain saya menemukan informasi berikut:
โBeberapa program berasumsi (dan ini sangat naif di pihak mereka) bahwa pembukaan di header selalu tepat 44 byte (seperti yang dinyatakan dalam tabel di atas) dan bahwa sisa file hanya data audio. Tidak aman membuat asumsi seperti itu."
Yah, saya memutuskan bahwa tidak apa-apa: saya menulis program dalam C, jadi tidak perlu terlalu khawatir tentang keamanan.
Kode
Kodenya tidak rumit, dalam waktu kurang dari seratus baris. Bahkan, dia memeriksa seluruh file byte demi byte, kecuali empat puluh empat yang pertama, dan menghitung angka nol berturut-turut. Segera setelah menemukan sesuatu yang bukan nol, program akan berhenti, menyimpan indeks yang sesuai, dan mulai membaca file dari awal. Kali ini, ia melewatkan semua yang mendahului indeks (tidak termasuk header), dan mengeluarkan semua byte lainnya dengan cara standar.
Tidak perlu mengutip seluruh kode, tetapi inilah bagian yang menarik bagi kami:
// 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);
Semuanya keren, semuanya sederhana. Saatnya untuk menguji. Saya menjalankan program pada salah satu file dengan jeda yang sangat lama.
./strip_audio testfile1.wav > testfile1.nosilence.wav
Memeriksa apa yang dihasilkan xxd untuk testfile1.nosilence.wav. Bagus, tidak ada nol di depan. Jadi itu berhasil. Yang pasti, saya akan segera membuka file di pemutar audio saya.
Sumber
Segera, suara statis paling kuat yang pernah saya dengar dalam hidup saya menghantam telinga saya. Aku hampir jatuh dari kursi dan berusaha mati-matian untuk melepas headphone-ku. Saya ingat saat itu tengah malam, dan anjing itu berlari untuk memeriksa apa yang salah dengan saya.
Di mana saya salah?
Telingaku masih berdenging, dan aku duduk dan mencoba memahami keputusanku yang terburu-buru.
- Kesalahan nomor 1: perlu untuk mengecilkan suara.
- Kesalahan # 2: Anda seharusnya tidak memakai headphone.
- Kesalahan # 3: unit tidak tercatat.
Pernahkah Anda memperhatikan kesalahan ketiga dalam kode yang saya berikan di atas? Petunjuk: lihat komentarnya. Saya menghitung indeks variabel sebagai indeks byte terakhir yang mewakili nol. Ini berarti, dikurangi 44 byte header, sekarang kami hanya mereproduksi apa yang mengikuti atau tumpang tindih dengan indeks. indeks berada di nol terakhir dalam seri, yaitu, kami menyertakan satu byte nol tambahan di bagian data.
Ini dapat diperbaiki sebagai berikut:
// replaced >= with just >
if (ind < 44 || ind > index) {
fputc(current_byte, stdout);
}
Sekarang tidak ada nol tambahan dalam output, dan jika Anda memutar file, tidak ada hal buruk yang akan terjadi. Saya memperbaiki semuanya ... Tapi berhenti.
Dalam file WAV, kami memiliki audio PCM, dan nol dalam jenis data audio ini sesuai dengan keheningan total. Jadi bukankah byte tambahan ini harus benar-benar diam? Mengapa begitu keras dan begitu statis?
Pertama, mari kita bandingkan file audio normal dengan monster yang saya buat dengan Audacity:
Tebak di mana monster itu? Ya, ini yang amplitudonya stabil hampir maksimal. Mengapa demikian?
Bagaimana sampel audio dibaca
Saya kembali ke sumber yang telah saya pilih dan mencoba mencari tahu bagaimana kesalahan satu unit dapat menyebabkan ledakan dalam amplitudo. Saya tahu bahwa dalam file saya sampel berisi 16 bit, dan ada dua saluran (stereo), jadi saya mulai mencari informasi yang sesuai. Inilah yang saya katakan di bagian audio PCM stereo 16-bit:
โSetiap sampel terkandung dalam bilangan bulat i, yang mewakili jumlah byte minimum yang cukup untuk menyimpan ukuran sampel tertentu. Byte paling tidak signifikan ditempatkan pertama di toko. "
"Jumlah byte minimum yang cukup untuk menyimpan ukuran tertentu" - kata-katanya tidak perlu membingungkan. i sesuai dengan jumlah bit yang terkandung dalam sampel. Dalam kasus kami, ada enam belas dari mereka. Dengan demikian, jika kita memiliki nilai tertentu dengan panjang 16 bit, tentu saja akan disimpan dalam dua byte. Dan kemudian poin penting: byte yang paling tidak signifikan terletak di penyimpanan terlebih dahulu. Ini dia.
Lihatlah grafik yang saya buat untuk menunjukkan apa yang menyebabkan sinyal yang begitu kuat:
Bagian atas menunjukkan file monster saya, di mana saya secara tidak sengaja meninggalkan byte tambahan dengan nol. Masing-masing dari tiga sampel - s1, s2 dan s3 - berisi dua byte, dan yang kedua lebih signifikan. Oleh karena itu, ketika mengonversi pasangan byte ini ke desimal, kami mendapatkan amplitudo yang sangat tinggi.
Pada saat yang sama, di bagian bawah Anda dapat melihat bahwa jika Anda menghapus byte nol, sampel dibaca sebagaimana mestinya, dan nilai dalam file audio berada dalam batas yang wajar.
Ternyata jika saya memiliki audio 8-bit, maka byte tambahan yang hilang tidak akan menimbulkan masalah. Tapi itu 16-bit, dan sebagai hasilnya, saya menggeser seluruh urutan dalam sampel, sehingga byte yang paling tidak signifikan dibaca sebagai yang paling signifikan.
kesimpulan
- Periksa gelombang suara file audio sebelum memutarnya pada volume maksimum
- ( )
- ,