FDS audio: Difference between revisions
Rainwarrior (talk | contribs) m (→Modulation append ($4088): rm implementation speculation) |
Rainwarrior (talk | contribs) (→Registers: revising with new information gained from hardware testing) |
||
Line 7: | Line 7: | ||
=== Master I/O enable ($4023) === | === Master I/O enable ($4023) === | ||
This register must be written to with bit 1 set for the sound registers to function. The FDS bios initializes this by writing $00 followed by $83 to it. | |||
7 bit 0 | 7 bit 0 | ||
Line 15: | Line 17: | ||
+-- Enable sound I/O registers | +-- Enable sound I/O registers | ||
=== Wavetable RAM ($4040-$407F) === | |||
The 64-step waveform to be fed to the DAC. Each step consists of an unsigned value in the range [0, 63]. This can always be read by the CPU. However, it cannot be modified unless it is write-enabled, and it cannot be write-enabled while the sound is being played. (See also $4089 below.) | The 64-step waveform to be fed to the DAC. Each step consists of an unsigned value in the range [0, 63]. This can always be read by the CPU. However, it cannot be modified unless it is write-enabled, and it cannot be write-enabled while the sound is being played. (See also $4089 below.) | ||
7 bit 0 (read/write) | 7 bit 0 (read/write) | ||
---- ---- | ---- ---- | ||
Line 27: | Line 29: | ||
=== Volume envelope ($4080) === | === Volume envelope ($4080) === | ||
The volume | |||
The envelope speed is set by this register whether or not the envelope is enabled by the high bit, | |||
but the current volume is set only if the high bit is set. | |||
The volume gain can range from 0 to 63; however, volume values above 32 are clamped to 32 before output. | |||
Writing to this register immediately resets the clock timer that ticks the volume envelope (delaying the next tick slightly). | |||
7 bit 0 (write; read through $4090) | 7 bit 0 (write; read through $4090) | ||
---- ---- | ---- ---- | ||
Line 33: | Line 42: | ||
|||| |||| | |||| |||| | ||
||++-++++- (D=0) Volume envelope speed | ||++-++++- (D=0) Volume envelope speed | ||
|| (D=1) | || (D=1) Volume gain and envelope speed. | ||
|+-------- Volume change direction (0: decrease; 1: increase) | |+-------- Volume change direction (0: decrease; 1: increase) | ||
+--------- Volume envelope mode (0: on; 1: off) | +--------- Volume envelope mode (0: on; 1: off) | ||
=== Frequency low ($4082) === | === Frequency low ($4082) === | ||
7 bit 0 (write) | 7 bit 0 (write) | ||
---- ---- | ---- ---- | ||
Line 45: | Line 55: | ||
=== Frequency high ($4083) === | === Frequency high ($4083) === | ||
The high bit of this register halts the waveform and resets its phase to 0. | |||
Note that if halted it will output the constant value at $4040, and | |||
writes to the volume register $4080 or master volume $4089 will affect the output. | |||
The envelopes are not ticked while the waveform is halted. | |||
Bit 6 halts just the envelopes without halting the waveform, and also | |||
resets both of their timers. | |||
7 bit 0 (write) | 7 bit 0 (write) | ||
---- ---- | ---- ---- | ||
Line 51: | Line 70: | ||
|| ++++- Bits 8-11 of frequency | || ++++- Bits 8-11 of frequency | ||
|+-------- Disable volume and sweep envelopes (but not modulation) | |+-------- Disable volume and sweep envelopes (but not modulation) | ||
+--------- | +--------- Halt waveform and reset phase to 0, disable envelopes | ||
=== Mod envelope ($4084) === | |||
The envelope speed is set by this register whether or not the envelope is enabled by the high bit, | |||
but the current mod gain is set only if the high bit is set. | |||
Writing to this register immediately resets the clock timer that ticks the modulator envelope (delaying the next tick slightly). | |||
7 bit 0 (write; read through $4092) | 7 bit 0 (write; read through $4092) | ||
---- ---- | ---- ---- | ||
DMSS SSSS | DMSS SSSS | ||
|||| |||| | |||| |||| | ||
||++-++++- (D=0) | ||++-++++- (D=0) Mod envelope speed | ||
|| (D=1) | || (D=1) Mod gain and envelope speed. | ||
|+-------- | |+-------- Mod envelope direction (0: decrease; 1: increase) | ||
+--------- | +--------- Mod envelope mode (0: on; 1: off) | ||
=== Mod counter ($4085) === | |||
This directly sets the 7-bit signed modulator counter that is otherwise controlled by the mod unit. | |||
Because the current playback position of the modulator unit is generally hard to predict while active, | |||
it is bad practice to write $4085 unless the mod unit is disabled via $4087, | |||
because it will generally result in a detuned note. | |||
Bio Miracle Bokutte Upa does this, and it requires cycle-accurate timing to emulate correctly. | |||
Some emulators incorrectly treat $4085 as a phase-reset for the mod table, which | |||
will obviate this timing issue. | |||
It is generally good practice to write 0 to $4085 to reset the counter after | |||
writing the mod table via $4088. | |||
7 bit 0 (write) | 7 bit 0 (write) | ||
---- ---- | ---- ---- | ||
xBBB BBBB | xBBB BBBB | ||
||| |||| | ||| |||| | ||
+++-++++- | +++-++++- Mod counter (7-bit signed; minimum $40; maximum $3F) | ||
=== Mod frequency low ($4086) === | |||
If the 12-bit frequency is set to 0, modulation is disabled. | If the 12-bit frequency is set to 0, modulation is disabled. | ||
7 bit 0 (write) | 7 bit 0 (write) | ||
---- ---- | ---- ---- | ||
FFFF FFFF | FFFF FFFF | ||
|||| |||| | |||| |||| | ||
++++-++++- Bits 0-7 of modulation frequency | ++++-++++- Bits 0-7 of modulation unit frequency | ||
=== Mod frequency high ($4087) === | |||
Setting the high bit of this register halts the mod unit, | |||
and allows the mod table to be written via $4088. | |||
7 bit 0 (write) | 7 bit 0 (write) | ||
---- ---- | ---- ---- | ||
Line 87: | Line 130: | ||
+--------- Disable modulation | +--------- Disable modulation | ||
=== | === Mod table write ($4088) === | ||
The | |||
This register has no effect unless the mod unit is disabled via the high bit of $4087. | |||
The mod table is a ring buffer containing 64 entries. | |||
Writing to this register replaces two consecutive entries starting at the current | |||
mod table playback position with the written value, then advances the playback position | |||
to the following entry. | |||
Writing to this register 32 times will effectively reset the phase of the mod table, | |||
having advanced the playback position back to its starting point. | |||
Writing to this register also resets the timer counting clocks until the next | |||
tick, delaying the first tick after the mod unit is re-enabled. | |||
7 bit 0 (write) | 7 bit 0 (write) | ||
---- ---- | ---- ---- | ||
Line 95: | Line 151: | ||
+++- Modulation input | +++- Modulation input | ||
=== | === Wave write / master volume ($4089) === | ||
When the high bit is set, the current waveform output is held at | |||
its current level until the bit is cleared again. During this time, | |||
the wave unit will continue to run, even though the output level | |||
is held. | |||
7 bit 0 (write) | 7 bit 0 (write) | ||
---- ---- | ---- ---- | ||
Line 103: | Line 165: | ||
| Output volume = current volume (see $4080 above) * master volume | | Output volume = current volume (see $4080 above) * master volume | ||
+--------- Wavetable write enable | +--------- Wavetable write enable | ||
(0: write protect RAM; 1: write enable RAM and | (0: write protect RAM; 1: write enable RAM and hold channel) | ||
=== Envelope speed ($408A) === | === Envelope speed ($408A) === | ||
Few FDS NSFs write to this register. BIOS | |||
This sets a clock multiplier for the volume and modulator envelopes. | |||
Few FDS NSFs write to this register. The BIOS initializes this to $FF. | |||
7 bit 0 (write) | 7 bit 0 (write) | ||
---- ---- | ---- ---- | ||
Line 115: | Line 180: | ||
=== Volume gain ($4090) === | === Volume gain ($4090) === | ||
7 bit 0 (read; write through $4080) | 7 bit 0 (read; write through $4080) | ||
---- ---- | ---- ---- | ||
Line 122: | Line 188: | ||
++-------- Returns 01 on read, likely from open bus | ++-------- Returns 01 on read, likely from open bus | ||
=== | === Mod gain ($4092) === | ||
7 bit 0 (read; write through $4084) | 7 bit 0 (read; write through $4084) | ||
---- ---- | ---- ---- | ||
OOVV VVVV | OOVV VVVV | ||
|||| |||| | |||| |||| | ||
||++-++++- Current | ||++-++++- Current mod gain level | ||
++-------- Returns 01 on read, likely from open bus | ++-------- Returns 01 on read, likely from open bus | ||
Revision as of 07:53, 17 July 2013
The Famicom Disk System audio is an audio channel generated by the 2C33 chip on the Famicom Disk System's RAM card and output through the Famicom cart edge connector's expansion audio pins.
This channel rapidly repeats a wavetable set up by the CPU in a manner similar to channel 3 of the Game Boy but with more sophisticated modulation. By changing the waveform, the program can have it simulate many different instruments. Many NSF composers have found this useful.
Registers
Master I/O enable ($4023)
This register must be written to with bit 1 set for the sound registers to function. The FDS bios initializes this by writing $00 followed by $83 to it.
7 bit 0 --------- xxxx xxSD || |+- Enable disk I/O registers +-- Enable sound I/O registers
Wavetable RAM ($4040-$407F)
The 64-step waveform to be fed to the DAC. Each step consists of an unsigned value in the range [0, 63]. This can always be read by the CPU. However, it cannot be modified unless it is write-enabled, and it cannot be write-enabled while the sound is being played. (See also $4089 below.)
7 bit 0 (read/write) ---- ---- OOSS SSSS |||| |||| ||++-++++- Sample ++-------- Returns 01 on read, likely from open bus
Volume envelope ($4080)
The envelope speed is set by this register whether or not the envelope is enabled by the high bit, but the current volume is set only if the high bit is set.
The volume gain can range from 0 to 63; however, volume values above 32 are clamped to 32 before output.
Writing to this register immediately resets the clock timer that ticks the volume envelope (delaying the next tick slightly).
7 bit 0 (write; read through $4090) ---- ---- DMVV VVVV |||| |||| ||++-++++- (D=0) Volume envelope speed || (D=1) Volume gain and envelope speed. |+-------- Volume change direction (0: decrease; 1: increase) +--------- Volume envelope mode (0: on; 1: off)
Frequency low ($4082)
7 bit 0 (write) ---- ---- FFFF FFFF |||| |||| ++++-++++- Bits 0-7 of frequency
Frequency high ($4083)
The high bit of this register halts the waveform and resets its phase to 0. Note that if halted it will output the constant value at $4040, and writes to the volume register $4080 or master volume $4089 will affect the output. The envelopes are not ticked while the waveform is halted.
Bit 6 halts just the envelopes without halting the waveform, and also resets both of their timers.
7 bit 0 (write) ---- ---- MExx FFFF || |||| || ++++- Bits 8-11 of frequency |+-------- Disable volume and sweep envelopes (but not modulation) +--------- Halt waveform and reset phase to 0, disable envelopes
Mod envelope ($4084)
The envelope speed is set by this register whether or not the envelope is enabled by the high bit, but the current mod gain is set only if the high bit is set.
Writing to this register immediately resets the clock timer that ticks the modulator envelope (delaying the next tick slightly).
7 bit 0 (write; read through $4092) ---- ---- DMSS SSSS |||| |||| ||++-++++- (D=0) Mod envelope speed || (D=1) Mod gain and envelope speed. |+-------- Mod envelope direction (0: decrease; 1: increase) +--------- Mod envelope mode (0: on; 1: off)
Mod counter ($4085)
This directly sets the 7-bit signed modulator counter that is otherwise controlled by the mod unit.
Because the current playback position of the modulator unit is generally hard to predict while active, it is bad practice to write $4085 unless the mod unit is disabled via $4087, because it will generally result in a detuned note. Bio Miracle Bokutte Upa does this, and it requires cycle-accurate timing to emulate correctly. Some emulators incorrectly treat $4085 as a phase-reset for the mod table, which will obviate this timing issue.
It is generally good practice to write 0 to $4085 to reset the counter after writing the mod table via $4088.
7 bit 0 (write) ---- ---- xBBB BBBB ||| |||| +++-++++- Mod counter (7-bit signed; minimum $40; maximum $3F)
Mod frequency low ($4086)
If the 12-bit frequency is set to 0, modulation is disabled.
7 bit 0 (write) ---- ---- FFFF FFFF |||| |||| ++++-++++- Bits 0-7 of modulation unit frequency
Mod frequency high ($4087)
Setting the high bit of this register halts the mod unit, and allows the mod table to be written via $4088.
7 bit 0 (write) ---- ---- Dxxx FFFF | |||| | ++++- Bits 8-11 of modulation frequency +--------- Disable modulation
Mod table write ($4088)
This register has no effect unless the mod unit is disabled via the high bit of $4087.
The mod table is a ring buffer containing 64 entries. Writing to this register replaces two consecutive entries starting at the current mod table playback position with the written value, then advances the playback position to the following entry.
Writing to this register 32 times will effectively reset the phase of the mod table, having advanced the playback position back to its starting point.
Writing to this register also resets the timer counting clocks until the next tick, delaying the first tick after the mod unit is re-enabled.
7 bit 0 (write) ---- ---- xxxx xMMM ||| +++- Modulation input
Wave write / master volume ($4089)
When the high bit is set, the current waveform output is held at its current level until the bit is cleared again. During this time, the wave unit will continue to run, even though the output level is held.
7 bit 0 (write) ---- ---- Wxxx xxVV | || | ++- Master volume (0: full; 1: 2/3; 2: 2/4; 3: 2/5) | Output volume = current volume (see $4080 above) * master volume +--------- Wavetable write enable (0: write protect RAM; 1: write enable RAM and hold channel)
Envelope speed ($408A)
This sets a clock multiplier for the volume and modulator envelopes. Few FDS NSFs write to this register. The BIOS initializes this to $FF.
7 bit 0 (write) ---- ---- SSSS SSSS |||| |||| ++++-++++- Sets speed of volume envelope and sweep envelope (0: disable them)
Volume gain ($4090)
7 bit 0 (read; write through $4080) ---- ---- OOVV VVVV |||| |||| ||++-++++- Current volume gain level ++-------- Returns 01 on read, likely from open bus
Mod gain ($4092)
7 bit 0 (read; write through $4084) ---- ---- OOVV VVVV |||| |||| ||++-++++- Current mod gain level ++-------- Returns 01 on read, likely from open bus
Frequency calculation and timing
The 4 different areas of the FDS Sound channel (Volume Envelope, Sweep Envelope, Modulation Unit, and Main Unit) are clocked at independent rates. This section covers how to calculate the number of clocks per second (in Hz) from the various values written to the registers.
Volume envelope unit
Hz = (232 * 960) / (Envelope_Speed * (Volume_Envelope_Speed + 1)), where
- Hz = how many times per second a clock occurs
- Envelope_Speed = value written to $408A (if zero, Envelope is disabled)
- Volume_Envelope_Speed = value set by writes to $4080
When Disch was working with this formula to fit in his NSF player, he was converting the formula to work with NES CPU cycles (~1798772 a second). This involved taking the reciprocal of the above formula and dividing by the NES frequency. This produced a somewhat simpler formula:
Cyc = 8 * Envelope_Speed * (Volume_Envelope_Speed + 1), where
- Cyc = Number of NES CPU cycles that need to pass for 1 clock to occur
For this alternate formula in Hertz:
Hz = NES / Cyc, where
- NES = NTSC NES CPU frequency (1789772.7272, or half the NTSC color subcarrier frequency)
Since all the other NES channels revolve around the CPU clock rate, this second formula seems more likely, since it also uses the NES clock as the base. In any case, the 2 formulas produce very similar results. If you work the conversion yourself... you end up simplifying:
1789772.7272 / (232 * 960) = ~8.036
Sweep envelope unit
Hz = (232 * 960) / (Envelope_Speed * (Sweep_Envelope_Speed + 1)), where
- Sweep_Envelope_Speed = value set by writes to $4084
- or
Cyc = 8 * Envelope_Speed * (Sweep_Envelope_Speed + 1)
Hz = NES / Cyc
Modulation unit
Hz = NES * ModFreq / 65536, where
- ModFreq = 12-bit Modulation Frequency value set by $4086/$4087
Note that this frequency is how many times per second the modulation unit gets clocked... not how many times it goes through the entire Frequency Modulation Table (which would be this value / 64, since there are 32 entries in the table and each is used twice)
Main unit
Hz = NES * ( (Freq + Mod) / 65536 ), where
- Freq = 12-bit Frequency set by $4082/$4083
- Mod = Frequency change based on the Modulation unit (see next section)
Note again that this is the how many times per second the main unit gets clocked (taking 1 step further in the table). The entire table is 64 entries, so the frequency of it playing the entire wave would be this value / 64.
What each unit does in a clock
Volume envelope unit
Every clock, the Volume Envelope Unit alters the Volume_Gain depending on which mode we're in ($4080.D6).
- Increase Mode: If Volume Gain is less than 32, it's increased by 1
- Decrease Mode: If Volume Gain is greater than 0, it's decreased by 1
Note that despite Volume Gain in only increased if less than 32, it still can be greater than $20 (up to $3F) if set that way through a write to $4080.
Also on a clock, the output volume is set to the smaller of Volume Gain or 32 whichever is less (so while Volume Gain may be higher than 32, the actual output volume caps at 32).
Sweep envelope unit
Sweep Envelope unit behaves just like the Volume Envelope, only it alters Sweep Gain instead of Volume Gain. The Envelope Unit never pushes Sweep Gain above $20, but it still can get above $20 if set that way via $4084.
Increase/Decrease mode is determined by bit 6 of $4084
Sweep Gain is used when calculating the Frequency change in the Modulation Unit:
Modulation unit
The Modulation Unit, when clocked, takes 1 step through the Modulation Table (set by writes to $4088). The Sweep Bias is adjusted based on the 3-bit value in the list [+0, +1, +2, +4, reset to 0, -4, -2, -1].
The address of the Modulation unit is incremented every other clock to use the next 3-bit value in the table. This address wraps at 32 and can be reset to zero by any write to $4085.
After the Sweep Bias is adjusted, it wraps to fit within a signed 7-bit value. That is, if it goes greater than 63, it wraps around to -64, and if it goes below -64, it wraps to 63.
The Modulation Unit works by altering the Frequency of the Main Unit by a value calculated from the Sweep Gain and Sweep Bias values. The logic for this calculation is complicated, represented by the following pseudocode:
temp = Sweep_Bias * Sweep_Gain; if (temp & 0x0F) { temp /= 16; if( Sweep_Bias < 0 ) temp -= 1; else temp += 2; } else temp /= 16; if (temp > 193) temp -= 258; // not a typo... for some reason the wraps are inconsistent if( temp < -64 ) temp += 256; Mod = Freq * temp / 64;
In this code, Freq is the 12-bit MAIN UNIT frequency, and Mod is the amount that
frequency is altered (to bend the playback frequency in either direction). This
generated 'Mod' value is used in the frequency calculation of the main unit (given
earlier):
Hz = NES * ( (Freq + Mod) / 65536 )
If at any time the Modulation unit is off, 'Mod' is zero. Otherwise 'Mod' is the above calculated value. If Freq + Mod produces a number less than or equal to zero, the channel is presumably silenced (<0 Hz output isn't really possible/audible).
Main unit
When the main Unit is clocked, the next entry in the 64 entry waveform table (accessed via regs $4040-$407F) is output. Once the 64'th sample is played ($407F), the table restarts ($4040 is played) and it continues to loop.
Unit activity
Remember that each unit can be active regardless of the activitiy of other units. For example, even though the main unit is off and the channel is silent, this does not mean the Volume Envelope or Modulation units are inactive.
If any of the supplied conditions are false, the unit is inactive and will not be clocked. All conditions must be true for the unit to be active.
- Volume envelope unit
- Volume Envelope must be enabled (bit 7 of $4080 must be off), AND
- Envelope Speed must be nonzero (set by $408A), AND
- Envelope must be enabled (bit 6 of $4083 must be off)
- Sweep envelope unit
- Sweep Envelope must be enabled (bit 7 of $4084 must be off), AND
- Envelope Speed must be nonzero (set by $408A), AND
- Envelope must be enabled (bit 6 of $4083 must be off)
- Modulation unit
- Modulation must be enabled (bit 7 of $4087 must be off), AND
- Modulation frequency must be non-zero (set by $4086/$4087)
- Main unit:
- Main Unit must be enabled (bit 7 of $4083 must be off), AND
- Main Unit Frequency must be non-zero (set by $4082/$4083), AND
- 'Freq + Mod' must be greater than zero (see Frequency Calculation section), AND
- Write Mode must be off (bit 7 of $4089 must be off)
References
- FDS Sound by Disch
- Famicom Disk System technical reference by Brad Taylor
- US Patent 4783812 on the FDS sound system