Skip to content

Latest commit

 

History

History
659 lines (524 loc) · 29.4 KB

File metadata and controls

659 lines (524 loc) · 29.4 KB

Falcon API Reference

Complete reference for every way to use Falcon: the falcon command-line tool, the Rust library crates, and the C / C++ bindings. For a project overview, benchmarks, and the bitstream format, see the main README.

Throughout, PCM is 32-bit float, nominally in the range [-1.0, 1.0], and the codec is tuned for 48 kHz. One Falcon frame is 960 samples per channel (20 ms @ 48 kHz). Other sample rates are stored faithfully in the header, but the band tables assume 48 kHz.


1. Overview — which surface to use

Falcon exposes the same codec through three surfaces. Pick by what you are building:

You want to… Use Entry points
Convert files, inspect a .falcon, or benchmark decode from a shell or script CLI (falcon) encode, decode, info, bench-decode
Encode/decode from a Rust program, with full control over configuration and streaming Rust crates falcon_encoder, falcon_decoder, falcon_core
Integrate into a C or C++ application (e.g. a game engine) C ABI / header-only C++ wrapper falcon.h, falcon.hpp

All three sit on the same falcon_core kernel, so a file produced by any of them decodes on any of the others.

  • The CLI is the quickest way to try Falcon and is what the benchmarks use.
  • The Rust API gives the deepest access: streaming frame-by-frame encode/decode, custom EncoderConfig, and direct header inspection.
  • The C API is a small, stable ABI designed for real-time playback (one 20 ms frame of look-ahead, O(frame) memory). The C++ wrapper adds RAII and typed error codes on top with zero extra dependencies.

2. Command-Line Interface

Falcon ships a single binary, falcon, with four subcommands. Build it with cargo build --release -p falcon_cli (the binary is named falcon).

falcon <SUBCOMMAND> [ARGS...] [OPTIONS]

Global behavior (standard clap conventions):

  • -h, --help is available on the top-level command and on every subcommand.
  • -V, --version prints the CLI version (top-level command).

Exit behavior

Situation Stream Exit code
Success stdout (progress/results) 0
Runtime error (bad file, I/O, invalid bitstream, …) Error: <message> on stderr 1
Usage / argument-parse error clap usage message on stderr 2

encode — WAV → Falcon

falcon encode <INPUT> <OUTPUT> [OPTIONS]

Reads an integer-PCM WAV file (e.g. 16- or 24-bit) and writes a .falcon bitstream. Channel count and sample rate are taken from the WAV header; stereo coupling (M/S) is enabled automatically when the input has ≥ 2 channels.

Positional arguments

Argument Description
<INPUT> Input WAV file (path). Required.
<OUTPUT> Output Falcon file (path). Required.

Options

Option Type / default Description
-b, --bitrate <BITRATE> u16, default 128 Target bitrate in kbps. This is the default rate-control target when nothing else is given; it is also recorded in the file header.
--target-bytes <TARGET_BYTES> usize, optional Rate control: pick the finest quality whose total output ≤ N bytes. Overrides --target-kbps and --bitrate.
--target-kbps <TARGET_KBPS> f32, optional Rate control: target a bitrate of R kbps (converted to a byte budget from the clip duration). Overridden by --target-bytes.
--quality-index <QUALITY_INDEX> u8 (0–255), optional Directly set the quality index (0 = finest, 255 = coarsest). Bypasses rate control entirely.

Rate-control resolution (highest priority first — matches the source):

  1. --quality-index set → rate control is disabled; that fixed index is used.
  2. else --target-bytes → exact byte budget.
  3. else --target-kbps → byte budget derived from duration.
  4. else --bitrate (default 128) → byte budget derived from duration.

See also the Rate Control section of the README.

Examples

# Default: constant-quality VBR toward 128 kbps
falcon encode input.wav output.falcon

# Explicit bitrate
falcon encode input.wav output.falcon --bitrate 96

# Exact size target (finest quality that fits 500,000 bytes)
falcon encode input.wav output.falcon --target-bytes 500000

