Web Audio API के साथ शुरुआत करना

HTML5 <audio> एलिमेंट से पहले, वेब की आवाज़ बंद करने के लिए Flash या अन्य प्लगिन की ज़रूरत होती थी. वेब पर ऑडियो चलाने के लिए अब प्लगिन की ज़रूरत नहीं होती. हालांकि, ऑडियो टैग की वजह से, बेहतर गेम और इंटरैक्टिव ऐप्लिकेशन लागू करने में कुछ पाबंदियां लगती हैं.

Web Audio API, वेब ऐप्लिकेशन में ऑडियो को प्रोसेस और संश्लेषित करने के लिए एक उच्च-स्तरीय JavaScript API है. इस एपीआई का मकसद मॉडर्न गेम ऑडियो इंजन में मिलने वाली सुविधाओं के साथ-साथ, आधुनिक डेस्कटॉप ऑडियो प्रोडक्शन ऐप्लिकेशन में मिलने वाले कुछ टास्क को मिक्स, प्रोसेस, और फ़िल्टर करना है. यहां पर इस दमदार API को इस्तेमाल करने के बारे में आसान जानकारी दी गई है.

AudioContext का इस्तेमाल शुरू करना

AudioContext की मदद से, सभी साउंड को मैनेज किया जा सकता है और चलाया जा सकता है. Web Audio API का इस्तेमाल करके साउंड बनाने के लिए, एक या उससे ज़्यादा साउंड सोर्स बनाएं. साथ ही, उन्हें AudioContext इंस्टेंस से मिले साउंड डेस्टिनेशन से जोड़ें. यह कनेक्शन सीधे तौर पर होना ज़रूरी नहीं है. साथ ही, यह कई इंटरमीडिएट AudioNodes से गुज़र सकते हैं, जो ऑडियो सिग्नल के लिए प्रोसेसिंग मॉड्यूल की तरह काम करते हैं. इस रूटिंग के बारे में, वेब ऑडियो की खास जानकारी में ज़्यादा जानकारी दी गई है.

AudioContext के एक इंस्टेंस में, कई साउंड इनपुट और जटिल ऑडियो ग्राफ़ हो सकते हैं. इसलिए, हमें अपने बनाए हुए हर ऑडियो ऐप्लिकेशन के लिए इनमें से सिर्फ़ एक ग्राफ़ की ज़रूरत होगी.

यह स्निपेट एक 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');
    }
}

WebKit का इस्तेमाल करने वाले पुराने ब्राउज़र के लिए, webkit प्रीफ़िक्स इस्तेमाल करें, जैसा कि webkitAudioContext के साथ होता है.

Web Audio API के कई दिलचस्प फ़ंक्शन, जैसे कि AudioNodes बनाना और ऑडियो फ़ाइल का डेटा डिकोड करना, AudioContext के तरीके हैं.

साउंड लोड हो रहे हैं

Web Audio API, छोटी से मध्यम अवधि की आवाज़ों के लिए, AudioBuffer का इस्तेमाल करता है. सबसे सही तरीका है कि साउंड फ़ाइलें फ़ेच करने के लिए, XMLHttpRequest का इस्तेमाल किया जाए.

यह एपीआई, ऑडियो फ़ाइल का डेटा कई फ़ॉर्मैट में लोड करने की सुविधा देता है. जैसे, WAV, MP3, AAC, OGG, और अन्य. अलग-अलग ऑडियो फ़ॉर्मैट के लिए ब्राउज़र पर काम करने की सुविधा अलग-अलग होती है.

नीचे दिया गया स्निपेट, आवाज़ का नमूना लोड करने के बारे में बताता है:

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();
}

ऑडियो फ़ाइल का डेटा बाइनरी (टेक्स्ट नहीं) होता है. इसलिए, हमने अनुरोध के responseType को 'arraybuffer' पर सेट कर दिया है. ArrayBuffers के बारे में ज़्यादा जानकारी के लिए, XHR2 के बारे में यह लेख देखें.

ऑडियो फ़ाइल का (बिना कोड किया गया) डेटा मिलने के बाद, उसे डिकोड करने के लिए आस-पास रखा जा सकता है. इसके अलावा, AudioContext decodeAudioData() तरीके का इस्तेमाल करके, इसे तुरंत डिकोड किया जा सकता है. यह तरीका, request.response में सेव की गई ऑडियो फ़ाइल के ArrayBuffer डेटा को लेता है. साथ ही, इसे एसिंक्रोनस तरीके से डिकोड करता है. इससे मुख्य JavaScript एक्ज़ीक्यूशन थ्रेड नहीं रुकता.

