APU Mixer: Difference between revisions

From NESdev Wiki
Jump to navigationJump to search
m (revise highpass corner frequency of original famicom)
m (fix deadlink)
 
(4 intermediate revisions by 2 users not shown)
Line 1: Line 1:
[[Category:APU]]
[[Category:APU]]
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.
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 calculates the 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
Line 18: Line 18:
The values for [[APU Pulse|pulse1]], [[APU Pulse|pulse2]], [[APU Triangle|triangle]], [[APU Noise|noise]], and [[APU DMC|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.
The values for [[APU Pulse|pulse1]], [[APU Pulse|pulse2]], [[APU Triangle|triangle]], [[APU Noise|noise]], and [[APU DMC|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.


This formula can be closely approximated using an efficient [[#Lookup Table|lookup table]], or roughly approximated with a [[#Linear Approximation|linear formula]].
Faster but less accurate approximations are also possible: using an efficient [[#Lookup Table|lookup table]], or even rougher with a [[#Linear Approximation|linear formula]].


 
The NES hardware follows the DACs with a [//archive.nesdev.org/NESAudio.gif surprisingly involved circuit] that adds several low-pass and high-pass filters:
The NES hardware follows the DACs with a [http://nesdev.org/NESAudio.gif surprisingly involved circuit] that adds several low-pass and high-pass filters:
* A first-order high-pass filter at 90 Hz
* A first-order high-pass filter at 90 Hz
* Another first-order high-pass filter at 440 Hz
* Another first-order high-pass filter at 440 Hz
Line 54: Line 53:
     tnd_out = tnd_table [3 * triangle + 2 * noise + dmc]
     tnd_out = tnd_table [3 * triangle + 2 * noise + dmc]
</pre>
</pre>


=== Linear Approximation ===
=== Linear Approximation ===
Line 67: Line 65:
     tnd_out = 0.00851 * triangle + 0.00494 * noise + 0.00335 * dmc
     tnd_out = 0.00851 * triangle + 0.00494 * noise + 0.00335 * dmc
</pre>
</pre>
== References ==
<references />

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