APU Mixer: Difference between revisions
m (revise highpass corner frequency of original famicom) |
(Games believed to use $4011 as volume) |
||
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 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: |
Revision as of 21:39, 11 October 2020
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 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:
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.
This formula can be closely approximated using an efficient lookup table, or roughly approximated 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