Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

MSU-1 support #79

Closed
Hydro5 opened this issue May 19, 2015 · 92 comments
Closed

MSU-1 support #79

Hydro5 opened this issue May 19, 2015 · 92 comments
Assignees

Comments

@Hydro5
Copy link

Hydro5 commented May 19, 2015

How difficult would it be to add support for the MSU-1?

@DerekTurtleRoe
Copy link

Considering the MSU-1 was created as an open standard, and considering BSNES/Higan already has support, it shouldn't be impossible. Possible difficulty is probably the only thing from stopping anybody.

@jcdenton2k
Copy link

It would not be difficult but there's a lot of politics involved. A custom chip created by byuu (already a polarizing figure in the emulation community) despite the best intentions and even despite the open-sourcing of it does create an artificial demand for one very specific flash kart that has the MSU-1 and throws money at byuu with every sale.

That is only the tip of the iceberg. If you really want such support then use whatever version of higan/bsnes that you wish to use. I'd say bsnes-classic if you have the hardware to handle the strain.

@Drakonas
Copy link

The problem arises that when you want netplay, Higan/BSNES is lacking in this area. I'd like to be able to have netplay with the MSU-1 romhacks if at all possible... I understand there may be desyncs though. There is a "server" tab in Higan, but documentation is lacking on the feature.

@jcdenton2k
Copy link

jcdenton2k commented Jul 23, 2016

Your best bet is to poke this as a feature suggestion on SNES9X-Next over at RetroArch and see if they're willing to drop in support. This SNES9X vanilla development has already stalled out for the forseeable future.

Alternatively, you could try making an account on the higan forums and asking byuu to do netplay. I admire the passion and dedication to accurate emulation that byuu has helped to accomplish in the emulation community but holy shit it will be like trying to steal gold from Fort Knoxx if you go that route.

I'd poke my head in there myself but my forum account was very quickly permabanned for having the audacity to suggest that maybe having a modified folder solution (while keeping the original ROM file intact) would be more ideal to the end-user. As in obfuscate all that folder stuff into a separate thing and automagically extract the necessary things from the ROM file when it is loaded so that the end-user does not even need to be aware of anything going on behind the scenes. It would just be transparent and easy.

The response I got was legendary and I wish I'd screencapped it. Just figured I'd let you know what you're getting yourself into if you try to make suggestions for higan.

Then there's the various bsnes forks that you could poke to see if any of them want to add in netplay. That is a much more sane option, IMHO.

@qwertymodo
Copy link
Collaborator

MSU-1 is very simple to implement, netplay is not, especially for a cycle-based emulator like higan, especially now that the formerly-labeled "accuracy" core is now the only one maintained. Now that the MSU-1 has gained some significant traction and has been added to quite a few games, it would be a really neat feature to have.

The entire implementation in higan is <200 lines of code: https://gitlab.com/higan/higan/blob/master/higan/sfc/coprocessor/msu1/msu1.cpp

@jcdenton2k
Copy link

Since my last post, development has increased but I'm not certain how many devs there are willing to put in MSU-1 support. Might be worthwhile to ping a dev and ask em directly.

@bearoso
Copy link
Collaborator

bearoso commented Nov 2, 2016

That file is deceptive, since it omits the entire audio file logic.

Nonetheless, it is merely a memory-mapped API which is fairly simple. The difficulties would be platform-specific, and the fact that we have no way of specifying a MSU-1 game or its data (higan uses manifests).

@bearoso
Copy link
Collaborator

bearoso commented Nov 2, 2016

Manifests, I should add, come partly from game folders. So if you want that oft-maligned feature to come to Snes9x, byuu will be very happy.

@qwertymodo
Copy link
Collaborator

Don't bother with manifests, I would use the SD2SNES logic. If romname.msu exists in the same folder as the ROM, enable MSU-1 for the game, then the music files are just assumed to be romname-{tracknum}.pcm.

@qwertymodo
Copy link
Collaborator

There is no audio file logic unless you mean the mixing. The files are raw 16-bit pcm, so you just load the 16-bit value and mix it directly into the audio steam.

@qwertymodo
Copy link
Collaborator