decodeAudioData() पूरा हो जाने पर, यह एक कॉलबैक फ़ंक्शन को कॉल करता है, जो डीकोड किया गया पीसीएम ऑडियो डेटा AudioBuffer के तौर पर देता है.

आवाज़ चालू की जा रही है

सामान्य ऑडियो ग्राफ़
आसान ऑडियो ग्राफ़

एक या ज़्यादा AudioBuffers लोड होने के बाद, हम आवाज़ें चलाने के लिए तैयार हैं. मान लें कि हमने अभी-अभी एक AudioBuffer को, कुत्ते के भौंकने की आवाज़ के साथ लोड किया है और लोड होने की प्रोसेस पूरी हो गई है. फिर हम इस बफ़र को नीचे दिए गए कोड के साथ चला सकते हैं.

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
}

जब भी कोई व्यक्ति माउस से कोई बटन दबाएं या क्लिक करता है, तब हर बार यह playSound() फ़ंक्शन कॉल किया जा सकता है.

noteOn(time) फ़ंक्शन से गेम और समय के हिसाब से ज़रूरी दूसरे ऐप्लिकेशन के लिए सटीक साउंड प्लेबैक शेड्यूल करना आसान हो जाता है. हालाँकि, यह शेड्यूल सही से काम करे, इसके लिए पक्का करें कि आपके साउंड बफ़र पहले से लोड हों.

Web Audio API को एब्सट्रैक्ट करना

बेहतर होगा कि आप एक सामान्य लोडिंग सिस्टम बनाएं जिसे इस साउंड को लोड करने के लिए हार्ड कोड न किया गया हो. किसी ऑडियो ऐप्लिकेशन या गेम में कम से लेकर मध्यम लंबाई की कई तरह की आवाज़ों का इस्तेमाल करने के कई तरीके होते हैं. इन तरीकों में से एक बफ़रलोडर (वेब स्टैंडर्ड का हिस्सा नहीं) का इस्तेमाल करने का एक तरीका है.

BufferLoader क्लास को इस्तेमाल करने का तरीका नीचे दिया गया है. चलिए, दो AudioBuffers बनाते हैं और उनके लोड होने के बाद, उन्हें एक साथ फिर से चला देते हैं.

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);
}

समय से निपटना: लय के साथ आवाज़ें बजाना

Web Audio API से, डेवलपर को वीडियो चलाने का सटीक समय तय करने में मदद मिलती है. इसे दिखाने के लिए, आइए एक आसान रिदम ट्रैक सेट अप करते हैं. शायद सबसे ज़्यादा लोकप्रिय ड्रमकिट पैटर्न ये हैं:

सिंपल रॉक ड्रम पैटर्न
एक आसान रॉक ड्रम पैटर्न

इसमें हर आठवें नोट में हिहत को बजाया जाता है. किक और स्नेयर को हर तिमाही में, 4/4 समय में बारी-बारी से बजाया जाता है.

मान लें कि हमने kick, snare, और hihat बफ़र लोड किया है, इसलिए ऐसा करने का कोड आसान है:

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);
    }
}

यहां, शीट म्यूज़िक में दिखने वाले अनलिमिटेड लूप के बजाय, सिर्फ़ एक बार दोहराया जाता है. playSound फ़ंक्शन एक ऐसा तरीका है जो बताए गए समय पर बफ़र चलाता है. इसके बारे में नीचे बताया गया है:

function playSound(buffer, time) {
    var source = context.createBufferSource();
    source.buffer = buffer;
    source.connect(context.destination);
    source.noteOn(time);
}

आवाज़ का वॉल्यूम बदलना

किसी आवाज़ के लिए सबसे ज़रूरी चीज़ों में से एक है उसकी आवाज़ कम या ज़्यादा करना. Web Audio API का इस्तेमाल करके, हम वॉल्यूम में बदलाव करने के लिए, अपने सोर्स को AudioGainNode की मदद से उसके डेस्टिनेशन पर ले जा सकते हैं:

गेन नोड वाला ऑडियो ग्राफ़
गेन नोड के साथ ऑडियो ग्राफ़

कनेक्शन को सेटअप करने के लिए, यहां दिया गया तरीका अपनाएं:

// 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);

ग्राफ़ सेट अप होने के बाद, gainNode.gain.value में इस तरह से बदलाव करके, प्रोग्राम के हिसाब से वॉल्यूम में बदलाव किया जा सकता है:

// Reduce the volume.
gainNode.gain.value = 0.5;

दो आवाज़ों के बीच क्रॉस-फ़ेडिंग

