|Home | Downloads | Screenshots | Forums | Source code | RSS|
Another of those long-due fixes
Nov 11th 2017, by StapleButter
The sound core is fixed, or mostly.
If you've been playing with melonDS, you may have noticed that effects like surround generally didn't work, and that whenever they worked, they resulted in crappy sound. Resetting or loading different games would also give different results.
So I've been addressing all that junk.
The randomness was easily fixed -- the write position for capture units wasn't being reset properly, so whenever the capture unit was started, it would start writing wherever it was previously left. Not really a good thing.
The rest was trickier though.
The DS sound controller provides 16 channels that can play a few types of audio, and 2 capture units that can capture sound output and write it to memory.
Several games provide different audio modes, typically headphones/stereo/surround. In those games, the audio output isn't directly sent to the speakers, but it is sent to the capture units. The game then alters it as it wishes, and two special channels (1 and 3) are used to send the final output to the speakers.
The mechanism is generally used for the aforementioned audio modes, but some games take it further -- Golden Sun: Dark Dawn goes as far as using it to play its sound effects.
While the mechanism (which we will name "surround setup") may sound simple, getting it to work is actually tricky.
It has been known for a while why it didn't work in melonDS: capture and channel 1/3 playback were done in the wrong order. However, putting them in the right order resulted in distorted, tinny sound. So I just kept it in the wrong order and ignored it.
When you start a sound channel on the DS, it doesn't start playing immediately, there is a delay of a few samples. However, capture units start immediately.
The surround setup starts the capture units and their associated output channels at the same time, and gives them the same memory address. The idea is that, since channels are processed before capture units, the output channel reads sound data before the capture unit writes new data, and the distance is the largest possible, as to give the game enough time to apply effects to it.
However, the channel starts with a delay, which means it's lagging behind a little. In the case of melonDS, as the mixer processed 16 samples per run, the output channels would get bits of freshly captured data mixed in with the older data as a result of this. You guess how this goes.
Reducing the number of samples per run to 2 or 1 got rid of the audio distortion, but surround didn't work at all since the channels would only get freshly captured data.
Removing the channel start delay fixed the problem, but obviously it's not proper emulation.
The killer detail is that when the sound controller needs to access memory, it doesn't do so directly, but uses a buffering mechanism (FIFO) for each channel and capture unit. GBAtek mentions their existence, but... that's all.
The FIFOs need to be emulated for surround to work properly.
Which means that I had to do hardware tests to figure out how it works. There are probably still missing details.
Channel FIFOs can hold 8 words (32 bytes) of data. They are filled in chunks of 4 words when needed. An interesting detail is that when starting a channel, two chunks are buffered. Then it seems that a new chunk is buffered every time the FIFO runs less than half full.
Capture unit FIFOs are simple write buffers that hold 4 words. They are flushed to memory either when they're full of when the end of the capture length is reached (regardless of whether the capture loops).
So after implementing the whole FIFO thing, we can finally say that a bunch of sound issues are fixed! Surround works, sound effects in Golden Sun: Dark Dawn work too, some crackling that appeared in Rayman RR2 is gone, etc...
|6 comments have been posted.|