APU Mixer: Difference between revisions

From NESdev Wiki
Jump to navigationJump to search
(fix link to legacy content)
m (fix deadlink)
 
Line 2: Line 2:
The [[APU|NES APU]] mixer takes the channel outputs and converts them to an analog audio signal. Each channel has its own internal digital-to-analog convertor (DAC), implemented in a way that causes non-linearity and interaction between channels, so calculation of the resulting amplitude is somewhat involved. In particular, games such as ''Super Mario Bros.'' and ''StarTropics'' use the DMC level ($4011) as a crude volume control for the triangle and noise channels.
The [[APU|NES APU]] mixer takes the channel outputs and converts them to an analog audio signal. Each channel has its own internal digital-to-analog convertor (DAC), implemented in a way that causes non-linearity and interaction between channels, so calculation of the resulting amplitude is somewhat involved. In particular, games such as ''Super Mario Bros.'' and ''StarTropics'' use the DMC level ($4011) as a crude volume control for the triangle and noise channels.


The following formula<ref>[http://blargg.8bitalley.com/nes-emu/apu_ref.txt apu_ref.txt] by blargg</ref> calculates the approximate audio output level within the range of 0.0 to 1.0. It is the sum of two sub-groupings of the channels:
The following formula<ref>[//www.nesdev.org/apu_ref.txt apu_ref.txt] by blargg</ref> calculates the approximate audio output level within the range of 0.0 to 1.0. It is the sum of two sub-groupings of the channels:


  output = pulse_out + tnd_out
  output = pulse_out + tnd_out

Latest revision as of 18:54, 13 December 2021

The NES APU mixer takes the channel outputs and converts them to an analog audio signal. Each channel has its own internal digital-to-analog convertor (DAC), implemented in a way that causes non-linearity and interaction between channels, so calculation of the resulting amplitude is somewhat involved. In particular, games such as Super Mario Bros. and StarTropics use the DMC level ($4011) as a crude volume control for the triangle and noise channels.

The following formula[1] calculates the approximate audio output level within the range of 0.0 to 1.0. It is the sum of two sub-groupings of the channels:

output = pulse_out + tnd_out

                            95.88
pulse_out = ------------------------------------
             (8128 / (pulse1 + pulse2)) + 100

                                       159.79
tnd_out = -------------------------------------------------------------
                                    1
           ----------------------------------------------------- + 100
            (triangle / 8227) + (noise / 12241) + (dmc / 22638)

The values for pulse1, pulse2, triangle, noise, and dmc are the output values for the corresponding channel. The dmc value ranges from 0 to 127 and the others range from 0 to 15. When the values for one of the groups are all zero, the result for that group should be treated as zero rather than undefined due to the division by 0 that otherwise results.

Faster but less accurate approximations are also possible: using an efficient lookup table, or even rougher with a linear formula.

The NES hardware follows the DACs with a surprisingly involved circuit that adds several low-pass and high-pass filters:

  • A first-order high-pass filter at 90 Hz
  • Another first-order high-pass filter at 440 Hz
  • A first-order low-pass filter at 14 kHz

See also:

The Famicom hardware instead ONLY specifies a first-order high-pass filter at 37 Hz, followed by the unknown (and varying) properties of the RF modulator and demodulator.

Emulation

The NES APU Mixer can be efficiently emulated using a lookup table or a less-accurate linear approximation.

Lookup Table

The APU mixer formulas can be efficiently implemented using two lookup tables: a 31-entry table for the two pulse channels and a 203-entry table for the remaining channels (due to the approximation of tnd_out, the numerators are adjusted slightly to preserve the normalized output range).

    output = pulse_out + tnd_out

    pulse_table [n] = 95.52 / (8128.0 / n + 100)

    pulse_out = pulse_table [pulse1 + pulse2]

The tnd_out table is approximated (within 4%) by using a base unit close to the DMC's DAC.

    tnd_table [n] = 163.67 / (24329.0 / n + 100)

    tnd_out = tnd_table [3 * triangle + 2 * noise + dmc]

Linear Approximation

A linear approximation can also be used, which results in slightly louder DMC samples, but otherwise fairly accurate operation since the wave channels use a small portion of the transfer curve. The overall volume will be reduced due to the headroom required by the DMC approximation.

    output = pulse_out + tnd_out
    
    pulse_out = 0.00752 * (pulse1 + pulse2)
    
    tnd_out = 0.00851 * triangle + 0.00494 * noise + 0.00335 * dmc

References

  1. apu_ref.txt by blargg