ওয়েব অডিও API দিয়ে শুরু করা

বোরিস স্মাস
Boris Smus

HTML5-এর <audio> এলিমেন্ট আসার আগে, ওয়েবের নীরবতা ভাঙতে ফ্ল্যাশ বা অন্য কোনো প্লাগইনের প্রয়োজন হতো। যদিও ওয়েবে অডিওর জন্য এখন আর প্লাগইনের প্রয়োজন হয় না, তবে উন্নতমানের গেম এবং ইন্টারেক্টিভ অ্যাপ্লিকেশন তৈরির ক্ষেত্রে এই অডিও ট্যাগটি বেশ কিছু উল্লেখযোগ্য সীমাবদ্ধতা নিয়ে আসে।

ওয়েব অডিও এপিআই হলো ওয়েব অ্যাপ্লিকেশনে অডিও প্রসেসিং এবং সিন্থেসাইজ করার জন্য একটি উচ্চ-স্তরের জাভাস্ক্রিপ্ট এপিআই। এই এপিআই-এর লক্ষ্য হলো আধুনিক গেম অডিও ইঞ্জিনে থাকা সক্ষমতা এবং আধুনিক ডেস্কটপ অডিও প্রোডাকশন অ্যাপ্লিকেশনে পাওয়া যায় এমন কিছু মিক্সিং, প্রসেসিং ও ফিল্টারিংয়ের কাজ অন্তর্ভুক্ত করা। নিচে এই শক্তিশালী এপিআই ব্যবহারের একটি সহজ ভূমিকা দেওয়া হলো।

AudioContext দিয়ে শুরু করা

একটি AudioContext সমস্ত শব্দ পরিচালনা এবং বাজানোর জন্য ব্যবহৃত হয়। Web Audio API ব্যবহার করে একটি শব্দ তৈরি করতে, এক বা একাধিক সাউন্ড সোর্স তৈরি করুন এবং সেগুলোকে AudioContext ইনস্ট্যান্স দ্বারা প্রদত্ত সাউন্ড ডেস্টিনেশনের সাথে সংযুক্ত করুন। এই সংযোগটি সরাসরি হওয়ার প্রয়োজন নেই এবং এটি যেকোনো সংখ্যক মধ্যবর্তী AudioNode-এর মধ্য দিয়ে যেতে পারে, যেগুলো অডিও সিগন্যালের জন্য প্রসেসিং মডিউল হিসেবে কাজ করে। এই রাউটিং সম্পর্কে Web Audio স্পেসিফিকেশনে আরও বিস্তারিতভাবে বর্ণনা করা হয়েছে।

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-ভিত্তিক ব্রাউজারগুলির জন্য, webkitAudioContext এর মতোই webkit প্রিফিক্সটি ব্যবহার করুন।

ওয়েব অডিও এপিআই-এর অনেক আকর্ষণীয় কার্যকারিতা, যেমন অডিওনোড তৈরি করা এবং অডিও ফাইলের ডেটা ডিকোড করা, হলো AudioContext )-এর মেথড।

লোড হওয়ার শব্দ

ওয়েব অডিও এপিআই স্বল্প থেকে মাঝারি দৈর্ঘ্যের শব্দের জন্য একটি 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 গ্রহণ করে এবং এটিকে অ্যাসিঙ্ক্রোনাসভাবে ডিকোড করে (যা মূল জাভাস্ক্রিপ্ট এক্সিকিউশন থ্রেডকে ব্লক করে না)।

decodeAudioData() কাজ শেষ হলে, এটি একটি কলব্যাক ফাংশনকে কল করে যা ডিকোড করা PCM অডিও ডেটা একটি 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) ফাংশনটি গেম এবং অন্যান্য সময়-সংবেদনশীল অ্যাপ্লিকেশনের জন্য সুনির্দিষ্ট সাউন্ড প্লেব্যাক শিডিউল করা সহজ করে তোলে। তবে, এই শিডিউলিং সঠিকভাবে কাজ করানোর জন্য, আপনার সাউন্ড বাফারগুলো আগে থেকে লোড করা আছে কিনা তা নিশ্চিত করুন।

ওয়েব অডিও এপিআই বিমূর্তকরণ

অবশ্যই, এমন একটি আরও সাধারণ লোডিং সিস্টেম তৈরি করা ভালো হবে যা এই নির্দিষ্ট সাউন্ডটি লোড করার জন্য হার্ড-কোড করা নয়। একটি অডিও অ্যাপ্লিকেশন বা গেমে ব্যবহৃত বিভিন্ন ছোট থেকে মাঝারি দৈর্ঘ্যের সাউন্ডগুলো সামলানোর জন্য নানা পদ্ধতি রয়েছে—এখানে বাফারলোডার (BufferLoader) ব্যবহারের একটি উপায় দেওয়া হলো (যা ওয়েব স্ট্যান্ডার্ডের অংশ নয়)।

নিচে 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);
}

সময়ের সাথে বোঝাপড়া: ছন্দের সাথে শব্দের খেলা

ওয়েব অডিও এপিআই ডেভেলপারদেরকে প্লেব্যাকের সময়সূচী সুনির্দিষ্টভাবে নির্ধারণ করতে দেয়। এটি দেখানোর জন্য, চলুন একটি সাধারণ রিদম ট্র্যাক তৈরি করি। সম্ভবত সবচেয়ে বহুল পরিচিত ড্রামকিট প্যাটার্নটি হলো নিম্নরূপ:

একটি সাধারণ রক ড্রাম প্যাটার্ন

যেখানে প্রতি অষ্টম নোটে একটি হাই-হ্যাট এবং প্রতি কোয়ার্টারে পর্যায়ক্রমে কিক ও স্নেয়ার বাজানো হয়, ৪/৪ তালে।

