Class: Web Audio Helpers
Web Audio API tools
When running in the browser, Superpowered sits on top of the Web Audio API's AudioContext. The AudioContext manages the streams to and from the computers audio hardware and also schedules the audio processing callback which we use to render our audio buffers with the Superpowered WebAssembly library.
We've created some helpers which will help you get audio up and running.
For a complete guide to getting setup, you may want to take a look at our guide:
SuperpoweredGlue
SuperpoweredGlue helps you fetch and initialize the Superpowered WebAssembly library you'll be using throughout your application. It creates all the convenient, but also efficient interfaces you can use with Javascript. A WebAssembly interface doesn't even have classes, but this glue creates the plumbing for the Superpowered API. Once initialized, the instantiated Superpowered object is made available for use inside the Javascript context you use.
// Importing in javascript main application (bundled)import { SuperpoweredGlue } from '@superpoweredsdk/web';// Importing inside a Worker scriptimport { SuperpoweredGlue } from 'https://cdn.jsdelivr.net/npm/@superpoweredsdk/web@2.7.2';// TO evluate Superpowered, create a SuperpoweredGlue instance. Insert your license key here or use the one provided below for evaluation.var Superpowered = await SuperpoweredGlue.Instantiate('ExampleLicenseKey-WillExpire-OnNextUpdate');// or use in production, also pass in the wasm location which you hostvar Superpowered = await SuperpoweredGlue.Instantiate('ExampleLicenseKey-WillExpire-OnNextUpdate', 'https://LOCATION_OF_PUBLICALLY_ACESSABLE_WASM_FILE');
For more help please see the guide for more help with getting Superpowered started.
SuperpoweredWebAudio
We've wrapped the standard AudioContext class with some helpers to streamline some common tasks when writing audio web applications. The SuperpoweredWebAudio class contains helper functions for easier Web Audio initialization. The returned objects are standard Web Audio objects without any quirks.
Please note that to enable Web Audio features on a page, you are required to be running from a secure context: HTTPS or localhost.
audioContext
PROPERTYType | Min | Max | Default | AudioContext |
---|
constructor
METHODCreates an instance of the SupowereedWebAudio class.ParametersReturnsName Type Description samplerate Number
The initial sample rate in Hz. Superpowered Number
An initialised Superpowered instance. Type Description Superpowered.WebAudioManager
A Superpowered WebAudioManager createAudioNode
METHODParametersCreates a Superpowered AudioWorkletNode.
This function was made to help with browser-specific quirks and to properly initialize Superpowered in an Audio Worklet context.
ReturnsName Type Description url Number
The publicly accessible AudioWorkletProcessor module. name Number
The name of the Processor you have registered within your AudioWorkletProcessor script (case-sensitive) onSuccess Number
Runs after the audio node is created. Single argument `newNode`, which is a standard AudioNode for use in your WebAudio graph. onMessageFromAudioScope Number
Is called whenever `sendMessageToAudioScope` is called from the within the AudioWorkletProcessor. Single argument `message` provided. NonecreateAudioNodeAsync
METHODParametersCreates an AudioWorkletNode.
This function was made to help with browser-specific quirks and to properly initialize Superpowered in an Audio Worklet context.
ReturnsName Type Description url Number
The publicly accessible AudioWorkletProcessor module. name Number
The name of the Processor you have registered within your AudioWorkletProcessor script (case-sensitive) onSuccess Number
Runs after the audio node is created. Single argument `newNode`, which is a standard AudioNode for use in your WebAudio graph. onMessageFromAudioScope Number
Is called whenever `sendMessageToAudioScope` is called from the within the AudioWorkletProcessor. Single argument `message` provided. Type Description Number
A standard AudioNode for use in a Web Audio graph. destruct
METHODParametersWill return
false
from the process() method of the AudioWorkletNode and runonDestruct
within the associated AudioWorkletProcessor, to help you clean up your class instances.NoneReturnsNonegetUserMediaForAudio
METHODParametersPrompts the user for permission to use a media input (typically the microphone) with an audio track and no video tracks.
This function was made to help with browser-specific quirks, see here.
ReturnsName Type Description mediaConstraints Number
See here for more information about MediaContraints.
onSuccess Number
Callback on successful audio capture. Single argument `stream` provided. onError Number
Callback on unsuccessful audio capture. Single argument `error` provided. NonegetUserMediaForAudioAsync
METHODAsynchronous version of getUserMediaForAudio.ParametersReturnsName Type Description mediaConstraints Number
See here for more information about MediaContraints.
Type Description Number
Returns with a standard MediaStream object or undefined on error.
Code examples
var webaudioManager = new SuperpoweredWebAudio(44100, // The minimum sample rate of the AudioContext. The actual sample rate may be equal or higher.Superpowered // The SuperpoweredGlue instance.);// Returns with a standard AudioContext. Reference: https://developer.mozilla.org/en-US/docs/Web/API/AudioContextlet audioContext = webaudioManager.audioContext;// Prompts the user for permission to use a media input (typically the microphone) with an audio track and no video tracks. Has no return value.// This function was made to help with browser-specific quirks.// Reference https://developer.mozilla.org/en-US/docs/Web/API/MediaDevices/getUserMediawebaudioManager.getUserMediaForAudio({ // navigator.mediaDevices.getUserMedia constraints'echoCancellation': false},function(stream) {// Called when the user provided permission (for the microphone).// stream is a standard MediaStream object:// https://developer.mozilla.org/en-US/docs/Web/API/MediaStream},function(error) {// Called when the user refused the (microphone) permission.// Visit the reference above on what error represents.});// Asynchronous version of getUserMediaForAudio.// Returns with a standard MediaStream object or undefined on error.let audioInputStream = await webaudioManager.getUserMediaForAudioAsync({ // navigator.mediaDevices.getUserMedia constraints or "fastAndTransparentAudio" to disable all processing on the audio input'fastAndTransparentAudio': true},).catch((error) => {// Called when the user provided permission (typically for the microphone).});if (!audioInputStream) return; // Program flow will reach this point even on error.// Creates an AudioWorkletNode.// This function was made to help with browser-specific quirks and to properly initialize Superpowered in an Audio Worklet context.var myAudioNode = null;webaudioManager.createAudioNode('/example_effects/processor.js', // The JavaScript module source of the node.'MyProcessor', // The registered processor name.function(newNode) {// Runs after the audio node is created.// newNode is a standard AudioWorkletNode.myAudioNode = newNode;},function(message) {// Runs in the main scope (main thread) when the audio node sends a message.// message is a standard JavaScript object.// Let's send some data to the audio scope (audio thread).// This method accepts any object (string, array, etc.) as it's single input parameter.myAudioNode.sendMessageToAudioScope({someText: "Hey!"});});// Asynchronous version of createAudioNode.// Returns with a standard AudioWorkletNode.let audioNode = await webaudioManager.createAudioNodeAsync(audioContext, // The standard AudioContext instance.'/example_effects/processor.js', // The JavaScript module source of the node.'MyProcessor', // The registered processor name.function(message) {// Runs in the main scope (main thread) when the audio node sends a message.// message is a standard JavaScript object.});// Will return false from the process() method of the AudioWorkletNode and run onDestruct to clean up WebAssembly and more.audioNode.destruct();
AudioWorkletProcessor
The easiest way to use Superpowered features in a Web Audio AudioNode is the SuperpoweredWebAudio.AudioWorkletProcessor class.
It can be created by createAudioNode (see the example above) and should be loaded from a dedicated .js file, because it's a JS module in modern browsers.
class MyProcessor extends SuperpoweredWebAudio.AudioWorkletProcessor {onReady() {// Runs after the constructor. This is "your" constructor basically.}onDestruct() {// Runs before the node is destroyed.// Clean up memory and objects here (such as free allocated linear memory or destruct Superpowered objects).}onMessageFromMainScope(message) {// Runs when a message (data) is received from the main scope (main thread).// Let's figure out the samplerate we're working with.let samplerate = this.Superpowered.samplerate;// Let's send some data back to the main scope (main thread).// This method accepts any object (string, array, etc.) as it's single input parameter.this.sendMessageToMainScope({someText: "Got your message!",hz: samplerate});}processAudio(inputBuffer, outputBuffer, buffersize, parameters) {// The audio processing callback running in the audio thread.// buffersize is the current number of frames, typically 128.// parameters is a map of string keys and associated Float32Arrays, as standardized by W3:// https://www.w3.org/TR/webaudio/#AudioNode-methods (see the process() method)// parameters are not very useful here, because they don't work for older browsers with ScriptProcessorNode.// Superpowered objects are automatically smoothing parameter changes as required, so there is no need to use the AudioParam features of Web Audio.// Use sendMessageToAudioScope() to send parameters instead, as you can find in the example projects.// inputBuffer and outputBuffer contain stereo interleaved 32-bit floating point audio.// They have both direct WASM linear memory index (pointer) access and JavaScript Float32Array access.// Typically, Superpowered objects require direct WASM linear memory indexes (pointers) for audio input and/or output:SomeSuperpoweredObject.process(inputBuffer.pointer, outputBufer.pointer, buffersize);// Direct JavaScript Float32Array access to audio input and/or output:let firstInputSampleLeft = inputBuffer.array[0];let firstInputSampleRight = inputBuffer.array[1];outputBuffer.array[0] = firstInputSampleLeft;outputBuffer.array[1] = firstInputSampleRight;}}
Linear Memory
Most Superpowered APIs work on arrays of floating point numbers representing PCM audio. A simple buffer containing audio input for example. But WebAssembly can not access traditional JavaScript Float32Arrays directly and efficiently.
In the low-level memory model of WebAssembly, memory is represented as a contiguous range of untyped bytes called Linear Memory, which is a standard ArrayBuffer.
Memory can be "allocated" in the Linear Memory, returning with a pointer to the allocated region, which can be used to represent an array of data, such as an array of floating point numbers. This pointer (aka address) is just a simple integer Number, the byte index inside the Linear Memory. For example, 0 represents the first byte in the Linear Memory, however Superpowered occupies this part and 0 means "NULL".
The following example demonstrates how to allocate a region in the Linear Memory and how to create a Float32Array "view" of this region with standard WebAssembly JavaScript:
...let length = 128; // We want the buffer to store 128 floating point numbers.let pointer = Superpowered.malloc(length * 4); // A floating point number is 4 bytes, therefore we allocate length * 4 bytes of memory.// You can use "pointer" to pass audio to most Superpowered APIs.// Maybe we want to directly manipulate this data from JavaScript as well. Let's create a Float32Array view of this region.let arrayView = new Float32Array(Superpowered.linearMemory, // Standard WebAssembly Module reference to the Linear Memory.pointer, // The address of the allocated region.length // The length of the region.);// Now this is possible:arrayView[0] = 0.5;// Deallocate the region when we don't need it anymore.Superpowered.free(pointer);...
SuperpoweredGlue offers some special typed buffer APIs to make this allocation process a little bit easier:
...// Total memory consumption in this example: 256 * 4 = 1024 bytes.let someBuffer = new Superpowered.Float32Buffer(256);someBuffer.pointer; // Getting the linear memory index (pointer).someBuffer.length; // Getting the length of the buffer (256).someBuffer.array; // A Float32Array view of this buffer (standard TypedArray).someBuffer.array[0] = 0.5; // Accessing the buffer as a Float32Array.someBuffer.free(); // Deallocate the buffer....
Uint8Buffer
Methods
- constructorMETHODCreates a Superpowered.Uint8Buffer instance.ParametersReturns
Name Type Description length Number
Length of buffer array. Type Description Superpowered.Uint8Buffer
- freeMETHODDeallocate the buffer.ParametersNoneReturnsNone
Properties
Type | Min | Max | Default | Uint8Array |
---|
Type | Min | Max | Default | Number |
---|
Type | Min | Max | Default | Number |
---|
Int8Buffer
Methods
- constructorMETHODCreates a Superpowered.Int8Buffer instance.ParametersReturns
Name Type Description length Number
Length of buffer array. Type Description Superpowered.Int8Buffer
- freeMETHODDeallocate the buffer.ParametersNoneReturnsNone
Properties
Type | Min | Max | Default | Int8Array |
---|
Type | Min | Max | Default | Number |
---|
Type | Min | Max | Default | Number |
---|
Uint16Buffer
Methods
- constructorMETHODCreates a Superpowered.Uint16Buffer instance.ParametersReturns
Name Type Description length Number
Length of buffer array. Type Description Superpowered.Uint16Buffer
- freeMETHODDeallocate the buffer.ParametersNoneReturnsNone
Properties
Type | Min | Max | Default | Uint16Array |
---|
Type | Min | Max | Default | Number |
---|
Type | Min | Max | Default | Number |
---|
Int16Buffer
Methods
- constructorMETHODCreates a Superpowered.Int16Buffer instance.ParametersReturns
Name Type Description length Number
Length of buffer array. Type Description Superpowered.Int16Buffer
- freeMETHODDeallocate the buffer.ParametersNoneReturnsNone
Properties
Type | Min | Max | Default | Int16Array |
---|
Type | Min | Max | Default | Number |
---|
Type | Min | Max | Default | Number |
---|
Uint32Buffer
Methods
- constructorMETHODCreates a Superpowered.Uint32Buffer instance.ParametersReturns
Name Type Description length Number
Length of buffer array. Type Description Superpowered.Uint32Buffer
- freeMETHODDeallocate the buffer.ParametersNoneReturnsNone
Properties
Type | Min | Max | Default | Uint32Array |
---|
Type | Min | Max | Default | Number |
---|
Type | Min | Max | Default | Number |
---|
Int32Buffer
Methods
- constructorMETHODCreates a Superpowered.Int32Buffer instance.ParametersReturns
Name Type Description length Number
Length of buffer array. Type Description Superpowered.Int32Buffer
- freeMETHODDeallocate the buffer.ParametersNoneReturnsNone
Properties
Type | Min | Max | Default | Int32Array |
---|
Type | Min | Max | Default | Number |
---|
Type | Min | Max | Default | Number |
---|
BigUint64Buffer
Methods
- constructorMETHODCreates a Superpowered.BigUint64Buffer instance.ParametersReturns
Name Type Description length Number
Length of buffer array. Type Description Superpowered.BigUint64Buffer
- freeMETHODDeallocate the buffer.ParametersNoneReturnsNone
Properties
Type | Min | Max | Default | BigUInt64Array |
---|
Type | Min | Max | Default | Number |
---|
Type | Min | Max | Default | Number |
---|
BigInt64Buffer
Methods
- constructorMETHODCreates a Superpowered.BigInt64Buffer instance.ParametersReturns
Name Type Description length Number
Length of buffer array. Type Description Superpowered.BigInt64Buffer
- freeMETHODDeallocate the buffer.ParametersNoneReturnsNone
Properties
Type | Min | Max | Default | BigInt64Array |
---|
Type | Min | Max | Default | Number |
---|
Type | Min | Max | Default | Number |
---|
Float32Buffer
Methods
- constructorMETHODCreates a Superpowered.Float32Buffer instance.ParametersReturns
Name Type Description length Number
Length of buffer array. Type Description Superpowered.Float32Buffer
- freeMETHODDeallocate the buffer.ParametersNoneReturnsNone
Properties
Type | Min | Max | Default | Float32Array |
---|
Type | Min | Max | Default | Number |
---|
Type | Min | Max | Default | Number |
---|
Float64Buffer
Methods
- constructorMETHODCreates a Superpowered.Float64Buffer instance.ParametersReturns
Name Type Description length Number
Length of buffer array. Type Description Superpowered.Float64Buffer
- freeMETHODDeallocate the buffer.ParametersNoneReturnsNone
Properties
Type | Min | Max | Default | Float64Array |
---|
Type | Min | Max | Default | Number |
---|
Type | Min | Max | Default | Number |
---|
Memory utilities
The memoryCopy and memorySet functions are also available for quick memory operations:
// Allocate two buffers, each with four 32-bit integer numbers (16 bytes).let buf1 = new Superpowered.Int32Buffer(4);let buf2 = new Superpowered.Int32Buffer(4);// buf1 to [ 0, 1, 2, 3 ], buf2 contains memory garbagebuf1.array[0] = 0;buf1.array[1] = 1;buf1.array[2] = 2;buf1.array[3] = 3;// Copy in Linear Memory. Similar to memcpy in C.Superpowered.memoryCopy(buf2.pointer, // Output pointer.buf1.pointer, // Input pointer.16 // Number of bytes to copy.);// buf2 is now [ 0, 1, 2, 3 ]// Set data in Linear Memory. Similar to memset in C.Superpowered.memorySet(buf1.pointer, // Pointer to data.0, // Set this value to each byte. Should be between 0..255.16 // Number of bytes to set.);// buf1 is now [ 0, 0, 0, 0 ]
memoryCopy
METHODCopy in Linear Memory. Similar to memcpy in C.ParametersReturnsName Type Description output Number
Output pointer. input Number
Input pointer. bytes Number
Number of bytes to copy. NonememorySet
METHODSet data in Linear Memory. Similar to memset in C.ParametersReturnsName Type Description data Number
Pointer to data. value Number
Set each byte to this value, should be between 0 - 255. bytes Number
Number of bytes to set. None
Loading Audio
The downloadAndDecode method of a Superpowered instance is a tool you can use to download and decode a remote audio file from either the main thread or from within an AudioWorkletProcessor
in a single easy step. It will automatically create a Worker (a background-thread) for the downloading and decoding process, so it doesn't put any load on the current AudioWorkletProcessor
or the main thread.
Please note that downloadAndDecode cannot be used inside a standard Worker. See below for a example of fetching audio inside a
Worker
.
The downloadAndDecode
utility wraps the HTTP fetching and decoding of the audio file into Superpowered's AudioInMemory format ready to be used with an AdvancedAudioPlayer class.
Under the hood it uses the Decoder class which offers the following consistent codec support across all devices.
- Stereo or mono pcm WAV and AIFF (16-bit int, 24-bit int, 32-bit int or 32-bit IEEE float).
- MP3: MPEG-1 Layer III (sample rates: 32000 Hz, 44100 Hz, 48000 Hz). MPEG-2 Layer III is not supported (mp3 with sample rates below 32000 Hz).
- AAC or HE-AAC in M4A container (iTunes) or ADTS container (.aac).
The downloadAndDecode
utility will automatically create a Worker on another thread to download and decode the remote data so it does not put any work on the thread from which is was called. This is a clear performance advantage over the standard WebAudio APIs native decodeAudioData pattern.
You may find our Loading Audio guide useful as it walks you through every step required.
You can call downloadAndDecode
within you application from any scope.
From within an AudioWorkletProcessor
class YourSuperpoweredProcessor extends SuperpoweredWebAudio.AudioWorkletProcessor {....// Called automatically by the parent class when the worklet is readyonReady() {this.player = new this.Superpowered.AdvancedAudioPlayer(this.samplerate, 2, 2, 0, 0.501, 2, false);this.loadTrackByUrl('./music/track.mp3');}loadTrackByUrl(url) {this.Superpowered.downloadAndDecode(url, this);// the second argument 'this' refers to the YourSuperpoweredProcessor class, it will automatically call the onMessageFromMainScope method unless overridden by passing in a reference to a function.}onMessageFromMainScope(message) {if (message.SuperpoweredLoaded) {// SuperpoweredLoaded is a special message type which will always represent the SuperpoweredTrackLoader having fetched and decoded an asset.let buffer = message.SuperpoweredLoaded.buffer; // ArrayBuffer with the downloaded and decoded audio in AudioInMemory format.let url = message.SuperpoweredLoaded.url; // The url of the audio file ('./music/track.mp3' in this example).// Now we have the audio buffer we can use it to load audio into our player class.this.player.openMemory(this.Superpowered.arrayBufferToWASM(buffer), false, false);this.player.play();}}processAudio(inputBuffer, outputBuffer, buffersize) {if (!this.player.processStereo(outputBuffer.pointer, false, buffersize, 1)) {// return 0's if the player has no audio buffer loadedthis.Superpowered.memorySet(outputBuffer.pointer, 0, buffersize * 8); // 8 bytes for each frame (1 channel is 4 bytes)}}....}
downloadAndDecode
METHODSpins up a Worklet to fetch the url provided and then decodes automatically.ParametersReturnsName Type Description url Number
The remote url of the audio asset the Worker should fetch. handler Number
A reference to the AudioWorklet instance or Worker handler to be called when fetching and decoding completed. None
From within a Worker
You should not use downloadAndDecode
in Workers. To fetch audio within a standard Worker, we fetch the buffer using fetch, then decode with Superpowered and transfer it back to the main thread.
...// AudioFetcherWorker.jsimportScripts('/Superpowered.js'); // You host this file, must be publically accessibleself.onmessage = async function(e) {const Superpowered = await SuperpoweredGlue.Instantiate('');await fetch(e.data.url).then(response =>response.arrayBuffer()).then(audiofileArrayBuffer => {// Copy the ArrayBuffer to WebAssembly Linear Memory.const audiofileInWASMHeap = Superpowered.arrayBufferToWASM(audiofileArrayBuffer);// Decode the entire file.const decodedAudio = Superpowered.Decoder.decodeToAudioInMemory(audiofileInWASMHeap, audiofileArrayBuffer.byteLength);// Copy the pcm audio from the WebAssembly heap into a regular ArrayBuffer that can be transfered.const arrayBuffer = Superpowered.moveWASMToArrayBuffer(decodedAudio, Superpowered.AudioInMemory.getSize(decodedAudio) * 4);// Transfer the ArrayBuffer.self.postMessage(arrayBuffer, [ arrayBuffer ]);});}
To call the worker to from the main thread, we must create it, pass the url to be downloaded and listen for the response, then finally terminate the Worker instance for garbage collection.
// In your main application// The url of the audio we want to laodconst audioAssetUrl = '/audio/samples/pads.mp3';// Create a worker from the script we created aboveconst downloadWorker = new Worker('AudioFetcherWorker.js', { type: "module" });// Setup listener on the worker to receive the payloaddownloadWorker.onmessage = (message) => {// This is the decoded audio buffer, transferred from the worker threadconst audioBufferTransferredBackFromWorker = msg.data;// ... do whatever we want with buffer hereconsole.log(audioBufferTransferredBackFromWorker);// Terminate the worker once we have the datadownloadWorker.terminate()};// Send a mesagage over to the worker to trigger a download.downloadWorker.postMessage({ url: audioAssetUrl });
Remember you can find a working example of getting Superpowered up and running with WebAudio here:
is not supported here.