Encode arbitrary bytes into a WAV file using Bell-202-style Audio Frequency-Shift Keying (AFSK), and decode them back — losslessly.
Most data-over-audio tools are tightly coupled to specific protocols (APRS, KISS, etc.) or sacrifice correctness for simplicity. RustWave is a self-contained, dependency-light Rust library and CLI that gives you a clean primitive: any byte buffer in → a valid WAV file out → the same byte buffer back, with a robust framing layer, CRC-16 integrity checking, and a Goertzel-filter decoder that tolerates real-world signal noise and arbitrary byte offsets.
It is also the audio codec layer underpinning HAMNET-RELAY, a planned HAM radio data relay that bridges AX.25 packet radio with a local HTTP/WebSocket API.
Requires Rust 1.75+ (2021 edition).
cargo install rustwaveOr build from source:
git clone https://github.com/csd113/rustwave
cd rustwave
cargo build --release
# binary at: target/release/rustwave-cli# Encode a file to WAV
rustwave encode -i data.bin -o signal.wav
# Decode a WAV back to bytes
rustwave decode -i signal.wav -o data.bin
# Launch the graphical interface
rustwave-cli --guiuse rustwave::{encode, decode};
fn main() {
let payload = b"Hello, RustWave!";
// Encode bytes → WAV samples
let wav_path = "signal.wav";
encode(payload, wav_path).expect("encode failed");
// Decode WAV → original bytes
let recovered = decode(wav_path).expect("decode failed");
assert_eq!(payload, recovered.as_slice());
}[ your bytes ]
│
FRAMER preamble (24 × 0xAA) | sync (0x7E 0x7E) | length (u32 LE) | payload | CRC-16
│
ENCODER each bit → sine wave at 1200 Hz (mark=1) or 2200 Hz (space=0)
continuous-phase FSK at 1200 baud, 44100 Hz / 16-bit mono WAV
│
[ .wav ]
│
DECODER non-integer Goertzel filter per bit-window; bit-level sync-word
search (handles any byte offset); CRC verification
│
FRAMER reconstruct original bytes
│
[ your bytes ]
| Parameter | Value |
|---|---|
| Sample rate | 44 100 Hz |
| Bit rate | 1 200 baud |
| Mark (1) | 1 200 Hz |
| Space (0) | 2 200 Hz |
| Modulation | CPFSK (continuous-phase FSK) |
| WAV format | 16-bit signed PCM, mono |
| Frame overhead | 28 bytes (preamble + sync + length + CRC) |
The framer wraps every payload in a Bell-202-compatible envelope. A 24-byte 0xAA preamble allows the decoder to lock onto the signal, followed by a 0x7E 0x7E sync word, a 4-byte little-endian length field, the raw payload, and a CRC-16/CCITT checksum. The decoder performs a bit-level sync-word search that handles arbitrary byte offsets in the audio stream.
Launch the built-in eframe-powered GUI for drag-and-drop encoding and decoding without the CLI:
./rustwave-cli --guiRustWave is designed as the AFSK codec layer for HAMNET-RELAY, a multi-phase HAM radio data relay project that adds AX.25 packet framing, CSMA channel access, a local HTTP/WebSocket API, and full RustChan imageboard integration on top of this codec. See docs/hamnet-relay-build-roadmap.md for the full architecture.
src/
main.rs CLI (clap — encode / decode subcommands, --gui flag)
config.rs Shared constants (sample rate, baud rate, frequencies)
framer.rs Byte envelope: preamble, sync word, length, CRC-16/CCITT
wav.rs WAV file I/O via hound
encoder.rs Bytes → CPFSK audio samples
decoder.rs Audio samples → bytes (Goertzel filter, bit-level sync search)
cargo test12 unit and integration tests cover:
- Framer round-trips (empty payload, ASCII, all 256 byte values, corrupt CRC)
- CRC-16/CCITT known-value verification
- WAV write/read round-trip (silence and sine wave)
- Goertzel mark-vs-space discrimination
- Full encode → decode round-trips (empty, text, all byte values)
A strict dev-check script runs fmt, clippy (pedantic + nursery), cargo test, cargo audit, and cargo deny in sequence:
./dev-check-strict.shGenerate and open local docs:
cargo doc --open- Fork the repository and create a feature branch off
main. - Run
./dev-check-strict.sh— all checks must pass before submitting. - Open a pull request with a clear description of the change and any relevant test coverage.
- Follow standard Rust style (
rustfmtdefaults). Clippy pedantic warnings are treated as errors.
This project is licensed under the MIT License.
Copyright © 2026 csd113.
- hound — WAV file I/O
- clap — CLI argument parsing
- eframe / egui — immediate-mode GUI
- Bell 202 modem standard — 1200/2200 Hz AFSK tone pair
- Goertzel algorithm — efficient single-frequency DFT for decoding
- cargo-deny — license and advisory enforcement