# Public API

[中文](../zh/API_SPECIFICATION.md)

The authoritative complete public signatures are generated by `moon info`: [root interface](../../pkg.generated.mbti), [facade interface](../../src/facade/pkg.generated.mbti), and each feature package's `pkg.generated.mbti`. The root module re-exports the facade without owning DSP implementations.

## Core extraction

| API | Input / result |
| --- | --- |
| `FeatureConfig::default()` | 16 kHz, 1024 FFT/window, 256 hop, 80 Mel bands, 13 MFCC, periodic Hann, reflect centering, power 2, Slaney, dB and orthonormal DCT |
| `analyze(samples, config?)` | `Result[AnalysisResult, MelError]`; shared STFT, filterbank, Mel, Log-Mel, MFCC |
| `stft(samples, config?)`, `stft_complex(samples, config)` | Real feature matrix or one-sided complex frames |
| `mel_filterbank(config)`, `mel_spectrogram(samples, config?)` | Triangular filterbank or Mel features |
| `log_mel_spectrogram(samples, config?)`, `mfcc(samples, config?)` | Configured log compression or cepstral coefficients |
| `decode_wav(bytes)` | `Result[AudioBuffer, MelError]`; integer PCM 8/16/24/32-bit, arithmetic channel downmix |
| `decode_wav_multichannel(bytes)` | `Result[MultiChannelAudioBuffer, MelError]`; preserves file channel order |
| `cmvn(matrix, normalize_variance?, variance_floor?)` | Offline per-row mean and optional population-variance normalization |
| `create_streaming_extractor(config?)` | Reusable incremental extractor; complete left-aligned frames |

`AudioBuffer::new(samples, sample_rate)` constructs a validated buffer. No `AudioBuffer::mfcc()` or `AudioBuffer::from_wav_bytes()` method is implemented: use the facade functions shown above. Defaults describe 16 kHz input; update `sample_rate` and `f_max` for another rate. A Whisper-size preset exists, but it is not a complete Whisper normalization frontend.

## Shapes and error boundaries

Feature matrices are `[n_rows][n_cols]`, with feature/frequency rows and time columns. STFT has `n_fft / 2 + 1` bins; the odd-size final bin is below Nyquist. Complex STFT/ISTFT frames use `[time][frequency]`. `FeatureMatrix::validate()` checks public mutable shape metadata; low-level indexing assumes valid dimensions/indices.

High-level transforms validate config and finite PCM. Config windows must satisfy `1 <= win_length <= n_fft`. Frequencies must be finite and inside `[0, sample_rate/2]`; dimensions/hop/Mel/MFCC must be positive; power/amin/reference must be finite positive; top_db must be finite nonnegative. Standalone FFT `fft`/`ifft` are radix-2, while `dft`/`idft` and STFT accept positive arbitrary sizes. Raw `fft_in_place` has explicit radix-2 and buffer preconditions; use the checked dispatcher for uncertain sizes.

## Reusable stages

Direct package imports expose `mel_from_spectrogram`, `apply_filterbank`, `log_mel_from_mel`, and `mfcc_from_log_mel`. They validate matrix shapes and let callers avoid repeated transforms. `analyze` is the normal facade entry for four core outputs; its filterbank is available for inspection.

## Streaming

`push_samples`, `available_frames`, `pop_mel_frames`, `pop_mfcc_frames`, and `reset` operate on a left-aligned timeline, even if `config.center` is true. Pops consume ready frames; selecting Mel and then MFCC does not return the same consumed frames twice. Incomplete tails remain buffered and are not padded/flushed. Hop gaps survive chunk boundaries. Log options and DCT normalization are honored; `top_db` is per returned matrix, so globally clipped offline MFCCs can differ across chunk batches.

