Penulis artikel ini adalah programmer Polandia Tomek Rekavek, yang mengembangkan proyek Jackrabbit Oak sebagai bagian dari Yayasan Perangkat Lunak Apache untuk Adobe. Artikel ini diterbitkan di blog pribadi penulis pada 24 Februari 2016.Polish βRadio-3β (disebut βTroikaβ) Polandia terkenal dengan musik yang bagus dan presenter yang cerdas. Di sisi lain, ia menderita dari kehadiran unit iklan yang keras dan menjengkelkan dalam siaran, yang biasanya mengiklankan beberapa jenis elektronik atau obat-obatan. Saya hampir selalu mendengarkan Troika di tempat kerja dan di rumah, jadi saya bertanya-tanya: bagaimana cara menghapus iklan? Saya pikir saya berhasil menemukan solusi.
Pemrosesan sinyal digital
Tujuan saya adalah membuat aplikasi yang membisukan iklan. Blok komersial 
dimulai dan 
diakhiri dengan jingle, sehingga program harus mengenali suara-suara spesifik ini dan mematikan suara di antara mereka.
Saya tahu bahwa bidang ilmu matematika / komputer ini disebut 
pemrosesan sinyal digital , tetapi bagi saya DSP selalu terasa ajaib. Nah, peluang bagus untuk belajar sesuatu yang baru. Saya menghabiskan satu atau dua hari untuk mencari tahu mekanisme mana yang digunakan untuk menganalisis aliran audio. Dan pada akhirnya, saya menemukan apa yang saya butuhkan: itu adalah 
korelasi silang atau korelasi silang (korelasi silang).
Oktaf
Biasanya semua orang mengacu pada implementasi MATLAB. Tapi MATLAB adalah aplikasi mahal yang menyederhanakan pelaksanaan operasi matematika yang kompleks, termasuk DSP. Untungnya, ada alternatif gratis bernama 
Octave . Tampaknya dalam Octave mudah untuk menjalankan korelasi silang pada dua file audio. Hanya perlu menjalankan perintah berikut:
pkg load signal jingle = wavread('jingle.wav')(:,1); audio = wavread ('audio.wav')(:,1); [R, lag] = xcorr(jingle, audio); plot(R); 
Anda mendapatkan bagan berikut:

Puncak terlihat jelas yang menggambarkan posisi 
jingle.wav di 
audio.wav . Yang mengejutkan saya adalah kesederhanaan metode ini: 
xcorr() melakukan semua pekerjaan, sisa kode hanya untuk membaca file dan menampilkan hasilnya.
Saya ingin mengimplementasikan algoritma yang sama di Java, dan kemudian saya akan memiliki alat yang:
- membaca aliran audio dari input standar (misalnya, dari ffmpeg),
- menganalisisnya untuk mencari jingle,
- mencetak aliran yang sama ke stdout dan / atau menonaktifkannya.
Menggunakan stdin dan stdout akan memungkinkan Anda untuk menghubungkan 
alat analisis baru ke aplikasi lain yang bertanggung jawab atas penyiaran audio dan pemutaran hasilnya.
Membaca file suara
Hal pertama yang harus dibaca oleh program Java adalah jingle (disimpan sebagai file 
.wav ) ke dalam sebuah array. Ada beberapa informasi tambahan dalam file seperti header, metadata, dan banyak lagi, tetapi kita hanya perlu suara. Format yang cocok disebut PCM, itu hanya daftar angka yang mewakili suara. Konversi WAV ke PCM dapat ffmpeg:
 ffmpeg -i input.wav -f s16le -acodec pcm_s16le output.raw 
Di sini, setiap sampel disimpan sebagai angka 16-bit dengan urutan byte terbalik (little endian). Di Jawa, angka ini disebut 
short , dan Anda bisa menggunakan kelas 
ByteBuffer untuk secara otomatis mengonversi aliran input ke daftar nilai 
short :
 ByteBuffer buf = ByteBuffer.allocate(4); buf.order(ByteOrder.LITTLE_ENDIAN); buf.put(bytes); short leftChannel = buf.readShort();  
