This may belong in the noobie section, but I figured since it deals solely with music that it would be more fitting here. Anyway...
I'm trying to modify an NES emulator (can be any NES emu, basically, though I've been working mostly with Nestopia and FCEU) to play a set of preset MP3s in place of its normal sound routines, specifically for Mega Man 2. I've already seen precedents of this sort of thing with Metal Mame (
http://metalmame.megadriver.com.br/meta ... =downloads) and a similar hack for snes9x (
http://www.megadriver.com.br/sitev2.html) but I don't know enough about the inner workings of MAME for the source to be helpful for anything more than a very general idea.
Admittedly, I have virtually no experience with emulation (or Assembly, which unfortunately I'm going to need, aren't I...), but I have a fair amount of exposure to C/C++, but I'm just wondering a few things, and thought this would be the right place to ask.
1. Am I in over my head or should this be relatively painless? I've already toyed around with the FCEU source a bit, but I don't want to waste my time if it simply isn't reasonable.
2. What would be the easiest emulator to accomplish this with? The MP3 support seems to be the biggest annoyance so far, since most of the sound libraries these emulators are using only support WAV or OGG.
Right now I'm thinking that the general solution is to recognize the sound init function being called (or maybe the play function?), determine what exactly is being accessed, and compare that to a hard-coded set of memory locations that correspond to the 24 songs in the game. Then any time that song would begin playing, just start streaming the MP3 and prevent the emu from actually playing the original music. Obviously, I'm using pretty general terms, as I still don't completely have my head around the specifics of what the emulator is doing. So...
3. Does that solution sound feasible/correct? If so, what's really the best way to implement it?
Anyway, I greatly appreciate any help, and, uh, sorry for that wall of text.
Seems simple enough. You need to first find/write a ROM patch that causes music tracks in the game to be silent (trying to do this on the emulator side would be very difficult), then have the emulator watch whatever memory location the game uses to keep track of the current song playing.
kalzone wrote:
The MP3 support seems to be the biggest annoyance so far, since most of the sound libraries these emulators are using only support WAV or OGG.
That's because Vorbis is both technically and legally better than MP3:
- Technically: Vorbis supports sample-accurate seeking, which makes it a heck of a lot easier to loop a song.
- Technically: For the same subjective sound quality, Vorbis uses about half to three-fourths the data size of MP3.
- Legally: MP3 is subject to numerous patents, some of which won't expire for another decade.
If you have the original wave files or CDs, you can transcode them to Vorbis using OggDropXPd. Otherwise, where did you get the MP3 files?
Quote:
Right now I'm thinking that the general solution is to recognize the sound init function being called (or maybe the play function?)
There's a cleaner solution: the NES program writes the song number to a register somewhere in $5000-$5FFF, and then the emulator plays the song. It'd be a lot like the way the Famicom version of Bases Loaded plays some of its sound effects. In fact, the method I describe could easily be implemented on the NES hardware by mapping a serial port into that address space and having the serial port control a CD player or an MP3 player.
Well, the reason I'm using MP3 is I'm intending to distribute this in a technically legal manner. So I'd include the emulator, and I suppose the ROM patch (which is actually a pretty good idea), but it would be up to the end user to supply the MP3s and the ROM...and I'm pretty confident the end user will have the songs in an MP3 format (since that's how they were originally distributed).
Basically, if I use OGG or WAV, then I need to include a song pack, or require the end user to convert their MP3's, which would be an annoyance.
Oh, and I got the MP3 files legally from the band (The Megas,
www.themegas.com) when I bought the CD.
Anyway, I found a RAM map for MM2:
http://datacrystal.org/wiki/Mega_Man_2:RAM_map
So, if I'm reading this correctly, the current song playing is stored in $0067 in the RAM, right? That'd make it pretty simple.
kalzone wrote:
I'm pretty confident the end user will have the songs in an MP3 format (since that's how they were originally distributed).
If you must use MP3, you can have the emulator use whatever MP3 player is already installed on the user's computer. Otherwise, you're going to have to license proprietary MP3 player software from Thomson Multimedia, and this license isn't going to be compatible with the GNU General Public License of, say, Nestopia or FCE Ultra.
Quote:
Oh, and I got the MP3 files legally from the band (The Megas,
www.themegas.com) when I bought the CD.
You could include a command-line ripper with your hack's installer. That way, you can be sure that the tracks are named in a way that your custom emulator can find.
Quote:
So, if I'm reading this correctly, the current song playing is stored in $0067 in the RAM, right? That'd make it pretty simple.
Yes, it would be pretty simple to patch the ROM to write to a mapper register instead of $0067.
Decided to take a couple minutes and do this much for you:
Megaman 2 (U):
www.angelfire.com/nc/ugetab/Megaman2_U_Music_Remove.ips
(copy and paste the link to a new window)
Removes all SFX under 21, which are music. Leaves the rest intact.
6502 isn't everyone's bag, even if they know a decent programming language. There's space enough to specifically make 00-20 music inits write to multiple unique addresses.
Oh man, awesome, I really appreciate it. I'll go download a rom patcher and try it out.
Works like a charm, can't thank you enough. At this rate, I could probably have this entire thing finished tonight. I figured out I misread that RAM map, and the byte representing the sound to be played is $0580 and not $0067...and with the beauty that is FCEUXD, I already have all of the corresponding values for each song. The rest should be pretty straightforward.
I've done something similar with my (stalled) Super Mario World project, except instead of integrating the player with the emulator, I made a stand-alone app that runs in the background. All it does is peek at the emulator's memory (currently ZSNES, others can be added easily) and wait for a specific byte sequence at a specific location in the emulated WRAM. Once found, it uses the next two bytes as a track number (xx.MP3) and play control. It only took a few minor hacks in SMW's sound code to interface with the player, and I'll probably add a routine that will reactivate the standard SPC music if the player isn't running (hopefully keeping emulation purists happy).
Now if I could just get my hacking groove back...
The MM2 "combo" is a LDA #music_id followed by a JSR $music_playback. I don't remeber the address, but that's it. As far as I know, there's no need of deep analysis over it. If the emulator finds the specific JSR, check the music_id and play the custom track.
Sure enough, I just ran MM2 through a trace logger and the "combo" is:
LDA #music_id
JSR $C051
Already fixed the code to reflect that, now it attempts to play all of the songs at the correct times...the problem is, now I can't seem to get them to play. I'm using the FMOD library for MP3 support, and it works fine when I test it in another project, and it even occasionally decides to work properly with this project, but for whatever reason, it just doesn't work consistently.
...
...
Apparently, FMOD likes having a slash before filenames.
>.>
<.<
Get equipped with fail!
Anyway, with that, looks like I finally have this finished up. Thanks for all the help guys, I'll make sure to give you all a shoutout in the readme.
Do you plan to make your customized emulator MM2-specific, or could I patch any other ROM with code to play MP3s as background music?
It's designed with only Mega Man 2 in mind...the design is basically:
//in LDA(), DT is BYTE
songCounter = DT
//in JSR(), EA is WORD
if (EA==0xC051)
{
switch (songCounter)
{
...
}
}
It relies entirely on what Fx3 mentioned, looking for specific arguments to LDA and JSR...it could probably be tweaked to work with other games, but it would be very game-specific.
Like tepples hinted at, it would make more sense to generalize this. Have the emulator respond to writes to a certain otherwise unused address, and patch the ROM to write there instead of starting the music normally. Then the emulator can have a directory of replacement soundtracks, each named by the byte written, in a directory named after the original ROM, with perhaps an IPS patch inside. Then you could add a GUI option "use custom soundtrack, if available" and it'd be completely automatic, and extensible without having to recompile the emulator.
Take a look at the coding for NSFs. That has custom addresses in action. 5FF8-5FFF control standard channels. If you have reads return 00 or 01 depending on external music availability, you can have writes to this address affect the music being played.
Well, it's finished up and packaged with all the necessary files to make it work properly (except the rom and some of the music)...but I have a kind of unrelated question. What's a good site I can use to host it? I'm a little iffy about posting it one of these normal hosting sites like Filefactory/Fileshack etc. based on the content..
kalzone wrote:
What's a good site I can use to host it?
Go Daddy hosting costs money per year, but at least I think it's worth it.
That's all right, I just stuck it on Rapidshare, should be good enough.
Lately, Rapidshare has been next to impossible to download from. Either you have to solve what might be the hardest
CAPTCHA on the Internet, or you have to pay. The members of tetrisconcept.com appear to recommend Mediafire or Sendspace or Zshare.
- Did you take care about *stopping the music*? If mind is good, the code is FEh or FFh. ^_^;; Just wondering since you mentioned "things ready".
- I can't wait to give a try.
There's no need to stop the music (except possibly when the emulator is paused, but I didn't bother to add that in)...every time the music is "stopped" it's only because something else is about to be played, so that handles itself.
Anyway, for anyone who
does want to give a try, you can download it
here. It's still on Rapidshare though, so be careful with that CAPTCHA, it's a doozy, apparently. The rom and some of the MP3's aren't included for legal issues, though, so I'm not sure how much use you'll get out of it unless you find all that.
kalzone wrote:
There's no need to stop the music (except possibly when the emulator is paused, but I didn't bother to add that in)...every time the music is "stopped" it's only because something else is about to be played, so that handles itself.
Anyway, for anyone who
does want to give a try, you can download it
here. It's still on Rapidshare though, so be careful with that CAPTCHA, it's a doozy, apparently. The rom and some of the MP3's aren't included for legal issues, though, so I'm not sure how much use you'll get out of it unless you find all that.
Can I please have permission to use a Windows (32bit EXE) Disassembler to privately use your code to make it handle the Mario Series, And only release it in EXEcutable form? Mario Hackers really need it too, I give credit for the permissive use of disassembled code
Heh, under the condition YOU know how to handle Mario's music playback, okay?
My code? Whoa...let's take a step back here...the original emulator is under the GNU public license; you and everyone else here has full rights to the source...I just figured it was too sloppy for it to be particularly useful to anyone. If there's actually a demand I'll go ahead and post the source. I need to switch to my other computer but give me a few minutes and I'll have it up. Fair warning: the sections I added are not commented at all.
In the same vein though...if you use this code for your Mario hack, you're basically obligated to release the source.
The thing is...my code is really designed to be generalized, for the most part. The MP3 playing code is fully self-contained (and mostly ripped from Metal MAME, actually)...but the code that triggers it is based on a specific sequence of instructions in the MM2 code. I'm not really sure how similar this sequence may be to that of other games, but I'm sure someone here could help.[/i]
Fx3 wrote:
Heh, under the condition YOU know how to handle Mario's music playback, okay?
Yea, I know how to delete mario's music data. But also know to see if the music is playing
Kalzone: Thank you for distributing the code, I will give you credit for using it.
If you already know all that, I'm not sure my code will really be any help, but good luck either way.
kalzone wrote:
If you already know all that, I'm not sure my code will really be any help, but good luck either way.
I do not know how to make music, Just know how to delete music in SMB1.
Oh, I was referring more to the "know if music is playing" part. The major difficulty I had with this project was just figuring out when exactly to play to the music...if you've got that down, then most of your work is already finished.
Anyway, because I hardly commented at all on the portions I edited, here's a few pointers:
-MP3play.h/MP3play.cpp is where all of the MP3 playback capabilities are
-The PlayFile function takes 4 arguments:
File path/name (and make sure to start that with a '/')
Whether the file loops or not (1 if it does, 0 if it doesn't)
Sample to begin the loop (int)
Sample to end the loop (int)
-The code that actually calls MP3play::PlayFile() is in Cpu.cpp
-This was briefly mentioned in a previous post, but the basic design is as follows:
There are two distinct blocks of instructions that mark the playing of a new sound effect or song in MM2:
LDA $XX ($XX = song/sfx identifier)
JSR $C051
...and...
LDA $XXXX, $XX ($XX = song/sfx identifier)
JSR $C051
The implentations of all of these instructions are located in the CPU.cpp source file. So, in MR_AX() and MR_IM(), which are called as part of the LDA opcodes (which one is called is dependent on whether the instruction is LDA $XXXX, $XX or LDA $XX), a BYTE variable named songCounter is set to whatever the current value of DT (the BYTE data being used with the instruction) is.
Then, whenever JSR is called, EA (the WORD used in the instruction) is checked against $C051. If EA==0xC051, then a switch statement just calls PlayFile according to the current value of songCounter. With this implementation, theoretically all sound effects could be replaced as well.
There is one exception, however. Through testing, it became apparent that Heat Man's weapon sfx had the same "sound effect number" as the "stage selected" music, so firing his weapon just causes that music to play over and over. The boolean value stageSelected was introduced to prevent this particular case. By default, stageSelected is false. When a call is made to play the "stage selection" music, it is assumed that the "stage selected" music will follow before Heat Man's weapon would be fired. Therefore, stageSelected is set to true whenever the "stage selection" music plays, and reset to false afterward.
So there you have it, a more thorough description of my modifications. Hopefully that'll help a bit, as much of what I described is specific to MM2, and now you have a better idea of what needs tweaking and what can be outright removed when working with another game.
- Interesting, and it's an old idea becoming reality thanks to an easy effort.
However, I have a few advices:
1. You didn't include stages music tracks in the package. ^_^;;
2. As I said, you should apply the FE (or FF) to stop the music. Some game transitions become weird if you don't do this... but fine.
3. Think about creating an INI file to save custom tracks. The user could change the default music track by another file, it would be cool.
4. The next "natural" step would be gfx enhancement...
Fx3 wrote:
- Interesting, and it's an old idea becoming reality thanks to an easy effort.
However, I have a few advices:
1. You didn't include stages music tracks in the package. ^_^;;
2. As I said, you should apply the FE (or FF) to stop the music. Some game transitions become weird if you don't do this... but fine.
3. Think about creating an INI file to save custom tracks. The user could change the default music track by another file, it would be cool.
4. The next "natural" step would be gfx enhancement...
1. Well, under the circumstances, I really
couldn't. The intention from the beginning was to release this directly to The Megas and their fans...and I'm sure they wouldn't be too happy with me distributing pirated copies of the album. Given that that was the target audience, though, there really wasn't a problem, because everyone would have their own legal copy.
2. I still can't think of any particular examples in game at all...if you were to try to apply these techniques to another game, that might be an issue, but in MM2, one ends when another starts.
3. Probably a good idea, as far as generalizing the code goes.
4. Gfx is a whole other ballpark, really, I'll let someone more experienced try to tackle something like that.
Oh guys ,awesome !I'll go download a rom patcher and try it out.
This is going to sound like a weird request, but could anyone that downloaded that code archive I posted rehost it somewhere?
In cleaning out my computer a few months ago, I accidentally erased it, and I want to make some minor modifications.