Note: This doesn't work quite yet, but the structure is drafted out.
A stream that decodes ArrayBuffers into AudioBuffers. The decoders are made in WebAssembly so they are portable (Node.js and browser) and decent speed.
const decoder = require('audio-decode-wasm')
// Obtain codec module and initialize decoder:
const mod = await fetch('wav.wasm').then(req => WebAssembly.compileStreaming(res))
const decode = await decoder(mod)
// Decode ArrayBuffers:
decode(arrayBuf, (err, audioBuf) => {
// ...
})
npm i -D audio-decode-wasm
Initializes a decoder from a given [WebAssembly.Module
]. The available ones
can be seen in src/
.
const mod = new WebAssembly.Module(...)
decoder(mod).then(decode => {
// ...
})
Decodes arrayBuffer
and calls done(err, audioBuffer)
when finished.
To stop or "reset" the stream send decode(null)
.
const decode = await decoder(mod)
fetch('foo.wav')
.then(res => res.arrayBuffer())
.then(buf => {
decode(buf, (err, audio) => {
// ...
})
})
Promise.all([
decoder(...),
decoder(...)
]).then(([ wav, mp3, ... ]) => {
// ...
})
The decoders are wrote in C and compiled with Emscripten. The code is more restricted than a normal Emscripten runtime so it's cheap to load.
Each C modules has the functions
Context* open(unsigned char* input, float* output)
void process(Context* context, int amount)
From JS you can create the context with _open(input, output)
, where the parameters and return values are pointers on WebAssembly's memory, which JS can access and modify.
The Context
from C looks like:
typedef struct {
unsigned char* input;
float* output;
uint16_t number_of_channels;
uint32_t sample_rate;
unsigned char params;
// ...
} Context;
To construct an AudioBuffer
you need numberOfChannels
and sampleRate
, so JS imports a set_params(int, int)
function which C can call.
The stream routine would look like this:
- JS copies
ArrayBuffer
into WebAssembly's input buffer. - WebAssembly decodes it to planar float values on the output buffer.
- JS copies the output buffer as
Float32Array
s into anAudioBuffer
. - Repeat until stream is done.
Requires Emscripten, Binaryen, and WABT. Then, using make
:
make
to createdist/
make debug
to producedist/*.wat
make clean
to remove output