FCEUX's FrameAdvance() Function

Discuss emulation of the Nintendo Entertainment System and Famicom.

Moderator: Moderators

Post Reply
User avatar
BioMechanical Dude
Formerly AlienX
Posts: 137
Joined: Fri Apr 18, 2014 7:41 am
Location: Bulgaria

FCEUX's FrameAdvance() Function

Post by BioMechanical Dude »

I'm working on a Lua script for FCEUX and I just realized, that there are some details, regarding the FrameAdvance() function, that I don't know.
First of all, what does the function exactly do? From what I understand it unpauses the emulator for 1/60 seconds, so that one frame can play out and then it pauses it again. Is that just it, or is there a bit more?
When, for example, you use the sound.get() function in between frames, does that access the state of the APU from the frame that was just played, or from the frame that is about to play, when using the FrameAdvance() function? Does any of the game code, executed during VBlank come into play?
I hope someone can tell me. It'll be very useful.

Thanks.
Greetings! I'm That Bio Mechanical Dude and I like creating various stuff like movies, games and of course chiptunes!
You can check out my YouTube Channel.
You can also follow me on Twitter.
Bavi_H
Posts: 141
Joined: Sun Mar 03, 2013 1:52 am
Location: Texas, USA
Contact:

Re: FCEUX's FrameAdvance() Function

Post by Bavi_H »

I don't know the exact details to answer your question, but when I investigated NES sound using FCEUX's lua, I copied the method the included scripts SoundDisplay.lua and SoundDisplay2.lua use -- they set up a function that gets called every frame using emu.registerafter.

While using those scripts, if I pause the emulation and step it a frame at a time, I can hear a new sound start and the corresponding display change at the same time, so that's good enough for me for now.

But if anyone else has more details about the exact timing positions of FCEUX's emu.frameadvance (and emu.registerafter, emu.registerbefore, and gui.register), I'd be interested to learn more.
User avatar
rainwarrior
Posts: 8062
Joined: Sun Jan 22, 2012 12:03 pm
Location: Canada
Contact:

Re: FCEUX's FrameAdvance() Function

Post by rainwarrior »

Unless I'm mistaken, I believe it runs until the next NMI. i.e. when control returns to the lua script, the PPU is about to generate an NMI signal for a new frame.
(I could be wrong, but I don't know any other place that would be sensible to break.)

All accesses to memory or the APU, etc. should be consistent with this timing.
User avatar
BioMechanical Dude
Formerly AlienX
Posts: 137
Joined: Fri Apr 18, 2014 7:41 am
Location: Bulgaria

Re: FCEUX's FrameAdvance() Function

Post by BioMechanical Dude »

Well, after playing around with the various functions, including frameadvance(), it seems that they won't do good and I'll have to have the script pause the emulator manually. Basically, I need the script to execute code every time a VBlank has ended and the PPU is about to draw the screen again. Most games update their sound during VBlank and I need to catch the updates at the right time. Because frameadvance() seems to pause the emulator, when an NMI occurs, there is a one frame delay between when the game updates its sound and when the script reads the state of the APU. Check out this thread for more information.
Greetings! I'm That Bio Mechanical Dude and I like creating various stuff like movies, games and of course chiptunes!
You can check out my YouTube Channel.
You can also follow me on Twitter.
User avatar
rainwarrior
Posts: 8062
Joined: Sun Jan 22, 2012 12:03 pm
Location: Canada
Contact:

Re: FCEUX's FrameAdvance() Function

Post by rainwarrior »

Many games will finish their sound update past the end of vblank. It's usually consistently timed from the start of NMI, but there's no constraints in there that require the APU to be operated within vblank, only the PPU stuff needs to finish by then.

I don't think there's a consistent thing you could do to trap the end of APU updates, it's going to be very different, game to game.

You could try to trap it at the RTI from NMI, and this would be good for games that do sound last in their NMI, but not good for any game that does its game logic or raster effects in the NMI routine, or games that do music outside of NMI. Optimally, you need to analyze each game and figure out where the sound routine ends; put a trap there.

Pragmatically, maybe just do your test 30 scanlines or so into the picture. You'd probably be early enough to avoid the first frame counter clock (1/4 frame), so the APU state should still be "fresh", and you'd probably be late enough that most music engines are done by then.
User avatar
BioMechanical Dude
Formerly AlienX
Posts: 137
Joined: Fri Apr 18, 2014 7:41 am
Location: Bulgaria

Re: FCEUX's FrameAdvance() Function

Post by BioMechanical Dude »

Well, at first I wanted to pause the emulator at the RTI, but considering all you've mentioned and that frameadvance() won't do much good anyway, and that the FCEUX.pause() function pauses the emulator until you manually unpause it, I've decided to just put an event listener for when the necessary writes happen to the APU. That way it wouldn't matter whether they're happening during VBlank or outside of it, the code will be executed immediately after the writes.
Greetings! I'm That Bio Mechanical Dude and I like creating various stuff like movies, games and of course chiptunes!
You can check out my YouTube Channel.
You can also follow me on Twitter.
Post Reply