Background Matter
In case you missed my master plan (e.g.: you’re reading my Github and were never on metconst), I’m trying to build a music editor for, at the very least, SPC files from Super Metroid.
It seems like the fastest way for such an editor to be able to play the music being edited, is to have a real SPC player built-in. But not one that dumps straight to the platform audio output device—one that buffers into RAM to make play/pause and seeking possible.
To that end, I’m presently trying to rip the SMP/DSP subsystem out of higan (née bsnes) and pull it into a library that runs in a subthread and lets the main thread request blocks of audio from it.
Oh yes, I’m going to be building in QT. I may, or may not, eventually borrow
some source code from qtractor
(certainly not the audio output chain,
though; AFAIK, if you don’t really want audio to play, then JACK is an
excellent backend for you.) QT appears to be the one cross-platform library
that’s monolithic enough to be an easy (if fat) install on Windows, that also
provides everything I absolutely need: threads, audio, GUI widgets, and a C++
FFI for binding to higan’s SMP core.
Higan v093
So with that out of the way, let’s take a closer look at higan. I’m specifically using v093 here, which is, as of late September 2013, the latest version published. I hear it even builds on OS X now.
Why higan? Accuracy. There doesn’t seem to be any point in going for anything less, when I won’t have competition for host time from the CPU and PPU. I’ve also heard (but been unable to find any trace of the actual code involved) that the SMW community came up with some music editor(s) once upon a time, but they were based on the ZSNES emulation, and failed hard on the real hardware because ZSNES cheated on echo buffering. Echo didn’t get written back to PSRAM and destroy the code/instruments under emulation.
That’s a mistake that’s worth not repeating.
Synchronization
higan does threading (when threaded) by using its built-in public domain
libco
(coroutine, I presume) library. But if you just look at
sfc/smp/smp.cpp
you will find some synchronization functions, but no
callers… right there. And the obvious ones like step()
don’t seem to do
much.
There are some more functions in sfc/smp/timing/timing.cpp
, but that turns
out to be a very small file, because it’s just providing some more sync
functions to be called. The real synchronization is driven from the
memory files, sfc/smp/memory/memory.cpp
. Quoting my notes:
step(clocks): adjusts clocks only, no sync
cycle_edge: tick SMP timers
add_clocks: step(); sync DSP; may sync CPU
...
add_clocks called in op_{io|read|write}
It appears that higan’s philosophy is to synchronize the bus state of the system. That is, when a CPU (the S-SMP in the case of audio) makes some sort of move like loading the next instruction from memory, it triggers a synchronization with the rest of the system. However many cycles the DSP should have taken while that one SMP instruction was running becomes accounted for, and the DSP state is “caught up” so that its current bus state will be visible to the emulation of the SMP when the thread returns.
That’s pretty much how the main CPU and the SMP are sync’ed, as well: whenever either side writes to an IO port connecting them, at end-of-scanline, and any time they get more than 24 samples of audio output out-of-sync. Or, at every bus transaction, if the debugger is built (or maybe enabled? I forget which.)
I didn’t look, but I’d guess that’s how the CPU and PPU are wired, as well.
struct Everything
Apparently in the C++ world, a struct
is a class
with default-public
instead of default-private. byuu uses a lot of struct
and very few, if
any, class
keywords.
Why you would use C-compatible keywords to build non-C features? I’m baffled. It’s just how Bjarne rolls, I guess.
The Mystery of Privilege
There’s apparently a “privileged” access modifier. How this may differ from
private
or protected
, I’m not really certain, because so far I’ve been
unable to find a description of it online. It’s just too generic a word:
every discussion of public
vs. private
tends to use it to talk about
access control.
Unfortunately, there’s a good chance I may need to understand it before finishing this library.