libflo-audio

Crates.iolibflo-audio
lib.rslibflo-audio
version0.1.2
created_at2026-01-03 06:34:56.005669+00
updated_at2026-01-03 19:44:57.172787+00
descriptionThe official encoder/decoder for the flo™ audio format
homepagehttps://github.com/flo-audio/flo
repositoryhttps://github.com/flo-audio/flo
max_upload_size
id2019693
size338,796
NellowTCS (NellowTCS)

documentation

README

libflo

A Rust library for encoding and decoding flo™ audio files with WASM support. Available on crates.io! https://crates.io/crates/libflo-audio

Features

  • Dual-mode compression: Lossless (ALPC) and lossy (MDCT transform)
  • ALPC Compression: Adaptive Linear Predictive Coding (orders 1-12) for lossless
  • Transform Coding: MDCT with psychoacoustic model for lossy (~10-30x compression)
  • Rice Coding: Efficient residual compression
  • CRC32 Integrity: Data chunk verification
  • Multi-channel: Mono and stereo support
  • Streaming Decoder: Frame-by-frame decoding for real-time playback
  • WASM Ready: Full WebAssembly compatibility
  • Clean API: Unified interface for CLI, WASM, and library use

Module Structure

src/
├── lib.rs              # Main exports and WASM bindings
├── core/               # Core utilities
│   ├── crc32.rs        # CRC32 checksums
│   ├── rice.rs         # Rice coding for entropy
│   ├── types.rs        # Common types (Header, Frame, etc.)
│   └── metadata.rs     # Metadata structures (ID3-like)
├── lossless/           # Lossless mode (ALPC)
│   ├── encoder.rs      # Lossless encoder
│   ├── decoder.rs      # Lossless decoder
│   └── lpc.rs          # LPC analysis/synthesis
├── lossy/              # Lossy mode (Transform)
│   ├── encoder.rs      # Transform encoder (TransformEncoder)
│   ├── decoder.rs      # Transform decoder (TransformDecoder)
│   ├── mdct.rs         # MDCT/IMDCT transform
│   └── psychoacoustic.rs # Perceptual model
├── streaming/          # Streaming decoder
│   ├── encoder.rs      # Frame-by-frame streaming encoder
│   ├── decoder.rs      # Frame-by-frame streaming decoder
├── reader.rs           # Binary file parser
└── writer.rs           # Binary file writer

Installation

Add to your Cargo.toml:

[dependencies]
libflo-audio = { version = "0.1.2" }

API Reference

Functions

Function Description
encode(samples, sample_rate, channels, bit_depth, metadata) Encode audio (lossless)
encode_lossy(samples, sample_rate, channels, bit_depth, quality, metadata) Encode audio (lossy, quality 0-4)
encode_transform(samples, sample_rate, channels, bit_depth, quality, metadata) Encode audio (lossy, quality 0.0-1.0)
encode_with_bitrate(samples, sample_rate, channels, bit_depth, bitrate_kbps, metadata) Encode audio (lossy, target bitrate)
decode(data) Decode flo™ file (auto-detects mode)
validate(data) Verify file integrity (CRC32)
info(data) Get file information
version() Get library version

Metadata Functions (No Re-encode!)

flo™ stores metadata separately from audio data, enabling instant metadata updates without re-encoding.

Function Description
update_metadata(data, new_metadata) Update metadata without re-encoding (WASM)
update_metadata_bytes(data, new_metadata) Update metadata without re-encoding (Rust)
strip_metadata(data) Remove all metadata (WASM)
strip_metadata_bytes(data) Remove all metadata (Rust)
get_metadata_bytes(data) Get raw metadata bytes (WASM)
get_metadata_bytes_native(data) Get raw metadata bytes (Rust)
has_metadata(data) Check if file has metadata (fast header check)

Streaming Functions

Function Description
WasmStreamingDecoder::new() Create new streaming decoder
feed(data) Feed bytes incrementally
get_info() Get file info (sample rate, channels, etc.)
next_frame() Decode next frame (returns samples or null)
decode_available() Decode all buffered data at once
reset() Reset decoder state
free() Release resources

