Page 1 of 1

Vibrato on square without phase reset

Posted: Tue Mar 08, 2005 4:12 am
by blargg
When the high 3 bits of the timer period of a square channel are changed by writing to $4003 or $4007, the waveform is restarted (phase is reset). This is fine if a new note is starting, but inconvenient if vibrato is being applied to one of the few notes which are near the timer periods of $100, $200, $300, $400, $500, $600, and $700.

After writing the recent sweep test ROMs, I was realized that the sweep could be used to set the high 3 bits of the timer period without restarting the wave. The basic idea is to use the sweep with shift = 7 to increment or decrement the high 3 bits, then clock the sweep immediately by writing to $4017. A shift of 7 results in an offset of of 1 to 15, greater for higher timer periods. If the low 8 bits are set to $ff when adding, $00 when subtracting, the offset will reliably increment or decrement the high 3 bits as desired. Once the high 3 bits have been changed with the sweep, the low 8 bits can be set directly.

I made a simple demo ROM that plays a tone that slow rises and falls, with slight vibrato. The phase never gets reset, so it always sounds clean. This technique might be useful for sound engines. The only issue is that the extra clocking of the sweep would rule out the use of the length counters, linear counter, volume envelopes, and normal sweeps, since the frame counter is used in a non-standard way. This wouldn't be a problem in a modern music engine that implements its own versions of these features in software to allow more flexibility and control.

Posted: Tue Mar 08, 2005 1:36 pm
by Bregalad
Interesting. I didn't got it very well. You write a 7 to the sweep's unit depht, but this could change to change vibrato depht, isn't it ? You said it would clock the lenght counters ? I belived it would just fixes their speed between two possible speeds.
So this would allow the sweep to start imediately, so a higer/lower tune is in the frequencey register, right ? So we have to never write anythig at the freqencey register exept at a new note state, right ?
This method won't allow any vibratoes on the triangle channel, but I think writing to $400b doesn't reset the triangle step generator or something, I've never heard anything like that so this could be done softwarely.
For now the simplest way to do vibratoes witout gliches is to toggle the frequencey's LSB bit with an EOR #$01.

Posted: Tue Mar 08, 2005 9:02 pm
by blargg
Vibrato is always done in software by constantly varying the note's frequency; there is no direct hardware support for it. When this requires adjusting the high 3 bits of the square's timer period, the usual method will result in the phase being reset constantly. This isn't necessary on the triangle channel beacuse its phase is never reset, even when changing the high 3 bits of its timer period.

Consider a square channel note with a period of $200. The music player's vibrato might set it to $200, $1FF, $200, $201, $200, $1FF etc. The music player must change the high 3 bits when going from $200 to $1FF and from $1FF to $200. This is the core problem.

Assuming the square is already set up as follows,

Code: Select all

lda  #$FF      ; low 8 bits
sta  $4002
lda  #$01      ; high 3 bits
sta  $4003
the usual way is to set the timer period normally,

Code: Select all

lda  #$00      ; set low 8 bits
sta  $4002
lda  #$02      ; set high 3 bits
sta  $4003
while the method I describe uses the sweep:

Code: Select all

lda  #$87      ; sweep enabled, shift = 7 (1/128)
sta  $4001
lda  #$C0      ; clock sweep immediately
sta  $4017
               ; timer period is now $202 ($1FF + ($1FF >> 7))
lda  #$00      ; set correct low 8 bits
sta  $4002
This special sequence is only necessary when the upper 3 bits of the timer period need to be changed without resetting the phase. When just the lower 8 bits need to be changed, they can be written directly.

