Sebelum elemen <audio>
HTML5, Flash, atau plugin lain diperlukan
untuk memecah 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 JavaScript API tingkat tinggi untuk memproses dan menyintesis audio dalam aplikasi web. Tujuan API ini adalah untuk mencakup kemampuan yang ada di mesin audio game modern dan beberapa mencampur, memproses, dan memfilter tugas yang ditemukan di {i>desktop<i} modern aplikasi produksi audio. Selanjutnya adalah pengantar lancar tentang menggunakan API canggih ini.
Mulai menggunakan AudioContext
AudioContext berfungsi untuk mengelola dan memutar semua suara. Untuk memproduksi
suara menggunakan Web Audio API, membuat satu atau beberapa sumber suara
dan menghubungkannya ke tujuan suara yang disediakan oleh AudioContext
di instance Compute Engine. Koneksi ini tidak perlu terhubung
langsung, dan dapat melewati
sejumlah AudioNodes perantara yang berfungsi sebagai pemrosesan
untuk sinyal audio. Perutean ini dijelaskan secara lebih dalam
di spesifikasi Audio Web.
Satu instance AudioContext
dapat mendukung beberapa input suara
dan grafik audio yang kompleks. Oleh karena itu, kita hanya memerlukan salah satunya untuk
aplikasi audio yang kita buat.
Cuplikan berikut akan 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 versi lama, gunakan awalan webkit
, seperti pada
webkitAudioContext
.
Banyak fungsi Web Audio API yang menarik seperti membuat
AudioNodes dan decoding data file audio adalah metode AudioContext
.
Memuat suara
Web Audio API menggunakan AudioBuffer untuk video berdurasi singkat hingga sedang audio. 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 berupa biner (bukan teks), jadi kita setel responseType
permintaan kepada 'arraybuffer'
. Untuk mengetahui informasi selengkapnya tentang
ArrayBuffers
, lihat artikel tentang XHR2 ini.
Setelah data file audio (yang tidak didekode) diterima, data tersebut dapat disimpan
untuk melakukan dekode nanti, atau dapat langsung didekode menggunakan
Metode decodeAudioData()
AudioContext. Metode ini mengambil
ArrayBuffer
data file audio disimpan di request.response
dan
mendekodenya secara asinkron (tidak memblokir eksekusi JavaScript utama
).
Setelah selesai, decodeAudioData()
akan memanggil fungsi callback yang
memberikan data audio PCM yang didekode sebagai AudioBuffer
.
Memutar suara
Setelah satu atau beberapa AudioBuffers
dimuat, kita siap untuk memainkan
audio. Anggaplah kita baru saja memuat AudioBuffer
dengan suara
suara menggonggong dan
pemuatan telah selesai. Lalu, kita bisa memainkan
{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
mengeklik sesuatu dengan {i>mouse<i}.
Fungsi noteOn(time)
memudahkan penjadwalan suara yang presisi
untuk game dan aplikasi penting lainnya. Namun, untuk mendapatkan
penjadwalan ini bekerja dengan baik, pastikan buffer suara Anda
dipramuat.
Mengabstraksi Web Audio API
Tentu saja, akan lebih baik untuk membuat sistem pemuatan yang lebih umum yang tidak dikodekan langsung untuk memuat suara spesifik ini. Ada banyak pendekatan untuk menangani banyak suara berdurasi pendek hingga sedang aplikasi audio atau game akan digunakan–berikut ini 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 kembali
pada saat yang sama.
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. Kepada tunjukkan ini, mari kita siapkan trek ritme sederhana. Mungkin pola drumkit yang paling dikenal adalah sebagai berikut:
di mana hihat dimainkan pada setiap not kedelapan, dan tendangan dan snare dimainkan bergantian setiap kuartal, dalam 4/4 waktu.
Misalkan kita telah memuat buffer kick
, snare
dan hihat
,
kode program untuk melakukannya
cukup mudah:
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 musik. Fungsi playSound
adalah metode yang memutar
buffer pada waktu tertentu, 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 mungkin ingin Anda lakukan terhadap suara adalah mengubah volumenya. Dengan menggunakan Web Audio API, kita dapat merutekan sumber kita 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 dengan memanipulasi gainNode.gain.value
sebagai berikut:
// Reduce the volume.
gainNode.gain.value = 0.5;
Fase silang antara dua suara
Sekarang, anggaplah kita memiliki skenario yang sedikit lebih kompleks, di mana kita memutar beberapa suara tetapi ingin memudar di antara suara tersebut. Ini adalah umumnya dalam aplikasi mirip DJ, di mana kita memiliki dua {i>turntable<i} dan ingin dapat menggeser dari satu sumber suara ke sumber suara lainnya.
Hal ini dapat dilakukan dengan grafik audio berikut:
Untuk menyiapkannya, cukup buat dua AudioGainNodes, lalu hubungkan setiap sumber melalui node, menggunakan sesuatu seperti fungsi 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, di mana kurva keuntungan yang sesuai bersifat non-linear, dan berpotongan dengan amplitudo. Tindakan ini akan meminimalkan penurunan volume antararea audio, sehingga dalam bentuk crossfade yang lebih merata antar-area yang mungkin sedikit tingkatan yang berbeda.
Crossfading playlist
Aplikasi {i>crossfader<i} umum lainnya adalah
untuk aplikasi pemutar musik.
Saat sebuah lagu berubah, kita ingin memudarkan lagu yang sedang diputar, dan memperjelas
yang baru, untuk menghindari
transisi yang mengagetkan. Untuk melakukannya, jadwalkan
{i>crossfade<i} ke masa depan. Meskipun kita dapat menggunakan setTimeout
untuk melakukannya
penjadwalan, ini tidak tepat. Dengan Web Audio API, kita
dapat menggunakan antarmuka AudioParam untuk menjadwalkan nilai mendatang untuk
seperti nilai perolehan AudioGainNode
.
Oleh karena itu, dengan menyediakan playlist, kita dapat beralih antar-lagu dengan menjadwalkan adanya penurunan pada lagu yang sedang diputar, dan peningkatan yang berikutnya, keduanya sedikit sebelum lagu yang diputar selesai:
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 sekumpulan metode RampToValue
yang mudah untuk
secara bertahap mengubah nilai parameter, seperti
linearRampToValueAtTime
dan exponentialRampToValueAtTime
.
Sedangkan fungsi pengaturan waktu transisi
dapat dipilih dari
dan eksponensial (seperti di atas), Anda juga dapat menentukan nilai sendiri
kurva 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 lainnya, membuat rantai prosesor yang berpotensi kompleks untuk menambahkan efek pada bentuk suara Anda.
Salah satu cara untuk melakukannya adalah dengan menempatkan BiquadFilterNode di antara suara Anda sumber dan tujuannya. Jenis node audio ini dapat melakukan berbagai filter urutan rendah yang dapat digunakan untuk membuat equalizer grafis dan bahkan efek yang lebih kompleks, terutama terkait dengan pemilihan bagian mana dari spektrum frekuensi suara yang harus ditekankan dan mana yang harus ditundukkan.
Jenis filter yang didukung meliputi:
- Filter low pass
- Filter high pass
- Filter band pass
- Filter rak bawah
- Filter rak tinggi
- Filter puncak
- Filter lekukan
- Filter semua kartu
Dan semua filter menyertakan parameter untuk menentukan sejumlah gain, frekuensi untuk menerapkan filter, dan faktor kualitas. Filter low-pass mempertahankan rentang frekuensi yang lebih rendah, tetapi menghapus frekuensi yang tinggi dengan frekuensi yang sama. Titik jeda ditentukan oleh nilai frekuensi, dan faktor Q tidak memiliki satuan, serta menentukan bentuk grafik. Keuntungan hanya mempengaruhi filter tertentu, seperti rak bawah dan filter puncak, dan bukan filter low-pass ini.
Mari kita atur 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
diatur agar berfungsi pada
skala logaritmik karena pendengaran manusia itu sendiri bekerja dengan prinsip yang sama
(yaitu, A4 adalah 440hz, dan A5 adalah 880hz). Untuk mengetahui detail selengkapnya, lihat
Fungsi FilterSample.changeFrequency
dalam link kode sumber di atas.
Terakhir, perhatikan bahwa kode contoh memungkinkan Anda menghubungkan dan memutuskan
filter, mengubah grafik AudioContext secara dinamis. Kita bisa memutuskan
AudioNodes dari grafik dengan memanggil node.disconnect(outputNumber)
.
Misalnya, untuk merutekan ulang grafik dari proses 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 audio sampel. Kita telah membuat grafik audio dengan node dan filter perolehan, serta penyesuaian parameter audio dan suara terjadwal untuk mengaktifkan beberapa suara umum yang dihasilkan. Pada tahap ini, Anda siap untuk pergi dan membangun beberapa web manis aplikasi audio!
Jika Anda sedang mencari inspirasi, banyak developer yang sudah membuat kerja bagus dengan menggunakan Web Audio API. Beberapa favorit saya termasuk:
- AudioJedit, alat penyambungan suara dalam browser yang menggunakan Link permanen SoundCloud.
- ToneCraft, sequencer suara yang menghasilkan suara menyusun blok 3D.
- Plink, game pembuatan musik kolaboratif menggunakan Audio Web dan Web Soket.