fm_synth/
├── Cargo.toml
├── src/
│ ├── main.rs # The Rust code (fm_synth_rust artifact)
│ └── lib.rs # Same code as main.rs for WASM build
├── index.html # Web interface (fm_synth_web artifact)
├── build.sh # Build script for WASM
└── README.md # This file
- Rust - Install from https://rustup.rs/
- wasm-pack - Install with:
cargo install wasm-pack - Basic HTTP server - Python or Node.js for local testing
mkdir fm_synth
cd fm_synth
cargo init[package]
name = "fm_synth"
version = "0.1.0"
edition = "2021"
[lib]
crate-type = ["cdylib", "rlib"]
[[bin]]
name = "fm_synth"
path = "src/main.rs"
[dependencies]
anyhow = "1.0"
[target.'cfg(not(target_arch = "wasm32"))'.dependencies]
cpal = "0.15"
[target.'cfg(target_arch = "wasm32")'.dependencies]
wasm-bindgen = "0.2"
wasm-bindgen-futures = "0.4"
js-sys = "0.3"
[dependencies.web-sys]
version = "0.3"
features = [
"AudioContext",
"OscillatorNode",
"GainNode",
"AudioDestinationNode",
"AudioParam",
"Window",
]- Copy the Rust code to both
src/main.rsandsrc/lib.rs - Copy the HTML code to
index.htmlin the project root
#!/bin/bash
echo "Building WebAssembly module..."
wasm-pack build --target web --out-dir pkg
echo "Build complete! Files in ./pkg/"
echo "To run the web version:"
echo " 1. Start a local server: python3 -m http.server 8000"
echo " 2. Open http://localhost:8000 in your browser"Make it executable:
chmod +x build.sh# Build
cargo build --release
# Run
cargo run --release# Build WASM
./build.sh
# Serve locally (Python)
python3 -m http.server 8000
# Or with Node.js
npx http-server -p 8000
# Open in browser
# http://localhost:8000list presets- Show all 12 available sound presetslist melodies- Show all 10 available melodiesplay <preset> <melody>- Play a melody with a specific preset- Example:
play bell twinkle - Example:
play 1 3(using numbers)
- Example:
demo- Play all presets with a scalehelp- Show command listquit- Exit the program
Same as desktop, plus:
clear- Clear the terminal display
- Bell - Bright, metallic bell sound
- Bass - Deep bass synth
- Electric Piano - Classic FM electric piano
- Brass - Synthetic brass sound
- Organ - Church/Hammond organ style
- Synth Lead - Sharp lead synthesizer
- Marimba - Wooden xylophone sound
- Strings - Soft string pad
- Flute - Simple flute tone
- Metallic - Harsh metallic sound
- Glockenspiel - Light bell sound
- Wood Block - Percussive wood sound
- Twinkle Twinkle - Classic children's song
- Happy Birthday - Birthday celebration tune
- Ode to Joy - Beethoven's famous melody
- Mary Had a Little Lamb - Simple nursery rhyme
- Chromatic Scale - All semitones ascending
- Major Arpeggio - C major broken chord
- Minor Pentatonic - Blues/rock scale
- Jazz Lick - Short jazz phrase
- Bach Invention - Classical melody fragment
- Synth Demo - Arpeggio demonstration
- Carrier Frequency: Main pitch of the sound
- Modulator Frequency: Affects timbre/harmonics
- Modulation Index: Brightness/complexity (0-12)
- Amplitude: Volume level (0.0-1.0)
- Attack: 10ms (fast attack)
- Decay: 100ms
- Sustain: 70% level
- Release: 500ms
- No audio device: Ensure your system has audio output enabled
- Compilation errors: Update cpal with
cargo update - Performance: Reduce buffer size in audio config if needed
- No sound: Click anywhere on the page first (browser security)
- Module not loading: Check browser console for errors
- CORS errors: Use a proper HTTP server, not file:// protocol
Edit the get_presets() function:
("Your Preset", FMParams {
carrier_freq: 440.0,
modulator_freq: 880.0, // Try ratios like 2:1, 3:2, etc
modulation_index: 3.0, // 0.5-12, higher = brighter
amplitude: 0.3,
})Edit the get_melodies() function:
("Your Melody", vec![
("C4", 500), // Note, Duration in ms
("E4", 500),
("G4", 1000),
])This project is provided as an educational example for FM synthesis in Rust.