APU Triangle: Difference between revisions
Rainwarrior (talk | contribs) (rewriting the silencing advice. in particular the advice to write $400B after $4008 seems very confused (probably because of the omission remedied by my last edit)) |
Rainwarrior (talk | contribs) (a redundant clarifying note that points out why the write to $400B isn't quite intuitive as a linear counter reload) |
||
Line 52: | Line 52: | ||
# If the linear counter reload flag is set, the linear counter is reloaded with the counter reload value, otherwise if the linear counter is non-zero, it is decremented. | # If the linear counter reload flag is set, the linear counter is reloaded with the counter reload value, otherwise if the linear counter is non-zero, it is decremented. | ||
# If the control flag is clear, the linear counter reload flag is cleared. | # If the control flag is clear, the linear counter reload flag is cleared. | ||
Note that writes to both $4008 and $400B will set the reload flag and cause a reload of the linear counter at the next frame sequence tick, even though $400B does not change the reload value. | |||
The sequencer is clocked by the timer as long as both the linear counter and the [[APU Length Counter|length counter]] are nonzero. | The sequencer is clocked by the timer as long as both the linear counter and the [[APU Length Counter|length counter]] are nonzero. |
Revision as of 02:44, 20 March 2019
The NES APU triangle channel generates a pseudo-triangle wave. It has no volume control; the waveform is either cycling or suspended. It includes a linear counter, an extra duration timer of higher accuracy than the length counter.
The triangle channel contains the following: timer, length counter, linear counter, linear counter reload flag, control flag, sequencer.
Linear Counter Length Counter | | v v Timer ---> Gate ----------> Gate ---> Sequencer ---> (to mixer)
$4008 | CRRR.RRRR | Linear counter setup (write) |
bit 7 | C---.---- | Control flag (this bit is also the length counter halt flag) |
bits 6-0 | -RRR RRRR | Counter reload value |
Side effects | Sets the linear counter reload flag | |
$400A | LLLL.LLLL | Timer low (write) |
bits 7-0 | LLLL LLLL | Timer low 8 bits |
$400B | llll.lHHH | Length counter load and timer high (write) |
bits 2-0 | ---- -HHH | Timer high 3 bits |
Side effects | Sets the linear counter reload flag |
The sequencer is clocked by a timer whose period is the 11-bit value (%HHH.LLLLLLLL) formed by timer high and timer low, plus one. Given t = HHHLLLLLLLL, the timer counts t, t-1, ..., 0, t, t-1, ..., clocking the waveform generator when it goes from 0 to t. Unlike the pulse channels, this timer ticks at the rate of the CPU clock rather than the APU (CPU/2) clock. So given the following:
- fCPU = the clock rate of the CPU
- tval = the value written to the timer high and low registers
- f = the frequency of the wave generated by this channel
The following relationships hold:
- f = fCPU/(32*(tval + 1))
- tval = fCPU/(32*f) - 1
Unlike the pulse channels, the triangle channel supports frequencies up to the maximum frequency the timer will allow, meaning frequencies up to fCPU/32 (about 55.9 kHz for NTSC) are possible - far above the audible range. Some games, e.g. Mega Man 2, "silence" the triangle channel by setting the timer to zero, which produces a popping sound when an audible frequency is resumed, easily heard e.g. in Crash Man's stage. At the expense of accuracy, these can be eliminated in an emulator e.g. by halting the triangle channel when an ultrasonic frequency is set (a timer value less than 2).
When the frame counter generates a linear counter clock, the following actions occur in order:
- If the linear counter reload flag is set, the linear counter is reloaded with the counter reload value, otherwise if the linear counter is non-zero, it is decremented.
- If the control flag is clear, the linear counter reload flag is cleared.
Note that writes to both $4008 and $400B will set the reload flag and cause a reload of the linear counter at the next frame sequence tick, even though $400B does not change the reload value.
The sequencer is clocked by the timer as long as both the linear counter and the length counter are nonzero.
The sequencer sends the following looping 32-step sequence of values to the mixer:
15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15
The triangle channel can be silenced by several methods:
- Write $80 to $4008, which will halt and reload the linear counter with 0 at the next frame sequence tick. This can be simply resumed by writing $FF to $4008.
- Optionally: a write to $4017 after the write to $4008 can trigger an immediate frame sequence tick, if the 1/4 frame delay of the frame sequence is undesirable. This has all the other consequences of the frame sequence tick, however.
- Use $4015 to turn off the channel, which will clear its length counter. To resume, turn it back on via $4015, then write to $400B to reload the length counter.
- When using DPCM samples, it is difficult to manipulate a single bit in $4015 without risking conflict with the DPCM control.
- Write a period value of 0 or 1 to $400A/$400B, causing a very high frequency. Due to the averaging effect of the lowpass filter, the resulting value is halfway between 7 and 8.
- This sudden jump to "7.5" causes a harder popping noise than other triangle silencing methods, which will instead halt it in whatever its current output position is.
- Mega Man 1 and 2 use this technique.
- Either the length counter or linear counter can be used to automatically halt the triangle after a period of time.
- Unfortunately this is limited to very short durations because the linear counter can only go as high as 127 quarter frames.