Fixing Broken Emulator Audio on iPod Classic (Rockbox Rockboy)
The Problem
I run Rockbox 4.0 on my iPod Classic 7G and use the built-in retro handheld emulator (rockboy) to play compatible ROM files. The games run fine visually, but the audio sounds terrible: harsh, crackly, metallic. Nothing like the warm chiptune audio the original hardware produces.
This bothered me enough to dig into the source code. I found five bugs, one of which is a single misread preprocessor condition that degrades audio quality to 25% of what it should be.
The Biggest Bug: Wrong Sample Rate
The iPod Classic defines HW_HAVE_11 because its hardware supports 11025 Hz as one of its available rates. Rockboy misreads this as “use 11025 Hz” and forces the emulator output to the lowest supported sample rate instead of the best one.
1
2
3
4
5
6
// Original code — WRONG
#if defined(HW_HAVE_11) && !defined(TOSHIBA_GIGABEAT_F)
pcm.hz = SAMPR_11; // 11025 Hz forced on iPod Classic
#else
pcm.hz = SAMPR_44; // 44100 Hz for everything else
#endif
At 11025 Hz, the emulator sets snd.quality = 44100 / 11025 = 4, meaning it generates only every 4th audio sample with zero interpolation between them. The four emulated sound channels get destroyed by aliasing artifacts. Classic chiptune soundtracks sound like they’re being played through a broken AM radio.
The fix is one line: always output at 44100 Hz. The iPod Classic’s audio hardware handles it natively. The Rockbox mixer resamples if needed.
1
2
// Fixed
pcm.hz = SAMPR_44;
The Other Four Bugs
Beyond the sample rate, the audio pipeline had:
Broken double-buffering: The code allocates two buffer halves (N_BUFS=2) but pcm.buf always points to the first half. The audio ISR callback reads from buf[pcm.len * doneplay] — when doneplay=1, this accesses the second half which is always zeroed. Hardware alternates between real audio and silence on every callback, producing constant crackling.
Non-volatile ISR flag: The doneplay synchronization flag between the audio ISR and the emulation thread was a plain bool. With GCC -O2, the compiler caches it in a register and the ISR write becomes invisible to the main thread — a potential permanent hang.
No timeout on the yield loop: while (!doneplay) { rb->yield(); } has no escape condition. If audio hardware stops (headphones unplugged, mixer error), the emulator hangs until you force-reset the iPod.
Redundant copy buffer: A separate hwbuf allocation memcpy’d the entire audio buffer on every ISR callback. Wasteful 4KB of plugin heap and unnecessary latency — the Rockbox mixer API accepts a direct pointer.
The Fix
The rewritten audio backend uses a proper ping-pong double buffer:
pcmbuf[0]andpcmbuf[1]are the two slotsfill_buftracks which slot the emulator is writing tosubmit_buf(volatile) tells the ISR which slot to deliverready(volatile bool) signals when a slot is full- Timeout prevents deadlock if audio hardware disappears
1
2
3
4
5
6
7
static void get_more(const void **start, size_t *size)
{
if (ready)
ready = false; // emulator can now refill the other slot
*start = pcmbuf[submit_buf];
*size = sizeof(pcmbuf[0]);
}
On underrun the ISR replays the last good buffer rather than playing silence, avoiding pops.
Building the Toolchain
Getting this to compile on macOS took some work. The Rockbox build system requires its own arm-elf-eabi-gcc 9.5.0 cross-compiler, which rockboxdev.sh builds from source.
Two macOS-specific issues I hit and documented:
Spaces in path: autoconf’s
--prefixcannot contain spaces. Google Drive paths (~/Library/CloudStorage/Google Drive/...) break the build silently. Solution: install the toolchain to~/rockbox-toolchaininstead.-fbracket-depth=512is Clang-only:rockboxdev.shinjects this flag on Darwin assuming you’re using Clang as the host compiler. With Homebrew GCC 15 it fails immediately. Fix: detect whether$CXXcontainsg++and skip the flag.
Both issues are documented in the repo’s BUILD.md so nobody else hits them.
Result
Five bugs fixed. Compiled ARM binary built and tested against the Rockbox 4.0 source for iPod Classic 6G/7G. The plugin is 51KB.
The pre-built binary is in the releases folder — copy it to .rockbox/rocks/games/rockboy.rock on your iPod to try it.
The patch is also formatted for upstream submission to the Rockbox project via their Gerrit review system, which is the next step.
GitHub repo: Tyal13/rockbox-rockboy-audio-fix
If this fix helped you, consider sponsoring the project on GitHub. Every contribution helps fund continued Rockbox development work.