DSP HLE: reaching the finish line
In the last post, the last things that needed to be added to DSP HLE were the G711 ucode, and the basic audio functions common to all ucodes.

G711 was rather trivial to add. The rest was... more involved. Reason was that adding the new audio features required reworking some of melonDS's audio support.


melonDS was originally built around the DS hardware. As far as sound is concerned, the DS has a simple 16-channel mixer, and the output from said mixer is degraded to 10-bit and PWM'd to the speakers. Microphone input is even simpler: the mic is connected to the touchscreen controller's AUX input. Reading said input gives you the current mic level, and you need to set up a timer to manually sample it at the frequency you want.

So obviously, in the early days, melonDS was built around that design.

The DSi, however, provides a less archaic system for producing and acquiring sound.

Namely, it adds a TI audio amplifier, which is similar to the one found in the Wii U gamepad, for example. This audio amplifier also doubles as a touchscreen controller, for DS backwards compatibility.

Instead of the old PWM stuff, output from the DS mixer is sent to the amplifier over an I2S interface. There is some extra hardware to support that interface. It is possible to set the sampling frequency to 32 KHz (like the DS) or 47 KHz. There is also a ratio for mixing outputs from the DS mixer and the DSP.

Microphone input also goes through an I2S interface. The DSi provides hardware to automatically sample mic input at a preset frequency, and it's even possible to automate it entirely with a NDMA transfer. All in all, quite the upgrade compared to the DS. Oh, and mic input is also routed to the DSP, and the ucodes have basic functions for mic sampling too.

All fine and dandy...


So I based my work on CasualPokePlayer's PR, which implemented some of the new DSi audio functionality. I added support for mixing in DSP audio. The "play sound" command in itself was trivial to implement in HLE, once there was something in place to actually output DSP audio.

I added support for the different I2S sampling frequencies. The 47 KHz setting doesn't affect DS mixer output beyond improving quality somewhat, but it affects the rate at which DSP output plays.

For this, I changed melonDS to always produce audio at 47 KHz (instead of 32 KHz). In 32 KHz mode (or in DS mode), audio output will be resampled to 47 KHz. It was the easiest way to deal with this sort of feature.

Then, I added support for audio output to Teakra. I had to record the audio output to a file to check whether it was working correctly, because it's just too slow with DSP LLE, but a couple bugfixes later, it was working.


Then came the turn of microphone input. The way it's done on the DSP is a bit weird. Given the "play sound" command will DMA sound data from ARM9 memory, I thought the mic commands would work in a similar way, but no. Instead, they just continually write mic input to a circular buffer in DSP memory, and that's about it. Then you need to set up a timer to periodically read that circular buffer with PDATA.

But there was more work to be done around mic input.

I implemented a centralized hub for mic functionality, so buffers and logic wouldn't be duplicated in several places in melonDS. I also changed the way mic input data is fed into melonDS. With the hub in place, I could also add logic for starting and stopping mic recording. This way, when using an external microphone, it's possible to only request the mic when the game needs it, instead of hogging it all the time.

Besides that, it wasn't very hard to make this new mic input system work, including in DSi mode. I made some changes to CasualPokePlayer's code to make it more accurate to hardware. I also added the mic sampling commands to DSP HLE, and added BTDMP input support to Teakra so it can also receive mic input.

The tricky part was getting input from an external mic to play nicely and smoothly, but I got there.

There is only one problem left: libnds homebrew in DSi mode will have noisy mic input. This is a timing issue: libnds uses a really oddball way to sample the DSi mic (in order to keep it compatible with the old DS APIs), where it will repeatedly disable, flush and re-enable the mic interface, and wait to receive one sample. The wait is a polling loop with a timeout counter, but it's running too fast on melonDS, so sometimes it doesn't get sampled properly.


So, this is mostly it. What's left is a bunch of cleanup, misc testing, and adding the new state to savestates.

DSP HLE is done. It should allow most DSP titles to play at decent speeds, however if a game uses an unrecognized DSP ucode, it will fall back to LLE.

The dsp_hle branch also went beyond the original scope of DSP HLE, but it's all good.

DSi mode finally gets microphone input. I believe this was the last big missing feature, so this brings DSi mode on par with DS mode.

The last big thing that might need to be added would be a DSP JIT, if there's demand for this. I might look into it at some point, would be an occasion to learn new stuff.

I'm thinking those changes might warrant a lil' release.
Reual says:
Oct 13th 2025
I have a request that I hope someday we can see. Short of it is, rtcom support. (Circlepad patch for 3ds for example on super Mario 64 ds)

While it is absolutely not part of the Nintendo ds, unfortunately it is kinda one of those things that doesn't really fit cleanly.

If I understood it better I would try to do a PR, but I don't really have that much time between my job and other stuff I have to do.
Arisotura says:
Oct 14th 2025
I was actually looking into it a while back, and while it sounds fun, it also seems annoying to do from a technical standpoint, because the rtcom stuff seems to run code on the 3DS ARM11 and it seems to be different for each game...
Post a comment
Name:
DO NOT TOUCH