Special thanks to raddad772 https://github.com/raddad772
Also added some fixes to the Z80 for panicking math operations, but
it still won't complete due to an unimplemented instruction
It now actually checks the clock and tries to mix the audio in sync
relative to the clock, but the cpal output doesn't yet try to sync
to the StreamInstant time. Sound seems a lot better on chrome in
wasm, but and kind of better on firefox despite frame skipping not
being supported yet, but it's way slower for some reason (12fps)
It now sort of sounds like the main instrument, but the drums and bass
aren't there, and I'm not sure why. I'm pretty sure the envelope and
phase generators are working, and there is feedback although it might
not be correct. There's no LFO but that isn't used by Sonic 1 from
the register writes at least.
It was previously only updating the frequency if the A0 registers
were written last, but now it works the way the rate code does, using
the cached register values to set the frequency whenever a register
is written to. It also stores the fnumber and block in the operator
which I guess would be needed eventually if I want to save and restore
state.
- The envelope generator wasn't working as it should have, minor issues
with the limits and whether to use 10-bit or 12-bit values (more to come)
- fixed issues with sustain level where it was always set to 0
- fixed release rate and levels to make them 5-bit and 10-bit numbers
respectively, so they match the others
- switched from SineWave to SquareWave and this alone made it go from
terrible and muddy to not that far off. I probably need to completely
change the output
- also included an attempt at removing HostData, still needed for an
interrupt that is triggered by user input
It does something, but doesn't work as it should. It could be a few
things including the on/off signal being too slow due to how time
works in the sample generation, but I wanted to at least commit what
I have. It seems to work roughly right according to the forum post
that describes the chip's operation in detail, but there could still
be some glaring bugs
The hope was that this would reduce the amount of copying and bit
shifting required by the frontend to get the data on screen, but
it doesn't seem to offer much advantage, surprisingly. I'll leave
it in though. There are a few other minor tweaks included here to
try to improve the performance a bit
It was using the DAC value as a positive offset, which makes a slight
click at the start and end of the SEGA voice at the start of a game.
now subtracts half the value and amplifies it a bit so that it
crosses the 0 value
It wasn't copying the frame data from the sources to the output frame
correctly, and there was a small period of zeros at the start of the
frame.
I also converted to using a vec of tuples for the two channels to
make it easier to reason about, since some of the issues were related
to the differences sizes calculated from the clock based on the sample
rate
If the sim is running slower than 60Hz, it was using the frame limiter
to not apply because no frame was drawn, and so it would end up running
at full speed. Minifb can save the last frame without cloning it, and
redraw the same frame if no new frame is ready, which allows the limiter
to still delay the next frame, so slower speeds work. This was also
preventing things that didn't update the screen from allowing inputs
including escape to have any effect
AddressRepeater now takes the range it should repeat over, which only
really affects its reported size.
AddressAdapter is now AddressRightShifter, which is literally the operation
it performs, where the input is still the bits to shift the address right by
It turns out to not be too much of a performance issue to allocate
a new frame each time one is produced, so to reduce lock contention
I added a queue where frames are added to and taken from without
locking the frame for the whole update. I'm hoping this will give
more flexibility to frontend implementations, which can simply
skip or repeat frames if needed.
Mortal Kombat 2 was working but somewhere while getting the harte
tests to work, I fixed interrupts to change the flags before they're
pushed to the stack, in order to match the expected behaviour from
the tests when an address error occurs (sr is changed and the stack
push causes the error). I correctly saved the state of sr in the
function for group0 interrupts, to push to the stack later, but the
normal interrupts was saving sr *after* the flags were changed...
Now it saves sr beforehand
I also included some changes to the gfx interface to allow taking
frames, to fix a compile error introduced by the last commit.
I wanted to make this a bit more modular, so it's easier in theory to
write external crates that can reuse bits, and selectively compile in
bits, such as adding new systems or new cpu implementations