In 0.1.6, prefer `try_push_samples(chunk)` for user input: it checks every sample before any mutation, returns `Result[Unit, MelError]` and treats an empty chunk as a no-op. Legacy `push_samples` remains unchecked. `buffered_samples()` reports retained samples excluding pending hop gaps. `pop_features()` returns `Result[StreamingFeatures, MelError]`, with aligned `mel`, `log_mel`, `mfcc` matrices derived from one consumed batch. Empty pops return correctly shaped zero-column matrices.

`FeatureMatrix::concat_frames(batches)` joins time columns without aliasing input data. Shapes must validate and feature counts must match, including empty batches; an empty batch list yields 0×0. Retained tail samples include frame overlap. `reset()` discards them. Use NaturalLog/Log10 for the supplied cross-batch/offline parity example; dB clipping remains batch-local.

## CMVN and WAV conventions

`cmvn` preserves input and applies row-wise utterance statistics over all time columns. It defaults to variance normalization with population variance (divide by frame count), and a `variance_floor` of `1e-10` in squared input units. Set `normalize_variance=false` for mean subtraction only. Constant rows become zero; empty matrices retain their shape. Ragged/non-finite inputs and nonpositive/non-finite floors return `DimensionMismatch`. Scaled moment accumulation avoids overflow on large finite inputs; a nonrepresentable centered result returns an error. This is not speaker-level or online sliding-window CMVN and does not imply Kaldi model compatibility. The general convention follows [Kaldi's CMVN description](https://kaldi-asr.org/doc/transform.html); no Kaldi source was copied.

WAV decoding accepts little-endian RIFF format tag 1: unsigned 8-bit and signed 16/24/32-bit integers scaled by `2^(bits-1)`. Both decoders share bounded chunk/format validation. Float, compressed and extensible formats are rejected explicitly. Mono decoding averages all channels; channel-preserving decoding does no spatial reordering. Format layout follows the [Microsoft WAVE format description](https://learn.microsoft.com/en-us/windows/win32/api/mmreg/ns-mmreg-waveformatex).

## Other feature families

Spectral descriptors, energy/RMS, deltas, Chroma, CQT, HPSS, multichannel ILD/IPD, onset, LPC/LPCC, YIN, tempo, contrast, loudness and effects remain available through the root. Their individual generated interfaces specify optional labels and types. They have algorithm-specific conventions: deltas use repeated HTK regression with nearest edges; CQT is direct kernel correlation; spectral descriptors use the configured spectrum power; spectral contrast uses empirical peak/valley quantiles; loudness has finite silent sentinels and has not been certified against a full compliance suite. Consult the health report before asserting equivalence with a different library.

`spectral_rolloff` accepts a finite `roll_percent` in `[0, 1]`, including both endpoints. `spectral_flatness` requires a finite, positive `amin`. Invalid values return `DimensionMismatch` before computing the STFT.

`chroma_from_spectrogram` requires finite `tuning` and a finite `f_min` in `[0, sample_rate / 2]`. Invalid tuning returns `DimensionMismatch`; an invalid cutoff returns `InvalidFrequencyRange` before filterbank access.

`super_flux` uses a frequency-neighborhood radius of `filter_size / 2` for sizes greater than one. Sizes of one or less use ordinary spectral flux, without frequency spreading; this also applies to `OnsetMethod::SuperFlux`.

`tempogram_from_onset` intersects integer lags with the inclusive `[min_bpm, max_bpm]` interval and the analysis window. If no lag fits, it returns `bpm=0`, empty `tempi` and a `0 x 0` tempogram instead of inventing a candidate outside the requested range.

## Browser transport

`src/bindings/web` exports `process_audio`, `process_audio_config`, `process_wav_bytes` and `decode_wav_audio` for JS. Core analysis transport includes matrices, actual filterbank and STFT preview-bin indices. Success/failure envelopes always reflect the computation outcome and errors are JSON-escaped. WASM artifacts are build targets; the current demo explicitly uses generated JS. Browser preview/file limits belong to the UI domain, not the MoonBit library API.

Browser transport declares only JS/WASM/WASM-GC support so Native builds do not try linking a browser foreign library as an executable. The core library and examples support Native.
