Comments (92)
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.
from snes9x.
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).
from snes9x.
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.
from snes9x.
@bearoso here you go https://github.com/qwertymodo/snes9x/commit/3c0f6bfdee082441f429a399ccb6af5575f5015c
from snes9x.
Added you as a collaborator, and cloned your branch to msu1 in git repository.
from snes9x.
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.
from snes9x.
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.
from snes9x.
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.
from snes9x.
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
from snes9x.
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.
from snes9x.
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).
from snes9x.
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.
from snes9x.
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.
from snes9x.
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.
from snes9x.
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.
from snes9x.
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.
from snes9x.
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.
from snes9x.
Well, progress. The mapping is working now, so the S9xMSU1ReadPort and S9xMSU1WritePort functions are being called properly. Now to actually implement those functions...
from snes9x.
I have data reads working, my Chrono Trigger FMV hack plays the video perfectly. Now I just need to figure out the audio mixing.
from snes9x.
That was certainly fast O.O
from snes9x.
Cool to see that a feature I've been hoping for is possibly going to happen. ^^ Here's hoping for no hiccups.
from snes9x.
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.
from snes9x.
What have BearOSO and OV2 said about that?
from snes9x.
Nobody has said anything. I just got bored and started writing code.
from snes9x.
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 -_-
from snes9x.
@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.
from snes9x.
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
from snes9x.
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?
from snes9x.
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.
from snes9x.
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.
from snes9x.
It's in msu1 branch of the main git.
from snes9x.
I've switched everything over to the branch you created, so I'll go ahead and delete my fork.
from snes9x.
OK, I think I got it right this time. We really need to get rid of 8-bit and Mono support. Nothing needs those any more.
from snes9x.
Are you able to actually test with an MSU-1 enabled ROM? This one should work (you'll need the .bps, the .pcm, and the .msu, all in the same directory as the ROM file): https://github.com/qwertymodo/ct-anime-intro
The FMV should load immediately after the opening title.
from snes9x.
Yeah, I literally just finished testing that. Nope, no sound still.
from snes9x.
Both dest and msu_sample are of type uint8 *, so I need to extract the actual samples as uint16 before summing. No sound here as well. At least increasing the buffer size and fixing the loop counters seems to have eliminated the unhandled exception crashes I was getting, though.
from snes9x.
You don't have an actual buffer in msu1.cpp. You're just tossing pointers around. For that matter, I see what you meant about not knowing where to put MSU1Execute. You're trying to implement the audio playing logic like the SPC chip, but it has no clock-speed or LLE implementation--I think it should just generate the samples on-demand for the output.
from snes9x.
Yeah, there's no need for a clock or LLE since it's just streaming samples directly from the file. So long as the buffer doesn't underrun, it doesn't really matter how fast you fill it, or when. The buffer lives in apu.cpp (msu::landing_buffer), and just gets passed to the MSU, the same way spc::landing_buffer does. The problem I'm seeing in my debugging is that the test msu::resampler->avail() >= sample_count isn't ever evaluating as true, although msu::resampler->avail() is nonzero. I probably need to be using a separate sample_count for the MSU samples, but that's back into the territory of things-I-don't-understand-yet about the way inner workings of the APU implementation.
from snes9x.
My idea is to reuse MSU1Execute as a generation function, and just call it during S9xFinalizeSamples with the appropriate ratio to get a relative number from the audio file.
from snes9x.
Ok, I'll play around with that idea.
from snes9x.
I pushed a general idea of what I had in mind. The buffer management I think is still broken, though, because it can only ever use 1 buffer of data.
from snes9x.
There are quite a number of problems in my S9xMSU1Execute function. For one, the pointer comparison to end the while loop was broken because it was translating the pointers as signed types. Now that's fixed, but I'm running into some kind of file IO error where audioFile.fail() is being set. That would explain the msu::landing_buffer->avail() not being large enough.
from snes9x.
Also keep in mind s9xinitsound is called before any game is loaded, so comparing to Settings.MSU1 will always fail the first time unless you change a setting that reinits sound.
from snes9x.
Good catch, I already removed 2 of those checks in initsound, but I missed the one for the buffer_size.
from snes9x.
Made some more changes. Unfortunately, I'm still getting the audioFile.failbit set after about 70 samples, resulting in all further samples being read as 0. I'm not sure why the failbit is being set...
from snes9x.
Oh FFS, I was opening the audioFile without ios::binary. It works now, and I'm getting audio. Just need to test a bit more before I push.
from snes9x.
The audio is popping quite a bit. Probably still need to hammer out some details with the buffering, but other than that, it's working. I also need to add the additional config option for adding an "MSU Data" path, and the GUI code for setting it, and then savestate support.
For consistency's sake, what is the current file load logic for things like .srm and .ips files located in the same directory as the ROM file? Do they override files in their respective config path, or is it config path > rom dir, or is it just config path and nothing else?
from snes9x.
For loading things it's really a mess. Could be port specific or might not be.
Might need to increase the landing buffer size to 441000/320405 times its current size and take into account input-rate, which it's not currently doing. I'll do that.
from snes9x.
Adjusted input rate and I'm not getting any popping.
Generally, I think stuff should go in what Snes9x calls the "patch directory." If you're loading from that I think things should be fine.
from snes9x.
For SRM it's port specific, for patches you can check CMemory::CheckForAnyPatch and mimic its logic (matching files in ROM dir first, otherwise checks IPS directory).
from snes9x.
The files in question (.msu/.pcm) aren't patch files, they are data files, so I don't feel like they belong in the patch directory (the .bps is another matter, of course).
@bearoso I tried the buffer_size adjustment without the time_ratio adjustment that you reverted, and I'm still getting pops.
from snes9x.
For those of you following along at home...
https://www.youtube.com/watch?v=wf5dwf6eSLU
from snes9x.
Holy crap O.O So glad that Higan won't be required for this, I could never get the manifest and PCM files to work correctly.
from snes9x.
The main reason for that, roflcopter777, is there is actually two main formats for manifest.bml's: pre-Higan 0.96 and 0.96+. They changed the format, and you have to match the format with the emulator version or convert it manually which can be complicated for end-users.
For reference to developers, here's two manifests for either format for Zelda Link to the Past:
And just a hint: Most of the MSU-1 hacks are in the old format.
from snes9x.
Ugh, no wonder I was confused, go fig -_- Hopefully this will make it easier for me to do once it's finalized, I feel like a...never mind.
from snes9x.
A fig?
from snes9x.
Go figure* Slang. Anyways, I was just saying no wonder it didn't work, sorry about that.
from snes9x.
I'm so excited to see this happening. Love the video! :)
from snes9x.
I was making a joke roflcopter777. Lol.
from snes9x.
Sorry, long stressful day >.> Anyways, looking forward to MSU1 on Snes9x
from snes9x.
How is it on your end with the time ratio adjustment still there? That adjustment is logically required to keep parity with the SNES sound, but it seemed to me like it desynced with the video in Chrono trigger.
from snes9x.
I managed to pick up nasty bug of some kind, I probably won't be working on this much for a few days. I'll try out the time ratio when I get the chance. I also don't remember, when it reads out from the resampler, I feel like I had it read all available samples from the msu resampler, when what I should have done is read out as many msu samples as there were spc samples, that would be the real solution, syncing it up on the the output end of the resamplers, not the input. But I don't have the code in front of me, so I'm not sure.
from snes9x.
That's...not a good sign -_-
from snes9x.
I'm sick, not dead. Just give me a few days to rest up.
from snes9x.
Take your time
from snes9x.
That's what it's doing since I made it into S9xMSU1Generate. It looks at how many SPC samples have been made and makes the appropriate number of MSU1 samples. So it should be synced up there. With the time ratio multiplying the MSU1 resampler, both resamplers should then have the same amount of output timewise.
I'm sure what byuu's doing is resampling down to 32040hz, and mixing in to the SNES audio at its native rate. This is what would happen on the SD2SNES, too.
from snes9x.
No that's not what happens on the SD2SNES, it plays it back at the full 44.1k and the mixing is done in analog.
from snes9x.
OK. I've monitored the buffer levels with the input rate change and they're balanced now. Things shouldn't be popping unless the audio output in general is doing so.
from snes9x.
And was not aware the mixing was done in analog. Wouldn't being output by the SNES DSP force it to 32040hz?
from snes9x.
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.
from snes9x.
Crap, I hit the wrong button, ignore that close.
from snes9x.
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.
from snes9x.
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.
from snes9x.
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?
from snes9x.
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).
from snes9x.
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.
from snes9x.
Awesome work :D
from snes9x.
48 downloads, and no complaints so far...
from snes9x.
What downloads?
from snes9x.
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?
from snes9x.
Do the ROMs need a special folder in the Snes9x root directory?
from snes9x.
@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.
from snes9x.
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
from snes9x.
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.
from snes9x.
@bparker06 Is that in a separate repo, or are you talking about the libretro core in this repo?
from snes9x.
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?
from snes9x.
@qwertymodo Their forked repo libretro/snes9x has MSU-1 support in master.
from snes9x.
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.
from snes9x.
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.
from snes9x.
Ok, hang on, I'm screwing things up. Let me fix things.
from snes9x.
Ok, should be fixed and done.
from snes9x.
Looks good to me.
from snes9x.
Related Issues (20)
- Request: Some Cheat Search & Editor improvements HOT 2
- What is stdout.txt and stderr.txt? And a request. HOT 11
- Snes9x game genie cheat codes HOT 4
- Request: Add a VRAM/Graphics viewer
- Clarification: App requires monitor keystrokes from any apps permission HOT 6
- Bug: Missing Background Graphics HOT 4
- Request: Overhaul the Hotkey Configuration Menu HOT 4
- Bug? Hotkey config isn't saving "Bank-" & "Bank+" entries HOT 1
- Request: a small screenshot behavior change HOT 2
- Linux 32-bit Version
- Request: 2 small Cheat Search window improvements
- Emulation runs twice as fast when interlacing is turned on HOT 2
- Snes9x crashes with Vulkan. HOT 2
- v1.63's readme-windows.txt is outdated HOT 2
- Hotkeys for cheat edit/search don't show. HOT 3
- No Game Window MacOS Sonoma HOT 5
- Frame Count does not appear in Snes9X 1.63. HOT 2
- Can't load roms made from the Quad randomizer HOT 7
- Request: More options for Joypad swap!
- [Request] A new audio backend for windows port HOT 1
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from snes9x.