अब, मान लीजिए कि हमारे पास एक जटिल स्थिति है, जहां हम कई साउंड चला रहे हैं लेकिन उनके बीच फ़ेड आउट करना चाहते हैं. ऐसा आम तौर पर डीजे जैसे ऐप्लिकेशन में होता है, जिसमें हमारे पास दो टर्नटेबल होती हैं. साथ ही, हम चाहते हैं कि दूसरे साउंड सोर्स से दूसरे में पैन किया जा सके.

ऐसा करने के लिए, इस ऑडियो ग्राफ़ का इस्तेमाल किया जा सकता है:

गेन नोड से कनेक्ट किए गए दो सोर्स वाला ऑडियो ग्राफ़
ऐसा ऑडियो ग्राफ़ जिसमें दो सोर्स, गेन नोड से कनेक्ट किए गए हों

इसे सेट अप करने के लिए, हम सिर्फ़ दो AudioGainNodes बनाते हैं और इस फ़ंक्शन का इस्तेमाल करके, हर सोर्स को नोड के ज़रिए कनेक्ट करते हैं:

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
    };
}

इक्वल पावर क्रॉसफ़ेडिंग

इस तरीके से, सैंपल के बीच पैन करते समय आवाज़ में गिरावट आती है.

लीनियर क्रॉसफ़ेड
लीनियर क्रॉसफ़ेड

इस समस्या को हल करने के लिए, हम एक बराबर पावर कर्व का इस्तेमाल करते हैं. इसमें मौजूदा गेन कर्व में नॉन-लीनियर होते हैं और एक-दूसरे को ज़्यादा डाइमेंशन पर काटते हैं. इससे ऑडियो क्षेत्रों के बीच वॉल्यूम में कमी आती है. इससे उन इलाकों के बीच क्रॉसफ़ेड हो जाता है जो लेवल में थोड़ा अलग हो सकते हैं.

एक बराबर पावर क्रॉसफ़ेड.
एक बराबर पावर क्रॉसफ़ेड

प्लेलिस्ट क्रॉसफ़ेडिंग

अन्य सामान्य क्रॉसफ़ेडर ऐप्लिकेशन, म्यूज़िक प्लेयर ऐप्लिकेशन के लिए है. जब कोई गाना बदलता है, तो हम मौजूदा ट्रैक को धुंधला करना चाहते हैं और नए ट्रैक को फ़ेड करना चाहते हैं, ताकि मुश्किल ट्रांज़िशन से बचा जा सके. ऐसा करने के लिए, आने वाले समय में क्रॉसफ़ेड शेड्यूल करें. हालांकि, ऐसा शेड्यूल करने के लिए हम setTimeout का इस्तेमाल कर सकते हैं, लेकिन यह सटीक नहीं है. Web Audio API के साथ, हम AudioParam इंटरफ़ेस का इस्तेमाल करके, पैरामीटर के लिए आने वाली वैल्यू शेड्यूल कर सकते हैं. जैसे, AudioGainNode की गेन वैल्यू.

इसलिए, मौजूदा ट्रैक के चलने से थोड़ा पहले, मौजूदा ट्रैक के चलने से थोड़ा पहले, मौजूदा ट्रैक के चलने से, अगले ट्रैक पर बढ़ोतरी को शेड्यूल करके, एक प्लेलिस्ट से एक से दूसरे ट्रैक पर ट्रांज़िशन किया जा सकता है.

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, RampToValue के ऐसे आसान सेट तरीके उपलब्ध कराता है जिनसे linearRampToValueAtTime और exponentialRampToValueAtTime जैसे किसी पैरामीटर की वैल्यू को धीरे-धीरे बदला जा सकता है.

ट्रांज़िशन टाइम फ़ंक्शन को पहले से मौजूद लीनियर और एक्सपोनेन्शियल फ़ंक्शन में से चुना जा सकता है (जैसा कि ऊपर बताया गया है), लेकिन setValueCurveAtTime फ़ंक्शन का इस्तेमाल करके, वैल्यू के कलेक्शन के ज़रिए अपना खुद का वैल्यू कर्व भी तय किया जा सकता है.

किसी आवाज़ पर आसान फ़िल्टर इफ़ेक्ट लागू करना

BiquadFilterNode वाला ऑडियो ग्राफ़
BiquadFilterNode के साथ ऑडियो ग्राफ़

Web Audio API से, आपको एक ऑडियो नोड से दूसरे में साउंड को कनेक्ट करने में मदद मिलती है. इससे आपके साउंडफ़ॉर्म में जटिल इफ़ेक्ट जोड़ने के लिए, प्रोसेसर की एक ऐसी चेन बन जाती है जो काफ़ी जटिल हो सकती है.

