A modern audio codec supporting both lossless and lossy compression.
- Lossless mode: Adaptive Linear Predictive Coding (ALPC) with Rice encoding (~2-3x compression)
- Lossy mode: MDCT-based psychoacoustic transform coding (~10-30x compression)
- Dual-mode compression: Lossless for perfect quality, lossy for smaller files
- Lossy quality levels: Low (~48kbps), Medium (~128kbps), High (~192kbps), VeryHigh (~256kbps), Transparent (~320kbps)
- Psychoacoustic masking: Automatically discards inaudible frequencies for efficient lossy encoding
- Lossless compression with typical 2-3x compression ratios
- Mono and stereo audio support
- Multiple sample rates (44100, 48000, etc.)
- WebAssembly support for browser-based encoding/decoding
- CLI converter for converting MP3, WAV, FLAC, OGG to flo™
- Streaming decoder for real-time playback and progressive loading
- Rich metadata support (ID3v2.4 compatible + flo-unique extensions)
| Mode | Quality | Typical Ratio | Equivalent Bitrate | Use Case |
|---|---|---|---|---|
| Lossy | Low | ~30x | ~48 kbps | Speech, podcasts |
| Lossy | Medium | ~10x | ~128 kbps | General music |
| Lossy | High | ~6x | ~192 kbps | Quality listening |
| Lossy | VeryHigh | ~4x | ~256 kbps | Near-transparent |
| Lossy | Transparent | ~3x | ~320 kbps | Archival |
| Lossless | - | ~2-3x | - | Perfect quality |
# Build everything (native, CLI, WASM)
./scripts/build.sh
# Build only CLI converter
./scripts/build.sh reflo
# Build only WASM for web
./scripts/build.sh wasm# Convert MP3 to flo™ (lossless)
flo encode music.mp3 music.flo
# Convert with lossy mode (smaller file)
flo encode music.mp3 music.flo --lossy --quality high
# Lossy with bitrate target
flo encode music.mp3 music.flo --bitrate 192
# With metadata
flo encode music.mp3 music.flo --title "My Song" --artist "Artist" --album "Album"
# Convert flo™ back to WAV
flo decode music.flo music.wav
# Show file info
flo info music.flo
# Show info with metadata
flo info music.flo --metadata
# View full metadata (human-readable)
flo metadata music.flo
# View metadata as JSON
flo metadata music.flo --json
# Validate file
flo validate music.flo# Start dev server
./scripts/serve.sh
# Open http://localhost:8080The web demo supports:
- Encoding mode selection: Toggle between lossless and lossy
- Quality slider: Choose from 5 lossy quality levels
- Generating test signals (sine wave, stereo test, white noise)
- Recording from microphone
- Uploading audio files (MP3, WAV, FLAC, OGG, etc.)
- Displaying metadata, cover art, sections, and synced lyrics
- Downloading as .flo or .wav
flo™ supports comprehensive metadata in MessagePack format, compatible with ~80% of ID3v2.4 fields plus flo-unique extensions.
Unlike other formats where editing metadata requires:
- Re-encoding the entire file (lossy formats)
- Complex block manipulation (FLAC)
- Hope you have enough padding (MP3)
FLO's design separates metadata from audio data, allowing instant updates. No re-encoding. No quality loss. No waiting.
| Category | Fields |
|---|---|
| Identification | title, subtitle, album, track_number/total, disc_number/total, isrc |
| People | artist, album_artist, composer, conductor, lyricist, remixer |
| Properties | genre, mood, bpm, key, language |
| Dates | year, recording_time, release_time |
| Media | pictures (APIC), comments (COMM), lyrics (USLT), synced_lyrics (SYLT) |
| Feature | Description |
|---|---|
| waveform_data | Pre-computed waveform peaks for instant visualization |
| section_markers | Intro/verse/chorus/bridge/outro timestamps |
| bpm_map | Tempo changes throughout the track |
| key_changes | Musical key changes with timestamps |
| loudness_profile | Frame-by-frame LUFS measurements |
| synced_lyrics | First-party SYLT support with timestamps |
| creator_notes | Timestamped producer/artist commentary |
| collaboration_credits | Detailed per-person contribution tracking |
| remix_chain | Track derivation/sample history |
| animated_cover | GIF/WebP animated artwork |
| cover_variants | Multiple cover versions (explicit, clean, etc.) |
import { encode, get_metadata, get_cover_art, get_synced_lyrics } from './libflo_audio.js';
// Create metadata
const metadata = create_metadata_from_object({
title: "My Song",
artist: "Artist",
bpm: 128,
section_markers: [
{ timestamp_ms: 0, section_type: "intro" },
{ timestamp_ms: 30000, section_type: "verse" }
]
});
// Encode with metadata
const floData = encode(samples, 44100, 2, 16, metadata);
// Read metadata
const meta = get_metadata(floData);
const cover = get_cover_art(floData);
const lyrics = get_synced_lyrics(floData);The flo™ format uses:
- Magic:
FLO!(0x464C4F21) - 66-byte header with chunk offsets
- CRC32 for integrity
Lossless (ALPC):
- Frame types 1-12 indicate LPC prediction order
- Rice-coded residuals for entropy compression
- Perfect bit-for-bit reconstruction
Lossy (Transform):
- Frame type 253 indicates MDCT-based encoding
- 2048-sample blocks with 50% overlap (Vorbis window)
- Psychoacoustic model identifies masked frequencies
- Sparse RLE encoding for quantized coefficients
See flo_audio.ksy for the complete Kaitai Struct specification.
flo/
├── libflo/ # Core Rust library (also builds to WASM)
│ └── src/
│ ├── core/ # Core utilities (CRC32, Rice coding, types, metadata)
│ ├── lossless/ # Lossless encoder/decoder (ALPC)
│ └── lossy/ # Lossy encoder/decoder (MDCT, psychoacoustic)
├── reflo/ # CLI converter tool
├── Demo/ # Web demo with JS frontend
├── Examples/ # Example flo™ files
├── scripts/ # Build and test scripts
├── .github/workflows/ # CI configuration
└── flo_audio.ksy # Kaitai Struct specification
use libflo_audio::{Encoder, Decoder, LossyEncoder, QualityPreset, FloMetadata, SectionType};
// === Lossless Encoding ===
let encoder = Encoder::new(44100, 2, 16);
let flo_data = encoder.encode(&samples, &metadata)?;
// === Lossy Encoding ===
// With quality preset
let quality = QualityPreset::High.as_f32();
let mut lossy = LossyEncoder::new(44100, 2, quality);
let flo_data = lossy.encode_to_flo(&samples, &metadata)?;
// With bitrate target
let quality = QualityPreset::from_bitrate(192, 44100, 2).as_f32();
let mut lossy = LossyEncoder::new(44100, 2, quality);
let flo_data = lossy.encode_to_flo(&samples, &metadata)?;
// === Metadata ===
let mut meta = FloMetadata::new();
meta.title = Some("My Song".to_string());
meta.artist = Some("Artist".to_string());
meta.add_section(0, SectionType::Intro, None);
meta.add_section(30000, SectionType::Verse, Some("Verse 1"));
let metadata = meta.to_msgpack()?;
// Encode with metadata
let encoder = Encoder::new(44100, 2, 16);
let flo_data = encoder.encode(&samples, &metadata)?;
// Decode (auto-detects lossless vs lossy)
let decoder = Decoder::new();
let samples = decoder.decode(&flo_data)?;import init, {
encode, encode_lossy, encode_transform, encode_with_bitrate,
decode, info, validate, get_metadata
} from './pkg-libflo/libflo_audio.js';
await init();
// Lossless encoding
const floData = encode(samples, 44100, 2, 16, metadata);
// Lossy encoding with quality level (0-4)
// 0=Low, 1=Medium, 2=High, 3=VeryHigh, 4=Transparent
const floDataLossy = encode_lossy(samples, 44100, 2, 16, 2, metadata);
// Lossy encoding with continuous quality (0.0-1.0)
const floDataTransform = encode_transform(samples, 44100, 2, 16, 0.55, metadata);
// Lossy encoding with target bitrate (kbps)
const floDataBitrate = encode_with_bitrate(samples, 44100, 2, 16, 192, metadata);
// Decode (auto-detects mode)
const decoded = decode(floData);
// Get file info
const fileInfo = info(floData);
console.log(fileInfo.is_lossy, fileInfo.compression_ratio);
// Get metadata
const meta = get_metadata(floData);For real-time playback and progressive loading:
import init, { WasmStreamingDecoder } from './pkg-libflo/libflo_audio.js';
await init();
// Create streaming decoder
const decoder = new WasmStreamingDecoder();
// Feed data incrementally (e.g., from fetch chunks)
decoder.feed(chunk1);
decoder.feed(chunk2);
// Get file info once header is parsed
const info = decoder.get_info();
console.log(`Sample rate: ${info.sample_rate}, Channels: ${info.channels}`);
// Decode frame-by-frame for streaming playback
while (true) {
const samples = decoder.next_frame();
if (samples === null) break;
// Schedule samples for audio playback
playAudioSamples(samples);
}
// Or decode all available data at once
const allSamples = decoder.decode_available();
// Clean up
decoder.free();- WAV (via hound)
- MP3 (via symphonia)
- FLAC (via symphonia)
- OGG Vorbis (via symphonia)
- AAC/M4A (via symphonia)
Copyright 2026 NellowTCS
The flo™ codec is licensed under the Apache License, Version 2.0. Check LICENSE for more details.
"flo" and related branding are (not yet) trademarks of NellowTCS. While the flo™ codec is open-source, the name "flo" and the branding are protected (by common decency). You may not distribute modified versions of this software under the name "flo" without permission.