Managing mmc3 splits and sound engine

Discuss technical or other issues relating to programming the Nintendo Entertainment System, Famicom, or compatible systems. See the NESdev wiki for more information.

Moderator: Moderators

Post Reply
User avatar
GradualGames
Posts: 1106
Joined: Sun Nov 09, 2008 9:18 pm
Location: Pennsylvania, USA
Contact:

Managing mmc3 splits and sound engine

Post by GradualGames »

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.
tepples
Posts: 22708
Joined: Sun Sep 19, 2004 11:12 pm
Location: NE Indiana, USA (NTSC)
Contact:

Re: Managing mmc3 splits and sound engine

Post by tepples »

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.
User avatar
GradualGames
Posts: 1106
Joined: Sun Nov 09, 2008 9:18 pm
Location: Pennsylvania, USA
Contact:

Re: Managing mmc3 splits and sound engine

Post by GradualGames »

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.
User avatar
rainwarrior
Posts: 8732
Joined: Sun Jan 22, 2012 12:03 pm
Location: Canada
Contact:

Re: Managing mmc3 splits and sound engine

Post by rainwarrior »

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.
User avatar
TmEE
Posts: 960
Joined: Wed Feb 13, 2008 9:10 am
Location: Norway (50 and 60Hz compatible :P)
Contact:

Re: Managing mmc3 splits and sound engine

Post by TmEE »

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.
User avatar
pubby
Posts: 583
Joined: Thu Mar 31, 2016 11:15 am

Re: Managing mmc3 splits and sound engine

Post by pubby »

Use a sound engine that runs in a fixed number of cycles every frame 8-)
User avatar
GradualGames
Posts: 1106
Joined: Sun Nov 09, 2008 9:18 pm
Location: Pennsylvania, USA
Contact:

Re: Managing mmc3 splits and sound engine

Post by GradualGames »

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.
User avatar
TmEE
Posts: 960
Joined: Wed Feb 13, 2008 9:10 am
Location: Norway (50 and 60Hz compatible :P)
Contact:

Re: Managing mmc3 splits and sound engine

Post by TmEE »

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.
Post Reply