# Fixed quality index, no rate control
falcon encode input.wav output.falcon --quality-index 20

On success it prints the input format, the resolved rate-control target, frame/byte counts, average bitrate, encode time, and compression ratio.

decode — Falcon → WAV

falcon decode <INPUT> <OUTPUT>
Argument Description
<INPUT> Input .falcon file. Required.
<OUTPUT> Output WAV file. Required.

Reconstructs a 16-bit integer PCM WAV at the stream's sample rate and channel count, and reports sample rate, channels, samples per channel, decode time, and the real-time decode ratio.

info — inspect a Falcon file

falcon info <INPUT>
Argument Description
<INPUT> Input .falcon file. Required.

Prints the file header: sample rate, channel count, channel layout, total frames, bitrate, duration (frames × 20 ms), file size, and — if any bit is set — the LFE channel mask.

bench-decode — measure decode speed

falcon bench-decode <INPUT> [-i <ITERATIONS>]
Argument / option Type / default Description
<INPUT> — Input .falcon file. Required.
-i, --iterations <ITERATIONS> u32, default 10 Number of decode iterations to average over.

Loads the whole file into memory, then decodes it ITERATIONS times and reports first-iteration time, average decode time, audio duration, real-time ratio, and throughput in MB/s.


3. Rust library

Three crates make up the library:

Crate Role Key public items
falcon_core Shared kernel: types, constants, error type FalconError, FileHeader, ChannelLayout, Mode, FRAME_SIZE, VERSION, …
falcon_encoder Encoder encode::encode_file, Encoder, EncoderConfig, EncoderStats
falcon_decoder Decoder decode::decode_file, Decoder, DecoderConfig, FRAME_SAMPLES

Add them to your Cargo.toml as dependencies (by path or git, pointing at this workspace). The encoder and decoder both re-export the falcon_core items you need, so you rarely have to depend on falcon_core directly.

Sample-format expectations

Where Layout Type
encode_file input De-interleaved, one Vec<f32> per channel (&[Vec<f32>]) f32, nominally [-1.0, 1.0]
Encoder::encode_frame input Interleaved, exactly channels × FRAME_SIZE (= channels × 960) samples f32
decode_file output De-interleaved, one Vec<f32> per channel f32
Decoder::get_interleaved_samples output Interleaved f32

Sample rate is u32 Hz (use 48000); channel count is u8 (1–64). The CLI is the place that converts to/from i16/24-bit WAV — the library itself is f32 end to end.

3.1 falcon_core — types you will touch

pub enum FalconError {         // implements std::error::Error (via thiserror)
    InvalidMagic,
    UnsupportedVersion(u8),
    InvalidFrameHeader,
    CrcMismatch { expected: u8, actual: u8 },
    UnexpectedEof,
    InvalidChannelCount(u8),
    InvalidSampleRate(u32),
    BitstreamError(String),
    IoError(std::io::Error),   // From<std::io::Error>
    EncoderError(String),
    DecoderError(String),
}
pub type Result<T> = std::result::Result<T, FalconError>;

pub struct FileHeader {
    pub sample_rate: u32,
    pub channels: u8,
    pub channel_layout: ChannelLayout,
    pub total_frames: u32,
    pub bitrate: u16,          // kbps; 0 = VBR
    pub lfe_mask: u64,         // one bit per channel
    pub quality_index: u8,     // 0 = finest .. 255 = coarsest
    pub quality_frac: u8,      // 0..15, sixteenths of one index step
}

pub enum ChannelLayout { Mono, Stereo, Surround51, Surround71, Custom(u8) }
// ChannelLayout::channel_count() -> usize
// ChannelLayout::from_channel_count(u8) -> ChannelLayout

pub enum Mode {                // frame coding mode (2-bit header field)
    Mdct,      // 0: MDCT frame, long-window chain
    Flagged,   // 1: MDCT frame with the transient flag (four short blocks)
    Ext,       // 2: overflow extension (MDCT layout at a coarser rate level)
    Silent,    // 3: silent frame (optionally the LSB-floor payload)
}

Useful constants (all pub in falcon_core):

