Sebelum elemen <audio>
HTML5, Flash atau plugin lain diperlukan
untuk menghentikan keheningan web. Meskipun audio di web tidak lagi
memerlukan plugin, tag audio memiliki batasan yang signifikan untuk
menerapkan game canggih dan aplikasi interaktif.
Web Audio API adalah API JavaScript tingkat tinggi untuk memproses dan menyintetisasikan audio di aplikasi web. Tujuan API ini adalah untuk menyertakan kemampuan yang ditemukan di game engine audio modern dan beberapa tugas pencampuran, pemrosesan, dan pemfilteran yang ditemukan di aplikasi produksi audio desktop modern. Berikut adalah pengantar sederhana untuk menggunakan API yang canggih ini.
Memulai AudioContext
AudioContext digunakan untuk mengelola dan memutar semua suara. Untuk menghasilkan
suara menggunakan Web Audio API, buat satu atau beberapa sumber suara
dan hubungkan ke tujuan suara yang disediakan oleh instance
AudioContext
. Koneksi ini tidak harus langsung, dan dapat melalui
berbagai AudioNodes perantara yang berfungsi sebagai modul
pemrosesan untuk sinyal audio. Pemetaan ini dijelaskan secara lebih detail di spesifikasi Audio Web.
Satu instance AudioContext
dapat mendukung beberapa input suara
dan grafik audio yang kompleks, sehingga kita hanya memerlukan salah satu dari ini 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
webkitAudioContext
.
Banyak fungsi Web Audio API yang menarik seperti membuat
AudioNodes dan mendekode data file audio adalah metode AudioContext
.
Memuat suara
Web Audio API menggunakan AudioBuffer untuk suara dengan durasi pendek hingga sedang. Pendekatan dasarnya adalah menggunakan XMLHttpRequest untuk mengambil file suara.
API ini mendukung pemuatan data file audio dalam beberapa format, seperti WAV, MP3, AAC, OGG, dan lainnya. Dukungan browser untuk berbagai format audio bervariasi.
Cuplikan berikut menunjukkan pemuatan sampel 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 bersifat biner (bukan teks), jadi kita menetapkan responseType
permintaan ke 'arraybuffer'
. Untuk informasi selengkapnya tentang
ArrayBuffers
, lihat artikel tentang XHR2 ini.
Setelah data file audio (yang tidak didekode) diterima, data tersebut dapat disimpan
untuk dekode 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).
Saat 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
gonggongan dan pemuatan telah selesai. Kemudian, kita dapat memutar buffer 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 akurat untuk game dan aplikasi penting lainnya. Namun, agar
penjadwalan ini berfungsi dengan benar, pastikan buffering suara Anda
dimuat sebelumnya.
Mengabstraksi Web Audio API
Tentu saja, akan lebih baik untuk membuat sistem pemuatan yang lebih umum yang tidak di-hardcode untuk memuat suara tertentu ini. Ada banyak pendekatan untuk menangani banyak suara berdurasi pendek hingga sedang yang akan digunakan aplikasi atau game audio. Berikut adalah salah 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 ulang 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
Web Audio API memungkinkan developer menjadwalkan pemutaran dengan tepat. Untuk mendemonstrasikannya, mari kita siapkan trek ritme sederhana. Mungkin pola drumkit yang paling dikenal adalah sebagai berikut:
dengan hihat dimainkan setiap not delapan, dan kick dan snare dimainkan secara bergantian setiap kuartal, dalam waktu 4/4.
Misalkan kita telah memuat buffer kick
, snare
, dan hihat
, kode untuk melakukannya sangat 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 tanpa batas yang kita lihat di
partitur. Fungsi playSound
adalah metode yang memutar
buffer pada waktu yang ditentukan, sebagai 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 mungkin ingin Anda lakukan pada suara adalah mengubah volumenya. Dengan menggunakan Web Audio API, kita dapat merutekan 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;
Cross-fade antara dua suara
Sekarang, misalkan kita memiliki skenario yang sedikit lebih kompleks, yaitu kita memutar beberapa suara, tetapi ingin melakukan cross fade di antara suara tersebut. Ini adalah kasus umum dalam aplikasi seperti DJ, dengan 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
};
}
Crossfade daya yang sama
Pendekatan crossfade linear naif menunjukkan penurunan volume saat Anda menggeser di antara sampel.
Untuk mengatasi masalah ini, kita menggunakan kurva daya yang sama, dengan kurva penguatan yang sesuai bersifat non-linear, dan berpotongan pada amplitudo yang lebih tinggi. Hal ini meminimalkan penurunan volume di antara region audio, sehingga menyebabkan crossfade yang lebih merata di antara region yang mungkin sedikit berbeda levelnya.
Crossfade playlist
Aplikasi crossfader umum lainnya adalah untuk aplikasi pemutar musik.
Saat lagu berubah, kita ingin memudarkan lagu saat ini, dan memudarkan
lagu baru, untuk menghindari transisi yang tidak menyenangkan. Untuk melakukannya, jadwalkan
crossfade ke masa mendatang. Meskipun kita dapat menggunakan setTimeout
untuk melakukan
penjadwalan ini, hal ini tidak akurat. Dengan Web Audio API, kita
dapat menggunakan antarmuka AudioParam untuk menjadwalkan nilai mendatang untuk
parameter seperti nilai gain AudioGainNode
.
Dengan demikian, dengan playlist, kita dapat bertransisi antar-trek dengan menjadwalkan penurunan gain pada trek yang sedang diputar, dan peningkatan gain pada trek berikutnya, keduanya 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 kumpulan metode RampToValue
yang mudah untuk
berangsur-angsur mengubah nilai parameter, seperti
linearRampToValueAtTime
dan exponentialRampToValueAtTime
.
Meskipun fungsi pengaturan waktu transisi dapat dipilih dari fungsi linear
dan eksponensial bawaan (seperti di atas), Anda juga dapat menentukan kurva nilai
Anda sendiri melalui array nilai menggunakan fungsi setValueCurveAtTime
.
Menerapkan efek filter sederhana ke suara
Web Audio API memungkinkan Anda menyalurkan suara dari satu node audio ke node audio lainnya, sehingga membuat rantai pemroses yang berpotensi kompleks untuk menambahkan efek kompleks ke soundform Anda.
Salah satu cara untuk melakukannya adalah dengan menempatkan BiquadFilterNode di antara sumber dan tujuan suara Anda. Jenis node audio ini dapat melakukan berbagai filter tingkat rendah yang dapat digunakan untuk membuat equalizer grafis dan bahkan efek yang lebih kompleks, sebagian besar berkaitan dengan memilih bagian spektrum frekuensi suara yang akan ditekankan dan yang akan diredam.
Jenis filter yang didukung mencakup:
- Filter lewat rendah
- Filter high pass
- Filter band pass
- Filter rak rendah
- Filter rak tinggi
- Filter puncak
- Filter notch
- Filter semua kartu
Selain itu, semua filter menyertakan parameter untuk menentukan sejumlah gain, frekuensi penerapan filter, dan faktor kualitas. Filter low-pass mempertahankan rentang frekuensi yang lebih rendah, tetapi menghapus frekuensi tinggi. Titik pemisahan ditentukan oleh nilai frekuensi, dan faktor Q tidak memiliki satuan, serta menentukan bentuk grafik. Gain hanya memengaruhi filter tertentu, seperti filter low-shelf dan peaking, bukan filter low-pass ini.
Mari kita siapkan filter low-pass sederhana untuk hanya mengekstrak basis dari contoh suara:
// 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 logaritmik karena pendengaran manusia sendiri bekerja berdasarkan prinsip yang sama
(yaitu, A4 adalah 440 Hz, dan A5 adalah 880 Hz). Untuk mengetahui detail selengkapnya, lihat
fungsi FilterSample.changeFrequency
di link kode sumber di atas.
Terakhir, perhatikan bahwa kode contoh memungkinkan Anda menghubungkan dan memutuskan koneksi
filter, yang secara dinamis mengubah grafik AudioContext. Kita dapat memutuskan
hubungan AudioNodes dari grafik dengan memanggil node.disconnect(outputNumber)
.
Misalnya, untuk merutekan ulang grafik dari melalui filter, ke
koneksi langsung, kita dapat melakukan hal berikut:
// Disconnect the source and filter.
source.disconnect(0);
filter.disconnect(0);
// Connect the source directly.
source.connect(context.destination);
Mendengarkan lebih lanjut
Kita telah membahas dasar-dasar API, termasuk memuat dan memutar contoh audio. Kami telah membuat grafik audio dengan node dan filter gain, serta suara terjadwal dan penyesuaian parameter audio untuk mengaktifkan beberapa efek suara umum. Pada tahap ini, Anda siap untuk membuat beberapa aplikasi audio web yang keren.
Jika Anda mencari inspirasi, banyak developer telah membuat karya yang luar biasa menggunakan Web Audio API. Beberapa favorit saya meliputi:
- AudioJedit, alat penyambungan suara dalam browser yang menggunakan permalink SoundCloud.
- ToneCraft, sequencer suara tempat suara dibuat dengan menumpuk blok 3D.
- Plink, game pembuatan musik kolaboratif menggunakan Web Audio dan Web Socket.