Welcome

In this moment — breathing in, I hear the signal.
Breathing out, I return to stillness.

Recent writings

Fixing OpenWebRX+'s DAB+ crackle: a sample rate bug hiding behind a dozen red herrings

31 August 2026

If you've tried listening to DAB on OpenWebRX+ and found it plays sped-up with dropouts on some stations, this is for you. Short version: it's a known bug, it's fixable tonight, and the fix is below. Long version, if you want the diagnostic path: keep reading.

The symptom

Tuned into a UK DAB multiplex (Swansea SW Wales, 223.936 MHz, RTL-SDR Blog V4). FIC decoded fine — station list, ensemble label, everything looked healthy. Audio played back sped up, distorted, dropping out — consistently, on every browser tested, at every gain setting tried.

What it wasn't

Before finding the actual cause, I ruled out, in order:

  • Gain/AGC — tested manual gain across the full range (0 to 55, plus hardware AGC). No setting produced clean audio.
  • RTL-SDR frequency drift — instrumented the AFC correction loop directly and confirmed it was stable, well under 1ppm. Not a calibration issue.
  • CPU frequency scaling — the box was running its CPU governor at powersave, capped well below rated clock. Switching to performance made no measurable difference to the artifact rate.
  • USB/RTL-SDR buffer depthrtl_connector's buffer count is hardcoded low in its source. Swapped it for an rtl_tcp-backed source with much deeper buffering. Decode went to zero FIC/CRC errors — genuinely clean RF chain — but the audio artifact was unchanged. This was the key result: it proved the bug was downstream of decode, not an RF/timing problem.
  • ADPCM websocket compression — disabled it to rule out compression-related glitching. Made things audibly worse, which ruled out compression as the cause rather than confirming it.

What it was

The station was broadcasting HE-AAC v2, 32 kHz Stereo — a completely normal, common configuration for UK DAB+. But OpenWebRX+'s DAB decoder chain declares a hardcoded output rate of 48000 Hz to the rest of its audio pipeline, with no actual resampling step to make that true. Every downstream buffer, every resampling ratio calculation, assumes 48 kHz input. When the real data arrives at 32 kHz, everything downstream is working from a false premise — hence the speed/pitch distortion and dropouts.

This turned out to already be a filed, open issue upstream: jketterl/openwebrx#384, described almost word-for-word — "32 kHz stations play sped up and then drop out" — and explicitly noted as common in the UK. A fix had also already been proposed in PR #419, refined by a follow-up contributor into a working patch.

The fix

The core idea: don't trust a declared rate — read the real one. dablin (the DAB+ decoder OpenWebRX+ shells out to) can output WAV instead of raw PCM (-w instead of -p), and a WAV header carries the actual sample rate and channel count. Pipe that through ffmpeg to force a real resample to 48 kHz, and the mismatch disappears for any station regardless of its native rate.

def _buildArgs(self):
    dab_cmd = (
        "dablin -w -s {:#06x} | mbuffer -q -m 4M | "
        "ffmpeg -v error -probesize 4096 -analyzeduration 0 -f wav -i pipe:0 "
        "-af aresample=48000 -f f32le -ar 48000 -ac 2 pipe:1"
    ).format(self.serviceId)
    return ["bash", "-c", dab_cmd]

This replaces the _buildArgs() method of the DablinModule class that wraps dablin (in csdr/module/toolbox.py on the luarvique/openwebrx fork — path may differ slightly by version). Needs ffmpeg and mbuffer installed (apt install ffmpeg mbuffer on Debian/Ubuntu).

Confirmed clean audio afterward on the same station, and on others in the multiplex at different bitrates. Remaining glitches on the odd station were ordinary weak-signal artifacts on lower-error-protection sub-channels — not the systematic issue this fix addresses.

The actual lesson

Nearly everything I tested was a reasonable hypothesis given the symptom, and nearly all of it was wrong. The result that actually mattered was the one that isolated where the problem lived (before vs. after decode) rather than what it looked like (crackle, speed, dropouts all sound similar from several different root causes). Once the RF/decode chain was proven clean, the remaining search space was small enough that a five-minute search for existing bug reports found it immediately — something worth doing before several hours of gain sliders and frequency correction, in hindsight, but the negative results weren't wasted: they're exactly what made the eventual GitHub search specific enough to land on the right issue.

