Broadcast · Worked Example

Running a Community Radio Station from a Headless Box

Scheduled programmes, live voice inserts, off-site control · 7 min read

Illustrative worked example — a representative scenario showing how Multilarm is configured, not an account of a specific customer.

A community radio station does not need a rack of studio automation software. If your programming is mostly pre-recorded, your live inserts are short, and your audience is local, the job reduces to: “play the right file at the right time, and let the presenter speak over the output when they want to.” That’s a Multilarm config.

The station

A small community broadcaster with a low-power FM transmitter and a live internet stream. The daily schedule is a mix of recorded shows, pre-recorded interviews, station IDs, and a handful of live windows where a presenter speaks from home. There is no studio staffed 24/7 — the feed runs itself most of the time.

Hardware, deliberately unglamorous

Two outputs, one stream

The FM transmitter and the streaming encoder both need the same audio, in sync, at the same moment. That is exactly what MirrorDevices is for:

<MAConfig><PlaybackDevice>2</PlaybackDevice></MAConfig>
<MAConfig><MirrorDevices>3</MirrorDevices></MAConfig>

Device 2 goes to the transmitter, device 3 to the encoder. Both are Ctrl+O-verified and labelled on the dongles. A listener on FM and a listener on the internet stream hear the same word at the same moment — which is the whole point of mirroring at the audio-buffer level rather than splitting downstream.

Programming as folders, not files

Traditional automation software thinks in playlists. Multilarm thinks in folders. A show becomes a folder; the schedule fires that folder at its slot; the engine picks a track at random and logs what it played. DateAndTimeData carries one time per slot, AlarmIndexData routes each slot to a folder in AlarmPath:

<MAConfig><RecurEveryDay>True</RecurEveryDay></MAConfig>
<MAConfig><TimeDelimiter>|</TimeDelimiter></MAConfig>
<MAConfig><AlarmPath>/srv/radio/Shows/MorningMix|/srv/radio/IDs|/srv/radio/News/Today|/srv/radio/Shows/Afternoon|/srv/radio/Shows/Overnight</AlarmPath></MAConfig>
<MAConfig><AlarmIndexData>5|1|2|3|4</AlarmIndexData></MAConfig>
<MAConfig><DateAndTimeData>0:00|8:00|9:00|9:02|13:00</DateAndTimeData></MAConfig>
<MAConfig><AlarmFileFormat>mp3</AlarmFileFormat></MAConfig>

Slots fire in ascending order: 00:00 (index 5, Overnight), 08:00 (MorningMix), 09:00 (IDs), 09:02 (News), 13:00 (Afternoon). Refresh a show folder’s contents, and the next time that slot fires, the new content is what goes out. No re-importing into a database, no re-publishing a playlist — just files on disk. Every fire is logged to Multilarm.playlist.log with the track name, which turns straight into a PRS/licensing return at the end of the month.

Station IDs via TTS

A short pre-recorded station ID is fine. But live shout-outs (“You’re listening to XYZ FM, ninety-two point one, the time is three oh seven”) date fast when pre-recorded. Multilarm’s built-in text-to-speech composes the ID on the fly from the pre-recorded word library in TTSPath. The schedule gets one slot per hour, with a parallel TextData entry for each:

<MAConfig><TextToSpeech>True</TextToSpeech></MAConfig>
<MAConfig><TTSPath>{app}/TTS</TTSPath></MAConfig>
<MAConfig><TTSFileFormat>mp3</TTSFileFormat></MAConfig>
<MAConfig><TextDelimiter>|</TextDelimiter></MAConfig>
<MAConfig><TextData>You&apos;re listening to XYZ FM, it&apos;s zero hundred hours.|You&apos;re listening to XYZ FM, it&apos;s nine hundred hours.|You&apos;re listening to XYZ FM, it&apos;s ten hundred hours.|You&apos;re listening to XYZ FM, it&apos;s thirteen hundred hours.</TextData></MAConfig>

Each TextData entry lines up one-for-one with its DateAndTimeData slot; the line for the 00:00 slot is spoken the moment the overnight show starts, etc. #TIMETOALARM+1# and other tokens can be embedded inside TextData if a countdown-style ID is wanted instead of the current hour label. Either way, the TTS word library is assembled once with Ctrl+R, and every future show ID speaks itself from disk without re-recording a single file.

Virtual radio between scheduled slots

Between scheduled shows, Multilarm’s virtual radio keeps the carrier alive with shuffled playback from a fallback music library. Set PlayRadio=Local, point RadioFolder at a well-stocked library, and the engine fades between tracks continuously, ducking automatically whenever a scheduled slot fires and returning afterwards:

<MAConfig><PlayRadio>Local</PlayRadio></MAConfig>
<MAConfig><RadioFolder>/srv/radio/Fallback/Music</RadioFolder></MAConfig>
<MAConfig><RadioFileFormat>mp3</RadioFileFormat></MAConfig>
<MAConfig><CrossfadeMs>2500</CrossfadeMs></MAConfig>

If a scheduled show is missing (folder empty because the producer hasn’t uploaded it yet), the startup audio health check flags it in yellow at boot; at run-time the slot simply no-ops and the virtual radio keeps playing. The listener hears continuous music instead of dead air, and the next scheduled slot takes over at its time. The status JSON field radio flips true whenever the virtual radio is on-air, so the station manager can see on the dashboard how often the fallback fills gaps — and go ask the producer why the show didn’t arrive.

Presenters working from home

Here is where the Cloud Relay pays for itself. The transmitter shed has no inbound ports — it sits behind a consumer NAT on a residential line. That used to mean presenters needed to either come on-site or SSH tunnel. Neither scales.

The Cloud Relay flips the direction of the relationship:

End result: a presenter on a train can hit Skip, change the volume, transmit a voice insert, or swap the loaded config file via the live editor — and the only thing between their phone and the transmitter is a $4/month PHP host.

Why outbound-only matters: community stations rarely control their own firewall. Renegotiating port-forwarding with a landlord or a broadband provider every year is the quickest way to end up with an off-air Monday. The Cloud Relay side-steps the problem by never asking the transmitter’s network to accept connections in the first place.

Live voice inserts from anywhere

Voice Broadcast through the Cloud Relay uses the same dashboard as everything else. The presenter’s phone records on-device (HTTPS, so the browser allows the microphone), uploads a WAV file to /api/voice/upload, previews it privately if they want, and then hits Transmit. The transmitter plays the clip straight out of the FM output.

A 30-second top-of-hour birthday shout from a listener’s grandmother? Fine. A live update from a sports event the presenter is attending in person? Fine. All of it without dragging a mixing desk, an interface, or a laptop.

What the station manager watches

The dashboard’s status card is refreshed every fifteen seconds. The meaningful fields for a broadcaster:

Four of those six are questions a traditional automation log can only answer after the fact. Multilarm answers them in near-real-time from anywhere with internet.

Takeaways

Community radio has always been resourceful. Multilarm fits that temperament: one binary, one config, a few folders of audio, and a small PHP endpoint you can host for the price of a coffee. Try it on your next programming day.