chiptunomatic
The core synthesis library. Turns any byte sequence into a deterministic chiptune: the same file name and byte length always produce the same music.
The library is no_std + alloc with an optional std layer, so it works on native targets and in WebAssembly (wasm32-unknown-unknown).
Adding the dependency
[]
= "0.3"
For WebAssembly in a JS host, enable the js feature so getrandom uses its JS backend:
[]
= { = "0.3", = false, = ["js", "std"] }
Quick start
use ;
// Build an instance with all built-in modes and a seeded RNG.
let mut chip = default
.with_default_plugins
.with_random;
// Load metadata from a file (derives seed from filename + byte length).
let meta = chip.load_song_metadata_from_path?;
println!;
// Collect every mixed sample into a Vec<Sample>.
let samples: = chip.samples;
for s in &samples
Metadata
SongMetadata is derived deterministically from a seed (typically the file name) and a byte length. It carries all musical decisions for the track.
// Non-mutating: compute without changing the instance state.
let meta = chip.song_metadata_from_path?;
// Mutating: compute and install (required before synthesis).
let meta = chip.load_song_metadata_from_path?;
// From a string name + known byte count — works on wasm32 too.
let meta = chip.load_song_metadata_from_string?;
// From raw seed bytes.
let meta = chip.load_song_metadata_from_seed?;
Key fields on SongMetadata:
| Field | Type | Description |
|---|---|---|
bpm |
i32 |
Beats per minute |
root_semitone |
u8 |
Root note (0 = C) |
chord_description |
String |
Human-readable chord loop (e.g. "C – Eb – G – Eb") |
total_beats |
u64 |
Total number of beats |
total_duration |
f64 |
Duration in seconds |
data_byte_len |
u64 |
Byte length used as seed |
Streaming synthesis (SampleReader)
For large files, generate samples on the fly from any std::io::Read source without loading everything into memory first:
use File;
use ;
let mut chip = default
.with_default_plugins
.with_random;
chip.load_song_metadata_from_path?;
let file = open?;
let mut reader = chip.sample_reader;
let mut buf = ;
loop
SampleReader also implements Iterator<Item = std::io::Result<Sample>>.
Mixer and stem control
Each track has four stems — voice, square (melody), triangle (bass), noise (drums) — plus a master output. All are controlled through MixerConfig:
use ;
chip.mixer_mut.set_config;
Multiple solos are additive: every stem whose solo flag is true is heard; the rest are silenced.
Sample::value is the normalised, mixed mono f32. Sample::stems exposes the raw per-stem floats before mixing, useful for visualisation or custom mixing.
Modes
Each mode produces a different musical style. The default instance has only the chiptune mode. Call .with_default_plugins() to register all built-in modes:
// List available modes.
let modes = chip.modes; // &["chiptune", "rock", "metal", ...]
// Switch mode (resets internal generator state automatically).
chip.set_mode?;
| Mode | Character |
|---|---|
chiptune |
Classic 8-bit square / triangle / noise |
rock |
Power chords, overdriven bass, loud kit |
metal |
Hard-clipped power chords, double-kick patterns |
rap |
Boom-bap FM piano, punchy sine bass |
trap |
FM bell melody, 808 pitch-sweep bass, stutter hi-hats |
toy |
FM kalimba tines with octave shimmer |
samba |
Reedy FM melody, surdo on beats 2 & 4, teleco-teco tamborim |
koto |
Karplus-Strong plucked strings, Hirajoshi pentatonic |
Custom mode (Plugin)
Implement Plugin to register a completely custom mode:
use Plugin;
;
chip.register_plugin;
chip.set_mode?;
Custom random
Provide any Random implementation to control how stochastic elements (drum fills, slight pitch variation, etc.) are generated. Use NoRandom (the default) for fully deterministic, RNG-free output:
use ;
// Fully deterministic — no random calls.
let chip = default;
// Seeded standard RNG — deterministic but with musical variation.
let chip = default
.with_random;
WAV export
With the wav feature (included in default), convert any file directly to a WAV on native targets:
chip.file_to_wav?;
This calls load_song_metadata_from_path and streams synthesis internally; no large intermediate buffer is allocated.
Feature flags
| Flag | Default | Description |
|---|---|---|
std |
yes | Enables std-dependent APIs (SampleReader, path helpers, StdRandom) |
wav |
yes | Enables file_to_wav via the hound crate (requires std) |
arpeggio |
yes | Enables the Arpeggiator for chord note expansion |
js |
no | Wires getrandom's JS backend for wasm32-unknown-unknown in a JS host |
Constants
use SAMPLE_RATE; // 44_100 u32
All synthesis runs at 44 100 Hz mono. Sample::value is a normalised f32 in roughly [-1, 1] — scale to i16 with (value * 32767.0) as i16 for 16-bit PCM.