Mostly for fun
This is a Halloween toy and an excuse to learn something, nothing more. The models transcribe whatever the radio actually said, and speech-to-text models are famous for inventing confident words out of noise, which happens to be exactly the property a spirit box wants. If the dead really are reaching out through internet radio, they are fighting the same battles I was: a TLS handshake per station, a CORS policy written by the living, and a two-second burst of stale buffer every time they reconnect. One assumes the afterlife has better retry logic.
Internet radio is not a radio
The original Eidolon is a command-line tool that drives real radio hardware. Retuning a software-defined radio is nearly instant and the audio is live. An internet station is an HTTP stream instead, and getting a few seconds of it means DNS, a TLS handshake and the server’s burst-on-connect: Icecast and StreamTheWorld servers send every new listener several seconds of pre-buffered audio so playback starts smoothly. Reconnect on every hop and you replay that catch-up burst each time; measured, it inflated the audio to about 3.5× real time. What the web version does instead:
- Stay connected. The server holds one connection per station open for the whole session and discards the first two seconds of each, so everything after that is live.
- Multiplex. Browsers allow six HTTP/1.1 connections per site, so nine open streams starved everything else, including the transcription request. The server merges all nine into one framed stream (
[station][length][bytes]) that the page splits back apart, and it disconnects any listener that stops reading rather than buffering for them. - Cut on frames. Playing the live edge in small pieces failed: an MP3 fragment decoded on its own starts in silence, and Firefox rejected 21 of 48 of them outright, losing 46% of the audio. Each hop now takes a station’s latest two seconds, cut on validated MP3 frame boundaries with three warm-up frames for the decoder, and schedules it to start the instant the previous snippet ends.
- Transcribe what you heard. The transcript is assembled from the exact bytes that were played, not fetched again, so it cannot drift from what came out of your speakers.
The hardware version: RTL-SDR Blog V4
The command-line version listens through an RTL-SDR Blog V4, an inexpensive USB software-defined radio built on the RTL2832U, a chip originally made for digital TV dongles, and an R828D tuner. The V4 adds a 1 PPM temperature-compensated oscillator, a built-in HF upconverter, a bias tee and an aluminium case. Eidolon hops the US FM grid (odd tenths from 88.1 MHz, 200 kHz apart) and favours frequencies where an rtl_power scan found real stations, with some purely random hops kept for static. A web page can’t reach a USB radio on a stranger’s desk, hence internet radio here.
Models, tokens and cost
Speech-to-text is mistralai/voxtral-mini-transcribe through OpenRouter, chosen for latency over Whisper-class models, at $0.003 per minute of audio. It doesn’t translate, and most of these stations aren’t in English, so a second call sends the transcript to openai/gpt-4o-mini with a one-paragraph system prompt ($0.15 per million input tokens, $0.60 per million output). A typical 30-second transcript costs about $0.0015 to transcribe and $0.00005 to translate, roughly 650 transcripts per dollar. The log above shows the exact token counts and cost OpenRouter reports for each request. Transcription is limited to ten requests a minute per visitor, which is all the protection the budget needs.