So I need to know this before designing my sound engine and NMI a certain way... I want to use two 16+1 byte "dummy" DMC samples to apply volume control to the triangle channel (the noise channel inconsistency I can get rid of easily) one of them being all $00 bytes and the other $FF bytes embedded into my Init code so that it doesn't have to take more space from the fixed bank. But in the meantime I also want to use my percussive samples, so what I would have to do is make a version of each drum I need that sets the IRQ flag. The loading process is pretty straightforward, I have a table with $1F entries (the upper 3 bits being the note length) for each of the 4 DMC registers, so a $4011 write is also assigned to every one of them. What I would do when I want to keep the triangle volume down is playing the drum, and when the IRQ fires, play the $FF ramp immediately.
But what if this IRQ happens to fire during NMI, or during my OAM transfer? Does the IRQ fire at all? And if so, can it potentially mess with my transfer? If it's not reliable I will give up on this approach, I can also imagine the IRQ firing right when my wait for the end of VBlank is about to end and this happens and I lose some time and return to game logic a bit late.
Interrupt question
Moderator: Moderators
Re: Interrupt question
As long as your NMI doesn't clear the IRQ enable bit and doesn't write to the APU status register, the IRQ will remain asserted. If it is asserted, it will be handled as soon as the NMI finishes.za909 wrote:But what if this IRQ happens to fire during NMI
Yes, that means you could miss your reload window if your NMI handler takes too long.
Consider instead having two copies of each DMC instrument such that it will end at +max or -max on the APU DMC DAC when the sample completes instead.
APU DMC correctly steals cycles from OAM DMA.or during my OAM transfer?
- rainwarrior
- Posts: 8062
- Joined: Sun Jan 22, 2012 12:03 pm
- Location: Canada
- Contact:
Re: Interrupt question
As an alternative to using an IRQ or two versions of the samples, you could just poll $4015, and start your ramp sample when the DMC flag is clear (i.e. the sample is finished). 1 frame of latency on the volume control probably wouldn't be bad at all.
Re: Interrupt question
Thank you, yes I think I'll go with running this once per frame:
(apu2vol can be set to 0 or 1 with effect commands)
I'm not sure if writing to the frame counter is necessary, but I got freaked out when I read this on the wiki about $4015 reads: "Reading this register clears the frame interrupt flag (but not the DMC interrupt flag)." I'm not sure if the thing mentioned here is the interrupt inhibit flag in $4017 or the internal state of it.
It's basically no problem because I always play these at pitch 7, so I lose around 40 cycles from the NMI at most, but a sample at pitch F (which does happen) will steal around 168 cycles from my NMI anyway.
This could also make it trivial to write to $4011 when I start a "real" sample because the signal will either stick to $00 or $7F by default, and I also don't have to destroy the end of my samples completely with Famitracker's tilting function.
(apu2vol can be set to 0 or 1 with effect commands)
Code: Select all
ldy #$40
lda APUchenable
sty APUframecnt
and #$10 ; if DMC is not playing atm, play the right ramp sample
bne +isactive ; skip ramp loading
ldy apu2vol
lda #$07
sta APUdpcmpitch
lda APU2Vol_TBL,y ; select ramp
sta APUdpcmaddr
lda #$01
sta APUdpcmlength
lda #$1F
sta APUchenableIt's basically no problem because I always play these at pitch 7, so I lose around 40 cycles from the NMI at most, but a sample at pitch F (which does happen) will steal around 168 cycles from my NMI anyway.
This could also make it trivial to write to $4011 when I start a "real" sample because the signal will either stick to $00 or $7F by default, and I also don't have to destroy the end of my samples completely with Famitracker's tilting function.
- rainwarrior
- Posts: 8062
- Joined: Sun Jan 22, 2012 12:03 pm
- Location: Canada
- Contact:
Re: Interrupt question
Reading $4015 doesn't clear the interrupt inhibit flag in $4017. It clears the frame counter's internal flag that signals the interrupt itself (i.e. "acknowledges" the IRQ).