Class: AudioInMemory
Overview
The Superpowered AudioInMemory format allows the Decoder and the AdvancedAudioPlayer to read compressed audio files or raw 16-bit PCM audio directly from memory.
The payload can be fully loaded onto the heap in one big piece, or multiple chunks can be added at any time to support for progressive loading (eg. add memory in chunks as downloaded).
Implementation example
The following shows how you would read a local audio file (MP3, but could be anything supported by the Superpowered Decoder class) and store into an instance of AudioInMemory.
#include <fstream>#include "Superpowered.h"#include "SuperpoweredSimple.h"#include "SuperpoweredDecoder.h"#include "SuperpoweredAdvancedAudioPlayer.h"using namespace std;using namespace Superpowered;AdvancedAudioPlayer *audioPlayer;AudioInMemory* audioInMemory;bool loadFile(const char* path, char** buffer, long* size){ifstream file(path, ios::in | ios::binary | ios::ate);if (!file.is_open()){return false;}*size = file.tellg();file.seekg(0, ios::beg);*buffer = new char[*size];file.read(*buffer, *size);file.close();return true;}void playAudioFile() {Initialize("ExampleLicenseKey-WillExpire-OnNextUpdate");const unsigned int sampleRate = 44100;audioPlayer = new AdvancedAudioPlayer(sampleRate, 0);const char* filePath = "example-file.mp3";char* fileData = nullptr;long fileSize = 0;loadFile(filePath, &fileData, &fileSize);if (fileSize == 0) {// Failed to load filereturn;}// Decoder::decodeToAudioInMemory takes ownership of fileData, memory of fileData will be automatically freed.audioInMemory = (AudioInMemory*)Decoder::decodeToAudioInMemory(fileData, (unsigned int)fileSize);if (audioInMemory == NULL) {// Failed to decode audioreturn;}audioPlayer->openMemory(audioInMemory);audioPlayer->play();}bool audioProcessingCallback(float** buffers, unsigned int numberOfFrames) {float tempInterleavedBuffer[sizeof(float) * numberOfFrames * 2];bool hasOutput = audioPlayer->processStereo(tempInterleavedBuffer, false, numberOfFrames, 0.8);if (hasOutput) {DeInterleave(tempInterleavedBuffer, buffers[0], buffers[1], numberOfFrames);}return hasOutput;}
The following examples show how you might fetch remote audio or generate a sine tone and convert into the AudioInMemory format to be played by an instance of a Superpowered Advanced Audio Player.
First, in the main thread fetch/generate an array buffer and then post it over to a AudioWorklet:
...async function fetchAudioFile(url) {return await fetch(url).then(response =>response.arrayBuffer()).then( => {// Copy the ArrayBuffer to WebAssembly Linear Memory.let audiofileInWASMHeap = Superpowered.arrayBufferToWASM(audiofileArrayBuffer);// Decode the entire file.let decodedAudio = Superpowered.Decoder.decodeToAudioInMemory(audiofileInWASMHeap, audiofileArrayBuffer.byteLength);//});}function generateSineTone(seconds, frequency, sampleRate) {const sineWaveArray = new Float32Array(sampleRate * seconds);for (i = 0; i < sineWaveArray.length; i++) {sineWaveArray[i] = Math.sin(Math.PI * 2 / frequency);}return sineWaveArray.buffer;}async function transferAudioBuffer() {let rawArrayBuffer;rawArrayBuffer = await fetchAudioFile('http://url.of.audio/audio.mp3');// orrawArrayBuffer = generateSineTone(volume, seconds, frequency);this.sendMessageToAudioThread({type: 'bufferTransfer',audioBuffer: rawArrayBuffer})}...
Then, within the AudioWorkletProcessor script you have loaded into your Web Audio graph
class YourCustomProcessor extends SuperpoweredWebAudio.AudioWorkletProcessor {onReady() {// Here we create an instance of the AdvancedAudioPlayer which will use later to play the decoded audio buffer.this.player = new this.Superpowered.AdvancedAudioPlayer(this.samplerate, 2, 2, 0, 0.501, 2, false);}onDestruct() {this.player.destruct();}onMessageFromMainScope(message) {if (message.type === 'bufferTransfer') {playAudioBuffer(audioBuffer)}}playAudioBuffer(audioBuffer) {const audioFileInWASMHeap = convertToLinearMemory(audioBuffer);const decodedAudioPointer = decodeAudio(audioFileInWASMHeap);this.loadAudioIntoPlayer(decodedAudioPointer);this.playAudio();}convertToLinearMemory(audioBuffer) {// Copy the ArrayBuffer to WebAssembly Linear Memory.return this.Superpowered.arrayBufferToWASM(message.audioBuffer);}decodeAudio(audiofileInWASMHeap) {// Decode the entire file. Returns a pointerreturn this.Superpowered.Decoder.decodeToAudioInMemory(audiofileInWASMHeap, audiofileArrayBuffer.byteLength);}loadAudioIntoPlayer(decodedAudioPointer) {// Once we have the pointer to the buffer, we pass the decoded audio into the AAP instance.this.player.openMemory(decodedAudioPointer, false, false);}playAudio() {// Play the audio once loaded. (optional of course).this.player.play()}
The next example shows how we might generate a 30 second long raw PCM sine wave and store into an instance of AudioInMemory.
#include "Superpowered.h"#include "SuperpoweredSimple.h"#include "SuperpoweredGenerator.h"#include "SuperpoweredDecoder.h"#include "SuperpoweredAdvancedAudioPlayer.h"using namespace std;using namespace Superpowered;Generator *generator;AudioInMemory* audioInMemory;AdvancedAudioPlayer *audioPlayer;void playSineWave() {Initialize("ExampleLicenseKey-WillExpire-OnNextUpdate");const unsigned int sampleRate = 44100;audioPlayer = new AdvancedAudioPlayer(sampleRate, 0);generator = new Superpowered::Generator(sampleRate, Superpowered::Generator::Sine);generator->frequency = 440.0;const unsigned int numberOfSeconds = 30;unsigned int totalSize = sampleRate * numberOfSeconds;audioInMemory = (AudioInMemory*)AudioInMemory::create(1, sampleRate, totalSize, true);const unsigned int size = sampleRate;float* payloadFloatMono = (float*)malloc(sizeof(float) * size);float* payloadFloat = (float*)malloc(sizeof(float) * size * 2);for (int i = 0; i < numberOfSeconds; i++) {generator->generate(payloadFloatMono, size);Interleave(payloadFloatMono, payloadFloatMono, payloadFloat, size);int16_t* payloadInt16 = (int16_t*)malloc(sizeof(int16_t) * size * 2);FloatToShortInt(payloadFloat, payloadInt16, size, 2);AudioInMemory::append(audioInMemory, payloadInt16, size);}free(payloadFloatMono);free(payloadFloat);audioPlayer->openMemory(audioInMemory);audioPlayer->play();}bool audioProcessingCallback(float** buffers, unsigned int numberOfFrames) {float tempInterleavedBuffer[sizeof(float) * numberOfFrames * 2];bool hasOutput = audioPlayer->processStereo(tempInterleavedBuffer, false, numberOfFrames, 0.8);if (hasOutput) {DeInterleave(tempInterleavedBuffer, buffers[0], buffers[1], numberOfFrames);}return hasOutput;}
Additional information
The format consists of a main table and zero or more buffer tables. Every item is a 64-bit number to support native 32/64-bit systems and the web (WebAssembly).
The main table consists of six numbers, 64-bit (int64_t) each:
[ version, retain count, samplerate, size, completed, address of the first buffer table ]
0 | version | Should be set to 0. |
1 | retain count | The retain count can be used to track usage (eg. multiple simultaneous access). If set to 0, the Decoder and the AdvancedAudioPlayer will take ownership on all the memory allocated (the main table, the buffer tables and their payloads) and will automatically free them using free(). The allocation should happen using malloc() (and not _aligned_malloc() or similar). |
2 | samplerate | Samplerate is used with the AdvancedAudioPlayer only (valid range is 8192 to 384000) and must be correctly set right at the beginning. Set it to 0 if using the Decoder. |
3 | size | AdvancedAudioPlayer: the total duration in frames. Decoder: the total file size in bytes. Set to 0 if unknown at the beginning (eg. progressive download). Set it at any point later if it gets known. |
4 | completed | set it to 0 if additional buffers can be added (such as progressive download). Set it to 1 if finished adding additional buffers. |
5 | address of the first buffer table | Memory address of the first buffer table. |
Every buffer table consists of four numbers, 64-bit (int64_t) each:
[ payload address, size, address of the next buffer table, reserved ]
0 | payload address | Memory address of the payload. |
1 | size | AdvancedAudioPlayer: the number of audio frames inside the payload. Decoder: the size of the payload in bytes. |
2 | address of the next buffer table | Memory address of the next buffer table, or 0 if there are none (yet). |
3 | reserved | Reserved. Don't change the contents of this. |
Special "self-contained" case:
If completed
is 1
and the memory address of the first buffer table is 0, then buffer tables are not used and the payload immediately starts after the main table, in the same memory region (so it's allocated together with the main table).
Example for a 1 MB big audio file loaded into the memory, to be decoded by the Decoder:
Main table at address 0x1000
:
[ 0, 0, 0, 1048576, 1, 0x2000 ]
Buffer table at address 0x2000
:
[ 0x3000, 1048576, 0, 0 ]
Example for 1 minute 16-bit PCM audio in the memory, to be played by the AdvancedAudioPlayer:
Main table at address 0x1000
:
[ 0, 0, 44100, 2646000, 1, 0x2000 ]
Buffer table at address 0x2000
:
[ 0x3000, 2646000, 0, 0 ]
Static Methods
append
METHODAdds data.ParametersReturnsName Type Description table Number (pointer in Linear Memory)
Pointer to the main table. payload Number (pointer in Linear Memory)
Pointer to the payload. Should be allocated with malloc() (NOT new or _aligned_malloc). size Number
For compressed (not decoded) audio data: the size of the payload in bytes. For raw 16-bit PCM audio: the number of audio frames inside the payload. Noneappend
METHODAdds data.ParametersReturnsName Type Default Description table void *
Pointer to the main table. payload void *
Pointer to the payload. Should be allocated with malloc() (NOT new or _aligned_malloc). size unsigned int
For compressed (not decoded) audio data: the size of the payload in bytes. For raw 16-bit PCM audio: the number of audio frames inside the payload. Nonecomplete
METHODSets completed to 1.ParametersReturnsName Type Description pointer Number (pointer in Linear Memory)
Pointer to the main table. Nonecomplete
METHODSets completed to 1.ParametersReturnsName Type Default Description pointer void *
Pointer to the main table. Nonecreate
METHODCreates a main table.ParametersReturnsName Type Description retainCount Number
The retain count can be used to track usage (eg. multiple simultaneous access). If set to 0, the Decoder and the AdvancedAudioPlayer will take ownership on all the memory allocated (the main table, the buffer tables and their payloads) and will automatically free them using free(). The allocation should happen using malloc() (and not _aligned_malloc() or similar). samplerate Number
For compressed (not decoded) audio data this must be set to 0. For raw 16-bit PCM audio it must be correctly set right at the beginning (valid range: 8192 to 384000). size Number
For compressed (not decoded) audio data: the total payload size in bytes. For raw 16-bit PCM audio: the total duration in frames. Set to 0 if unknown at the beginning (eg. progressive download). Set it at any point later if it gets known. completed Boolean
False if additional buffers can be added (such as progressive download), true otherwise. Type Description Number (pointer in Linear Memory)
Pointer to the main table. create
METHODCreates a main table.ParametersReturnsName Type Default Description retainCount unsigned int
The retain count can be used to track usage (eg. multiple simultaneous access). If set to 0, the Decoder and the AdvancedAudioPlayer will take ownership on all the memory allocated (the main table, the buffer tables and their payloads) and will automatically free them using free(). The allocation should happen using malloc() (and not _aligned_malloc() or similar). samplerate unsigned int
For compressed (not decoded) audio data this must be set to 0. For raw 16-bit PCM audio it must be correctly set right at the beginning (valid range: 8192 to 384000). size unsigned int
For compressed (not decoded) audio data: the total payload size in bytes. For raw 16-bit PCM audio: the total duration in frames. Set to 0 if unknown at the beginning (eg. progressive download). Set it at any point later if it gets known. completed bool
False if additional buffers can be added (such as progressive download), true otherwise. Type Description void *
Pointer to the main table. createSelfContained
METHODCreates a main table with the payload included (special "self-contained" case).ParametersReturnsName Type Description retainCount Number
The retain count can be used to track usage (eg. multiple simultaneous access). If set to 0, the Decoder and the AdvancedAudioPlayer will take ownership on all the memory allocated (the main table, the buffer tables and their payloads) and will automatically free them using free(). The allocation should happen using malloc() (and not _aligned_malloc() or similar). samplerate Number
For compressed (not decoded) audio data this must be set to 0. For raw 16-bit PCM audio it must be correctly set right at the beginning (valid range: 8192 to 384000). size Number
For compressed (not decoded) audio data: the total payload size in bytes. For raw 16-bit PCM audio: the total duration in frames. Set to 0 if unknown at the beginning (eg. progressive download). Set it at any point later if it gets known. Type Description Number (pointer in Linear Memory)
Pointer to the main table. createSelfContained
METHODCreates a main table with the payload included (special "self-contained" case).ParametersReturnsName Type Default Description retainCount unsigned int
The retain count can be used to track usage (eg. multiple simultaneous access). If set to 0, the Decoder and the AdvancedAudioPlayer will take ownership on all the memory allocated (the main table, the buffer tables and their payloads) and will automatically free them using free(). The allocation should happen using malloc() (and not _aligned_malloc() or similar). samplerate unsigned int
For compressed (not decoded) audio data this must be set to 0. For raw 16-bit PCM audio it must be correctly set right at the beginning (valid range: 8192 to 384000). size unsigned int
For compressed (not decoded) audio data: the total payload size in bytes. For raw 16-bit PCM audio: the total duration in frames. Set to 0 if unknown at the beginning (eg. progressive download). Set it at any point later if it gets known. Type Description void *
Pointer to the main table. getSamplerate
METHODReturns the sample rate.ParametersReturnsName Type Description pointer Number (pointer in Linear Memory)
Pointer to the main table. Type Description Number
The sample rate. getSamplerate
METHODReturns the sample rate.ParametersReturnsName Type Default Description pointer void *
Pointer to the main table. Type Description unsigned int
The sample rate. getSize
METHODReturns the size.ParametersReturnsName Type Description pointer Number (pointer in Linear Memory)
Pointer to the main table. Type Description Number
The size. getSize
METHODReturns the size.ParametersReturnsName Type Default Description pointer void *
Pointer to the main table. Type Description unsigned int
The size. release
METHODDecrease the retain count by 1.ParametersReturnsName Type Description pointer Number (pointer in Linear Memory)
Pointer to the main table. Nonerelease
METHODDecrease the retain count by 1.ParametersReturnsName Type Default Description pointer void *
Pointer to the main table. Noneretain
METHODAdds 1 to retain count.ParametersReturnsName Type Description pointer Number (pointer in Linear Memory)
Pointer to the main table. Noneretain
METHODAdds 1 to retain count.ParametersReturnsName Type Default Description pointer void *
Pointer to the main table. NonesetSize
METHODSets the size.ParametersReturnsName Type Description pointer Number (pointer in Linear Memory)
Pointer to the main table. size Number
For compressed (not decoded) audio data: the total payload size in bytes. For raw 16-bit PCM audio: the total duration in frames. Set to 0 if unknown at the beginning (eg. progressive download). Set it at any point later if it gets known. NonesetSize
METHODSets the size.ParametersReturnsName Type Default Description pointer void *
Pointer to the main table. size unsigned int
For compressed (not decoded) audio data: the total payload size in bytes. For raw 16-bit PCM audio: the total duration in frames. Set to 0 if unknown at the beginning (eg. progressive download). Set it at any point later if it gets known. None