Web Audio API: Mengapa Menulis Ketika Anda Bisa Membuat Kode?
Diterbitkan: 2022-03-11Draf pertama untuk API audio web muncul di W3C selama tahun 2011. Meskipun audio di halaman web telah didukung untuk waktu yang lama, cara yang tepat untuk menghasilkan audio dari browser web belum tersedia hingga baru-baru ini. Saya pribadi mengaitkan ini dengan Google Chrome, karena untuk kepentingan Google, browser mulai menjadi bagian terpenting dari sebuah komputer. Anda mungkin ingat, ranah browser web tidak mulai banyak berubah sampai Google Chrome muncul. Jika Anda menggunakan suara di halaman web saat ini, itu akan menjadi keputusan desain yang buruk. Tapi sejak ide percobaan web muncul, audio web mulai masuk akal lagi. Browser web saat ini adalah alat lain untuk ekspresi artistik, dan video dan audio di browser web memainkan peran penting di dalamnya.
Web Audio API bisa sangat sulit digunakan untuk beberapa tujuan, karena masih dalam pengembangan, tetapi sejumlah pustaka JavaScript sudah ada untuk mempermudah. Dalam hal ini saya akan menunjukkan kepada Anda bagaimana memulai dengan Web Audio API menggunakan perpustakaan yang disebut Tone.js. Dengan ini, Anda akan dapat memenuhi sebagian besar kebutuhan suara browser Anda dari hanya mempelajari dasar-dasarnya.
Halo API Audio Web
Mulai
Kami akan mulai tanpa menggunakan perpustakaan. Eksperimen pertama kami akan melibatkan pembuatan tiga gelombang sinus. Karena ini akan menjadi contoh sederhana, kita akan membuat hanya satu file bernama hello.html, file HTML kosong dengan sedikit markup.
<!DOCTYPE html> <html> <head> <meta charset="utf‐8"> <title> Hello web audio </title> </head> <body> </body> <script> </script> </html>
Inti dari Web Audio API adalah konteks audio. Konteks audio adalah objek yang akan berisi segala sesuatu yang berhubungan dengan audio web. Ini tidak dianggap sebagai praktik yang baik untuk memiliki lebih dari satu konteks audio dalam satu proyek. Kami akan mulai dengan membuat instance konteks audio mengikuti rekomendasi yang diberikan oleh dokumentasi API Audio Web Mozilla.
var audioCtx = new (window.AudioContext || window.webkitAudioContext);
Membuat Osilator
Dengan konteks audio yang dipakai, Anda sudah memiliki komponen audio: audioCtx.destination. Ini seperti pembicara Anda. Untuk membuat suara, Anda harus menghubungkannya ke audioCtx.destination. Sekarang untuk menghasilkan beberapa suara, mari buat osilator:
var sine = audioCtx.createOscillator();
Hebat, tapi tidak cukup. Itu juga perlu dimulai dan terhubung ke audioCtx.destination kami:
sine.start(); sine.connect(audioCtx.destination);
Dengan empat baris ini, Anda akan memiliki halaman web yang cukup mengganggu yang memainkan suara sinus, tetapi sekarang Anda mengerti bagaimana modul dapat terhubung satu sama lain. Dalam skrip berikut, akan ada tiga nada berbentuk sinus, terhubung ke output, masing-masing dengan nada yang berbeda. Kode ini sangat jelas:
//create the context for the web audio var audioCtx = new (window.AudioContext || window.webkitAudioContext)(); //create, tune, start and connect each oscillator sinea, sineb and sinec var sinea = audioCtx.createOscillator(); sinea.frequency.value = 440; sinea.type = "sine"; sinea.start(); sinea.connect(audioCtx.destination); var sineb = audioCtx.createOscillator(); sineb.frequency.value = 523.25; sineb.type = "sine"; sineb.start(); sineb.connect(audioCtx.destination); var sinec = audioCtx.createOscillator(); sinec.frequency.value = 698.46; sinec.type = "sine"; sinec.start(); sinec.connect(audioCtx.destination);
Osilator tidak terbatas pada gelombang sinus, tetapi juga dapat berbentuk segitiga, gigi gergaji, persegi dan bentuk khusus, sebagaimana dinyatakan dalam MDN.
Menambal Logika Audio Web
Selanjutnya, kami akan menambahkan modul gain ke orkestra komponen Audio Web kami. Modul ini memungkinkan kita untuk mengubah amplitudo suara kita. Ini mirip dengan tombol volume. Kami telah menggunakan fungsi connect untuk menghubungkan osilator ke output audio. Kita dapat menggunakan fungsi koneksi yang sama untuk menghubungkan komponen audio apa pun. Jika Anda menggunakan Firefox, dan Anda melihat konsol audio web, Anda akan melihat yang berikut:
Jika kita ingin mengubah volume, patch kita akan terlihat seperti:
Yang berarti bahwa osilator tidak lagi terhubung ke tujuan audio, melainkan ke modul Gain, dan modul gain terhubung ke tujuan. Adalah baik untuk selalu membayangkan bahwa Anda melakukan ini dengan pedal dan kabel gitar. Kode akan terlihat seperti ini:
var audioCtx = new (window.AudioContext || window.webkitAudioContext) // we create the gain module, named as volume, and connect it to our var volume = audioCtx.createGain(); volume.connect(audioCtx.destination); //these sines are the same, exept for the last connect statement. //Now they are connected to the volume gain module and not to the au var sinea = audioCtx.createOscillator(); sinea.frequency.value = 440; sinea.type = "sine"; sinea.start(); sinea.connect(volume); var sineb = audioCtx.createOscillator(); sineb.frequency.value = 523.25; sineb.type = "sine"; sineb.start(); sineb.connect(volume); var sinec = audioCtx.createOscillator(); sinec.frequency.value = 698.46; sinec.type = "sine"; sinec.start(); sinec.connect(volume); volume.gain.value=0.2;
Anda dapat menemukan solusinya di https://github.com/autotel/simple-webaudioapi/.
GainNode adalah unit efek paling dasar, tetapi ada juga penundaan, convolver, filter biquadratic, panner stereo, pembentuk gelombang, dan banyak lainnya. Anda dapat mengambil efek baru dari perpustakaan seperti Tone.js.
Menyimpan salah satu tambalan suara ini dalam objeknya sendiri akan memungkinkan Anda untuk menggunakannya kembali sesuai kebutuhan, dan membuat orkestrasi yang lebih kompleks dengan lebih sedikit kode. Ini bisa menjadi topik untuk posting masa depan.
Membuat Segalanya Lebih Mudah dengan Tone.js
Sekarang setelah kita melihat sekilas bagaimana modul Vanilla Web Audio bekerja, mari kita lihat kerangka kerja Audio Web yang mengagumkan: Tone.js. Dengan ini (dan NexusUI untuk komponen antarmuka pengguna), kita dapat dengan mudah membangun synth dan suara yang lebih menarik. Untuk mencobanya, mari kita membuat sampler dan menerapkan beberapa efek interaktif pengguna padanya, dan kemudian kita akan menambahkan beberapa kontrol sederhana untuk sampel ini.
Tone.js Sampler
Kita bisa mulai dengan membuat struktur proyek sederhana:
simpleSampler |-- js |-- nexusUI.js |-- Tone.js |-- noisecollector_hit4.wav |-- sampler.html
Pustaka JavaScript kami akan berada di direktori js . Untuk keperluan demo ini, kita dapat menggunakan file hit4.wav NoiseCollector yang dapat diunduh dari Freesound.org.

