Memulai Web Audio API

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

Grafik audio sederhana
Grafik audio sederhana

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:

Pola drum batu sederhana
Pola drum rock sederhana

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:

Grafik audio dengan node perolehan
Grafik audio dengan node perolehan

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:

Grafik audio dengan dua sumber yang terhubung melalui node perolehan
Grafik audio dengan dua sumber yang terhubung melalui node perolehan

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.

Crossfade linear
Crossfade linear

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.

Crossfade dengan daya yang sama.
Crossfade dengan daya yang sama

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

Grafik audio dengan BiquadFilterNode
Grafik audio dengan BiquadFilterNode

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.