Gelombang Adaptif untuk layanan audio Anda



Ketika saya perlu mengatur arsip audio untuk satu situs siaran, selain panel admin, saya juga membutuhkan pemutar audio. Siaran berlangsung 40 menit ditambah dua jeda musik. Menggunakan Waveform dalam format yang panjang sangat nyaman, oleh karena itu, seperti banyak layanan musik, saya memutuskan untuk menggunakan solusi ini dalam desain pemutar.

Dengan desain ulang masa depan yang direncanakan dari situs dan, mungkin, aplikasi mobile masa depan, bentuk gelombang raster di sini hanya bertumpu pada baji. Itu tidak adaptif, sangat intensif sumber daya untuk mendesain ulang jika ada di raster.

SOUNDCLOUD yang terkenal memecahkan masalah ini pada layar kecil dengan menggerakkan seluruh bentuk gelombang relatif ke pusat statis. Tetapi saya tidak menginginkan itu.

Penyiaran radio dilakukan melalui panel admin, dan saya segera membuat lebih banyak salinan file audio melalui ffmpeg. Adalah bodoh untuk melepaskan kemampuannya dan menghasilkan bentuk gelombang.

Algoritma tindakan:


1. Generasi bentuk gelombang dalam ukuran minimum untuk penyimpanan
2. Terjemahan ke dalam vektor (JSON)
3. Menggambar pemain untuk array ini
4. Implementasi kemampuan beradaptasi: pengurangan array yang seragam dan kembali ke langkah 3

Generasi bentuk gelombang



Pada saat penerapan pendekatan ini, kawan-kawan BBC belum merilis output dalam JSON dalam utilitas mereka , sejauh yang saya ingat. Dan pada saat ini, saya akan merekomendasikan agar Anda membangun kembali utilitas mereka untuk menghapus output angka negatif dan tambahan yang tidak berguna. Tua tentang saluran bitness dan omong kosong lainnya.
Sementara itu, lanjutkan:

Jika kita mengambil desain pemain saya (dikurangi lebarnya di sini), kita akan melihat bahwa ada 2 piksel per strip (ditambah 1 pemisah pixel). Ini berarti 600px akan memberi kita lebar 1200px.



Saya kira bahwa di masa depan akan sangat tidak mungkin bahwa presentasi yang lebih besar dari file audio akan dibutuhkan. Nah, jika Anda tidak menarik desain pada lebar penuh monitor 4K, Anda harus memikirkannya, tapi saya berhenti di 600x60px.

Dan sekarang lebih dekat ke kode:

shell_exec("ffmpeg -y -i '$name.mp3' -filter_complex 'aformat=channel_layouts=mono,compand,showwavespic=s=600x120,crop=in_w:in_h/2:0:0' -c:v png -pix_fmt monob -frames:v 1 '$png_path.png' > /dev/null 2>/dev/null &"); 

-filter_complex - sambungkan filter

aformat - bekerja dengan suara

channel_layouts

-mono - mode mono

-perusahaan adalah kompresor dan expander. Dalam mode ini, baik suara sunyi dan keras akan disamakan dalam volume, yang memungkinkan Anda untuk mendapatkan bentuk gelombang tanpa puncak dan kelebihan pada rekaman tenang dan keras. Bentuk gelombang, seolah-olah, selalu direntangkan secara maksimal.

-showwavespic = s = 600x120 - s mengambil ukuran gambar.

-crop = in_w: in_h / 2: 0: 0 - memotong gambar yang diterima. Sebagai aturan, respons frekuensi output dicerminkan di sekitar sumbu x. Karena itu, kami taburkan, hanya menyisakan ujung gunung es.

-c: v png -pix_fmt monob -frame: v 1 - format gambar keluaran, dengan palet warna dan hanya bingkai pertama (kita tidak perlu animasi). png8 sangat bagus untuk kualitas (lossless dalam kasus kami) / tempat.

> / dev / null 2> / dev / null & kirim output dan data yang berfungsi ke jurang. Dan '&' memungkinkan php untuk tidak menunggu konsol selesai bekerja, tetapi untuk melanjutkan.

Pada output, kita mendapatkan gambar ini:


Ukuran file akhir 2.4kb

Yang lucu adalah bahwa beberapa tahun yang lalu bukannya putih ada warna merah. Pengembang, tampaknya, mengubah nilai default.

