APU Mixer: Difference between revisions
Rainwarrior (talk | contribs) m (APU category) |
Rainwarrior (talk | contribs) (merge from APU Mixer Emulation) |
||
Line 19: | Line 19: | ||
''To do: determine and document the low-pass and high-pass filtering applied after the mixer.'' | ''To do: determine and document the low-pass and high-pass filtering applied after the mixer.'' | ||
== Emulation == | |||
The [[APU Mixer|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 [[APU Pulse|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). | |||
<pre> | |||
output = pulse_out + tnd_out | |||
pulse_table [n] = 95.52 / (8128.0 / n + 100) | |||
pulse_out = pulse_table [pulse1 + pulse2] | |||
</pre> | |||
The tnd_out table is approximated (within 4%) by using a base unit close to the [[APU DMC|DMC's]] DAC. | |||
<pre> | |||
tnd_table [n] = 163.67 / (24329.0 / n + 100) | |||
tnd_out = tnd_table [3 * triangle + 2 * noise + dmc] | |||
</pre> | |||
=== 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. | |||
<pre> | |||
output = pulse_out + tnd_out | |||
pulse_out = 0.00752 * (pulse1 + pulse2) | |||
tnd_out = 0.00851 * triangle + 0.00494 * noise + 0.00335 * dmc | |||
</pre> |
Revision as of 23:59, 26 May 2012
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.
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 pulse_out = \frac{95.88}{\frac{8128}{pulse1 + pulse2} + 100} tnd_out = \frac{159.79}{\frac{1}{\frac{triangle}{8227} + \frac{noise}{12241} + \frac{dmc}{22638}} + 100}
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.
To do: determine and document the low-pass and high-pass filtering applied after the mixer.
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