Constant Value Meaning
MAGIC b"FALC" File magic
VERSION 0x10 Current bitstream version
FRAME_SIZE 960 Samples per channel per frame (20 ms @ 48 kHz)
MAX_CHANNELS 64 Maximum channel count
NUM_BANDS 27 Bark-scale bands
DEFAULT_QUALITY_INDEX 43 Default quality index

3.2 falcon_encoder

High-level, one call (recommended):

pub fn encode_file<W: std::io::Write>(
    writer: W,
    samples: &[Vec<f32>],   // one Vec per channel (de-interleaved)
    sample_rate: u32,
    config: EncoderConfig,
) -> Result<EncoderStats, FalconError>;

EncoderStats { total_frames: u32, bytes_written: usize, average_bitrate: u16 }.

Configuration:

pub struct EncoderConfig {
    pub bitrate: u16,               // nominal kbps, recorded in the header (default 128)
    pub stereo_coupling: bool,      // M/S coupling (default true)
    pub ra_interval: u32,           // random-access interval in frames (default 50)
    pub quality_index: u8,          // 0..255; ignored when target_bytes is set
    pub quality_frac: u8,           // 0..15, sixteenths of a step; ignored when target_bytes is set
    pub target_bytes: Option<usize>,// Some(n): pick finest quality whose file is <= n bytes
}
impl Default for EncoderConfig { /* bitrate 128, coupling on, ra_interval 50,
                                    quality_index DEFAULT_QUALITY_INDEX, quality_frac 0,
                                    target_bytes None */ }

Lower-level, streaming (when you produce audio frame by frame):

pub struct Encoder<W: std::io::Write> { /* ... */ }
impl<W: std::io::Write> Encoder<W> {
    pub fn new(writer: W, sample_rate: u32, channels: u8) -> Result<Self, FalconError>;
    pub fn with_config(writer: W, sample_rate: u32, channels: u8,
                       config: EncoderConfig) -> Result<Self, FalconError>;
    pub fn with_config_and_frames(writer: W, sample_rate: u32, channels: u8,
                                  config: EncoderConfig, total_frames: u32)
                                  -> Result<Self, FalconError>;
    // `samples` is interleaved and must be exactly channels * FRAME_SIZE long.
    pub fn encode_frame(&mut self, samples: &[f32]) -> Result<(), FalconError>;
}

Most callers should prefer encode_file: it handles look-ahead transient detection, the M/S pre-scan, rate control, and header total_frames for you.

3.3 falcon_decoder

High-level, one call (recommended):

pub fn decode_file<R: std::io::Read>(reader: R)
    -> Result<(Vec<Vec<f32>>, u32, u8), FalconError>;
//              ^ per-channel   ^ sample  ^ channels
//                samples         rate

The first bitstream frame is TDAC priming and is dropped internally, so the returned per-channel length is (total_frames - 1) × 960; it may include up to one frame of trailing zero padding (the container stores whole frames).

Lower-level, streaming:

pub struct Decoder<R: std::io::Read> { /* ... */ }
impl<R: std::io::Read> Decoder<R> {
    pub fn new(reader: R) -> Result<Self, FalconError>;
    pub fn with_config(reader: R, config: DecoderConfig) -> Result<Self, FalconError>;
    pub fn header(&self) -> &FileHeader;
    pub fn sample_rate(&self) -> u32;
    pub fn channels(&self) -> usize;
    pub fn current_frame(&self) -> u32;
    pub fn total_frames(&self) -> u32;
    pub fn decode_frame(&mut self) -> Result<usize, FalconError>; // samples/ch, 0 = EOF
    pub fn get_samples(&self, channel: usize) -> &[f32];          // last decoded frame
    pub fn get_interleaved_samples(&self) -> Vec<f32>;            // last decoded frame
    pub fn reset_state(&mut self);                                // for seeking
    // Diagnostics (state of the last decoded MDCT frame):
    pub fn band_classes(&self, channel: usize) -> &[u8; NUM_BANDS]; // coding class per band
    pub fn last_class_update(&self) -> bool;                      // frame carried a class section
    pub fn last_shape_bits(&self) -> usize;                       // size of its shape section
}

