JavaScript API
The libflo WASM module provides full encoding, decoding, and metadata support for browsers.
Installation
npm
npm install @flo-audio/libflo
CDN / Direct
<script type="module">
import init, * as libflo from './pkg-libflo/libflo_audio.js';
await init();
</script>
Initialization
Always call init() before using any functions:
import init, { encode, decode } from '@flo-audio/libflo';
await init();
// Now you can use the API
Core Functions
encode()
Encode audio samples to lossless flo format.
encode(samples, sampleRate, channels, bitDepth, metadata) → Uint8Array
| Parameter | Type | Description |
|---|---|---|
samples |
Float32Array |
Interleaved audio samples (-1.0 to 1.0) |
sampleRate |
number |
Sample rate (e.g., 44100, 48000) |
channels |
number |
Number of channels (1 or 2) |
bitDepth |
number |
Bit depth (16, 24, or 32) |
metadata |
Uint8Array | null |
Optional MessagePack metadata |
Returns: Uint8Array - Encoded flo data
const samples = new Float32Array(44100 * 2); // 1 sec stereo
const floData = encode(samples, 44100, 2, 16, null);
encode_lossy()
Encode audio with lossy compression using quality presets.
encode_lossy(samples, sampleRate, channels, bitDepth, quality, metadata) → Uint8Array
| Parameter | Type | Description |
|---|---|---|
quality |
number |
Quality level: 0=Low, 1=Medium, 2=High, 3=VeryHigh, 4=Transparent |
// High quality lossy encoding
const floData = encode_lossy(samples, 44100, 2, 16, 2, null);
encode_transform()
Encode with continuous quality control (0.0 to 1.0).
encode_transform(samples, sampleRate, channels, bitDepth, quality, metadata) → Uint8Array
| Parameter | Type | Description |
|---|---|---|
quality |
number |
Quality from 0.0 (lowest) to 1.0 (highest) |
// 55% quality (roughly "high")
const floData = encode_transform(samples, 44100, 2, 16, 0.55, null);
encode_with_bitrate()
Encode targeting a specific bitrate.
encode_with_bitrate(samples, sampleRate, channels, bitDepth, bitrateKbps, metadata) → Uint8Array
| Parameter | Type | Description |
|---|---|---|
bitrateKbps |
number |
Target bitrate in kbps (e.g., 128, 192, 320) |
// Target 192 kbps
const floData = encode_with_bitrate(samples, 44100, 2, 16, 192, null);
decode()
Decode flo data to audio samples. Auto-detects lossless vs lossy.
decode(data) → Float32Array
| Parameter | Type | Description |
|---|---|---|
data |
Uint8Array |
flo file data |
Returns: Float32Array - Interleaved audio samples
const samples = decode(floData);
// samples.length = totalSamples * channels
info()
Get file information without decoding.
info(data) → Object
Returns:
{
sample_rate: number, // e.g., 44100
channels: number, // 1 or 2
bit_depth: number, // 16, 24, or 32
total_samples: number, // Total sample-frames (samples per channel)
duration_secs: number, // Duration in seconds
is_lossy: boolean, // true if lossy mode
compression_ratio: number // e.g., 2.5 for 2.5x compression
}
const fileInfo = info(floData);
console.log(`${fileInfo.duration_secs}s, ${fileInfo.is_lossy ? 'lossy' : 'lossless'}`);
validate()
Verify file integrity using CRC32.
validate(data) → boolean
if (validate(floData)) {
console.log('File is valid');
} else {
console.log('File is corrupted');
}
Metadata Functions
get_metadata()
Extract metadata as a JavaScript object.
get_metadata(data) → Object | null
const meta = get_metadata(floData);
if (meta) {
console.log(meta.title, meta.artist);
}
get_cover_art()
Extract cover art image.
get_cover_art(data) → Object | null
Returns:
{
mime_type: string, // e.g., "image/jpeg"
data: Uint8Array // Image bytes
}
const cover = get_cover_art(floData);
if (cover) {
const blob = new Blob([cover.data], { type: cover.mime_type });
const url = URL.createObjectURL(blob);
document.getElementById('cover').src = url;
}
get_synced_lyrics()
Extract synchronized lyrics.
get_synced_lyrics(data) → Array | null
Returns:
[
{ timestamp_ms: 0, text: "First line..." },
{ timestamp_ms: 5000, text: "Second line..." },
// ...
]
create_metadata_from_object()
Create metadata bytes from a JavaScript object.
create_metadata_from_object(obj) → Uint8Array
const metadata = create_metadata_from_object({
title: "My Song",
artist: "Artist Name",
album: "Album Name",
year: 2026,
genre: "Electronic",
bpm: 128,
section_markers: [
{ timestamp_ms: 0, section_type: "intro" },
{ timestamp_ms: 30000, section_type: "verse" },
{ timestamp_ms: 60000, section_type: "chorus" }
]
});
const floData = encode(samples, 44100, 2, 16, metadata);
Streaming Decoder
For real-time playback and progressive loading. See Streaming Guide for details.
import { WasmStreamingDecoder } from '@flo-audio/libflo';
const decoder = new WasmStreamingDecoder();
// Feed data incrementally
decoder.feed(chunk1);
decoder.feed(chunk2);
// Get info once header is parsed
const info = decoder.get_info();
// Decode frame-by-frame
while (true) {
const samples = decoder.next_frame();
if (samples === null) break;
playAudio(samples);
}
decoder.free();
Working with Web Audio API
From AudioBuffer to flo
async function encodeAudioBuffer(audioBuffer) {
const channels = audioBuffer.numberOfChannels;
const length = audioBuffer.length;
// Interleave channels
const samples = new Float32Array(length * channels);
for (let i = 0; i < length; i++) {
for (let ch = 0; ch < channels; ch++) {
samples[i * channels + ch] = audioBuffer.getChannelData(ch)[i];
}
}
return encode(samples, audioBuffer.sampleRate, channels, 16, null);
}
From flo to AudioBuffer
async function decodeToAudioBuffer(floData, audioContext) {
const samples = decode(floData);
const fileInfo = info(floData);
const audioBuffer = audioContext.createBuffer(
fileInfo.channels,
samples.length / fileInfo.channels,
fileInfo.sample_rate
);
// Deinterleave channels
for (let ch = 0; ch < fileInfo.channels; ch++) {
const channelData = audioBuffer.getChannelData(ch);
for (let i = 0; i < channelData.length; i++) {
channelData[i] = samples[i * fileInfo.channels + ch];
}
}
return audioBuffer;
}
Error Handling
All functions throw on error:
try {
const samples = decode(floData);
} catch (error) {
console.error('Decode failed:', error.message);
}
Common errors:
"Invalid magic bytes"- Not a flo file"Unsupported version"- File version too new"CRC32 mismatch"- File is corrupted"Invalid frame type"- Malformed audio data