APU Mixer: Difference between revisions
(these formulas are from apu_ref) |
(fix link to legacy content) |
||
Line 20: | Line 20: | ||
Faster but less accurate approximations are also possible: using an efficient [[#Lookup Table|lookup table]], or even rougher 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 [//nesdev.org/NESAudio.gif surprisingly involved circuit] that adds several low-pass and high-pass filters: | 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: | ||
* 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 |
Revision as of 05:04, 7 November 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
- ↑ apu_ref.txt by blargg