Signal processing
Acoustic Modem
Sending text in the A blues scale
A Python modem that turns text into musical notes and back again, using only a laptop’s speaker and microphone.
- Year
- 2026
- Role
- Co-creator
- Built with
- Python · FSK · Goertzel algorithm · NumPy
Explore the encoding
What notes would your text make?
Each character becomes four pairs of bits, wrapped in START and STOP notes. Try a short message to see its musical alphabet.
JAZZ · 4 characters · 5.4 seconds including preamble and silent tail
- STARTE♭61245 Hz
- 01C61047 Hz
- 01C61047 Hz
- 00A5880 Hz
- 10D61175 Hz
- STOPE61319 Hz
- STARTE♭61245 Hz
- 10D61175 Hz
- 00A5880 Hz
- 00A5880 Hz
- 10D61175 Hz
- STOPE61319 Hz
- STARTE♭61245 Hz
- 01C61047 Hz
- 01C61047 Hz
- 10D61175 Hz
- 10D61175 Hz
- STOPE61319 Hz
- STARTE♭61245 Hz
- 01C61047 Hz
- 01C61047 Hz
- 10D61175 Hz
- 10D61175 Hz
- STOPE61319 Hz
One note lasts 0.2 s. This visualizer shows the encoding only; it does not play or record audio.
See the frequency mapping in the sourceData with a musical vocabulary
Built with İrem Önen, this project sends text from one laptop to another through sound. The transmitter encodes characters as tones; the receiver listens for those frequencies and reconstructs the message. The six frequencies are notes of the A blues scale: A, C, D, E♭, E, and G.
The current configuration uses A5 (880 Hz), C6 (1047 Hz), D6 (1175 Hz), and G6 (1568 Hz) for the four possible pairs of data bits. E♭6 (1245 Hz) marks START, and E6 (1319 Hz) marks STOP and the message preamble.
Framing the message
Each character becomes eight bits in least-significant-bit-first order. The transmitter groups adjacent bits into four dibits, then adds dedicated START and STOP tones. At 5 symbols per second, each six-symbol character takes 1.2 seconds. A 0.4-second preamble is sent once per message, followed by the character frames and a 0.2-second silent tail.
The engineering decisions
- Continuous phase. Restarting each sine wave at phase zero created clicks at symbol boundaries. Carrying phase between tones keeps the waveform continuous; a short release ramp softens its end.
- Six targeted measurements. The receiver uses the Goertzel algorithm to measure energy at the six candidate frequencies in 50 ms chunks. Noise-floor and signal-concentration thresholds help reject unrelated sound.
- Stable framing. A four-state receiver—IDLE, ARMED, READING, WAITING—locks onto a stable preamble and samples near symbol centers.
- The same timing model in tests. Timing uses chunk counts, so an in-memory waveform follows the same decoding path as live microphone samples.
A live demonstration at 10 metres
In a live demonstration, we successfully sent text between our computers with 10 metres between them. We then asked the audience to gradually make more noise. As the noise increased, the modem began to fail to decode messages.
This demonstrated both that the acoustic link worked across the room and that background noise was a practical limit. It was an observation with our computers in that room, rather than a controlled range or noise-tolerance benchmark.
What it can—and cannot—do
This is a slow, half-duplex proof of concept. There is no checksum, error correction, acknowledgement, or retransmission. A corrupted data tone can therefore produce an incorrect character without being detected. Live performance also depends on room noise, distance, and threshold tuning.
The spectrogram above comes from an in-memory round trip of “JAZZ” through the repository’s transmitter and receiver. It verifies that example without using audio hardware; it is not a measurement of performance in a room.