Konversi bentuk gelombang ke vektor


Gambar yang dihasilkan adalah amplitudo dalam Y dan waktu dalam X. Ini adalah dasar untuk menerjemahkannya ke dalam array JSON satu dimensi. Di mana nilai akan bertindak sebagai nilai amplitudo, dan waktu hanyalah indeks ordinal mereka.

Saya memutuskan untuk melakukan terjemahan dengan cepat, tanpa caching hasilnya, sangat cepat dilakukan.
Kami mengukur jumlah piksel sepanjang Y dari atas ke yang lainnya , dan beralih ke piksel berikutnya sepanjang X.

 $a = imagecreatefrompng("test.png"); $i = 0; $h = '60'; // horizontal movener while ( $i < 600 ) { // vertical movener $y = $h-1; $c = 0; while ( $c < $h ) { //echo imagecolorat($aa, $i, $c ); // test color if(imagecolorat($a, $i, $c ) == "255") { $arr[$i] = $c; break; } else { $arr[$i] = $y; } $c++; } $i++; }; echo json_encode($arr); 

Array yang dihasilkan terdiri dari 600 nilai.

[46,28,34,35,34,35,26,33,39,29,29,30,30,30,33,33,28...]

Perenderan pemain oleh JSON


Untuk bilah kemajuan pekerjaan yang nyaman, saya mengambil progressor.js dari Elliot Bentley. Dia membuatnya untuk layanan transkripsi audio.

github.com/ejb/progressor.js 2.76 KB

Mari kita lihat pemain kita lagi.



Bilah progres terdiri dari dua lapisan: latar belakang dengan bilah abu-abu dan hijau.

Di bawah gambar diambil dengan fungsi getGraph.

