Memulai Web Audio API

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

Grafik audio sederhana
Grafik audio sederhana

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:

Pola drum batu sederhana
Pola drum batu sederhana

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:

Grafik audio dengan node penguatan
Grafik audio dengan node gap

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:

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

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.

Crossfade linear
Crossfade linear

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.

{i>Crossfade <i}kekuatan yang sama.
Crossfade daya yang sama

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

Grafik audio dengan BiquadFilterNode
Grafik audio dengan BiquadFilterNode

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.