nesdev.com
http://forums.nesdev.com/

Managing mmc3 splits and sound engine
http://forums.nesdev.com/viewtopic.php?f=2&t=17128
Page 1 of 1

Author:  GradualGames [ Sat Mar 10, 2018 3:30 pm ]
Post subject:  Managing mmc3 splits and sound engine

In the past, I would always run my sound engine after nmi. In my current game I've introduced mmc3 splits. In some parts of the game, there are some splits near the top of the screen. In others, they are near the bottom. Having the sound engine always run after nmi caused some jitters (with the splits) in some cases. So, I moved it to running after the last split irq. However, in this case I ran into a subtle intermittent chr bankswitching bug where the next nmi would interrupt the currently running irq, due to the sound engine running slightly long on occasion.

My solution has been to configure the split system I have to run the sound engine after a specific split where I know there's more than enough time before the next irq.

I was kinda curious if anybody else has done this out there, either for homebrew or if anyone has seen it done in commercial games.

Author:  tepples [ Sat Mar 10, 2018 4:47 pm ]
Post subject:  Re: Managing mmc3 splits and sound engine

Here's what The Curse of Possum Hollow (MMC3) does:

All bank switching outside interrupt handlers is done by writing to two variables in RAM and then calling a subroutine that copies the values in RAM to MMC3 window registers 6 and 7. Though the NMI and IRQ handlers modify CHR-related window registers (0-5), they always finish by restoring these values to registers 6 and 7. So even if the subroutine that restores these values is interrupted, the result will still be correct. I took pains to ensure the correctness of this reentrancy.

Neither the NMI handler nor the IRQ handler interacts with audio at all. Audio runs on the main thread, where the loop for each game state periodically calls a subroutine that does this:

  1. If the master NMI counter (incremented by NMI) and music NMI counter are equal: Return.
  2. Switch $8000 to the audio engine's bank and $A000 to the bank containing the current song's music sequence data (of which there are three).
  3. If a music change was requested, start it.
  4. If a sound effect was requested, switch in the audio engine and start it. This queue is organized as a bitfield, with one bit per sound effect. For simplicity, only one sound effect can start in each frame, and lower-numbered sound effects get priority.
  5. Until the master NMI counter and music NMI counter are equal: Call the audio engine's update routine once and increment the music NMI counter.

Because of this catch-up mechanism, lag frames do not cause a loss of tempo, only a momentary stutter. And so long as this subroutine is called a couple times per game loop and at strategic points during blank screen updates, this stutter is unnoticeable in practice.

Author:  GradualGames [ Sat Mar 10, 2018 5:05 pm ]
Post subject:  Re: Managing mmc3 splits and sound engine

tepples wrote:
So even if the subroutine that restores these values is interrupted, the result will still be correct. I took pains to ensure the correctness of this reentrancy.

I do have code in place to ensure that if PRG bankswitching is done during nmi, nmi will return and the bank select register will be what it was supposed to be before nmi. I do all chr bankswitching during nmi, and never in the main thread so I do not protect it there.

I believe I was running into issues where the last mmc3 irq I configured was itself being interrupted by nmi before returning (due to the sound engine).

I am not sure I understand exactly what is happening when this scenario occurs; it seems it is probably better to ensure that it CAN'T occur, would you agree?

...I was considering doing music updates during the main thread, myself, but this approach of choosing a split after which to run the sound engine appears to be working well.

Author:  rainwarrior [ Sat Mar 10, 2018 9:00 pm ]
Post subject:  Re: Managing mmc3 splits and sound engine

GradualGames wrote:
My solution has been to configure the split system I have to run the sound engine after a specific split where I know there's more than enough time before the next irq.

That seems pretty sensible to me.

Author:  TmEE [ Sun Mar 11, 2018 7:09 am ]
Post subject:  Re: Managing mmc3 splits and sound engine

I would make the sound engine just create list of IO writes allowing the engine to be called any time in the frame. Then in NMI you'll send that list to sound chip(s), it will surely take whole lot less cycles to do than running the entire sound engine there and you can even make the list writes take fixed amount of time allowing some additional possibilites.

Author:  pubby [ Sun Mar 11, 2018 7:19 am ]
Post subject:  Re: Managing mmc3 splits and sound engine

Use a sound engine that runs in a fixed number of cycles every frame 8-)

Author:  GradualGames [ Sun Mar 11, 2018 8:11 am ]
Post subject:  Re: Managing mmc3 splits and sound engine

pubby wrote:
Use a sound engine that runs in a fixed number of cycles every frame 8-)

:lol: I was actually thinking about your engine while solving this problem, but it's well in hand now.
TmEE wrote:
I would make the sound engine just create list of IO writes allowing the engine to be called any time in the frame. Then in NMI you'll send that list to sound chip(s), it will surely take whole lot less cycles to do than running the entire sound engine there and you can even make the list writes take fixed amount of time allowing some additional possibilites.

One of my goals is to keep the sound engine running at a consistent fps so even if the game slows down the sound/music does not.

Author:  TmEE [ Sun Mar 11, 2018 8:24 am ]
Post subject:  Re: Managing mmc3 splits and sound engine

You can always have one extra MMC3 IRQ for the sound engine at some non critical area of the frame or perhaps call the engine right after the code of last split.

Page 1 of 1 All times are UTC - 7 hours
Powered by phpBB® Forum Software © phpBB Group
http://www.phpbb.com/