DPCM + $2007 reads

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

User avatar
TakuikaNinja
Posts: 89
Joined: Mon Jan 09, 2023 6:42 pm
Location: New Zealand
Contact:

Re: DPCM + $2007 reads

Post by TakuikaNinja »

Honestly, I think the simplest workaround is to disable the DMC channel before the $2007 reads. Since you're aiming to use this in a pause menu, you can get away with playing a song which does not use DPCM. Otherwise, muting DMC can just be masked as some audio effect a la SMBUSA, where the pause track mutes everything but the triangle and noise.
User avatar
tokumaru
Posts: 12427
Joined: Sat Feb 12, 2005 9:43 pm
Location: Rio de Janeiro - Brazil

Re: DPCM + $2007 reads

Post by tokumaru »

Fiskbit wrote: Sun Mar 12, 2023 8:32 pmIf you can turn rendering off, the performance difference is not so impactful.
Yeah, this is just a hard transition to a separate pause screen, performance is hardly a concern.
TakuikaNinja wrote: Mon Mar 13, 2023 12:38 amHonestly, I think the simplest workaround is to disable the DMC channel before the $2007 reads.
Temporarily disabling the DMC channel might not be so trivial if you're using someone else's sound engine... If you can simply stop the current song, great, but doing raw APU writes that might conflict with what the engine is doing doesn't sound like a good idea.

The fact is that this problem exists, and much like every other problem, there are pros and cons to each possible solution, and the specificities of each project will have a great impact on determining which is the most appropriate one.
User avatar
Jarhmander
Formerly ~J-@D!~
Posts: 569
Joined: Sun Mar 12, 2006 12:36 am
Location: Rive nord de Montréal

Re: DPCM + $2007 reads

Post by Jarhmander »

TakuikaNinja wrote: Mon Mar 13, 2023 12:38 am Honestly, I think the simplest workaround is to disable the DMC channel before the $2007 reads. Since you're aiming to use this in a pause menu, you can get away with playing a song which does not use DPCM. Otherwise, muting DMC can just be masked as some audio effect a la SMBUSA, where the pause track mutes everything but the triangle and noise.
It's an interesting solution to the DMC conflict, but is it guaranteed that a DMC DMA will never occur after the store instruction that disable the DMC channel?
((λ (x) (x x)) (λ (x) (x x)))
User avatar
TakuikaNinja
Posts: 89
Joined: Mon Jan 09, 2023 6:42 pm
Location: New Zealand
Contact:

Re: DPCM + $2007 reads

Post by TakuikaNinja »

Jarhmander wrote: Mon Mar 13, 2023 7:25 pm It's an interesting solution to the DMC conflict, but is it guaranteed that a DMC DMA will never occur after the store instruction that disable the DMC channel?
Good question. Disabling DMC only makes the channel silent after finishing the remaining bits in the sample buffer. Even polling bit 4 of $4015 would only report if there are any bytes remaining, which doesn't consider the buffer contents.
tokumaru wrote: Mon Mar 13, 2023 6:01 am Temporarily disabling the DMC channel might not be so trivial if you're using someone else's sound engine... If you can simply stop the current song, great, but doing raw APU writes that might conflict with what the engine is doing doesn't sound like a good idea.
Playing a new sample is handled by most sound drivers as "toggle the DMC enable bit to ensure the new sample plays". A 1-byte sample at the highest playback rate should finish after around 432 cycles (approx. 4 scanlines, not accounting for any extra delays). Once the sample finishes, no more DMAs will occur unless a new sample is loaded. Given that info, here is a sound engine friendly solution I came up with:
  1. Play a 1-byte sample as a sound effect and change the song to something which does not use DMC. If the sound engine supports arbitrary DMC note/SFX lengths (not coupled to sample length), make it last longer than it takes to do the $2007 reads to eliminate the need for a song change.
  2. Kill some time until the sample finishes playing (1 frame is overkill, so more fine-grained timing methods should be used here).
  3. Proceed with the $2007 reads.
Last edited by TakuikaNinja on Tue Mar 14, 2023 12:01 am, edited 1 time in total.
Fiskbit
Posts: 891
Joined: Sat Nov 18, 2017 9:15 pm

Re: DPCM + $2007 reads

Post by Fiskbit »

Jarhmander wrote: Mon Mar 13, 2023 7:25 pm It's an interesting solution to the DMC conflict, but is it guaranteed that a DMC DMA will never occur after the store instruction that disable the DMC channel?
Yes. When you stop DMC playback by writing to $4015 (I call this 'explicitly' stopping playback), at worst you'll get a 1-cycle halt on the 2nd or 3rd cycle after the write (see DMA#Bugs).
User avatar
TakuikaNinja
Posts: 89
Joined: Mon Jan 09, 2023 6:42 pm
Location: New Zealand
Contact:

Re: DPCM + $2007 reads

Post by TakuikaNinja »

Ah, so my initial idea of polling $4015 until the remaining bytes becomes 0 would work in that case. Stupid me editing it out because I thought the DMAs would still happen while emptying the sample buffer after muting DMC... (outside of these bugs which I did not know about until now)
The revised steps would be:
  1. Play a 1-byte sample as a sound effect and change the song to something which does not use DMC. If the sound engine supports arbitrary DMC note/SFX lengths (not coupled to sample length), make it last longer than it takes to do the $2007 reads to eliminate the need for a song change.
  2. After returning from the sound engine update, poll bit 4 of $4015 until it gets cleared.
  3. Proceed with the $2007 reads.
User avatar
Jarhmander
Formerly ~J-@D!~
Posts: 569
Joined: Sun Mar 12, 2006 12:36 am
Location: Rive nord de Montréal

Re: DPCM + $2007 reads

Post by Jarhmander »

Fiskbit wrote: Mon Mar 13, 2023 10:30 pm
Jarhmander wrote: Mon Mar 13, 2023 7:25 pm It's an interesting solution to the DMC conflict, but is it guaranteed that a DMC DMA will never occur after the store instruction that disable the DMC channel?
Yes. When you stop DMC playback by writing to $4015 (I call this 'explicitly' stopping playback), at worst you'll get a 1-cycle halt on the 2nd or 3rd cycle after the write (see DMA#Bugs).
Nice, so it means that in the worst case, a DMC DMA will occur within like, 11 CPU cycles after the store? Seems pretty workable.
((λ (x) (x x)) (λ (x) (x x)))
Fiskbit
Posts: 891
Joined: Sat Nov 18, 2017 9:15 pm

Re: DPCM + $2007 reads

Post by Fiskbit »

When stopping playback explicitly by clearing the bit in $4015, you only have to worry about the 1-cycle halt on the 2nd or 3rd following cycle. When starting a sample, the next halt could be anytime in the current DMC period; if the buffer is empty, you'll get it on the 3rd or 4th following cycle, and otherwise sometime later when the buffer is emptied. If you're playing a 1-byte sample, then you can get these 1- or 4-cycle buggy DMAs, but they occur very close to your write as shown in the examples on the wiki, much earlier than the latest time the fetch could happen if the buffer were full.
Post Reply