Artinya adalah menggambar kolom dengan ketebalan dan warna yang diinginkan dengan pemisah kolom.

 var c = document.createElement("canvas"); c.width = width; c.height = height; var ctx = c.getContext("2d"); function getGraph(fillStyle1,fillStyle2,fillStyle3) { if (fillStyle3) { //console.log(fillStyle1); var grd = ctx.createLinearGradient(0,120,0,0); grd.addColorStop(0.5,fillStyle1); grd.addColorStop(1,fillStyle2); fillStyle1 = grd; fillStyle2 = fillStyle3; } json.forEach(function(item, i, arr) { ctx.fillStyle = fillStyle1; ctx.fillRect(i * 3, height, 2, item - height); ctx.fillStyle = fillStyle2; var next = json[i + 1]; if( item <= next ) { h2 = next; } else { h2 = item; } ctx.fillRect(i * 3 + 2, height, 1, h2 - height); }); return c.toDataURL(); } 

Ini adalah contoh kerja tanpa kemampuan beradaptasi

4. Implementasi kemampuan beradaptasi


Sekarang kita perlu mengurangi array JSON pada klien ke ukuran yang diinginkan dan di sini Anda memiliki kemampuan beradaptasi.

Rencanakan a


Metode pertama yang terlintas dalam pikiran adalah untuk menghapus setiap detik, ketiga, keempat ... dalam satu siklus, sehingga Anda tidak dapat mengurangi array kurang dari setengah, dan akurasi piksel tidak dapat dicapai di sini.

Memodifikasi bentuk gelombang dengan menghapus nilai array adalah jalan buntu. Ketika Anda melakukan ini, Anda akan melihat berapa banyak gelombang menjadi robek secara impersonal, karena Anda melemparkan ekstrem dan tidak rata-rata ketinggian tetangga.

Kita perlu melakukan resampling algoritma. Ada implementasi algoritma pada js:

terbesarTriangleTigaBuckets

Ini berfungsi dengan baik, hanya meminta input array seperti itu, pada indeks yang akan menerima koordinat XY. Kami memiliki array satu dimensi, jadi saya harus membuat sedikit kesenangan dan mengulangi fungsinya. Ini berfungsi seperti ini:



Dan di sini Anda dapat menyentuh dengan adaptif sebagai KDPV.

Tetapkan mode tampilan di mana bingkai html akan berada di sebelah kanan. Kemudian Anda dapat mengubah lebar jendela ini.

Plan B - Puff


Namun, saya masih tidak ingin memuat sisi klien. Sebagai contoh, saya ingin 1000 titik-5000, tetapi seluruh lebar layar. Jika saya memiliki lebih banyak poin, bagaimana hal ini akan berperilaku di ponsel? Di satu sisi, ini sama sekali tidak ada masalah, itu tidak begitu mahal, dilihat dari demo algoritma, itu mengunyah 5.000 poin dengan mudah. Tetapi di sisi lain, seseorang harus memberi sebanyak yang diminta. Pertanyaan desain.

Dasar, jika Anda memiliki Node.Js, Anda dapat mentransfer kode ini ke server. Dan jika Anda memiliki php, Anda dapat menemukan implementasi dari algoritma ini di php tapi ... mengapa, saya pikir.

Di mana algoritma resampling? Dalam lib GD asli yang sama yang kami gunakan untuk menghasilkan JSON. Kami hanya melewatkan parameter dari klien dalam piksel dengan lebar yang dibutuhkan dan mengubah ukuran bentuk gelombang kami sebelum dikonversi ke JSON.

Karena itu, saya akan memperluas kode yang ditulis di awal.

 $h = 60; $width_new = 600; $a = imagecreatefrompng("$id.png"); $width_old = imagesx($a); $aa = imagecreatetruecolor($width_new, $h); imagecopyresized($aa, $a, 0, 0, 0, 0, $width_new, $h, $width_old, $h); imagetruecolortopalette($aa, false, 2); $i = 0; // horizontal movener while ( $i < $width_new ) { // vertical movener $y = $h-1; $c = 0; while ( $c < $h ){ //echo imagecolorat($aa, $i, $c ); // search what color is needed if(imagecolorat($aa, $i, $c ) == "1"){ $arr[$i] = $c; break; } else { $arr[$i] = $y; } $c++; } $i++; }; echo json_encode($arr); 

Setelah itu, Anda tidak perlu khawatir jika perlu mengubah desain, lebar pemain, meluas menjadi aplikasi seluler. Semuanya terlihat cukup fleksibel dan sangat cerdas.

Kodenya ada di sini

.
Telur paskah.

Itu mungkin hari yang cerah. Jendela kamar kami menghadap ke dua lantai bata 9 lantai, yang saya ingat ketika masih remaja, saya tahu bahwa cincin trem terbuka di belakang mereka, sedikit lebih jauh - rumah sakit lama, tepat di belakang sekolah, dan bangunan saat ini dengan kantor tempat saya mencoba menggali. dalam memoarnya, ini adalah bekas rumah sakit yang belum selesai, sekarang menjadi gedung kantor murni. Saya ingat bagaimana di masa kecil saya pasukan khusus dilatih di sini, mereka ditampilkan di TV, dengan penuh semangat menyerbu sebuah bangunan beton, ditumbuhi segala sesuatu di sekitarnya. Dan sekarang, ternyata, saya dengan penuh semangat mengejutkan pagar mengkilap, menuruni tangga, dan mengagumi bentuk distorsi bangunan ini dalam pantulan kompleks perumahan terdekat. (Di dekatnya, di sepanjang jalur trem, dinding pemakaman besar tua terbuka. Dan di atasnya ada tulisan dalam cat hijau "Sementara Boris berkuasa" dan "Buruh Rusia." Tuhan tahu siapa dan kapan mereka dibuat, tetapi setelah beberapa dekade mereka masih membaca tetapi tetap sama sekali tidak terlihat. Saya belum melihat lagi dari warisan tahun 90-an sebuah monumen yang lebih kuno di kota.)

Di lantai atas kami itu kosong, seperti yang terjadi kosong dalam sebuah paket dengan soba yang dimulai: ada banyak semuanya di bawah dan ketat: beberapa penjahat dari geo-intelijen khusus, kantor 2gis, kemudian seoshniki biasa, dan di atas hampir tidak ada biji-bijian. Apakah Anda berpikir bahwa sesuatu harus tumbuh melalui lantai sesuatu di sini, tetapi selama 5 tahun hanya mesin cuci jendela yang melihat dari transendental, dan dari akuntan imanen dengan mata gila, yang mengetuk semua pintu di lantai untuk mencari seseorang , yang akan menjelaskan cara menandatangani pembayaran melalui plug-in gila untuk perbankan Internet karena pembaruan browser lainnya.

Source: https://habr.com/ru/post/id412629/


All Articles