pub struct DecoderConfig { pub verify_crc: bool }  // Default: verify_crc = true
pub const FRAME_SAMPLES: usize = 960;              // == falcon_core::FRAME_SIZE

Decoder::new parses the header immediately (so header()/sample_rate()/ channels() are valid before decoding). Each decode_frame() returns 960 until end of stream, then 0; the freshly decoded frame is read back with get_samples(ch) or get_interleaved_samples().

3.4 Minimal encode-then-decode example

use std::io::Cursor;
use falcon_encoder::{encode::encode_file, EncoderConfig};
use falcon_decoder::decode::decode_file;
use falcon_core::FalconError;

fn main() -> Result<(), FalconError> {
    // 1 second of 48 kHz stereo, de-interleaved f32 in [-1.0, 1.0].
    let sample_rate = 48_000u32;
    let n = sample_rate as usize;
    let left:  Vec<f32> = (0..n).map(|i| 0.2 * (i as f32 * 0.05).sin()).collect();
    let right: Vec<f32> = left.clone();
    let channels = vec![left, right];

    // Encode into an in-memory buffer (&mut Vec<u8> implements Write).
    let mut buf: Vec<u8> = Vec::new();
    let stats = encode_file(&mut buf, &channels, sample_rate, EncoderConfig::default())?;
    println!("encoded {} frames, {} bytes", stats.total_frames, stats.bytes_written);

    // Decode it back.
    let (decoded, sr, ch) = decode_file(Cursor::new(buf))?;
    println!("decoded {} ch @ {} Hz, {} samples/ch", ch, sr, decoded[0].len());
    Ok(())
}

4. C API (falcon.h)

C99 header at falcon_capi/include/falcon.h. Build the library with cargo build --release -p falcon_capi; a static library, a DLL, and an import library land in target/release/. See falcon_capi/README.md for per-toolchain link lines (MSVC, MinGW, CMake).

All PCM is interleaved 32-bit float. data/len refer to a complete Falcon file already in memory — the decoder is not a byte-stream parser.

Error codes

Return-code convention: 0 is success, negative values are errors. Getter functions (*_sample_rate, *_channels, *_total_samples) return 0 on a NULL handle instead of an error code.

Macro Value Meaning
FALCON_OK 0 Success
FALCON_ERR_INVALID_ARG -1 NULL pointer or out-of-domain value
FALCON_ERR_INVALID_DATA -2 Not a valid Falcon bitstream
FALCON_ERR_ALLOC -3 Memory allocation failed
FALCON_ERR_PANIC -4 Internal error caught at the FFI boundary
FALCON_ERR_UNSUPPORTED -5 Operation not supported
FALCON_ERR_IO -6 I/O error
FALCON_ERR_ENCODE -7 Encoding failed
FALCON_ERR_OUT_OF_RANGE -8 Position beyond end of stream

Types

  • typedef struct FalconDecoder FalconDecoder; — opaque streaming decoder handle. Create with falcon_decoder_open, destroy with falcon_decoder_close.

Streaming decoder

Function Signature Notes
falcon_decoder_open FalconDecoder* falcon_decoder_open(const uint8_t* data, size_t len) Parses the header immediately; copies data internally, so the caller may free its buffer right after this returns. Returns NULL on bad args or an invalid stream.
falcon_decoder_sample_rate int falcon_decoder_sample_rate(const FalconDecoder* dec) Hz. 0 if dec is NULL.
falcon_decoder_channels int falcon_decoder_channels(const FalconDecoder* dec) 1 = mono, 2 = stereo, …. 0 if dec is NULL.
falcon_decoder_total_samples uint64_t falcon_decoder_total_samples(const FalconDecoder* dec) Total PCM samples per channel. May include up to one frame of trailing zero padding.
falcon_decoder_read_f32 int64_t falcon_decoder_read_f32(FalconDecoder* dec, float* out_interleaved, size_t max_frames) Decodes up to max_frames frames of interleaved f32. out_interleaved must hold max_frames × channels floats. Returns frames written (> 0), 0 at end of stream, or a negative FALCON_ERR_*.
falcon_decoder_seek int falcon_decoder_seek(FalconDecoder* dec, uint64_t sample_pos) Seek so the next read starts at absolute per-channel sample sample_pos (0 = start). Sample-exact but linear (decode-and-discard; backward seeks restart from the beginning) — avoid per-tick seeking of long streams. Returns FALCON_OK, FALCON_ERR_OUT_OF_RANGE if past the end, or another negative code.
falcon_decoder_close void falcon_decoder_close(FalconDecoder* dec) Destroy the handle. NULL is a safe no-op.

