केस-स्टडी - Chrome के साथ JAM

हमने ऑडियो को बेहतर बनाने के लिए क्या किया

परिचय

Chrome के साथ JAM, Google का बनाया गया एक वेब-आधारित म्यूज़िकल प्रोजेक्ट है. 'Chrome के साथ JAM करें' सुविधा की मदद से, दुनिया भर के लोग ब्राउज़र में रीयल टाइम में एक साथ संगीत बना सकते हैं. DinahMoe के लिए, इस प्रोजेक्ट का हिस्सा बनना एक खुशी की बात थी. हमारी भूमिका, ऐप्लिकेशन के लिए संगीत बनाना और संगीत कॉम्पोनेंट को डिज़ाइन और डेवलप करना थी. इस सुविधा को बनाने के लिए, तीन मुख्य चीज़ों पर काम किया गया: "म्यूज़िक वर्कस्टेशन", जिसमें मिडी प्लेलबैक, सॉफ़्टवेयर सैंपलर, ऑडियो इफ़ेक्ट, रूटिंग, और मिक्सिंग शामिल हैं. साथ ही, रीयल-टाइम में संगीत को इंटरैक्टिव तरीके से कंट्रोल करने के लिए म्यूज़िक लॉजिक इंजन और सिंक्रोनाइसेशन कॉम्पोनेंट, जो यह पक्का करता है कि सेशन में शामिल सभी खिलाड़ियों को संगीत एक ही समय पर सुनाई दे. एक साथ संगीत बजाने के लिए, यह ज़रूरी है.

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

पसंद के मुताबिक ऑडियो इफ़ेक्ट लिखना

Web Audio API के स्पेसिफ़िकेशन में कई काम के इफ़ेक्ट शामिल हैं. हालांकि, हमें Chrome पर JAM में अपने इंस्ट्रूमेंट के लिए ज़्यादा बेहतर इफ़ेक्ट चाहिए थे. उदाहरण के लिए, वेब ऑडियो में नेटिव देरी नोड होता है, लेकिन देरी के कई टाइप होते हैं - स्टीरियो देरी, पिंग पोंग देरी, स्लैपबैक देरी वगैरह. अच्छी बात यह है कि वेब ऑडियो में, नेटिव इफ़ेक्ट नोड और थोड़ी कल्पना का इस्तेमाल करके, ये सभी इफ़ेक्ट बनाए जा सकते हैं.

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

var MyCustomNode = function(){
    this.input = audioContext.createGain();
    var output = audioContext.createGain();

    this.connect = function(target){
       output.connect(target);
    };
};

इस पैटर्न की मदद से, हम नेटिव नोड के बहुत करीब हैं. आइए, देखें कि इसका इस्तेमाल कैसे किया जाएगा.

//create a couple of native nodes and our custom node
var gain = audioContext.createGain(),
    customNode = new MyCustomNode(),
    anotherGain = audioContext.createGain();

//connect our custom node to the native nodes and send to the output
gain.connect(customNode.input);
customNode.connect(anotherGain);
anotherGain.connect(audioContext.destination);
कस्टम नोड को रूट करना

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

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

ज़रूरत पड़ने पर, पलटवार करें

स्लैपबैक देरी, जिसे कभी-कभी स्लैपबैक इको भी कहा जाता है, एक क्लासिक इफ़ेक्ट है. इसका इस्तेमाल कई तरह के इंस्ट्रूमेंट पर किया जाता है. जैसे, 50 के दशक के स्टाइल वाले वॉकल से लेकर सर्फ़ गिटार तक. यह इफ़ेक्ट, आने वाली आवाज़ को लेता है और उसकी कॉपी को करीब 75 से 250 मिलीसेकंड की देरी के साथ चलाता है. इससे ऐसा लगता है कि आवाज़ को पीछे धकेला जा रहा है. इसलिए, इसे स्लैप बैक कहा जाता है. हम इस तरह इफ़ेक्ट बना सकते हैं:

var SlapbackDelayNode = function(){
    //create the nodes we'll use
    this.input = audioContext.createGain();
    var output = audioContext.createGain(),
        delay = audioContext.createDelay(),
        feedback = audioContext.createGain(),
        wetLevel = audioContext.createGain();

    //set some decent values
    delay.delayTime.value = 0.15; //150 ms delay
    feedback.gain.value = 0.25;
    wetLevel.gain.value = 0.25;

    //set up the routing
    this.input.connect(delay);
    this.input.connect(output);
    delay.connect(feedback);
    delay.connect(wetLevel);
    feedback.connect(delay);
    wetLevel.connect(output);

    this.connect = function(target){
       output.connect(target);
    };
};
स्लैपबैक नोड का इंटरनल रूटिंग

आप में से कुछ लोगों को शायद पहले से ही पता हो कि इस देरी का इस्तेमाल, देरी के ज़्यादा समय के साथ भी किया जा सकता है. इससे, यह फ़ीडबैक के साथ एक सामान्य मोनो देरी बन जाती है. यहां इस देरी का इस्तेमाल करके, आपको यह सुनने के लिए एक उदाहरण दिया गया है कि यह कैसा लगता है.

ऑडियो रूट करना

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

AudioBus को रूट करना

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

var AudioBus = function(){
    this.input = audioContext.createGain();
    var output = audioContext.createGain();

    //create effect nodes (Convolver and Equalizer are other custom effects from the library presented at the end of the article)
    var delay = new SlapbackDelayNode(),
        convolver = new tuna.Convolver(),
        equalizer = new tuna.Equalizer();

    //route 'em
    //equalizer -> delay -> convolver
    this.input.connect(equalizer);
    equalizer.connect(delay.input);
    delay.connect(convolver);
    convolver.connect(output);

    this.connect = function(target){
       output.connect(target);
    };
};

इसका इस्तेमाल इस तरह किया जाएगा:

//create some native oscillators and our custom audio bus
var bus = new AudioBus(),
    instrument1 = audioContext.createOscillator(),
    instrument2 = audioContext.createOscillator(),
    instrument3 = audioContext.createOscillator();

//connect our instruments to the same bus
instrument1.connect(bus.input);
instrument2.connect(bus.input);
instrument3.connect(bus.input);
bus.connect(audioContext.destination);

और voila, हमने देरी, इक्वलाइज़ेशन, और रिवरब (परफ़ॉर्मेंस के हिसाब से यह एक महंगा इफ़ेक्ट है) को लागत के आधे हिस्से पर लागू किया है, जैसे कि हमने हर अलग-अलग इंस्ट्रूमेंट पर इफ़ेक्ट लागू किए हों. अगर हमें बस में कुछ और स्पाइस जोड़ना है, तो हम दो नए गेन नोड - preGain और postGain - जोड़ सकते हैं. इनकी मदद से, हम बस में मौजूद साउंड को दो अलग-अलग तरीकों से बंद या फ़ेड कर सकते हैं. preGain को इफ़ेक्ट से पहले और postGain को चेन के आखिर में रखा जाता है. अगर हम प्री-गेन को फ़ेड करते हैं, तो गेन के सबसे नीचे पहुंचने के बाद भी इफ़ेक्ट गूंजते रहेंगे. हालांकि, अगर हम पोस्ट-गेन को फ़ेड करते हैं, तो सभी साउंड एक ही समय पर म्यूट हो जाएंगे.

यहां से कहां जाना है?

मैंने यहां बताए गए तरीकों को और बेहतर बनाया जा सकता है और ऐसा करना चाहिए. कस्टम नोड के इनपुट और आउटपुट, और कनेक्ट करने के तरीकों जैसी चीज़ों को प्रोटोटाइप पर आधारित इनहेरिटेंस का इस्तेमाल करके लागू किया जा सकता है/चाहिए. बसों को इफ़ेक्ट की सूची पास करके, डाइनैमिक तरीके से इफ़ेक्ट बनाने चाहिए.

Chrome पर JAM की रिलीज़ का जश्न मनाने के लिए, हमने इफ़ेक्ट के फ़्रेमवर्क को ओपन सोर्स बनाने का फ़ैसला लिया है. अगर आपको यह जानकारी पसंद आई है, तो कृपया इसे देखें और इसमें योगदान दें. कस्टम वेब ऑडियो इकाइयों के लिए फ़ॉर्मैट को स्टैंडर्ड बनाने के बारे में यहां चर्चा की जा रही है. शामिल हों!