Structs

Struct Description
Encoder Lossless encoder instance
LossyEncoder Transform-based lossy encoder
Decoder Lossless decoder instance
LossyDecoder Transform-based decoder
QualityPreset Quality levels (Low, Medium, High, VeryHigh, Transparent)
Reader Low-level binary parser
Writer Low-level binary writer
AudioInfo File information container

Quick Start

Rust (Lossless)

use libflo_audio::{Encoder, decode, info};

// Encode audio (lossless)
let samples: Vec<f32> = vec![0.0; 44100]; // 1 second of silence
let encoder = Encoder::new(44100, 2, 16);
let flo_data = encoder.encode(&samples, &[])?;

// Decode audio (auto-detects mode)
let decoded = decode(&flo_data)?;

// Get info
let file_info = info(&flo_data)?;
println!("Duration: {} seconds", file_info.duration_secs);

Rust (Lossy)

use libflo_audio::{LossyEncoder, QualityPreset, decode};

// Encode with quality preset
let quality = QualityPreset::High.as_f32(); // 0.55
let mut encoder = LossyEncoder::new(44100, 2, quality);
let flo_data = encoder.encode_to_flo(&samples, &[])?;

// Encode with bitrate target
let quality = QualityPreset::from_bitrate(192, 44100, 2).as_f32();
let mut encoder = LossyEncoder::new(44100, 2, quality);
let flo_data = encoder.encode_to_flo(&samples, &[])?;

// Decode (auto-detects lossy mode)
let decoded = decode(&flo_data)?;

JavaScript (WASM)

import init, { encode, encode_lossy, decode, info, validate, version } from './libflo_audio.js';

await init();

// Lossless encode
const samples = new Float32Array(44100);
const floData = encode(samples, 44100, 1, 16, null);

// Lossy encode (quality: 0=Low, 1=Medium, 2=High, 3=VeryHigh, 4=Transparent)
const floDataLossy = encode_lossy(samples, 44100, 1, 16, 2, null);

// Decode (auto-detects mode)
const decoded = decode(floData);

// Validate
const isValid = validate(floData);

// Info
const fileInfo = info(floData);
console.log(`Lossy: ${fileInfo.is_lossy}, Ratio: ${fileInfo.compression_ratio}`);

Streaming Decoder (JavaScript)

For real-time playback and progressive loading:

import init, { WasmStreamingDecoder } from './libflo_audio.js';

await init();

// Create streaming decoder
const decoder = new WasmStreamingDecoder();

// Feed data incrementally
decoder.feed(chunk);

// Get file 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;
    // Play samples...
}

decoder.free();

File Format

flo™ follows the specification in flo_audio.ksy:

┌─────────────────────────────────────┐
│ MAGIC "flo™!" (4 bytes)             │
├─────────────────────────────────────┤
│ HEADER (66 bytes)                   │
│   - version, sample_rate, channels  │
│   - bit_depth, compression_level    │
│   - CRC32, chunk sizes              │
├─────────────────────────────────────┤
│ TOC CHUNK                           │
│   - Frame seek table                │
│   - 20 bytes per entry              │
├─────────────────────────────────────┤
│ DATA CHUNK                          │
│   - Compressed audio frames         │
│   - 1 second per frame              │
├─────────────────────────────────────┤
│ EXTRA CHUNK (reserved)              │
├─────────────────────────────────────┤
│ META CHUNK (MessagePack)            │
└─────────────────────────────────────┘

Frame Types

Value Type Description
0 Silence No audio data stored
1-12 ALPC Lossless LPC with order N
253 Transform MDCT-based lossy encoding
254 Raw Uncompressed PCM
255 Reserved Future use

Building

Native

cargo build --release

WASM

cargo build --target wasm32-unknown-unknown --release
# Or with wasm-pack:
wasm-pack build --target web

Testing

cargo test

License

Apache-2.0

Commit count: 0

cargo fmt