No sound card driver. No audio library. Just the CPU and 44100 numbers a second.
Assembly
62
22 commits
updated Sep 13, 2026
No sound card driver. No audio library. Just the CPU and 44100 numbers a second.
No libc. No external calls. Sound is a list of numbers — generate the right ones, write them to a .wav, and the speaker moves. That's the whole trick.
syscall or nothingmake # binaries land in bin/
The target is Linux, so run it in a container. Any OCI runtime works — Docker, Podman, Colima, OrbStack — they all read the same Dockerfile:
docker build -t asmfm .
docker run --rm -it -v "$PWD":/asmfm asmfm
make # inside the container
What I actually use: OrbStack + VS Code's Dev Containers extension. "Reopen in Container" and the terminal drops straight into Linux with make ready.
Note: sample buffers live in .data, not .bss — Rosetta's x86 translation chokes on pure-bss load segments (rosetta error: bss_size overflow).
./bin/beep # a single square wave. the "hello world" of sound
./bin/beep > out.wav # ...or dump it to a file and play it anywhere
aplay out.wav # (or open it in anything — it's a real WAV)
Everything writes a valid RIFF/WAVE stream: 16-bit PCM, mono, 44.1 kHz. Pipe it, play it, keep it.
A speaker is a cone that moves in and out. Describe its position 44100 times a second and you've described a sound.
A4 -> 440 Hz, and the rest of the notes fall out from there.{ note, duration }. The player walks it and fills the buffer.write(1, ...) and you're done.The story so far — from a single beep to a real synth:
write)Little side-by-side tests, for hearing what a single feature actually does:
melody_hard vs melody_smooth — the same solo melody with hard note edges vs a strong ADSR envelope. Play them back to back: one clicks, the other breathes.polyphony_adsr — polyphony and envelopes combined: the three-voice mix with per-note ADSR, so nothing clicks.Because I'd made the CPU count, sort, hash, and draw — but never sing.
1,503 followers · starred Aug 2026
Assembly
99.7%
No sound card driver. No audio library. Just the CPU and 44100 numbers a second.
Assembly
62
22 commits
updated Sep 13, 2026
No sound card driver. No audio library. Just the CPU and 44100 numbers a second.
No libc. No external calls. Sound is a list of numbers — generate the right ones, write them to a .wav, and the speaker moves. That's the whole trick.
syscall or nothingmake # binaries land in bin/
The target is Linux, so run it in a container. Any OCI runtime works — Docker, Podman, Colima, OrbStack — they all read the same Dockerfile:
docker build -t asmfm .
docker run --rm -it -v "$PWD":/asmfm asmfm
make # inside the container
What I actually use: OrbStack + VS Code's Dev Containers extension. "Reopen in Container" and the terminal drops straight into Linux with make ready.
Note: sample buffers live in .data, not .bss — Rosetta's x86 translation chokes on pure-bss load segments (rosetta error: bss_size overflow).
./bin/beep # a single square wave. the "hello world" of sound
./bin/beep > out.wav # ...or dump it to a file and play it anywhere
aplay out.wav # (or open it in anything — it's a real WAV)
Everything writes a valid RIFF/WAVE stream: 16-bit PCM, mono, 44.1 kHz. Pipe it, play it, keep it.
A speaker is a cone that moves in and out. Describe its position 44100 times a second and you've described a sound.
A4 -> 440 Hz, and the rest of the notes fall out from there.{ note, duration }. The player walks it and fills the buffer.write(1, ...) and you're done.The story so far — from a single beep to a real synth:
write)Little side-by-side tests, for hearing what a single feature actually does:
melody_hard vs melody_smooth — the same solo melody with hard note edges vs a strong ADSR envelope. Play them back to back: one clicks, the other breathes.polyphony_adsr — polyphony and envelopes combined: the three-voice mix with per-note ADSR, so nothing clicks.Because I'd made the CPU count, sort, hash, and draw — but never sing.
1,503 followers · starred Aug 2026
Assembly
99.7%