One-shot helpers

Function Signature Notes
falcon_decode_buffer int falcon_decode_buffer(const uint8_t* data, size_t len, float** out, uint64_t* out_frames, int* channels, int* sample_rate) Decodes an entire in-memory file in one call. On success *out points to (*out_frames × *channels) interleaved floats owned by the library — release with falcon_free. Returns FALCON_OK or a negative code.
falcon_encode_buffer int falcon_encode_buffer(const float* pcm_interleaved, uint64_t frames, int channels, int sample_rate, int32_t target_bytes, int32_t target_kbps, uint8_t** out, size_t* out_len) Encodes interleaved f32 PCM to a complete Falcon file. frames > 0, channels 1–64. Rate control: target_bytes > 0 is a total-file byte budget; else target_kbps > 0 sets the bitrate; if both <= 0, defaults to 128 kbps. On success *out (*out_len bytes) is library-owned — release with falcon_free. Returns FALCON_OK or a negative code.
falcon_free void falcon_free(void* ptr) Release a buffer returned by falcon_decode_buffer / falcon_encode_buffer. Never use free/delete on these. NULL is a safe no-op.

Version / errors

Function Signature Notes
falcon_version const char* falcon_version(void) Static NUL-terminated version string (the library semver, e.g. "2.0.0"). Never NULL.
falcon_error_message const char* falcon_error_message(int code) Static human-readable message for a FALCON_* code (unknown codes map to "unknown error code"). Never NULL.

Ownership, lifetime, and thread-safety

  • Ownership. Buffers delivered through float** / uint8_t** out-parameters are allocated by the library and must be released with falcon_free. Strings from falcon_version / falcon_error_message are static — do not free them. data passed to open/decode_buffer is copied, so it remains the caller's to free.
  • Lifetime. A FalconDecoder* is valid from open until close.
  • Thread-safety. A single FalconDecoder* is not thread-safe; use one handle per thread or serialize access. Distinct handles are fully independent. The stateless one-shot and version/error functions are safe to call concurrently.
  • Panics. Every entry point is wrapped so an internal Rust panic returns FALCON_ERR_PANIC rather than unwinding into C. (The workspace release profile builds with panic = "abort", so a panic aborts the process; all fallible paths use Result, making this a last-resort net.)
  • Linker note (MSVC): define FALCON_DLL before including falcon.h when linking against the DLL to get __declspec(dllimport); it is optional for import-library linking.

Compile-ready C snippet (encode → decode round trip)

/* cc example.c -I falcon_capi/include -L target/release -lfalcon_capi -lm */
#include <falcon.h>
#include <math.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>

int main(void) {
    const int sr = 48000, ch = 2;
    const uint64_t frames = 48000;            /* 1 second, stereo */
    float* pcm = malloc(sizeof(float) * frames * ch);
    for (uint64_t i = 0; i < frames; ++i) {
        float s = 0.2f * sinf((float)i * 0.05f);
        pcm[i * ch + 0] = s;                  /* interleaved */
        pcm[i * ch + 1] = s;
    }

    uint8_t* enc = NULL; size_t enc_len = 0;
    int rc = falcon_encode_buffer(pcm, frames, ch, sr,
                                  /*target_bytes*/ 0, /*target_kbps*/ 128,
                                  &enc, &enc_len);
    if (rc != FALCON_OK) {
        fprintf(stderr, "encode: %s\n", falcon_error_message(rc));
        return 1;
    }
    printf("encoded %zu bytes\n", enc_len);

    float* out = NULL; uint64_t out_frames = 0; int out_ch = 0, out_sr = 0;
    rc = falcon_decode_buffer(enc, enc_len, &out, &out_frames, &out_ch, &out_sr);
    if (rc != FALCON_OK) {
        fprintf(stderr, "decode: %s\n", falcon_error_message(rc));
        falcon_free(enc);
        return 1;
    }
    printf("decoded %llu frames, %d ch @ %d Hz\n",
           (unsigned long long)out_frames, out_ch, out_sr);

    falcon_free(enc);
    falcon_free(out);
    free(pcm);
    return 0;
}

