zeta0134 / LuaGB

A gameboy emulator written in pure Lua. Work in progress.
BSD 3-Clause "New" or "Revised" License
410 stars 33 forks source link

The APU implementation must be purged with FIRE AND SALT #26

Open zeta0134 opened 5 years ago

zeta0134 commented 5 years ago

I looked at the APU code today, intending to track down an inconsistency between the percussion tracks on real hardware and the output of LuaGB. I guess I was remembering the modular approach that RusticNes uses which is lovely, and closely matches the behavior of real hardware. This should have been trivial to find and fix. Alas, my thought process was:

The basic structural problem is that, at the time, I was still thinking of waveforms in terms of notes and their corresponding frequency, and real hardware doesn't work that way. The gameboy's APU is actually very simple: the program code sets a clock timer, this is decremented at some fixed rate (512 KHz?) and when the timer reaches 0, it gets reset and some work is performed. Pulse waveforms are shifted, waveform counters increment, and noise is LFSR'd. There are slower 128 Hz and 64 Hz timers that manage volume and envelope sweeps, but the principal idea remains the same.

LuaGB presently uses some unholy mix of clock cycle arithmetic and an awkward timing catchup... thing on register writes. This somewhat closely approximates hardware behavior, but this falls short of accuracy by a few yards. It's especially noticeable in the noise channel, and reviewing the code today, I'm not sure the volume envelopes actually work in any capacity, especially at lower periods. Since so few games rely on the hardware envelopes (most re-set volume every frame) I might just never have noticed.

This issue is here to mark my shame. Please, future me, rewrite this mess. For our honor.