APU Triangle

From Nesdev wiki
Jump to: navigation, search

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
$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:

  1. 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.
  2. If the control flag is clear, the linear counter reload flag is cleared.

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

At the lowest two timer periods ($400B = 0 and $400A = 0 or 1), the resulting frequency is so high (over 20 kHz) that the mixer effectively receives a value half way between 7 and 8.
Note: If you're using this to silence the triangle channel, be aware that this makes a popping noise, because the triangle output is basically jumping to "7.5", from wherever it was before (could be 0 or 15). Mega Man 1 and 2 do this.

If that's undesirable, then there are three other ways to silence the triangle channel:

  • Use the linear counter to control the length of the note. This may be a bit limiting, because the linear counter doesn't allow for super-long notes.
  • Use $4015 to turn off the triangle channel when it needs to be silent (don't forget to turn it back on). However, writing to $4015 may cause problems if you're using the DMC.
  • Use the following writes when you want to silence the triangle channel:
    1. Write $00 to $4008. This sets the linear counter to 0.
    2. Write to $400B. This is to reload the linear counter with that 0. Be careful, because this register contains 3 bits of the triangle channel's period. You'd either need to rewrite the same value to this register, or write $07 to change the period to something low pitched and unnoticable.
    3. Write to $4017 with bit 7 set. This will immediately clock the linear counter, reloading it, and silencing the triangle channel. This step is optional, but if you don't do this, there will be a random delay before the triangle channel is actually silenced, which is why it's important to pay attention to what you write to $400B in the previous step.
      • If you want to use the things that depend on the frame counter, you can simply write to $4017 every frame at the end of your music routine, instead of compulsively writing to $4017 only when you want to silence the triangle channel. This will keep the frame counter's sequencer consistent.