5. C++ API (falcon.hpp)

Header-only C++17 RAII wrapper at falcon_capi/include/falcon.hpp. It includes falcon.h and links against the same library. No exceptions are thrown — fallible calls return falcon::Error (an expected-style pattern) and handle validity is checked with explicit operator bool. Everything lives in namespace falcon.

Free functions

Item Signature Notes
falcon::version const char* version() noexcept Wraps falcon_version.
falcon::errorMessage const char* errorMessage(Error) / (int) noexcept Wraps falcon_error_message.
falcon::decodeAll Error decodeAll(const void* data, std::size_t len, DecodedAudio& out) noexcept One-shot decode; fills out and returns Error::Ok, else an error code. Handles falcon_free internally.
falcon::encode Error encode(const float* pcmInterleaved, std::uint64_t frames, int channels, int sampleRate, std::int32_t targetBytes, std::int32_t targetKbps, std::vector<std::uint8_t>& out) noexcept One-shot encode into out. Same rate-control rule as the C API (targetBytes > 0 wins, else targetKbps > 0, else 128 kbps).

enum class falcon::Error : int

Mirrors the FALCON_* codes: Ok, InvalidArg, InvalidData, Alloc, Panic, Unsupported, Io, Encode, OutOfRange.

struct falcon::DecodedAudio

struct DecodedAudio {
    std::vector<float> samples;    // interleaved, frames * channels floats
    std::uint64_t      frames = 0; // samples per channel
    int                channels = 0;
    int                sampleRate = 0;
};

class falcon::Decoder — RAII streaming decoder (move-only)

Member Signature Notes
Decoder::open static Decoder open(const void* data, std::size_t len) noexcept Factory. Copies data. Check the result with operator bool.
operator bool explicit operator bool() const noexcept True iff open succeeded and not yet closed.
sampleRate int sampleRate() const noexcept
channels int channels() const noexcept
totalSamples std::uint64_t totalSamples() const noexcept Per channel; may include padding.
read std::int64_t read(float* out, std::size_t maxFrames) noexcept Frames written, 0 at EOF, negative Error code on failure. out capacity ≥ maxFrames * channels().
seek Error seek(std::uint64_t samplePos) noexcept Sample-exact, O(n) linear (see the C API note).
close void close() noexcept Also called by the destructor.
native FalconDecoder* native() const noexcept Underlying C handle for interop; ownership stays with the object.

Decoder is move-only (copy is deleted); the destructor releases the handle, so there is nothing to free manually. It is not thread-safe, matching the C handle.

Compile-ready C++17 snippet (encode → streaming decode)

// c++ -std=c++17 example.cpp -I falcon_capi/include -L target/release -lfalcon_capi
#include <falcon.hpp>
#include <cmath>
#include <cstdint>
#include <cstdio>
#include <vector>