ধরা যাক আমরা 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;

দুটি শব্দের মধ্যে ক্রস-ফেডিং

এখন, ধরুন আমাদের কাছে আরও কিছুটা জটিল একটি পরিস্থিতি রয়েছে, যেখানে আমরা একাধিক সাউন্ড বাজাচ্ছি কিন্তু সেগুলোর মধ্যে ক্রস ফেড করতে চাই। ডিজে-সদৃশ অ্যাপ্লিকেশনগুলিতে এটি একটি সাধারণ ঘটনা, যেখানে আমাদের দুটি টার্নটেবল থাকে এবং আমরা একটি সাউন্ড সোর্স থেকে অন্যটিতে প্যান করতে চাই।

নিম্নলিখিত অডিও গ্রাফের সাহায্যে এটি করা যেতে পারে:

অডিও গ্রাফটিতে দুটি উৎস আলাদা গেইন নোডের সাথে সংযুক্ত থাকে, যেগুলোকে পরবর্তীতে একই গন্তব্যে পাঠানো হয়।

এটি সেট আপ করার জন্য, আমরা কেবল দুটি AudioGainNode তৈরি করব এবং এই ধরনের একটি ফাংশন ব্যবহার করে প্রতিটি সোর্সকে নোডগুলোর মাধ্যমে সংযুক্ত করব:

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

ওয়েব অডিও এপিআই কোনো প্যারামিটারের মান ক্রমান্বয়ে পরিবর্তন করার জন্য linearRampToValueAtTime এবং exponentialRampToValueAtTime এর মতো কিছু সুবিধাজনক RampToValue মেথড প্রদান করে।

যদিও ট্রানজিশন টাইমিং ফাংশনটি বিল্ট-ইন লিনিয়ার এবং এক্সপোনেনশিয়াল ফাংশনগুলো (যেমন উপরে দেখানো হয়েছে) থেকে বেছে নেওয়া যায়, আপনি setValueCurveAtTime ফাংশনটি ব্যবহার করে ভ্যালুর একটি অ্যারের মাধ্যমে আপনার নিজস্ব ভ্যালু কার্ভও নির্দিষ্ট করতে পারেন।

একটি শব্দে একটি সাধারণ ফিল্টার প্রভাব প্রয়োগ করা

উৎস থেকে বাইকোয়াডফিল্টারনোড হয়ে গন্তব্যে অডিও প্রবাহের একটি সরল ফ্লোচার্ট।

ওয়েব অডিও এপিআই আপনাকে একটি অডিও নোড থেকে অন্যটিতে শব্দ প্রেরণ করতে দেয়, যার মাধ্যমে আপনার সাউন্ডফর্মে জটিল ইফেক্ট যোগ করার জন্য প্রসেসরের একটি সম্ভাব্য জটিল শৃঙ্খল তৈরি করা যায়।

এটি করার একটি উপায় হলো আপনার সাউন্ড সোর্স এবং ডেস্টিনেশনের মধ্যে 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 হলো 440hz এবং A5 হলো 880hz)। আরও বিস্তারিত জানতে, উপরের সোর্স কোড লিঙ্কে থাকা FilterSample.changeFrequency ফাংশনটি দেখুন।

সবশেষে, লক্ষ্য করুন যে স্যাম্পল কোডটি আপনাকে ফিল্টার সংযোগ এবং বিচ্ছিন্ন করার সুযোগ দেয়, যার মাধ্যমে AudioContext গ্রাফটি গতিশীলভাবে পরিবর্তিত হয়। আমরা node.disconnect(outputNumber) কল করে গ্রাফ থেকে AudioNode-গুলোকে বিচ্ছিন্ন করতে পারি। উদাহরণস্বরূপ, গ্রাফটিকে ফিল্টারের মধ্য দিয়ে না পাঠিয়ে সরাসরি সংযোগে পুনঃনির্দেশিত করতে, আমরা নিম্নলিখিত কাজটি করতে পারি:

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

আরও শুনুন

আমরা এপিআই-এর মৌলিক বিষয়গুলো আলোচনা করেছি, যার মধ্যে অডিও স্যাম্পল লোড করা এবং প্লে করাও অন্তর্ভুক্ত। আমরা গেইন নোড ও ফিল্টার ব্যবহার করে অডিও গ্রাফ তৈরি করেছি এবং কিছু সাধারণ সাউন্ড ইফেক্ট চালু করার জন্য সাউন্ড শিডিউল করা ও অডিও প্যারামিটার পরিবর্তন করার পদ্ধতি শিখেছি। এই পর্যায়ে, আপনি কিছু চমৎকার ওয়েব অডিও অ্যাপ্লিকেশন তৈরি করার জন্য প্রস্তুত!

আপনি যদি অনুপ্রেরণা খুঁজে থাকেন, তবে অনেক ডেভেলপার ইতিমধ্যেই ওয়েব অডিও এপিআই ব্যবহার করে চমৎকার কাজ তৈরি করেছেন। আমার পছন্দের কয়েকটি হলো:

  • AudioJedit হলো ব্রাউজার-ভিত্তিক একটি সাউন্ড স্প্লাইসিং টুল যা SoundCloud পারমালিঙ্ক ব্যবহার করে।
  • টোনক্রাফট , একটি সাউন্ড সিকোয়েন্সার যেখানে ত্রিমাত্রিক ব্লক স্তূপ করে শব্দ তৈরি করা হয়।
  • প্লিঙ্ক , ওয়েব অডিও এবং ওয়েব সকেট ব্যবহার করে তৈরি একটি সহযোগিতামূলক সঙ্গীত তৈরির গেম।