ऑडियो वर्कलेट के पिछले लेख में, बुनियादी बातों और इसके इस्तेमाल के बारे में जानकारी दी गई है. Chrome 66 में लॉन्च होने के बाद से, इसे असल ऐप्लिकेशन में इस्तेमाल करने के कई तरह के उदाहरणों के लिए अनुरोध किए गए हैं. ऑडियो वर्कलेट से WebAudio की पूरी क्षमता का इस्तेमाल किया जा सकता है. हालांकि, इसका फ़ायदा लेना मुश्किल हो सकता है, क्योंकि इसके लिए कई JS एपीआई से रैप की गई एक साथ चलने वाली प्रोग्रामिंग को समझना ज़रूरी होता है. यहां तक कि जिन डेवलपर को WebAudio की जानकारी है उनके लिए भी, अन्य एपीआई (जैसे, WebAssembly) के साथ ऑडियो वर्कलेट को इंटिग्रेट करना मुश्किल हो सकता है.
इस लेख से लोगों को यह पता चलेगा कि असल सेटिंग में ऑडियो वर्कलेट का इस्तेमाल कैसे किया जाता है. साथ ही, इससे उन्हें काम की चीज़ों पर काम करने की सलाह भी मिलती है. कोड के उदाहरण और लाइव डेमो भी देखना न भूलें!
रीकैप: ऑडियो वर्कलेट
आगे बढ़ने से पहले, आइए ऑडियो वर्कलेट सिस्टम से जुड़े उन शब्दों और तथ्यों पर एक बार फिर से एक नज़र डालते हैं, जिनके बारे में पहले इस पोस्ट में बताया गया था.
- BaseAudioContext: वेब ऑडियो एपीआई का मुख्य ऑब्जेक्ट.
- ऑडियो वर्कलेट: ऑडियो वर्कलेट कार्रवाई के लिए, एक खास स्क्रिप्ट फ़ाइल लोडर. BaseAudioContext से है. BaseAudioContext में एक ऑडियो वर्कलेट हो सकता है. लोड की गई स्क्रिप्ट फ़ाइल का आकलन AudioWorkletGlobalScope में किया जाता है. इसका इस्तेमाल AudioWorkletProcessor इंस्टेंस बनाने के लिए किया जाता है.
- AudioWorkletGlobalScope : ऑडियो वर्कलेट कार्रवाई के लिए, एक खास JS ग्लोबल स्कोप. WebAudio के लिए, तय किए गए रेंडरिंग थ्रेड पर चलता है. BaseAudioContext में एक AudioWorkletGlobalScope हो सकता है.
- AudioWorkletNode : ऑडियो वर्कलेट से जुड़ी कार्रवाई के लिए डिज़ाइन किया गया AudioNode. BaseAudioContext से, इंस्टैंशिएट किया गया. BaseAudioContext में, उसी तरह कई AudioWorkletNodes हो सकते हैं जैसे मूल AudioNodes को.
- AudioWorkletProcessor : AudioWorkletNode का मिलता-जुलता हिस्सा. ऑडियो स्ट्रीम को उपयोगकर्ता के दिए गए कोड से प्रोसेस करने वाले AudioWorkletNode की वजह से हैं. जब एक AudioWorkletNode बनाया जाता है, तब यह AudioWorkletGlobalScope में इंस्टैंशिएट होता है. AudioWorkletNode से मेल खाने वाला एक AudioWorkletProcessor हो सकता है.
डिज़ाइन पैटर्न
WebAssembly के साथ ऑडियो वर्कलेट का इस्तेमाल करना
WebAssembly, AudioWorkletProcessor के लिए एक बढ़िया साथी है. इन दो सुविधाओं के मिलने-जुलने से वेब पर ऑडियो प्रोसेसिंग के कई फ़ायदे मिलते हैं, लेकिन इसके दो सबसे बड़े फ़ायदे हैं: a) मौजूदा C/C++ ऑडियो प्रोसेसिंग कोड को WebAudio नेटवर्क में शामिल करना और b) ऑडियो प्रोसेसिंग कोड में JS JIT कंपाइलेशन और ट्रैश कलेक्शन के ऊपर लगने वाले खर्च से बचना.
ऑडियो प्रोसेसिंग कोड और लाइब्रेरी में पहले से निवेश कर रहे डेवलपर के लिए, कोड और लाइब्रेरी भी अहम है. हालांकि, एपीआई का इस्तेमाल करने वाले करीब-करीब सभी उपयोगकर्ताओं के लिए, यह प्रोसेस ज़रूरी है. WebAudio की दुनिया में, स्टेबल ऑडियो स्ट्रीम के लिए टाइमिंग बजट बहुत मुश्किल है: 44.1 किलोहर्ट्ज़ के सैंपल रेट पर यह सिर्फ़ 3 मि॰से॰ है. ऑडियो प्रोसेसिंग कोड में थोड़ी सी भी गड़बड़ी होने पर भी समस्या हो सकती है. तेज़ी से प्रोसेस करने के लिए, डेवलपर को कोड को ऑप्टिमाइज़ करना होगा. साथ ही, JS गारबेज को भी कम से कम जनरेट करना होगा. WebAssembly का इस्तेमाल करना एक ऐसा समाधान है जिससे दोनों समस्याओं को एक साथ हल किया जा सकता है: यह ज़्यादा तेज़ है और कोड से कोई कचरा भी नहीं पैदा करता है.
अगले सेक्शन में बताया गया है कि ऑडियो वर्कलेट के साथ WebAssembly का इस्तेमाल कैसे किया जा सकता है. साथ ही, उसके साथ दिए गए कोड का उदाहरण यहां दिया गया है. Emscripten और WebAssembly (खास तौर पर, Emscripten ग्लू कोड) इस्तेमाल करने के तरीके से जुड़े बेसिक ट्यूटोरियल के लिए, कृपया यह लेख पढ़ें.
सेटअप करना
यह सब सुनने में ठीक लगता है, लेकिन हमें चीज़ों को ठीक से सेट अप करने के लिए थोड़ी संरचना की ज़रूरत है. डिज़ाइन से जुड़ा पहला सवाल यह है कि WebAssembly मॉड्यूल को कैसे और कहां इंस्टैंशिएट करना है. Emscripten का ग्लू कोड फ़ेच करने के बाद, मॉड्यूल इंस्टैंशिएट करने के लिए दो पाथ होते हैं:
audioContext.audioWorklet.addModule()
के ज़रिए AudioWorkletGlobalScope में ग्लू कोड लोड करके WebAssembly मॉड्यूल को इंस्टैंशिएट करें.- मुख्य स्कोप में WebAssembly मॉड्यूल इंस्टैंशिएट करें. इसके बाद, AudioWorkletNode के कंस्ट्रक्टर विकल्पों की मदद से, मॉड्यूल को ट्रांसफ़र करें.
यह फ़ैसला काफ़ी हद तक आपके डिज़ाइन और प्राथमिकता पर निर्भर करता है. हालांकि, आइडिया यह है कि WebAssembly मॉड्यूल, AudioWorkletGlobalScope में एक WebAssembly इंस्टेंस जनरेट कर सकता है. यह सुविधा, AudioWorkletProcessor इंस्टेंस में ऑडियो प्रोसेसिंग कर्नेल बन जाती है.
पैटर्न A के सही से काम करने के लिए, Emscripten को कुछ विकल्पों की ज़रूरत है ताकि हमारे कॉन्फ़िगरेशन के लिए सही WebAssembly ग्लू कोड जनरेट किया जा सके:
-s BINARYEN_ASYNC_COMPILATION=0 -s SINGLE_FILE=1 --post-js mycode.js
ये विकल्प यह पक्का करते हैं कि AudioWorkletGlobalScope में WebAssembly मॉड्यूल के सिंक्रोनस कंपाइलेशन को
भी शामिल किया जाए. यह mycode.js
में AudioWorkletProcessor की क्लास परिभाषा को भी जोड़ता है, ताकि मॉड्यूल शुरू होने के बाद इसे लोड किया जा सके.
सिंक्रोनस कंपाइलेशन का इस्तेमाल करने की मुख्य वजह यह है कि audioWorklet.addModule()
का प्रॉमिस
रिज़ॉल्यूशन, AudioWorkletGlobalScope में किए गए वादों के समाधान तक इंतज़ार नहीं करता. आम तौर पर, मुख्य थ्रेड में सिंक्रोनस लोडिंग या कंपाइलेशन का सुझाव नहीं दिया जाता, क्योंकि इससे एक ही थ्रेड में दूसरे टास्क ब्लॉक हो जाते हैं. हालांकि, यहां हम नियम को बायपास कर सकते हैं, क्योंकि कंपाइलेशन AudioWorkletGlobalScope पर होता है. यह मुख्य थ्रेड से अलग होता है. (ज़्यादा जानकारी के लिए
यह
देखें.)
अगर एसिंक्रोनस हेवी-लिफ़्टिंग ज़रूरी है, तो पैटर्न B काम का हो सकता है. यह सर्वर से ग्लू कोड फ़ेच करने और मॉड्यूल को कंपाइल करने के लिए, मुख्य थ्रेड का इस्तेमाल करता है. इसके बाद, यह AudioWorkletNode के कंस्ट्रक्टर के ज़रिए WASM मॉड्यूल को ट्रांसफ़र करेगा. यह पैटर्न तब और बेहतर तरीके से काम करता है, जब आपको AudioWorkletGlobalScope के ऑडियो स्ट्रीम को रेंडर करना शुरू करने के बाद, मॉड्यूल को डाइनैमिक तौर पर लोड करना होता है. मॉड्यूल के साइज़ के आधार पर, उसे रेंडरिंग के बीच कंपाइल करने से स्ट्रीम में रुकावट आ सकती है.
WASM हीप और ऑडियो डेटा
WebAssembly कोड, सिर्फ़ उस मेमोरी पर काम करता है जिसे खास WASM हीप में बांटा गया है. इसका फ़ायदा लेने के लिए, WASM हीप और ऑडियो डेटा कलेक्शन के बीच ऑडियो डेटा को क्लोन करना होगा. उदाहरण कोड में मौजूद HeapAudioBuffer क्लास इस काम को अच्छे से हैंडल करता है.
WASM हीप को सीधे ऑडियो वर्कलेट सिस्टम में इंटिग्रेट करने के लिए, शुरुआती प्रस्ताव है. JS मेमोरी और WASM हीप के बीच ग़ैर-ज़रूरी डेटा की क्लोनिंग को खत्म करना स्वाभाविक लगता है, लेकिन खास जानकारी पर ध्यान देने की ज़रूरत है.
बफ़र साइज़ मेल न खाने की समस्या हल करना
AudioWorkletNode और AudioWorkletProcessor की जोड़ी को किसी सामान्य AudioNode की तरह काम करने के लिए डिज़ाइन किया गया है; AudioWorkletNode अन्य कोड के साथ इंटरैक्शन को हैंडल करता है जबकि AudioWorkletProcessor अंदरूनी ऑडियो प्रोसेसिंग का काम करता है. एक सामान्य AudioNode एक समय में 128 फ़्रेम को प्रोसेस करता है, इसलिए AudioWorkletProcessor को मुख्य फ़ंक्शन बनने के लिए भी वही होना चाहिए. यह ऑडियो वर्कलेट डिज़ाइन का एक फ़ायदा है, जो यह पक्का करता है कि AudioWorkletProcessor में अंदरूनी बफ़रिंग के कारण कोई अतिरिक्त इंतज़ार न हो लेकिन अगर किसी प्रोसेसिंग फ़ंक्शन के लिए 128 फ़्रेम से अलग बफ़र साइज़ की ज़रूरत हो, तो समस्या हो सकती है. ऐसे मामले में आम तौर पर रिंग बफ़र का इस्तेमाल किया जाता है. इसे सर्कुलर बफ़र या एफ़आईएफ़ओ भी कहा जाता है.
यहां एक डायग्राम दिखाया गया है, जिसमें AudioWorkletProcessor में दो रिंग बफ़र इस्तेमाल करके, 512 फ़्रेम अंदर और बाहर ले जाने वाले WASM फ़ंक्शन को शामिल करने के लिए इस्तेमाल किया गया है. (यहां नंबर 512 को मनमाने तरीके से चुना गया है.)
डायग्राम के लिए एल्गोरिदम यह होगा:
- AudioWorkletप्रोसेसर, अपने इनपुट से इनपुट RingBuffer में 128 फ़्रेम पुश करता है.
- नीचे दिए गए चरणों को सिर्फ़ तब पूरा करें, जब इनपुट RingBuffer
512 फ़्रेम से ज़्यादा या उसके बराबर हो.
- इनपुट RingBuffer से 512 फ़्रेम खींचें.
- दिए गए WASM फ़ंक्शन की मदद से, 512 फ़्रेम प्रोसेस करें.
- आउटपुट RingBuffer पर 512 फ़्रेम पुश करें.
- AudioWorkletप्रोसेसर, आउटपुट RingBuffer से 128 फ़्रेम लेता है, ताकि उसका आउटपुट पूरा किया जा सके.
जैसा कि डायग्राम में दिखाया गया है, इनपुट फ़्रेम हमेशा इनपुट RingBuffer में इकट्ठा होते हैं. साथ ही, यह बफ़र में सबसे पुराने फ़्रेम ब्लॉक को ओवरराइट करके, बफ़र ओवरफ़्लो को मैनेज करता है. रीयल-टाइम में ऑडियो ऐप्लिकेशन के लिए ऐसा करना सही है. इसी तरह, आउटपुट फ़्रेम ब्लॉक हमेशा सिस्टम की ओर से निकाला जाएगा. आउटपुट RingBuffer में बफ़र अंडरफ़्लो (पूरा डेटा नहीं है) की वजह से स्ट्रीम में गड़बड़ी पैदा हो सकती है.
यह पैटर्न उस समय काम का होता है जब ScriptProcessorNode (SPN) को AudioWorkletNode से बदला जाता है. SPN की मदद से डेवलपर, 256 और 16384 फ़्रेम के बीच बफ़र साइज़ चुन सकता है. इसलिए, AudioWorkletNode के साथ SPN को ड्रॉप-इन में बदलना मुश्किल हो सकता है. रिंग बफ़र का इस्तेमाल करने से बेहतर नतीजे मिलते हैं. इस डिज़ाइन के ऊपर बनाया जा सकने वाला ऑडियो रिकॉर्डर एक अच्छा उदाहरण हो सकता है.
हालांकि, यह समझना ज़रूरी है कि यह डिज़ाइन सिर्फ़ मेल न खाने वाले बफ़र साइज़ का मिलान करता है और यह दिए गए स्क्रिप्ट कोड को चलाने के लिए ज़्यादा समय नहीं देता है. अगर कोड, रेंडर क्वांटम के टाइमिंग बजट में (~3 मि॰से॰ 44.1 किलोहर्ट्ज़) में टास्क पूरा नहीं कर पाता है, तो इससे बाद के कॉलबैक फ़ंक्शन के शुरू होने के समय पर असर पड़ेगा और इससे ग्लिच होंगी.
WASM हीप के लिए मेमोरी मैनेजमेंट की वजह से, इस डिज़ाइन को WebAssembly के साथ मिलाना मुश्किल हो सकता है. लिखते समय, WASM हीप से बाहर जाने वाले डेटा की क्लोन बनाना ज़रूरी है. हालांकि, मेमोरी मैनेजमेंट को थोड़ा आसान बनाने के लिए हम HeapAudioBuffer क्लास का इस्तेमाल कर सकते हैं. ग़ैर-ज़रूरी डेटा क्लोनिंग को कम करने के लिए, उपयोगकर्ता के लिए असाइन की गई मेमोरी के इस्तेमाल पर आने वाले समय में चर्चा की जाएगी.
RingBuffer क्लास यहां मिल सकती है.
Webऑडियो पावरहाउस: ऑडियो वर्कलेट और SharedArrayBuffer
इस लेख में दिए गए आखिरी डिज़ाइन पैटर्न में, कई आधुनिक एपीआई को एक ही जगह पर रखना है; ऑडियो वर्कलेट, SharedArrayBuffer, ऐटमिक्स, और वर्कर. इस छोटे सेटअप की मदद से, C/C++ में लिखे गए मौजूदा ऑडियो सॉफ़्टवेयर को वेब ब्राउज़र पर चलाया जा सकता है. साथ ही, इससे उपयोगकर्ता अनुभव को बेहतर बनाया जा सकता है.
इस डिज़ाइन का सबसे बड़ा फ़ायदा यह है कि इसमें ऑडियो प्रोसेसिंग के लिए, सिर्फ़ DedicatedWorkerGlobalScope का इस्तेमाल किया जा सकता है. Chrome में, WorkerGlobalScope, WebAudio रेंडरिंग थ्रेड के मुकाबले कम प्राथमिकता वाले थ्रेड पर चलता है. हालांकि AudioWorkletGlobalScope से ज़्यादा इसके कई फ़ायदे हैं. स्कोप में उपलब्ध एपीआई प्लैटफ़ॉर्म के हिसाब से, DedicatedWorkerGlobalScope को कम रखा जाता है. साथ ही, आपको Emscripten से बेहतर मदद मिल सकती है, क्योंकि कुछ सालों से Worker API मौजूद है.
इस डिज़ाइन को बेहतर तरीके से काम करने में, SharedArrayBuffer की भूमिका अहम भूमिका निभाती है. हालांकि, वर्कर और AudioWorkletProcessor दोनों में एसिंक्रोनस मैसेज सेवा (MessagePort) मौजूद है, लेकिन यह रीयल-टाइम में ऑडियो प्रोसेस करने के लिए सबसे अच्छा नहीं है. ऐसा मेमोरी के बार-बार बंटवारा और मैसेज सेवा के इंतज़ार में लगने वाले समय की वजह से होता है. इसलिए, हम ऊपर एक मेमोरी ब्लॉक तय करते हैं, जिसे दोनों थ्रेड से ऐक्सेस करके तेज़ी से दोनों तरफ़ डेटा ट्रांसफ़र किया जा सकता है.
Web Audio API के अनुभव के हिसाब से, यह डिज़ाइन शायद सबसे अच्छा न दिखे. इसकी वजह यह है कि यह ऑडियो वर्कलेट को एक सामान्य "ऑडियो सिंक" की तरह इस्तेमाल करता है और वर्कर में सभी काम करता है. हालांकि, JavaScript में C/C++ प्रोजेक्ट को फिर से लिखने में आने वाली लागत प्रतिबंधित हो सकती है या नामुमकिन भी हो सकती है. ऐसे प्रोजेक्ट के लिए यह डिज़ाइन सबसे कारगर हो सकता है.
शेयर राज्य और एटॉमिक्स
ऑडियो डेटा के लिए शेयर की गई मेमोरी का इस्तेमाल करते समय, दोनों तरफ़ से डेटा के ऐक्सेस को सावधानी से सिंक करना चाहिए. इस तरह की समस्याओं को हल करने के लिए,
ऐसे स्थिति शेयर की गई हैं जिन्हें अपने-आप ऐक्सेस किया जा सकता है. इस काम के लिए, हम SAB के साथ काम करने वाले Int32Array
का फ़ायदा ले सकते हैं.
सिंक करने के तरीके: SharedArrayBuffer और Atomics
राज्यों के कलेक्शन का हर फ़ील्ड, शेयर किए गए बफ़र के बारे में ज़रूरी जानकारी दिखाता है. सबसे ज़रूरी है सिंक करने के लिए फ़ील्ड (REQUEST_RENDER
). इसका मतलब है कि वर्कर को तब तक इंतज़ार करना चाहिए, जब तक इस फ़ील्ड को AudioWorkletProcessor से नहीं छुआ जाए और जब यह चालू हो जाए, तब ऑडियो प्रोसेस करें. SharedArrayBuffer (SAB) के साथ-साथ, Atomic API भी इस प्रोसेस को संभव बनाता है.
ध्यान दें कि दो थ्रेड का सिंक्रोनाइज़ेशन काफ़ी हद तक ढीला है. Worker.process()
के शुरू होने की प्रोसेस को AudioWorkletProcessor.process()
तरीके से ट्रिगर किया जाएगा. हालांकि, AudioWorkletProcessor में Worker.process()
के खत्म होने का इंतज़ार नहीं किया जाता. यह डिज़ाइन को ध्यान में रखकर किया जाता है. AudioWorkletप्रोसेसर, ऑडियो कॉलबैक से चलता है. इसलिए, इसे सिंक्रोनस रूप से ब्लॉक नहीं किया जाना चाहिए. सबसे खराब स्थिति में ऑडियो स्ट्रीम में डुप्लीकेट
या ड्रॉप-आउट की समस्या हो सकती है. हालांकि, रेंडरिंग परफ़ॉर्मेंस के स्थिर होने पर
ऑडियो स्ट्रीम वापस आ जाएगी.
सेट अप करना और चलाना
जैसा कि ऊपर दिए गए डायग्राम में दिखाया गया है, इस डिज़ाइन में व्यवस्थित करने के लिए कई कॉम्पोनेंट हैं: DedicatedWorkerGlobalScope (DWGS), AudioWorkletGlobalScope (AWGS), SharedArrayBuffer, और मुख्य थ्रेड. इन चरणों से पता चलता है कि शुरू करने के दौरान क्या होगा.
डेटा लेयर में इवेंट बनाने की प्रोसेस
- [मुख्य] AudioWorkletNode कंस्ट्रक्टर को कॉल किया जाता है.
- वर्कर बनाएं.
- इससे जुड़ा AudioWorkletProcessor बनाया जाएगा.
- [DWGS] वर्कर, दो SharedArrayBuffers बनाता है. (एक शेयर की गई स्थितियों के लिए और दूसरी ऑडियो डेटा के लिए)
- [DWGS] वर्कर, AudioWorkletNode को SharedArrayBuffer के रेफ़रंस भेजता है.
- [मुख्य] AudioWorkletNode, ऑडियोवर्कलेटप्रोसेसर को SharedArrayBuffer रेफ़रंस भेजता है.
- [AWGS] AudioWorkletProcessor AudioWorkletNode को सेट अप पूरा होने की सूचना देता है.
शुरू होने के बाद, AudioWorkletProcessor.process()
कॉल किया जाना शुरू हो जाता है. रेंडरिंग लूप के हर बार होने पर जो होना चाहिए, वह नीचे बताया गया है.
रेंडरिंग लूप
- [AWGS] हर रेंडर क्वांटम
के लिए
AudioWorkletProcessor.process(inputs, outputs)
को कॉल किया जाता है.inputs
को इनपुट SAB में पुश किया जाएगा.outputs
को भरने के लिए, आउटपुट SAB में ऑडियो डेटा इस्तेमाल किया जाएगा.- SAB की स्थितियों को नए बफ़र इंडेक्स के हिसाब से अपडेट करता है.
- अगर आउटपुट SAB अंडरफ़्लो थ्रेशोल्ड के करीब पहुंच जाता है, तो वेक वर्कर ज़्यादा ऑडियो डेटा रेंडर करेगा.
- [DWGS] वर्कर,
AudioWorkletProcessor.process()
से वेक सिग्नल के लिए इंतज़ार (नींद) करता है. जागने का समय:- SAB राज्यों से बफ़र इंडेक्स को फ़ेच करता है.
- आउटपुट SAB भरने के लिए, प्रोसेस फ़ंक्शन को इनपुट SAB के डेटा के साथ चलाएं.
- इसके हिसाब से बफ़र इंडेक्स की मदद से, SAB की स्थिति को अपडेट करता है.
- स्लीप मोड में चला जाता है और अगले सिग्नल का इंतज़ार करता है.
उदाहरण के तौर पर दिया गया कोड यहां मिल सकता है. ध्यान दें कि इस डेमो के काम करने के लिए, SharedArrayBuffer एक्सपेरिमेंटल फ़्लैग चालू करना ज़रूरी है. इस कोड को सिर्फ़ JS कोड में लिखा गया था, ताकि इसे आसानी से समझा जा सके. हालांकि, ज़रूरत पड़ने पर इसे WebAssembly कोड से बदला जा सकता है. ऐसे मामले में ज़्यादा सावधानी बरतनी चाहिए. इसके लिए, HeapAudioBuffer क्लास के साथ मेमोरी मैनेजमेंट को रैप करना चाहिए.
नतीजा
ऑडियो वर्कलेट का मुख्य मकसद Web Audio API को "बहुत ज़्यादा आसान" बनाना है. इसके डिज़ाइन पर कई साल तक मेहनत की गई, ताकि वेब ऑडियो एपीआई की बाकी सुविधाओं को ऑडियो वर्कलेट के साथ लागू किया जा सके. इस वजह से, अब इसके डिज़ाइन में ज़्यादा जटिलता आ गई है और यह एक अनचाही चुनौती हो सकती है.
अच्छी बात यह है कि इस तरह की जटिलता की वजह सिर्फ़ डेवलपर की मदद करना है. AudioWorkletGlobalScope पर WebAssembly चलाने में, वेब पर अच्छी परफ़ॉर्मेंस वाली ऑडियो प्रोसेसिंग की अपार संभावनाएं होती हैं. C या C++ में लिखे गए बड़े पैमाने पर उपलब्ध ऑडियो ऐप्लिकेशन के लिए, SharedArrayBuffers और Workers के साथ ऑडियो वर्कलेट का इस्तेमाल करना, एक्सप्लोर करने का एक आकर्षक विकल्प हो सकता है.
क्रेडिट देखें
इस लेख के ड्राफ़्ट की समीक्षा करने और अहम सुझाव देने के लिए क्रिस विल्सन, जेसन मिलर, जोशुआ बेल, और रेमंड टॉय का विशेष धन्यवाद.