Filming Mumbles with a Nintendo 2DS XL, for some reason

21 June 2026

I had a New Nintendo 2DS XL sat in a drawer doing nothing, so I did the obvious thing: pointed its terrible little dual cameras at the sea and the pier and recorded video like it was a real camera, looking like a weirdo to all the surrounding grockles.

It is a real camera, technically, just a very cursed one in 2026. It's VGA — 640×480, 0.3 megapixels, a resolution that was already behind the times when this console launched in 2013. The result has a very specific texture: grainy, slightly too real, somewhere between a 2010s camcorder and old LiveLeak footage. Found media from a timeline that skipped HD entirely.

Test 1 — the sea at Mumbles

25 seconds of the bay and the Mumbles seafront, shot on a console that was never meant to be anyone's main camera. Soft, washed out, slightly underwater looking even though it's pointed at actual water.

Test 2 — the wheel at Mumbles Pier

Same story, different landmark: the big wheel against a grey sky, smeary and low-bitrate, like found footage from a device that was already obsolete when it launched.

No further experiments planned, but if the 2DS XL has more to give, I'll keep finding out.

EtherLog — eQSL Logging for Shortwave Listeners

3 June 2026

I've been quietly building a desktop app for shortwave listeners who want a proper way to log and send electronic reception reports. It's called EtherLog, and it's now up on GitHub.

If you've ever tried to send an eQSL to a broadcaster and ended up cobbling together an email by hand, this is for you.

What it does:

  • Compose structured reception reports with SINPO ratings
  • Station autocomplete from the EIBI shortwave schedule database, updated on demand
  • EIBI autofill for frequency, language, and target region
  • Searchable, filterable report log with CSV export
  • Send reports directly via SMTP, with full body preview before sending
  • Passwords stored in your system keychain, not a plaintext config file
  • Light, dark, and system themes
  • Runs on Windows, macOS, and Linux

It's Python/PyQt5, GPL-3.0 licensed, and there's a PyInstaller spec included if you want a standalone executable without needing a Python install.

You can find it at github.com/hiraethclub/EtherLog.

A place to begin

16 May 2026

I've been meaning to build this for a while. A small corner of the internet that's properly mine. Not a feed, not a platform, just a site. Somewhere to put things down.

My name is Ais. I live in Mumbles, a small village on the edge of the Gower Peninsula in South Wales, where the bay opens out toward the Bristol Channel and the light changes constantly. It's a good place to think.

Most of my time is spent in my lab, that serves as radio shack, workshop, and general retreat from the world. It's where I do my IT repair work and run a 3D printer, where my custom Amiga A1200 lives alongside a 1987 Technics hi-fi and a Philips CRT television. It's a room that has accumulated a lot of history and a lot of wire.

The radio side of things covers more ground than I can easily summarise. I run three receivers: two RTL-SDR Blog v4s and a Nooelec NESDR SMArt, fed by a 20m inverted L end-fed halfwave, a Moonraker Scanking discone, and a small V-dipole. Between them I monitor AIS ship traffic on the Bristol Channel, airband, marine channels, pagers, the ham bands, FT8, mediumwave DX, and weather fax. I'm fascinated by HF propagation, by what the ionosphere is doing and why signals arrive the way they do. There's something quietly compelling about pulling meaning out of the air.

Buddhism came to me through a broader interest in theology, but when I found it, it fit in a way nothing else had. Looking back, I think I'd been living by something close to Buddhist ethics long before I had a name for it. I've been practising seriously for about two years now, mostly alone, in the Plum Village tradition alongside a growing interest in Gelug philosophy. It shapes how I relate to myself and to the world around me. It's helped me navigate some serious medical difficulties. It's probably saved my life. I don't say that lightly.

The site has a few sections: a journal (you're reading it), a projects page, a bookmarks page of things worth keeping, and a guestbook. There's a weather and tides widget because I live by the sea and I check it constantly.

I don't know how often I'll write here. When something seems worth saying, I will.

Ais