-
Notifications
You must be signed in to change notification settings - Fork 19
Use FM channel as DAC
This document describes a small trick to use YM2413's FM channel as D/A converter (DAC). This trick may not be limited to YM2413, however the author have not confirmed on other YM families.
- This approach is different from DAC in test mode.
- If you would like to get VGM files for test, vgm-conv is useful.
The cycle of phase generator can be stopped by writing 0 to f-number (fnum) register. So we can stop the phase counter when the channel reaches maximum ouptut level. In other words, we can sustain the level of the channel at the maximum level.
After phase generator is stopped, the output level of that channel can be fully controlled through the 4-bit volume register. This means the channel can be used as 4-bit DAC.
The YM2413's volume register is 4-bit log-scale. Single channel is not enough for both amplitude level and resolution. Here we use three FM channels (FM 6,7,8) to realize a linear-scale DAC functionality. It is similar to the way of well-known PSG-PCM approach.
First, set instrument and frequency to the channels. It is important for choosing instrument that the modulator's attack is the fastest (i.e. AR=15) to make sure the modulator's envelope has no attack phase after key-on. The following sequence uses the Violin(1) ROM instrument. Any proper user-defiend tone can be also adopted.
REGISTER | VALUE | |
---|---|---|
0x0e | 0x00 | disable rhythm mode |
0x46 | 0x1f | FM6 inst=Violin(1), volume=15(min) |
0x47 | 0x1f | FM7 inst=Violin(1), volume=15(min) |
0x48 | 0x1f | FM8 inst=Violin(1), volume=15(min) |
0x16 | 0x08 | FM6 fnum(bit7:0)=8 |
0x17 | 0x08 | FM7 fnum(bit7:0)=8 |
0x18 | 0x08 | FM8 fnum(bit7:0)=8 |
0x26 | 0x10 | FM6 key-on, blk=0 fnum(bit8)=0 |
0x27 | 0x10 | FM7 key-on, blk=0 fnum(bit8)=0 |
0x28 | 0x10 | FM8 key-on, blk=0 fnum(bit8)=0 |
In the above sequence, the channel frequency is set to 0.76Hz (fnum=8 and blk=0).
After key-on, we need to wait some time until the channel reaches maximum output level.
If we assume the multiple level on carrier slot is 1 (depends on the selected instrument), and pure-sine wave is produced from the channel, the time can be calulated by T=(1000/freq/4)
milliseconds where freq = fnum * 3579545 / 72 / (1<<(19-blk))
.
For example, T=330ms at fnum=8 and blk=0.
Now the volume register is ready to use as DAC. The higher 4-bits of volume register is for instrument number. The instrument should be set to pure-sine instrument whose carrier envelope preserves the maximum output level through decay or sustain phase (typically EG=1 and SL=0). Such instrument can be defined by user instrument register 0x00 to 0x07 values as follows.
0x21,0x21,0x3f,0x00,0x00,0xf0,0x0f,0x0f
However, if we want to play some music with PCM stream, it is better to avoid using user-defined instrument. To achive this, we need to find pure-sine like sound from ROM instruments. Practically, the candidates are limited to either Flute(4) or Organ(8). Flute is almost similar to pure-sine but its output is 6dB smaller than maxmum level. Organ's output level is 0dB from the maximum but slightly different from pure-sine.
Here we choose Organ(8) as a pure-sine substitute and assume that val
is a PCM value to write. The register sequence for DAC writing is as follows.
REGISTER | VALUE | |
---|---|---|
0x46 | 0x8n | FM6 inst=Organ, volume n=DACTable[val][0]
|
0x47 | 0x8n | FM7 inst=Organ, volume n=DACTable[val][1]
|
0x48 | 0x8n | FM8 inst=Organ, volume n=DACTable[val][2]
|
For optimized DACTable and generation code for YM2413, see ym2413-dac-table.ts. Since YM2413's volume register is the same as PSG (4-bit, log-scale, 3dB/step), PCM on PSG is useful to understand the table generation.