Sebelum elemen <audio>
HTML5, Flash atau plugin lain diperlukan
untuk memecahkan keheningan web. Meskipun audio di web tidak lagi
memerlukan plugin, tag audio memberikan batasan yang signifikan untuk
mengimplementasikan game dan aplikasi interaktif yang canggih.
Web Audio API adalah JavaScript API tingkat tinggi untuk memproses dan menyintesis audio dalam aplikasi web. Tujuan API ini adalah untuk menyertakan kemampuan yang ditemukan di mesin audio game modern dan beberapa tugas pencampuran, pemrosesan, dan pemfilteran yang ditemukan dalam aplikasi produksi audio desktop modern. Berikut ini adalah pengantar sederhana untuk menggunakan API yang andal ini.
Memulai AudioContext
AudioContext digunakan untuk mengelola dan memutar semua suara. Untuk menghasilkan
suara menggunakan Web Audio API, buat satu atau beberapa sumber suara,
lalu hubungkan ke tujuan suara yang disediakan oleh instance
AudioContext
. Koneksi ini tidak harus langsung, dan dapat melalui
AudioNodes perantara berapa pun yang berfungsi sebagai modul pemrosesan
untuk sinyal audio. Perutean ini dijelaskan secara lebih
mendetail di spesifikasi Audio Web.
Satu instance AudioContext
dapat mendukung beberapa input suara
dan grafik audio yang kompleks, sehingga kita hanya memerlukan salah satunya untuk setiap
aplikasi audio yang kita buat.
Cuplikan berikut membuat AudioContext
:
var context;
window.addEventListener('load', init, false);
function init() {
try {
context = new AudioContext();
}
catch(e) {
alert('Web Audio API is not supported in this browser');
}
}
Untuk browser berbasis WebKit lama, gunakan awalan webkit
, seperti pada
webkitAudioContext
.
Banyak fungsi Web Audio API yang menarik seperti membuat
AudioNode dan mendekode data file audio adalah metode AudioContext
.
Memuat suara
Web Audio API menggunakan AudioBuffer untuk suara pendek hingga sedang. Pendekatan dasarnya adalah menggunakan XMLHttpRequest untuk mengambil file suara.
API ini mendukung pemuatan data file audio dalam berbagai format, seperti WAV, MP3, AAC, OGG, dan lainnya. Dukungan browser untuk berbagai format audio bervariasi.
Cuplikan berikut menunjukkan pemuatan contoh suara:
var dogBarkingBuffer = null;
var context = new AudioContext();
function loadDogSound(url) {
var request = new XMLHttpRequest();
request.open('GET', url, true);
request.responseType = 'arraybuffer';
// Decode asynchronously
request.onload = function() {
context.decodeAudioData(request.response, function(buffer) {
dogBarkingBuffer = buffer;
}, onError);
}
request.send();
}
Data file audio adalah biner (bukan teks), jadi kami menetapkan responseType
permintaan ke 'arraybuffer'
. Untuk informasi selengkapnya tentang
ArrayBuffers
, lihat artikel tentang XHR2 ini.
Setelah diterima, data file audio (yang tidak dienkode) dapat disimpan
untuk didekode nanti, atau dapat langsung didekode menggunakan
metode decodeAudioData()
AudioContext. Metode ini mengambil
ArrayBuffer
data file audio yang disimpan di request.response
dan
mendekodenya secara asinkron (tidak memblokir thread eksekusi
JavaScript utama).
Setelah selesai, decodeAudioData()
akan memanggil fungsi callback yang menyediakan data audio PCM yang didekode sebagai AudioBuffer
.
Memutar suara
Setelah satu atau beberapa AudioBuffers
dimuat, kita siap memutar suara. Anggaplah kita baru saja memuat AudioBuffer
dengan suara menggoyang dan pemuatan telah selesai. Kemudian kita bisa memutar {i>
buffer<i} ini dengan kode berikut.
var context = new AudioContext();
function playSound(buffer) {
var source = context.createBufferSource(); // creates a sound source
source.buffer = buffer; // tell the source which sound to play
source.connect(context.destination); // connect the source to the context's destination (the speakers)
source.noteOn(0); // play the source now
}
Fungsi playSound()
ini dapat dipanggil setiap kali seseorang menekan tombol atau
mengklik sesuatu dengan mouse.
Fungsi noteOn(time)
memudahkan penjadwalan pemutaran suara
yang tepat untuk game dan aplikasi lain yang membutuhkan waktu. Namun, agar
penjadwalan ini berfungsi dengan baik, pastikan buffer suara Anda
sudah dimuat sebelumnya.
Mengabstraksi Web Audio API
Tentu saja, akan lebih baik untuk membuat sistem pemuatan yang lebih umum yang tidak di-hard code untuk memuat suara khusus ini. Ada banyak pendekatan untuk menangani banyaknya suara pendek hingga sedang yang akan digunakan aplikasi audio atau game–berikut satu cara menggunakan BufferLoader (bukan bagian dari standar web).
Berikut adalah contoh cara menggunakan class BufferLoader
.
Mari kita buat dua AudioBuffers
; dan, segera setelah dimuat,
mari kita putar kembali secara bersamaan.
window.onload = init;
var context;
var bufferLoader;
function init() {
context = new AudioContext();
bufferLoader = new BufferLoader(
context,
[
'../sounds/hyper-reality/br-jam-loop.wav',
'../sounds/hyper-reality/laughter.wav',
],
finishedLoading
);
bufferLoader.load();
}
function finishedLoading(bufferList) {
// Create two sources and play them both together.
var source1 = context.createBufferSource();
var source2 = context.createBufferSource();
source1.buffer = bufferList[0];
source2.buffer = bufferList[1];
source1.connect(context.destination);
source2.connect(context.destination);
source1.noteOn(0);
source2.noteOn(0);
}
Menangani waktu: memutar suara dengan ritme
API Audio Web memungkinkan developer menjadwalkan pemutaran dengan tepat. Untuk mendemonstrasikan ini, mari kita siapkan trek irama sederhana. Mungkin pola drumkit yang paling banyak dikenal adalah sebagai berikut:
yang memainkan hihat setiap not kedelapan, serta kick and snare dimainkan bergantian setiap kuartal, dalam 4/4 waktu.
Dengan asumsi kita telah memuat buffer kick
, snare
, dan hihat
, kode untuk melakukannya sederhana:
for (var bar = 0; bar < 2; bar++) {
var time = startTime + bar * 8 * eighthNoteTime;
// Play the bass (kick) drum on beats 1, 5
playSound(kick, time);
playSound(kick, time + 4 * eighthNoteTime);
// Play the snare drum on beats 3, 7
playSound(snare, time + 2 * eighthNoteTime);
playSound(snare, time + 6 * eighthNoteTime);
// Play the hi-hat every eighth note.
for (var i = 0; i < 8; ++i) {
playSound(hihat, time + i * eighthNoteTime);
}
}
Di sini, kita hanya membuat satu pengulangan, bukan loop tak terbatas yang kita lihat di partitur musik. Fungsi playSound
adalah metode yang memutar
buffer pada waktu yang ditentukan, seperti berikut:
function playSound(buffer, time) {
var source = context.createBufferSource();
source.buffer = buffer;
source.connect(context.destination);
source.noteOn(time);
}
Mengubah volume suara
Salah satu operasi paling dasar yang perlu dilakukan pada suara adalah mengubah volumenya. Dengan Web Audio API, kita dapat mengarahkan sumber ke tujuannya melalui AudioGainNode untuk memanipulasi volume:
Penyiapan koneksi ini dapat dilakukan sebagai berikut:
// Create a gain node.
var gainNode = context.createGainNode();
// Connect the source to the gain node.
source.connect(gainNode);
// Connect the gain node to the destination.
gainNode.connect(context.destination);
Setelah grafik disiapkan, Anda dapat mengubah volume secara terprogram dengan memanipulasi gainNode.gain.value
sebagai berikut:
// Reduce the volume.
gainNode.gain.value = 0.5;
Transisi memudar antara dua suara
Sekarang, anggaplah kita memiliki skenario yang sedikit lebih kompleks, ketika kita memutar beberapa suara, tetapi ingin melakukan cross fade di antara keduanya. Ini merupakan kasus yang umum terjadi pada aplikasi yang mirip DJ, ketika kita memiliki dua turntable dan ingin dapat menggeser dari satu sumber suara ke sumber suara lainnya.
Hal ini dapat dilakukan dengan grafik audio berikut:
Untuk menyiapkannya, kita cukup membuat dua AudioGainNodes, dan menghubungkan setiap sumber melalui node, menggunakan fungsi seperti ini:
function createSource(buffer) {
var source = context.createBufferSource();
// Create a gain node.
var gainNode = context.createGainNode();
source.buffer = buffer;
// Turn on looping.
source.loop = true;
// Connect source to gain.
source.connect(gainNode);
// Connect gain to destination.
gainNode.connect(context.destination);
return {
source: source,
gainNode: gainNode
};
}
Crossfading daya yang sama
Pendekatan crossfade linear yang naif menunjukkan penurunan volume saat Anda menggeser di antara sampel.
Untuk mengatasi masalah ini, kami menggunakan kurva daya yang sama, dengan kurva penguatan yang sesuai adalah non-linear, dan berpotongan pada amplitudo yang lebih tinggi. Hal ini akan meminimalkan penurunan volume antar-region audio, sehingga menghasilkan crossfade yang lebih merata antar-region yang mungkin sedikit berbeda levelnya.
Crossfading playlist
Aplikasi crossfader umum lainnya adalah aplikasi pemutar musik.
Saat sebuah lagu berubah, kita ingin memudarkan trek saat ini, dan memudarkan
lagu baru, untuk menghindari transisi yang mengganggu. Untuk melakukannya, jadwalkan
crossfade ke masa mendatang. Meskipun kita dapat menggunakan setTimeout
untuk melakukan
penjadwalan ini, ini tidak tepat. Dengan Web Audio API, kita dapat menggunakan antarmuka AudioParam untuk menjadwalkan nilai yang akan datang untuk parameter seperti nilai perolehan AudioGainNode
.
Jadi, dengan playlist, kita dapat bertransisi antar-trek dengan menjadwalkan penurunan perolehan pada trek yang sedang diputar, dan peningkatan penguatan pada lagu berikutnya, sedikit sebelum trek saat ini selesai diputar:
function playHelper(bufferNow, bufferLater) {
var playNow = createSource(bufferNow);
var source = playNow.source;
var gainNode = playNow.gainNode;
var duration = bufferNow.duration;
var currTime = context.currentTime;
// Fade the playNow track in.
gainNode.gain.linearRampToValueAtTime(0, currTime);
gainNode.gain.linearRampToValueAtTime(1, currTime + ctx.FADE_TIME);
// Play the playNow track.
source.noteOn(0);
// At the end of the track, fade it out.
gainNode.gain.linearRampToValueAtTime(1, currTime + duration-ctx.FADE_TIME);
gainNode.gain.linearRampToValueAtTime(0, currTime + duration);
// Schedule a recursive track change with the tracks swapped.
var recurse = arguments.callee;
ctx.timer = setTimeout(function() {
recurse(bufferLater, bufferNow);
}, (duration - ctx.FADE_TIME) - 1000);
}
Web Audio API menyediakan serangkaian metode RampToValue
yang praktis untuk
mengubah nilai parameter secara bertahap, seperti
linearRampToValueAtTime
dan exponentialRampToValueAtTime
.
Meskipun fungsi pengaturan waktu transisi dapat dipilih dari linear dan eksponensial bawaan (seperti di atas), Anda juga dapat menentukan kurva nilai sendiri melalui array nilai menggunakan fungsi setValueCurveAtTime
.
Menerapkan efek filter sederhana ke suara
Dengan Web Audio API, Anda dapat menyalurkan suara dari satu node audio ke node audio lainnya, sehingga membuat rantai prosesor yang berpotensi kompleks untuk menambahkan efek kompleks ke soundform Anda.
Salah satu cara untuk melakukannya adalah dengan menempatkan BiquadFilterNode di antara sumber suara dan tujuan. Jenis node audio ini dapat melakukan berbagai filter tingkat rendah yang dapat digunakan untuk membuat equalizer grafis dan efek yang lebih kompleks, sebagian besar terkait dengan memilih bagian spektrum frekuensi suara yang akan ditekankan dan mana yang harus ditaklukkan.
Jenis filter yang didukung meliputi:
- Filter tingkat rendah
- Filter tingkat tinggi
- Filter tiket band
- Filter rak rendah
- Filter tingkat tinggi
- Filter puncak
- Filter notch
- Filter semua kartu
Semua filter tersebut menyertakan parameter untuk menentukan jumlah pencapaian, frekuensi penerapan filter, dan faktor kualitas. Filter low-pass mempertahankan rentang frekuensi yang lebih rendah, tetapi menghapus frekuensi tinggi. Titik jeda ditentukan oleh nilai frekuensi, dan faktor Q tidak memiliki satuan, serta menentukan bentuk grafik. Keuntungan hanya memengaruhi filter tertentu, seperti filter low-shelf dan peaking, bukan filter low-pass ini.
Mari kita siapkan filter low-pass sederhana untuk mengekstrak basis dari sampel suara saja:
// Create the filter
var filter = context.createBiquadFilter();
// Create the audio graph.
source.connect(filter);
filter.connect(context.destination);
// Create and specify parameters for the low-pass filter.
filter.type = 0; // Low-pass filter. See BiquadFilterNode docs
filter.frequency.value = 440; // Set cutoff to 440 HZ
// Playback the sound.
source.noteOn(0);
Secara umum, kontrol frekuensi perlu disesuaikan agar berfungsi pada
skala logaritma karena pendengaran manusia sendiri berfungsi dengan prinsip yang sama
(yaitu, A4 adalah 440 hz dan A5 adalah 880 hz). Untuk mengetahui detail selengkapnya, lihat
fungsi FilterSample.changeFrequency
pada link kode sumber di atas.
Terakhir, perhatikan bahwa kode contoh memungkinkan Anda menghubungkan dan memutuskan
filter, yang secara dinamis mengubah grafik AudioContext. Kita dapat memutuskan sambungan AudioNode dari grafik dengan memanggil node.disconnect(outputNumber)
.
Misalnya, untuk mengubah rute grafik agar tidak melewati filter ke koneksi langsung, kita dapat melakukan tindakan berikut:
// Disconnect the source and filter.
source.disconnect(0);
filter.disconnect(0);
// Connect the source directly.
source.connect(context.destination);
Mendengarkan lebih jauh
Kita telah membahas dasar-dasar API, termasuk memuat dan memutar contoh audio. Kami telah membuat grafik audio dengan node dan filter penguatan, serta penyesuaian parameter audio dan suara terjadwal untuk mengaktifkan beberapa efek suara yang umum. Pada tahap ini, Anda siap membangun beberapa aplikasi audio web yang keren.
Jika Anda mencari inspirasi, banyak developer telah menciptakan karya yang hebat menggunakan Web Audio API. Beberapa favorit saya antara lain:
- AudioJedit, alat penyambungan suara dalam browser yang menggunakan permalink SoundCloud.
- ToneCraft, sequencer suara yang menghasilkan suara dengan menumpuk blok 3D.
- Plink, game pembuatan musik kolaboratif menggunakan Audio Web dan Web Sockets.