APU Mixer: Difference between revisions
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. | ||
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 [ | |||
* 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
- ↑ apu_ref.txt by blargg