# melpe-rs
Pure Rust implementation of the **MELPe** (Mixed Excitation Linear Prediction — enhanced) vocoder, conforming to **STANAG 4591** / **NATO narrowband voice coding**.
600 bps operation with superframe architecture. Zero heap allocation. `no_std` compatible for embedded/Xtensa targets.
## Features
- **600 bps codec** — 540 samples in, 6 bytes out (and back)
- **Superframe architecture** — 3 × 22.5 ms frames packed into a single 67.5 ms superframe
- **Full analysis chain** — pre-emphasis → LPC → LSF → pitch detection → bandpass voicing → quantization → bitstream packing
- **Full synthesis chain** — unpacking → dequantization → mixed excitation → all-pole filter → de-emphasis
- **Pure `core`** — no heap allocation in production code, all fixed-size arrays
- **Dual math backend** — native `f32` methods under `std`, [`libm`](https://crates.io/crates/libm) under `no_std`
## Quick start
```rust
use melpe::encoder::Encoder;
use melpe::decoder::Decoder;
use melpe::core_types::{SUPERFRAME_SAMPLES, SUPERFRAME_BYTES_600};
let mut enc = Encoder::new();
let mut dec = Decoder::new();
// Audio in: 540 f32 samples at 8 kHz
let samples = [0.0f32; SUPERFRAME_SAMPLES];
// Encode: 540 samples → 6 bytes
let mut bitstream = [0u8; SUPERFRAME_BYTES_600];
enc.encode(&samples, &mut bitstream);
// Decode: 6 bytes → 540 samples
let mut output = [0.0f32; SUPERFRAME_SAMPLES];
dec.decode(&bitstream, &mut output);
```
## Feature flags
| `std` | ✅ | Uses native `f32` math (hardware SIMD on x86_64) |
| `embedded` | — | `#![no_std]`, routes math through `libm` for bare-metal targets |
```sh
# Desktop / server (default)
cargo add melpe-rs
# Embedded / Xtensa / no_std
cargo add melpe-rs --no-default-features --features embedded
```
## Architecture
```
samples ──→ Encoder ──→ 6 bytes ──→ Decoder ──→ samples
│ │
├─ lpc.rs ├─ bitstream.rs (unpack)
├─ pitch.rs ├─ quantize.rs (dequantize)
├─ voicing.rs ├─ voicing.rs (mixed excitation)
├─ quantize.rs └─ synthesis.rs (all-pole filter)
└─ bitstream.rs (pack)
```
### Modules
| `core_types` | Constants, frame geometry, superframe structures |
| `lpc` | Autocorrelation, Levinson-Durbin, LPC↔LSF conversion, Hamming window |
| `pitch` | Normalized autocorrelation pitch estimator with parabolic interpolation |
| `voicing` | 5-band bandpass filter bank, per-band voicing strength, mixed excitation |
| `quantize` | Scalar LSF/pitch/gain quantization, voicing collapse, LSF interpolation |
| `bitstream` | Bit-level packing/unpacking to 6-byte superframe format |
| `synthesis` | All-pole filter, de-emphasis, frame-level synthesis processor |
| `encoder` | Top-level encode: 540 samples → 6 bytes |
| `decoder` | Top-level decode: 6 bytes → 540 samples |
| `math` | `no_std` shim — `std` ↔ `libm` dispatch for all floating-point intrinsics |
## Codec parameters
| Sample rate | 8000 Hz |
| Frame size | 180 samples (22.5 ms) |
| Superframe | 3 frames, 540 samples (67.5 ms) |
| Bit rate | 600 bps |
| Bits per superframe | 41 |
| Bytes per superframe | 6 (48 bits, 7 spare) |
| LPC order | 10 |
| LSF count | 10 |
| Voicing bands | 5 (0–500, 500–1000, 1000–2000, 2000–3000, 3000–4000 Hz) |
| Pitch range | 20–160 samples (50–400 Hz) |
## Testing
```sh
# Full test suite (138 tests: 125 unit + 13 integration)
cargo test
# no_std subset (100 tests — core-only, no heap)
cargo test --lib --no-default-features --features embedded
```
## License
[MIT](LICENSE)