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 file
return;
}
// 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 audio
return;
}
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');
// or
rawArrayBuffer = 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 pointer
return 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 ]

0versionShould be set to 0.
1retain countThe 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).
2samplerateSamplerate 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.
3sizeAdvancedAudioPlayer: 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.
4completedset it to 0 if additional buffers can be added (such as progressive download). Set it to 1 if finished adding additional buffers.
5address of the first buffer tableMemory 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 ]

0payload addressMemory address of the payload.
1sizeAdvancedAudioPlayer: the number of audio frames inside the payload. Decoder: the size of the payload in bytes.
2address of the next buffer tableMemory address of the next buffer table, or 0 if there are none (yet).
3reservedReserved. 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

    METHOD
    Adds data.
    Parameters
    NameTypeDescription
    tableNumber (pointer in Linear Memory)Pointer to the main table.
    payloadNumber (pointer in Linear Memory)Pointer to the payload. Should be allocated with malloc() (NOT new or _aligned_malloc).
    sizeNumberFor 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.
    Returns
    None
  • append

    METHOD
    Adds data.
    Parameters
    NameTypeDefaultDescription
    tablevoid *Pointer to the main table.
    payloadvoid *Pointer to the payload. Should be allocated with malloc() (NOT new or _aligned_malloc).
    sizeunsigned intFor 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.
    Returns
    None
  • complete

    METHOD
    Sets completed to 1.
    Parameters
    NameTypeDescription
    pointerNumber (pointer in Linear Memory)Pointer to the main table.
    Returns
    None
  • complete

    METHOD
    Sets completed to 1.
    Parameters
    NameTypeDefaultDescription
    pointervoid *Pointer to the main table.
    Returns
    None
  • create

    METHOD
    Creates a main table.
    Parameters
    NameTypeDescription
    retainCountNumberThe 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).
    samplerateNumberFor 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).
    sizeNumberFor 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.
    completedBooleanFalse if additional buffers can be added (such as progressive download), true otherwise.
    Returns
    TypeDescription
    Number (pointer in Linear Memory)Pointer to the main table.
  • create

    METHOD
    Creates a main table.
    Parameters
    NameTypeDefaultDescription
    retainCountunsigned intThe 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).
    samplerateunsigned intFor 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).
    sizeunsigned intFor 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.
    completedboolFalse if additional buffers can be added (such as progressive download), true otherwise.
    Returns
    TypeDescription
    void *Pointer to the main table.
  • createSelfContained

    METHOD
    Creates a main table with the payload included (special "self-contained" case).
    Parameters
    NameTypeDescription
    retainCountNumberThe 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).
    samplerateNumberFor 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).
    sizeNumberFor 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.
    Returns
    TypeDescription
    Number (pointer in Linear Memory)Pointer to the main table.
  • createSelfContained

    METHOD
    Creates a main table with the payload included (special "self-contained" case).
    Parameters
    NameTypeDefaultDescription
    retainCountunsigned intThe 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).
    samplerateunsigned intFor 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).
    sizeunsigned intFor 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.
    Returns
    TypeDescription
    void *Pointer to the main table.
  • getSamplerate

    METHOD
    Returns the sample rate.
    Parameters
    NameTypeDescription
    pointerNumber (pointer in Linear Memory)Pointer to the main table.
    Returns
    TypeDescription
    NumberThe sample rate.
  • getSamplerate

    METHOD
    Returns the sample rate.
    Parameters
    NameTypeDefaultDescription
    pointervoid *Pointer to the main table.
    Returns
    TypeDescription
    unsigned intThe sample rate.
  • getSize

    METHOD
    Returns the size.
    Parameters
    NameTypeDescription
    pointerNumber (pointer in Linear Memory)Pointer to the main table.
    Returns
    TypeDescription
    NumberThe size.
  • getSize

    METHOD
    Returns the size.
    Parameters
    NameTypeDefaultDescription
    pointervoid *Pointer to the main table.
    Returns
    TypeDescription
    unsigned intThe size.
  • release

    METHOD
    Decrease the retain count by 1.
    Parameters
    NameTypeDescription
    pointerNumber (pointer in Linear Memory)Pointer to the main table.
    Returns
    None
  • release

    METHOD
    Decrease the retain count by 1.
    Parameters
    NameTypeDefaultDescription
    pointervoid *Pointer to the main table.
    Returns
    None
  • retain

    METHOD
    Adds 1 to retain count.
    Parameters
    NameTypeDescription
    pointerNumber (pointer in Linear Memory)Pointer to the main table.
    Returns
    None
  • retain

    METHOD
    Adds 1 to retain count.
    Parameters
    NameTypeDefaultDescription
    pointervoid *Pointer to the main table.
    Returns
    None
  • setSize

    METHOD
    Sets the size.
    Parameters
    NameTypeDescription
    pointerNumber (pointer in Linear Memory)Pointer to the main table.
    sizeNumberFor 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.
    Returns
    None
  • setSize

    METHOD
    Sets the size.
    Parameters
    NameTypeDefaultDescription
    pointervoid *Pointer to the main table.
    sizeunsigned intFor 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.
    Returns
    None
v1.0.6