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 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