ऐसा करने का एक तरीका यह है कि आप BiquadFilterNode को साउंड सोर्स और डेस्टिनेशन के बीच रखें. इस तरह के ऑडियो नोड कई तरह के लो-ऑर्डर फ़िल्टर इस्तेमाल कर सकते हैं. इनका इस्तेमाल ग्राफ़िक इक्वलाइज़र बनाने और और भी जटिल इफ़ेक्ट बनाने के लिए किया जा सकता है. इनमें से ज़्यादातर यह चुनना होता है कि आवाज़ के फ़्रीक्वेंसी स्पेक्ट्रम के किन हिस्सों पर ज़ोर देना है और किसे कम करना है.

इस्तेमाल किए जा सकने वाले फ़िल्टर के ये टाइप हैं:

  • लो पास फ़िल्टर
  • हाई पास फ़िल्टर
  • बैंड पास फ़िल्टर
  • लो शेल्फ़ फ़िल्टर
  • हाई शेल्फ़ फ़िल्टर
  • पीकिंग फ़िल्टर
  • नॉच फ़िल्टर
  • पास से जुड़े सभी फ़िल्टर

सभी फ़िल्टर में कुछ शामिल होने वाले पैरामीटर, फ़िल्टर लागू करने की फ़्रीक्वेंसी, और क्वालिटी फ़ैक्टर के बारे में जानकारी शामिल होती है. लो-पास फ़िल्टर, कम फ़्रीक्वेंसी रेंज को बनाए रखता है, लेकिन ज़्यादा फ़्रीक्वेंसी को खारिज करता है. ब्रेक-ऑफ़ पॉइंट, फ़्रीक्वेंसी वैल्यू से तय होता है. Q फ़ैक्टर यूनिटलेस है और ग्राफ़ का आकार तय करता है. फ़ायदा सिर्फ़ कुछ फ़िल्टर पर असर डालता है, जैसे कि लो-शेल्फ़ और पीकिंग फ़िल्टर, न कि इस लो-पास फ़िल्टर पर.

सिर्फ़ साउंड के सैंपल से बेस एक्सट्रैक्ट करने के लिए, एक आसान लो-पास फ़िल्टर सेटअप करते हैं:

// 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);

आम तौर पर, लॉगारिद्मिक स्केल पर काम करने के लिए, फ़्रीक्वेंसी कंट्रोल में बदलाव करना ज़रूरी है, क्योंकि इंसान की सुनने की सुविधा इसी सिद्धांत पर काम करती है (यानी, A4 440 हर्ट्ज़ और A5 880 हर्ट्ज़) ज़्यादा जानकारी के लिए, ऊपर सोर्स कोड के लिंक में FilterSample.changeFrequency फ़ंक्शन देखें.

आखिर में, ध्यान दें कि सैंपल कोड की मदद से, फ़िल्टर को कनेक्ट और डिसकनेक्ट किया जा सकता है. इससे AudioContext ग्राफ़ को डाइनैमिक तरीके से बदला जा सकता है. हम node.disconnect(outputNumber) को कॉल करके, AudioNodes को ग्राफ़ से डिसकनेक्ट कर सकते हैं. उदाहरण के लिए, ग्राफ़ को फ़िल्टर से गुज़रने के बजाय सीधे कनेक्शन पर ले जाने के लिए, हम ये काम कर सकते हैं:

// Disconnect the source and filter.
source.disconnect(0);
filter.disconnect(0);
// Connect the source directly.
source.connect(context.destination);

आगे सुनें

हमने एपीआई के बारे में बुनियादी बातें बताई हैं. इसमें ऑडियो सैंपल लोड करना और चलाना शामिल है. हमने गेन नोड और फ़िल्टर के साथ ऑडियो ग्राफ़ बनाए हैं. साथ ही, कुछ समान साउंड इफ़ेक्ट को चालू करने के लिए, शेड्यूल की गई आवाज़ों और ऑडियो पैरामीटर में बदलाव किया है. अब आप कुछ अच्छे वेब ऑडियो ऐप्लिकेशन बनाने के लिए तैयार हैं!

अगर आपको प्रेरणा चाहिए, तो कई डेवलपर ने पहले ही Web Audio API का इस्तेमाल करके, बहुत अच्छा काम कर लिया है. ये मेरे पसंदीदा डिवाइस हैं:

  • AudioJedit, ब्राउज़र में मौजूद साउंड स्प्लिसिंग टूल है, जो SoundCloud के स्थायी लिंक का इस्तेमाल करता है.
  • ToneCraft, एक साउंड सीक्वेंसर, जिसमें 3D ब्लॉक को स्टैक करके साउंड जनरेट किए जाते हैं.
  • Plink, जो वेब ऑडियो और वेब सॉकेट का इस्तेमाल करके, संगीत बनाने वाला एक ऐसा गेम है जो साथ मिलकर संगीत बनाता है.