DPCM + $2007 reads
Moderator: Moderators
- TakuikaNinja
- Posts: 89
- Joined: Mon Jan 09, 2023 6:42 pm
- Location: New Zealand
- Contact:
Re: DPCM + $2007 reads
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.
Re: DPCM + $2007 reads
Yeah, this is just a hard transition to a separate pause screen, performance is hardly a concern.
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.TakuikaNinja wrote: ↑Mon Mar 13, 2023 12:38 amHonestly, I think the simplest workaround is to disable the DMC channel before the $2007 reads.
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.
- Jarhmander
- Formerly ~J-@D!~
- Posts: 569
- Joined: Sun Mar 12, 2006 12:36 am
- Location: Rive nord de Montréal
Re: DPCM + $2007 reads
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?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.
((λ (x) (x x)) (λ (x) (x x)))
- TakuikaNinja
- Posts: 89
- Joined: Mon Jan 09, 2023 6:42 pm
- Location: New Zealand
- Contact:
Re: DPCM + $2007 reads
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.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?
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: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.
- 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.
- Kill some time until the sample finishes playing (1 frame is overkill, so more fine-grained timing methods should be used here).
- Proceed with the $2007 reads.
Last edited by TakuikaNinja on Tue Mar 14, 2023 12:01 am, edited 1 time in total.
Re: DPCM + $2007 reads
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).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?
- TakuikaNinja
- Posts: 89
- Joined: Mon Jan 09, 2023 6:42 pm
- Location: New Zealand
- Contact:
Re: DPCM + $2007 reads
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:
The revised steps would be:
- 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.
- After returning from the sound engine update, poll bit 4 of $4015 until it gets cleared.
- Proceed with the $2007 reads.
- Jarhmander
- Formerly ~J-@D!~
- Posts: 569
- Joined: Sun Mar 12, 2006 12:36 am
- Location: Rive nord de Montréal
Re: DPCM + $2007 reads
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.Fiskbit wrote: ↑Mon Mar 13, 2023 10:30 pmYes. 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).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?
((λ (x) (x x)) (λ (x) (x x)))
Re: DPCM + $2007 reads
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.