APU Mixer: Difference between revisions
Rainwarrior (talk | contribs) (merge from APU Mixer Emulation) |
m (fix deadlink) |
||
(10 intermediate revisions by 3 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 | |||
95.88 | |||
pulse_out = ------------------------------------ | |||
(8128 / (pulse1 + pulse2)) + 100 | |||
159.79 | |||
tnd_out = ------------------------------------------------------------- | |||
1 | |||
----------------------------------------------------- + 100 | |||
(triangle / 8227) + (noise / 12241) + (dmc / 22638) | |||
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 | 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 | |||
* Another first-order high-pass filter at 440 Hz | |||
* A first-order low-pass filter at 14 kHz | |||
See also: | |||
* [http://forums.nesdev.org/viewtopic.php?p=44255#p44255 blargg's data and analysis, and lidnariq's matching analog components to filters] | |||
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 == | == Emulation == | ||
Line 43: | 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 56: | 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