Xcorr reverse engineering
Untuk mengimplementasikan fungsi 
xcorr() di Java, saya mempelajari 
kode sumber Oktaf. Tanpa mengubah hasil akhir, saya bisa mengganti panggilan xcorr () dengan baris berikut - mereka harus ditulis ulang di Jawa:
 N = length(audio); M = 2 ^ nextpow2(2 * N - 1); pre = fft(postpad(prepad(jingle(:), length(jingle) + N - 1), M)); post = fft(postpad(audio(:), M)); cor = ifft(pre .* conj(post)); R = real(cor(1:2 * N)); 
Ini terlihat menakutkan, tetapi sebagian besar fungsinya adalah operasi sepele dengan array. Korelasi-silang didasarkan pada penerapan 
transformasi Fourier cepat pada sampel suara.
Transformasi Fourier Cepat
Sebagai orang yang tidak memiliki pengalaman dengan DSP, saya hanya melihat FFT sebagai fungsi yang mengambil array dengan deskripsi sampel suara - dan mengembalikan array dengan bilangan kompleks yang mewakili frekuensi. Pendekatan minimalis ini bekerja dengan baik: Saya meluncurkan implementasi FFT dari paket 
JTransforms dan mendapatkan hasil yang sama seperti di Octave. Saya pikir ini sebagian 
kultus kargo , tapi sialnya, itu berhasil!
Menjalankan xcorr di utas
Algoritma di atas mengasumsikan bahwa 
audio adalah larik tempat kita mencari 
jingle . Ini tidak sepenuhnya cocok untuk siaran, di mana kami memiliki aliran suara yang berkelanjutan. Untuk menjalankan analisis, saya membuat buffer siklik sedikit lebih lama daripada durasi jingle untuk dikenali. Aliran masuk mengisi buffer, dan segera setelah penuh, uji korelasi silang dijalankan. Jika tidak ada yang ditemukan, maka bagian tertua dari buffer dibuang - dan sekali lagi kami berharap untuk diisi.
Saya bereksperimen sedikit dengan panjang buffer dan mendapatkan hasil terbaik dengan ukuran buffer 1,5 kali ukuran jingle.
Menyatukan semuanya
Mendapatkan aliran dalam format PCM itu mudah. Ini dapat dilakukan dengan menggunakan 
ffmpeg atas. Perintah di bawah ini mengalihkan aliran ke input 
java standar, dan kemudian output 
Got jingle 0 atau 
Got jingle 1 ketika pola yang sesuai ditemukan dalam stream.
 ffmpeg -loglevel -8 \ -i http://stream3.polskieradio.pl:8904/\;stream \ -f s16le -acodec pcm_s16le - \ | java -jar target/analyzer-1.0.0-SNAPSHOT-jar-with-dependencies.jar \ 2 \ src/test/resources/commercial-start-44.1k.raw 500 \ src/test/resources/commercial-end-44.1k.raw 700 
Versi mandiri
Saya juga menyiapkan versi mandiri sederhana dari penganalisis, yang dengan sendirinya menghubungkan ke aliran Troika (tanpa 
ffmpeg eksternal) dan mereproduksi hasilnya menggunakan 
javax.sound . Semuanya cocok menjadi satu file JAR dan berisi antarmuka pengguna dasar dengan tombol Star dan Stop. Itu bisa diunduh di 
sini . Jika Anda tidak suka menjalankan JAR orang lain di mesin Anda (yang benar-benar benar), maka semua sumber ada di 
GitHub .
 Semuanya
Semuanya sepertinya 
berfungsi sebagaimana mestinya :)
Pekerjaan selanjutnya
Tujuan utamanya adalah untuk menonaktifkan iklan di tingkat amplifier perangkat keras, menerima sinyal FM "nyata", dan bukan aliran Internet. Ini dijelaskan dalam 
artikel selanjutnya .
Pembaruan (Juni 2018)
Diskusi di Hacker NewsDiskusi tentang WykopDiskusi tentang Reddit