int main() {
    const int sr = 48000, ch = 2;
    const std::uint64_t frames = 48000;            // 1 second, stereo
    std::vector<float> pcm(frames * ch);
    for (std::uint64_t i = 0; i < frames; ++i) {
        float s = 0.2f * std::sin(float(i) * 0.05f);
        pcm[i * ch + 0] = s;                       // interleaved
        pcm[i * ch + 1] = s;
    }

    std::vector<std::uint8_t> file;
    falcon::Error e = falcon::encode(pcm.data(), frames, ch, sr,
                                     /*targetBytes*/ 0, /*targetKbps*/ 128, file);
    if (e != falcon::Error::Ok) {
        std::fprintf(stderr, "encode: %s\n", falcon::errorMessage(e));
        return 1;
    }

    falcon::Decoder dec = falcon::Decoder::open(file.data(), file.size());
    if (!dec) { std::fprintf(stderr, "open failed (invalid stream?)\n"); return 1; }

    std::vector<float> block(1024 * dec.channels());
    std::int64_t n = 0;
    std::uint64_t total = 0;
    while ((n = dec.read(block.data(), 1024)) > 0) total += static_cast<std::uint64_t>(n);
    if (n < 0) {
        std::fprintf(stderr, "read: %s\n", falcon::errorMessage(static_cast<int>(n)));
        return 1;
    }

    std::printf("decoded %llu frames, %d ch @ %d Hz\n",
                static_cast<unsigned long long>(total), dec.channels(), dec.sampleRate());
    return 0;   // dec's destructor releases the handle
}

A fuller, cross-checking example lives at falcon_capi/examples/cpp/decode_example.cpp (with a CMakeLists.txt alongside it).


6. Bitstream, versioning, and the v2 stability promise

Every Falcon file starts with a 25-byte header ("FALC" magic, a 1-byte version, 16-bit flags carrying the quality index, a 24-bit sample rate, the channel count, total frames, a nominal bitrate, and a 64-bit LFE mask), followed by frames of [2-byte frame header][payload][CRC-8]. The current bitstream version is falcon_core::VERSION = 0x10. For the exact byte layout of the file header, frame header, and MDCT payload, see Bitstream Format in the README.

  • Version handshake. The decoder checks the magic and version on open; a stream whose version it does not understand fails with FalconError::UnsupportedVersion (FALCON_ERR_INVALID_DATA at the C boundary). The band layout, cell tables, prefix-code tables and the pulse-count law are part of the encoder/decoder contract, so streams are not compatible across version bumps — the version byte is the guard.
  • 1.x streams are not decodable by 2.x (and vice versa): 1.x wrote version 0x04. Re-encode from the source audio.
  • v2 stability promise. For the v2.x series the 0x10 bitstream is frozen: any v2.x decoder decodes any v2.x-encoded file. The APIs documented here — the CLI subcommands/flags, the Rust encode_file / decode_file entry points, and the C ABI in falcon.h — are stable across v2.x; additions will be backward-compatible.
  • Room to grow without breaking you. The bitstream supports random-access frames (the encoder's ra_interval); the CLI and C API currently emit only the first one. Periodic RA frames plus a seek index would make seeking fast (today it is sample-exact but linear) with no change to the C API — falcon_decoder_seek keeps the same signature and semantics.

7. Migrating from 1.x

1.x 2.x
EncoderConfig { quality: Quality::…, .. } Remove the field; it had no effect. Use quality_index / target_bytes for quality vs size.
CLI -q, --quality <preset> Removed (it had no effect). Use --quality-index, --target-bytes or --target-kbps.
falcon_encoder::PsychoacousticModel, falcon_encoder::psychoacoustic Removed (never consulted by the encoder).
falcon_core::coeffcode::{k_scale, k_scale_frac, K_MIN, K_MAX, SIGMA_X} falcon_core::rate::… (also re-exported as falcon_core::k_scale*).
falcon_core::{BITS_PER_BAND, quantize_variable, dequantize_variable, pvq_lite, …} Removed (legacy scalar layout).
Mode::Lpc / Mode::Hybrid Mode::Flagged / Mode::Ext (same header values 1 / 2, new meaning for 2).
ModeDetector::detect(samples, energies), DetectedMode::{Speech, Music, …} ModeDetector::detect(samples), DetectedMode::{Active, Silent}.
FalconError::RansError Removed (rANS is gone).
.falcon files written by 1.x Not decodable; re-encode from the source audio.

The C ABI (falcon.h) and the C++ wrapper (falcon.hpp) are unchanged apart from the version string.


See also: the project README for benchmarks, design philosophy, and build instructions, and falcon_capi/README.md for detailed C/C++ link lines per toolchain.