Skip to content

Use FM channel as DAC

Mitsutaka Okazaki edited this page Aug 12, 2022 · 53 revisions

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.

Note

Basic idea

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 method

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.

Setup

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).

Wait for max output.

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.

Stream PCM data

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.