Ok, now that I'm in front of my computer instead of on my phone, I can add a little more detail. There is no need for either game folders or manifests. However, due to the large number of .pcm files in the average MSU-1 game hack, it might be worth having a separate folder for MSU-1 files, the same way there is for saves, screenshots, etc, so you don't have all of those files dumped into the ROM folder. Either way, like I said, the SD2SNES is able to detect and support MSU-1 games without any manifest or game folder, it just looks for the existence of romname.msu in the same folder as the ROM file (or possibly in the MSU folder if you wanted to go that route). If it exists, enable MSU-1 support. When a new track is loaded, assume romname-{trackname}.pcm (with no leading 0's, so -1, not -01). Loading a sample is as simple as reading the next 4 bytes as 2 16-bit PCM samples and adding them to the current DSP sample (higan used to average them instead, but eventually byuu realized there was plenty of headroom, and averaging caused MSU-1 games to sound quieter than the originals, so adding ended up being the better option all around).

Beyond that, the entire chip consists of 8 read-only registers and 8 write-only registers. The read-only registers consist of 6 ID constants 'S' '-' 'M' 'S' 'U' '1', a status register, and the data read port, which just outputs the value of the MSU data ROM at the current seek pointer, and then increments the seek pointer. The status register contains flags indicating data busy (for seek operations, not really necessary in an emulator), audio busy (again, for seek, also not necessary), audio repeating, audio playing, track missing (so that the game can fall back to its original SPC track in case the .pcm file for that track doesn't exist), and a 3-bit revision code.

The write-only registers are a 4-byte data seek address, 2-byte audio track, audio volume, and the audio control. Audio control only uses 3 bits, play, repeat, and resume.

That's really all there is to it. It was designed to be simple, and it is. Just for fun, I decided to try implementing it myself. I have never touched the Snes9x codebase before, so I still have no idea where a lot of the stuff is, but I already have a pretty good start on it. I think I have most of what I need added to memmap.h/cpp to detect and register the mapping, and have the basic framework of the msu1.h/cpp files set up, now I just need to figure out where the emulator actually does the mmio operations and how to hook that up into the new chip.

@qwertymodo
Copy link
Collaborator

qwertymodo commented Nov 2, 2016

Hmm... if I'm understanding the mapping code correctly, it seems like it's not possible to apply a mapping smaller than $1000 bytes. The MSU-1 registers are $00-$3F,$80-$BF:$2000-$2007, but when I try to apply that mapping, it overwrites the mapping for all of $2000-$2FFF, which includes the APU and PPU register mappings at $2100-$21FF.

Edit: Ok, now I see the whole section $2000-$2FFF is mapped as PPU, and then the APU writes are handled inside ppu.cpp. That's... inelegant, to say the least, but for consistency's sake, I'll forgo attempting to map the MSU-1 registers and just handle them there as well.

@roflcopter777
Copy link

Having a single dedicated MSU-1 folder in the Snes9x root folder would actually make it far easier to install and use MSU-1 ROM hacks without the need of a manifest file. So I agree, the SD2Snes method sounds better than the Higan method.

@qwertymodo
Copy link
Collaborator

Well, progress. The mapping is working now, so the S9xMSU1ReadPort and S9xMSU1WritePort functions are being called properly. Now to actually implement those functions...

@qwertymodo
Copy link
Collaborator

qwertymodo commented Nov 2, 2016

I have data reads working, my Chrono Trigger FMV hack plays the video perfectly. Now I just need to figure out the audio mixing.

snes9x_msu_video

@roflcopter777
Copy link

That was certainly fast O.O

@Drakonas
Copy link

Drakonas commented Nov 2, 2016

Cool to see that a feature I've been hoping for is possibly going to happen. ^^ Here's hoping for no hiccups.

@qwertymodo
Copy link
Collaborator

If there's anybody around here familiar with the audio code willing to give me a hand (or if this isn't a great place to find such a person, but there's a better place I could be asking), I'd certainly appreciate it. I need to read samples at 44.1kHz regardless of the output sampling rate, and mix them into the output audio.

Also, I need to figure out where the cleanup routines are called when resetting or loading another ROM, for things like closing the audio and data files. For now, I'm just loading files from the ROM directory, but if I get it all working, I'll look into adding a separate folder.

@roflcopter777
Copy link

What have BearOSO and OV2 said about that?

@qwertymodo
Copy link
Collaborator

Nobody has said anything. I just got bored and started writing code.

@roflcopter777
Copy link

But maybe they could offer some help? I'm too uh, unskilled at programming, believe me. I wish there was some way I could help -_-

@jcdenton2k
Copy link

jcdenton2k commented Nov 3, 2016

@bearoso @OV2 we summon thee into this thread to assist @qwertymodo with their awesome MSU-1 support implementation request! ❤️

That should get their attention. :)

Qwertymodo, you are absolutely amazing. The people over on the RetroCollective Discord are in awe at your technical prowess, as am I.

@bearoso
Copy link
Collaborator

bearoso commented Nov 3, 2016

I'm not sure how Higan handles the audio. There's two approaches: downsample to 32040.5hz and mix with the SNES audio directly, which gets resampled into the output rate, or resample from 44.1khz into whatever the output is, which would be port specific.

From memory, I believe it's the former, but I'd have to look into it to make sure. I would think the latter approach would lend itself to desyncing

@qwertymodo
Copy link
Collaborator

qwertymodo commented Nov 3, 2016

Looking at apu/apu.cpp, it collects samples from the DSP into a buffer called spc::landing_buffer, which it then pushes into a hermite_resampler ring buffer, then reads it back out again. It seems like that's where the resampling is done between the DSP rate and the output rate. The resampling ratio is set by a call to UpdatePlaybackRate(). This call would seem to be port agnostic, as it calculates the ratio like so:

double time_ratio = (double) Settings.SoundInputRate * spc::timing_hack_numerator / (Settings.SoundPlaybackRate * spc::timing_hack_denominator);

So, my thought is to instantiate a second hermite_resampler for the MSU-1 samples, set the time_ratio using 44100 in place of Settings.SoundInputRate, then basically mirror everything involving landing_buffer and the resampler to the MSU, then at the very end of the chain, just before the sample is sent off to the audio driver, combine the two. The part I haven't figured out yet is how the SPC is being synchronized, i.e. if I have a ReadNextSample() function that needs to be called at 44.1kHz, which is responsible for filling the landing_buffer, how do I do that?

@bearoso
Copy link
Collaborator

bearoso commented Nov 3, 2016

You wanna put up a GitHub repository with your changes so far? It would be easier to see what's going on and help.

I'd take where the DSP generates final samples and keep a running fraction of 441000:320405 DSP samples. That'd keep the two sound buffers close as possible. Then put the extra samples in the separate landing buffer that is also sized proportionately larger.

@qwertymodo
Copy link
Collaborator

@bearoso here you go https://github.com/qwertymodo/snes9x/commit/3c0f6bfdee082441f429a399ccb6af5575f5015c

@bearoso
Copy link
Collaborator

bearoso commented Nov 3, 2016

Added you as a collaborator, and cloned your branch to msu1 in git repository.

@bearoso
Copy link
Collaborator

bearoso commented Nov 3, 2016

Looks very good, but I noticed a couple things wrong. Your buffer size was too small relative to the main SPC buffer. You also made the faux pas of sizeofing the dest pointer in S9xMixSamples, so you were only looping 4/8 times instead of over the whole buffer. See if this improves things.

@bearoso
Copy link
Collaborator

bearoso commented Nov 3, 2016

It's in msu1 branch of the main git.

@qwertymodo
Copy link
Collaborator

I've switched everything over to the branch you created, so I'll go ahead and delete my fork.

@bearoso
Copy link
Collaborator

bearoso commented Nov 4, 2016

And was not aware the mixing was done in analog. Wouldn't being output by the SNES DSP force it to 32040hz?

@qwertymodo
Copy link
Collaborator

qwertymodo commented Nov 4, 2016

I could be wrong about that but I don't know how it would work if it did. The audio is definitely output from the cart in analog on pins 31/62. It wouldn't make sense to take an analog signal, digitize it, resample it, mix it as digital, then convert back to analog again. I'm pretty sure the mixing between the DSP/cart pins/expansion header is all done in analog. It's been awhile since I've looked at the schematics though.

@qwertymodo
Copy link
Collaborator

Crap, I hit the wrong button, ignore that close.

@qwertymodo qwertymodo reopened this Nov 4, 2016
@qwertymodo
Copy link
Collaborator

I'm having some weird issues with audio resume, and I'm not sure why. Now that things are actually working, I'm going to redo the control logic in the ReadPort and WritePort to match higan more closely. It'll also make the code easier to maintain if any changes need to be made in the future.

@qwertymodo
Copy link
Collaborator

Also, @bearoso re: analog mixing. See the schematics here http://forums.nesdev.com/viewtopic.php?f=12&t=10470

Or, here's just the analog mixer. The cart audio pins don't go into the DSP at all. The DSP output, cart output, and expansion output all get mixed in analog. However, the DSP is able to mute all 3 by pulling down the input of Q13, which grounds out the input into the LM324 op-amp.
snes_mixer

@qwertymodo
Copy link
Collaborator

I tried the latest audio sync update, and it sounds good. No pops, and I didn't notice any desync, though the real test for desync would be to try a much longer audio file like the BS-Zelda releases. Now, I need to dig into the savestate code. Other than that and cross-platform testing, is there anything else that needs to be done here?

@qwertymodo qwertymodo self-assigned this Nov 6, 2016
@qwertymodo
Copy link
Collaborator

I'm unable to get the GTK port running correctly in my Ubuntu VM, but from the commit logs, it seems like @bearoso is using that port, so I guess that means it's working in Linux? (I'm still working my way through snapshot.cpp, but I figured I'd try the Linux build in the meantime).

@qwertymodo
Copy link
Collaborator

Ok, I got snapshots working. The audio crackles a bit for a second when you load the state, but it goes away once the buffers sync up.

@qwertymodo
Copy link
Collaborator

At this point, I think it's basically done. I just need to actually play through a game for a bit to test out that everything is working as expected.

@roflcopter777
Copy link

Awesome work :D

@qwertymodo
Copy link
Collaborator

48 downloads, and no complaints so far...

@roflcopter777
Copy link

What downloads?

@qwertymodo
Copy link
Collaborator

http://forums.nesdev.com/viewtopic.php?f=12&t=15084

(Note, the links might be down for awhile today, I need to do server maintenance).

@roflcopter777
Copy link

Nice, I can test it out, glad we don't need those pesky manifest files anymore. Would the ROM hacks on .that hacking site have all the necessary files for the music?

@roflcopter777
Copy link

Do the ROMs need a special folder in the Snes9x root directory?

@qwertymodo
Copy link
Collaborator

qwertymodo commented Nov 10, 2016

@roflcopter777 no root folder. I briefly considered going down that route, and it was determined that it would be a bad idea to do so. MSU-1 games should probably go in their own subfolders though, to keep all of the files contained. e.g. {Snes9xDir}\ROM\somemsugame\somemsugame.(sfc|msu|pcm) and {Snes9xDir}\ROM\someothermsugame\someothermsugame.(sfc|msu|pcm)

Also, I went ahead and updated the links to more stable ones, so there shouldn't be any downtime now. I'll mess with the other server stuff later.

@roflcopter777
Copy link

Already downloaded a link for the Windows build, so I just place them in their respective ROM folders in the ROM directory, okay, sounds straightforward, will test :D

@ghost
Copy link

ghost commented Nov 13, 2016

It looks like the MSU-1 support was added to RetroArch's snes9x core, so it should be working there (along with netplay) as well.

@qwertymodo
Copy link
Collaborator

@bparker06 Is that in a separate repo, or are you talking about the libretro core in this repo?

@qwertymodo
Copy link
Collaborator

Just curious, what's the process to move forward with merging this? There haven't been any reported issues other than one that turned out to be an issue with the audio files and not with Snes9x. I don't know if anybody other than @bearoso has tested the GTK build, but I've had over 100 downloads of the Windows build I made. Is there anything else I need to do on my end, or is it just a wait until we get around to it kind of thing at this point?

@ghost
Copy link

ghost commented Nov 14, 2016

@qwertymodo Their forked repo libretro/snes9x has MSU-1 support in master.

@bearoso
Copy link
Collaborator

bearoso commented Nov 14, 2016

I was just waiting until you were done. I think the one thing left is the libretro port in this repository needs to add msu1.cpp to the build.

@qwertymodo
Copy link
Collaborator

Ok, added it to the libretro build. I think I'm done on my end, unless something comes up. As @OV2 mentioned above, probably best to omit 4a7d40e from the merge, but the rest should be good.

@bearoso
Copy link
Collaborator

bearoso commented Nov 14, 2016

Ok, hang on, I'm screwing things up. Let me fix things.

@bearoso
Copy link
Collaborator

bearoso commented Nov 14, 2016

Ok, should be fixed and done.

@qwertymodo
Copy link
Collaborator

Looks good to me.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

8 participants