Tone.js menyediakan fungsionalitasnya melalui objek Player. Kemampuan dasar objek adalah memuat sampel, dan memainkannya baik dalam satu lingkaran atau satu kali. Langkah pertama kita di sini adalah membuat objek player di var "sampler", di dalam file sampler.html:
<!doctype html> <html> <head> <title> Sampler </title> <script type="text/javascript" src="js/nexusUI.js" ></script> <script type="text/javascript" src="js/Tone.js" ></script> <script> var sampler = new Tone.Player("noisecollector_hit4.wav", function() { console.log("samples loaded"); }); </script> </head> <body> </body> </html>
Perhatikan bahwa parameter pertama dari konstruktor pemutar adalah nama file WAV, dan yang kedua adalah fungsi panggilan balik. WAV bukan satu-satunya jenis file yang didukung, dan kompatibilitasnya lebih bergantung pada browser web daripada perpustakaan. Fungsi callback akan berjalan ketika pemain telah selesai memuat sampel ke dalam buffernya.
Kami juga harus menghubungkan sampler kami ke output. Cara Tone.js melakukan ini adalah:
sampler.toMaster();
… di mana sampler adalah objek Tone.Player, setelah baris 10. Fungsi toMaster adalah singkatan dari connect(Tone.Master).
Jika Anda membuka browser web dengan konsol pengembang terbuka, Anda akan melihat pesan "sampel dimuat", yang menunjukkan bahwa pemutar dibuat dengan benar. Pada titik ini Anda mungkin ingin mendengar sampelnya. Untuk melakukan itu, kita perlu menambahkan tombol ke halaman web, dan memprogramnya untuk memutar sampel setelah ditekan. Kami akan menggunakan tombol NexusUI di badan:
<canvas nx="button"></canvas>
Anda sekarang akan melihat tombol bulat dirender dalam dokumen. Untuk memprogramnya untuk memutar sampel kami, kami menambahkan pendengar NexusUI, yang terlihat seperti ini:
button1.on('*',function(data) { console.log("button pressed!"); })
Sesuatu yang luar biasa tentang NexusUI adalah ia menciptakan variabel global untuk setiap elemen NexusUI. Anda dapat mengatur NexusUI untuk tidak melakukan itu, dan sebagai gantinya memiliki variabel ini hanya di nx.widgets[] dengan menyetel nx.globalWidgets ke false. Di sini kita akan membuat hanya beberapa elemen, jadi kita akan tetap berpegang pada perilaku ini.
Sama seperti di jQuery, kita dapat menempatkan event .on ini, dan argumen pertama adalah nama event. Di sini kami hanya menetapkan fungsi untuk apa pun yang dilakukan pada tombol. Ini apa pun yang ditulis sebagai "*". Anda dapat mempelajari lebih lanjut tentang peristiwa untuk setiap elemen di NexusUI API. Untuk memutar sampel alih-alih mencatat pesan saat kita menekan tombol, kita harus menjalankan fungsi awal sampler kita.
nx.onload = function() { button1.on('*',function(data) { console.log("button pressed!"); sampler.start(); }); }
Perhatikan juga bahwa listener masuk ke dalam callback onload. Elemen NexusUI digambar di kanvas, dan Anda tidak dapat merujuknya hingga nx memanggil fungsi onload. Sama seperti yang akan Anda lakukan dengan elemen DOM di jQuery.
Acara ini dipicu pada mouse ke bawah dan pada rilis. Jika Anda ingin dipicu hanya pada pers, Anda harus mengevaluasi apakah event.press sama dengan satu.
Dengan ini, Anda harus memiliki tombol yang memutar sampel pada setiap pers. Jika Anda menyetel sampler.retrigger ke true, itu akan memungkinkan Anda untuk memutar sampel terlepas dari apakah itu diputar atau tidak. Jika tidak, Anda harus menunggu sampai sampel selesai untuk memicunya kembali.
Menerapkan Efek
Dengan Tone.js, kita dapat dengan mudah membuat penundaan:
var delay= new Tone.FeedbackDelay("16n",0.5).toMaster();
Argumen pertama adalah waktu tunda, yang dapat ditulis dalam notasi musik seperti yang ditunjukkan di sini. Yang kedua adalah wet level, artinya campuran antara suara asli dan suara yang berpengaruh padanya. Untuk penundaan Anda biasanya tidak menginginkan 100% basah, karena penundaan menarik sehubungan dengan suara aslinya, dan basah saja tidak terlalu menarik karena keduanya bersama-sama.
Langkah selanjutnya adalah mencabut sampler kami dari master dan menyambungkannya ke penundaan. Tweak baris tempat sampler terhubung ke master:
sampler.connect(delay);
Sekarang coba tombol lagi dan lihat perbedaannya.
Selanjutnya, kita akan menambahkan dua tombol ke badan dokumen kita:
<canvas nx="dial"></canvas> <canvas nx="dial"></canvas>
Dan kami menerapkan nilai dial ke efek penundaan menggunakan NexusUIlistener:
dial1.on('*',function(data) { delay.delayTime.value=data.value; }) dial2.on('*',function(data) { delay.feedback.value=data.value; })
Parameter yang dapat Anda sesuaikan pada setiap peristiwa dapat ditemukan di dokumentasi Tone.js. Untuk penundaan, itu di sini. Sekarang Anda siap untuk mencoba contoh dan mengubah parameter penundaan dengan dial NexusUI. Proses ini dapat dengan mudah dilakukan dengan setiap elemen NexusUI, tidak terbatas hanya pada efek. Misalnya, coba tambahkan dial lain, dan tambahkan pendengarnya sebagai berikut:
dial3.on('*',function(data) { sampler.playbackRate=data.value; })
Anda dapat menemukan file-file ini di github.com/autotel/simpleSampler
Kesimpulan
Ketika saya melalui API ini, saya mulai merasa kewalahan dengan semua kemungkinan dan ide yang mulai muncul di pikiran saya. Perbedaan besar antara implementasi audio ini dan implementasi audio digital tradisional bukanlah pada audio itu sendiri, tetapi dalam konteksnya. Tidak ada metode baru untuk membuat sintesis di sini. Sebaliknya inovasinya adalah bahwa pembuatan audio dan musik sekarang bertemu dengan teknologi web.
Saya pribadi terlibat dalam pembuatan musik elektronik, dan area ini selalu memiliki paradoks ambiguitas antara benar-benar menampilkan musik dan hanya menekan putar ke trek yang direkam. Jika Anda ingin benar-benar membuat musik elektronik langsung, Anda harus bisa membuat alat performatif Anda sendiri atau “robot pembuat musik” untuk improvisasi langsung. Tetapi jika kinerja musik elektronik hanya menjadi parameter penyesuaian dalam algoritme pembuatan musik yang telah disiapkan sebelumnya, maka penonton juga dapat terlibat dalam proses ini. Saya telah mengerjakan eksperimen kecil mengenai integrasi web dan audio untuk musik crowdsourced ini, dan mungkin segera kami akan menghadiri pesta di mana musik berasal dari penonton melalui smartphone mereka. Lagi pula, ini tidak jauh berbeda dengan ritmis jam yang mungkin kita nikmati di zaman gua.
Bacaan Lebih Lanjut di Blog Teknik Toptal:
- WebAssembly/Rust Tutorial: Pemrosesan Audio Pitch-sempurna
- Tutorial MIDI: Membuat Aplikasi Audio Berbasis Browser yang Dikendalikan oleh Perangkat Keras MIDI