A full implementation of this technique needs to do a few more things than shown above. The sweep units must have the minimum period set at all times (write $0F into them when they aren't being used), and some extra things must be done when changing the timer period:

Code: Select all

               ; increment timer period's high 3 bits
lda  #$40      ; reset frame counter in case it was about to clock
sta  $4017
lda  #$FF      ; be sure low 8 bits of timer period are $FF
sta  $4002
lda  #$87      ; sweep enabled, shift = 7 (1/128)
sta  $4001
lda  #$C0      ; clock sweep immediately
sta  $4017
lda  #$0F      ; disable sweep
sta  $4001
lda  #$xx      ; set correct low 8 bits
sta  $4002

Posted: Wed Mar 09, 2005 9:08 am
by Memblers
What a great trick. :D

I haven't ran it on my NES yet, but it seems like it would work well.

Posted: Sun Aug 28, 2005 3:31 pm
by blargg
(Bregalad's original post is in the thread "Viable game sound and music solution")
Bregalad wrote:I ask myself why you said #$0f would be written in the sweep units when not wrapping around freq for vibratoes. I understand that the bit 7 should be clear, but since it's clear the sweep units are totally disabled and have no effect, exept for limited frequency below very small periods (that would be dog whistle or somthing)
The enable bit of the sweep unit only affects modification of the frequency; the low-frequency cutoff is still in effect unless it's in subtract mode (in subtract mode there's no frequency cutoff). In order to completely eliminate the sweep unit's effect, it must be disabled and the mode must be set to subtract mode, i.e. bit 7 must be clear and bit 3 set ($08). If disabled but in add mode ($00 to $07) the channel is silenced if its frequency gets too low.
However, writing $08 or $0f shouldn't make any difference, or does it ?
No difference; $08 to $0f are all sufficient.
Also, does writing $40 or $c0 to $4017 while clocking the sweep units manyally make any difference ?
Yes, it makes a difference; writing $c0 or $80 to $4017 clocks the sweep immediately, while $40 or $00 to $4017 doesn't (it gets clocked in 1/120 second). Also, to ensure that the sweep will respond immediately when it is clocked, the period must always be set to 0. This is because when the sweep is clocked after being written to, the divider is clocked before reloading it.
Timelength conter : Only few games uses it, and it can be done very easily with software, and it can be 100% replaced by software, scince it has a one-frame precision, and scince one APU frame is more or less the same than one PPU frame, it'll have the exact same precision.
[...]
Triangle timer : This timer feathures more precision, (1/4 of an APU frame or am I wrong ?), so it can't be 100% replaced by software.
[...]
Decay unit : This one has sure few precision and I'm sure the software can 100% replace all it's features, with one-frame precision.
The decay unit is clocked four times per frame, and the length counter twice per frame, double that of the PPU's NMI. Sometimes it's documented as occurring only once per frame because the length table values are all even.

I think the Sunsoft drums use very short durations for the triangle's linear counter. Note that you can still use the linear counter, you just need to reload it with the proper value after doing any sweeps for the current 1/60 second.
Maybe the same precision could be reached if the sound code would be triggered twice per frame: One time with the PPU's NMI, and one time with a frame IRQ. However, scince $4017 is manually clocked, the frame IRQ couldn't work as we wan't it to, so scanline IRQ would be needed.
You could have the sound driver manually update the frequency every 1/60 second and use the sweep on a one-shot basis to change the frequency 1/120 second between updates. Programming sound effects wouldn't be as simple, but this would salvage the timing accuracy.

As you describe, even if you arranged for the APU's frame IRQ to occur between the PPU's NMI, it would drift, and would get reset when you clocked the sweep by writing to $4017. If a song didn't use the DMC, that could be used to generate a timebase from 522-4142Hz, or one-shot delays from 0.24-1.91 msec plus an optional multiple of 3.86 msec.

Posted: Mon Aug 29, 2005 9:04 am
by Bregalad
blargg wrote: Yes, it makes a difference; writing $c0 or $80 to $4017 clocks the sweep immediately, while $40 or $00 to $4017 doesn't (it gets clocked in 1/120 second). Also, to ensure that the sweep will respond immediately when it is clocked, the period must always be set to 0. This is because when the sweep is clocked after being written to, the divider is clocked before reloading it.
Ah, okay I got it, thanks. Effectively, write $40 to $4017 before enabling the sweep to delay it, then enable the sweep to eventually write $c0 to it should be safe
The decay unit is clocked four times per frame, and the length counter twice per frame, double that of the PPU's NMI. Sometimes it's documented as occurring only once per frame because the length table values are all even.
Well, this is still replacable with software, because the difference between a note that will have a decay value of zero (the shortest), or one code that will softwarely write the values $xf, $xb, $x7, $x3 then $x0 to the square channels control register would make no difference to human ear.
About the timer, could it be used to make if stopping half-one frame, to make a note shorter than a frame ? I was under the impression that was impossible, but the lenght tables are so un-logical and gabraged that I'd be unable to get any benefit of them, do a more complex enveloppe with software is by far better.
I think the Sunsoft drums use very short durations for the triangle's linear counter. Note that you can still use the linear counter, you just need to reload it with the proper value after doing any sweeps for the current 1/60 second.
Well, use very short notes duration is something usefull to simulate more realistic bass drum that a huge sweep down on the triangle channel, that sounds rather crazy (this is cool too, but it doesn't fin in all music style). But I also ask myself how would sound some effect that would use very short notes to make the channel enable, disable, enable, disable, etc... (chaning the state twice per frame) for special sound effects, while changing the pitch fastly. Also, making the channel randomly silenced at the segond half of a frame would be cool to make a "bubble" effect (creating some glitches in the sound and use them in a profitable way to do special tricks on music). Scince all theese effects are less than a frame long, it would be possible to rely on a value of $40 or $c0 that would be clocked before treating the triangle channel, scince the square channels would be treated before then the value for this is pretty stable (or am I wrong ?). Then, if there is nothing special on the square channels, nothing will be written to $4017 and this may cause audible differences.
You could have the sound driver manually update the frequency every 1/60 second and use the sweep on a one-shot basis to change the frequency 1/120 second between updates. Programming sound effects wouldn't be as simple, but this would salvage the timing accuracy.
Capcom games doesn't use sweeps at all, and does everything by software. Konami however used a lot the sweeps for the sound registers. I think both was good, but still the sweeps allows more precision for sound effects, and the thing will be the same as the triangle's linear counter for triggering it a segond time in the same frame. However, what about if a sound effect does this in the first treated square channel, and then the segond may have the 3 highest bits affected and modify the APU clock, so the sound effect would be highly affected. If all APU writes exept the frequencey thing with $4017 trick are buffered, this may be okay, isn't it ?
As you describe, even if you arranged for the APU's frame IRQ to occur between the PPU's NMI, it would drift, and would get reset when you clocked the sweep by writing to $4017. If a song didn't use the DMC, that could be used to generate a timebase from 522-4142Hz, or one-shot delays from 0.24-1.91 msec plus an optional multiple of 3.86 msec.
Well, wouldn't it just have audible stuff ? Even with only $55 samples, it would waste ROM and make a cute buzzy noise. With only $00 of $ff samples, after reseting it's DAC by writing, respectively, $00 or $7f to $4011 if would work fine, but still, PPU IRQ woud be better.

Posted: Mon Jan 04, 2010 1:33 am
by neilbaldwin
Did Blargg ever make source code available for this?

Posted: Wed Jan 27, 2010 5:36 pm
by neilbaldwin
I've just put this in NTRQ - it's perfect!

Nice one blargg :D

Re: Vibrato on square without phase reset

Posted: Sat Sep 15, 2012 11:04 pm
by shiftmore
brilliant!!!!
thanks.