YM2612 register reference

Some explanation first. YM2612 has two sets of registers split in banks: bank 0 is accessed at $A04000/1 and bank 1 is accessed at $A04002/3. Registers come in three flavors: global, per-channel and per-operator. In the latter two cases, bank 0 is for the first three channels, and bank 1 is for the last three channels. Meanwhile, global registers only exist in bank 0.

For some reason, register order is different from operator order (registers come in S1, S3, S2, S4 order), which leads to a lot of confusion. This page is using operator names taken from the YM3438 datasheet. When it comes to programming a sound driver, it's usually easier to process them in register order (the YM2612 doesn't care as long as it gets the correct values in the correct registers).

Also you may notice discrepancies with the official documentation. This is because Sega documented the values as if they were for 8MHz, while the YM2612 is actually connected to a slighly slower clock (specifically, the same one that feeds the 68000, which is 7.67MHz in NTSC and 7.61MHz in PAL). This page tries to use the corrected values.

$22: low frequency oscillator

This is a global register. Its format is:

YM2612 register $22: low frequency oscillator
Bit 7 Bit 6 Bit 5 Bit 4 Bit 3 Bit 2 Bit 1 Bit 0
0 0 0 0 LFOEN LFO:2 LFO:1 LFO:0

The low frequency oscillator (LFO) is used to enable FMS and AMS to work for some simple vibrato- and tremolo-like effects. When the LFO is enabled, the following frequencies are available:

Possible LFO frequencies
ValueLFO frequency
0003.82 Hz
0015.33 Hz
0105.77 Hz
0116.11 Hz
1006.60 Hz
1019.23 Hz
11046.11 Hz
11169.22 Hz

$24,$25: timer A frequency

These are global registers. Their format is:

YM2612 register $24: timer A frequency (high)
Bit 7 Bit 6 Bit 5 Bit 4 Bit 3 Bit 2 Bit 1 Bit 0
TMRA:9 TMRA:8 TMRA:7 TMRA:6 TMRA:5 TMRA:4 TMRA:3 TMRA:2
YM2612 register $25: timer A frequency (low)
Bit 7 Bit 6 Bit 5 Bit 4 Bit 3 Bit 2 Bit 1 Bit 0
0 0 0 0 0 0 TMRA:1 TMRA:0

Timer A counts from TMRA to $400 (when it "overflows"), then reloads and repeats. The exact frequency is computed as follows (approximately):

($400 - TMRA) × 18.77µs

$26: timer B frequency

This is a global register. Its format is:

YM2612 register $26: timer B frequency
Bit 7 Bit 6 Bit 5 Bit 4 Bit 3 Bit 2 Bit 1 Bit 0
TMRB:7 TMRB:6 TMRB:5 TMRB:4 TMRB:3 TMRB:2 TMRB:1 TMRB:0

Timer B counts from TMRB to $100 (when it "overflows"), then reloads and repeats. The exact frequency is computed as follows (approximately):

($100 - TMRB) × 300.34µs

$27: channel 3 mode and timer control

This is a global register. Its format is:

YM2612 register $27: channel 3 mode and timer control
Bit 7 Bit 6 Bit 5 Bit 4 Bit 3 Bit 2 Bit 1 Bit 0
MODE:1 MODE:0 RST:B RST:A ENBL:B ENBL:A LOAD:B LOAD:A

Quick guide to using the timers (if you just want to let them run and check when they fire, which is probably the only thing you'll need):

Useful values to write to YM2612 register $27
ValueTimersch3 mode
$0FNormal
$1FAcknowledge timer ANormal
$2FAcknowledge timer BNormal
$3FAcknowledge both timersNormal
$4FSpecial
$5FAcknowledge timer ASpecial
$6FAcknowledge timer BSpecial
$7FAcknowledge both timersSpecial

$28: key-on and key-off

This is a global register. Its format is:

YM2612 register $28: key-on and key-off
Bit 7 Bit 6 Bit 5 Bit 4 Bit 3 Bit 2 Bit 1 Bit 0
OPERS3 OPERS2 OPERS1 OPERS0 0 CH:2 CH:1 CH:0

The first three channels are 000-010, the last three channels are 100-110.

Each operator can be set separately, but you'll usually set them all the same way. Attack rate starts when going from off to on, release rate starts when going from on to off. Envelope is not affected when staying the same.

$2A: DAC output

This is a global register. When DAC output is enabled, the value written here is output as-is on the 6th channel. To play PCM sound you need to be constantly writing to this register at the exact moment the samples are meant to be output (oof).

$2B: DAC enable

This is a global register. Its format is:

YM2612 register $2B: DAC output enable
Bit 7 Bit 6 Bit 5 Bit 4 Bit 3 Bit 2 Bit 1 Bit 0
DACEN 0 0 0 0 0 0 0

$30+: MUL (multiply) and DT (detune)

This register exists per-operator:

YM2612 assignments for registers $30 onward
ChannelOper S1Oper S2Oper S3Oper S4
1st/4th$30$38$34$3C
2nd/5th$31$39$35$3D
3rd/6th$32$3A$36$3E

The register format is:

YM2612 registers $30 onward: multiplier and detune
Bit 7 Bit 6 Bit 5 Bit 4 Bit 3 Bit 2 Bit 1 Bit 0
0 DT:2 DT:1 DT:0 MUL:3 MUL:2 MUL:1 MUL:0

The MUL field specifies by how much the base frequency is multiplied (by 1, 2, 3… up to 15). The exception to the rule is if this value is 0, in which case it multiplies by 0.5 (i.e. halves the frequency).

The DT field specifies a frequency detune, as follows (where E is a small value that depends on the exact tone):

Possible detune values
ValueDetune
000No detune
001+1 × E
010+2 × E
011+3 × E
100No detune
101-1 × E
110-2 × E
111-3 × E

$40+: TL (total level)

This register exists per-operator:

YM2612 assignments for registers $40 onward
ChannelOper S1Oper S2Oper S3Oper S4
1st/4th$40$48$44$4C
2nd/5th$41$49$45$4D
3rd/6th$42$4A$46$4E

The register format is:

YM2612 registers $40 onward: total level
Bit 7 Bit 6 Bit 5 Bit 4 Bit 3 Bit 2 Bit 1 Bit 0
0 TL:6 TL:5 TL:4 TL:3 TL:2 TL:1 TL:0

Total level is what is normally thought of as the "volume". If you want to affect the volume of a channel, make sure to only touch the TL of "slot" (output) operators and not those that feed into other operators.

$50+: AR (attack rate) and RS (rate scaling)

This register exists per-operator:

YM2612 assignments for registers $50 onward
ChannelOper S1Oper S2Oper S3Oper S4
1st/4th$50$58$54$5C
2nd/5th$51$59$55$5D
3rd/6th$52$5A$56$5E

The register format is:

YM2612 registers $50 onward: attack rate and rate scaling
Bit 7 Bit 6 Bit 5 Bit 4 Bit 3 Bit 2 Bit 1 Bit 0
RS:1 RS:0 0 AR:4 AR:3 AR:2 AR:1 AR:0

Rate scaling makes envelopes steeper at higher frequencies (needed to recreate how some instruments change sound as pitch becomes higher). A rate scaling of 0 does nothing, higher values increase this effect.

$60+: DR (decay rate) and AM enable

This register exists per-operator:

YM2612 assignments for registers $60 onward
ChannelOper S1Oper S2Oper S3Oper S4
1st/4th$60$68$64$6C
2nd/5th$61$69$65$6D
3rd/6th$62$6A$66$6E

The register format is:

YM2612 registers $60 onward: decay rate and AM enable
Bit 7 Bit 6 Bit 5 Bit 4 Bit 3 Bit 2 Bit 1 Bit 0
AMON 0 0 DR:4 DR:3 DR:2 DR:1 DR:0

Sometimes also called "first decay rate" (D1R).

$70+: SR (sustain rate)

This register exists per-operator:

YM2612 assignments for registers $70 onward
ChannelOper S1Oper S2Oper S3Oper S4
1st/4th$70$78$74$7C
2nd/5th$71$79$75$7D
3rd/6th$72$7A$76$7E

The register format is:

YM2612 registers $70 onward: sustain rate
Bit 7 Bit 6 Bit 5 Bit 4 Bit 3 Bit 2 Bit 1 Bit 0
0 0 0 SR:4 SR:3 SR:2 SR:1 SR:0

Sometimes also called "second decay rate" (D2R).

$80+: RR (release rate) and SL (sustain level)

This register exists per-operator:

YM2612 assignments for registers $80 onward
ChannelOper S1Oper S2Oper S3Oper S4
1st/4th$80$88$84$8C
2nd/5th$81$89$85$8D
3rd/6th$82$8A$86$8E

The register format is:

YM2612 registers $80 onward: release rate and sustain level
Bit 7 Bit 6 Bit 5 Bit 4 Bit 3 Bit 2 Bit 1 Bit 0
SL:3 SL:2 SL:1 SL:0 RR:3 RR:2 RR:1 RR:0

Release rate has one bit less than the other rates.

Sustain level is at the point in the envelope where it switches from the first to the second decay rate. 0 is the peak of the envelope, 15 is the bottom of the envelope.

$90+: SSG-EG

This register is often incorrectly implemented in inaccurate clones and if you're unlucky they'll result in awful noise. If you really want to support those make sure to set this register to 0 in those cases.

This register exists per-operator:

YM2612 assignments for registers $90 onward
ChannelOper S1Oper S2Oper S3Oper S4
1st/4th$90$98$94$9C
2nd/5th$91$99$95$9D
3rd/6th$92$9A$96$9E

The register format is:

YM2612 registers $90 onward: SSG-EG
Bit 7 Bit 6 Bit 5 Bit 4 Bit 3 Bit 2 Bit 1 Bit 0
0 0 0 0 SSGEG:EN SSGEG:2 SSGEG:1 SSGEG:0

When SSGEG:EN is clear, nothing unusual happens. When it's set, the envelope is processed in different ways (e.g. looping) depending on what values the SSGEG:2-0 bits have. You must make sure that attack rate is 31 or it will not work properly.

Available SSG-EG envelopes
SSGEG:2-0Envelope
000Envelope loops
001Plays once (same as if it was disabled)
010Envelope loops in zig-zag
011Plays once, then goes full volume
100Envelope loops, it's upside down
101Plays once upside down, then stays at full volume
110Envelope loops in zig-zag, it's upside down
111Plays once upside down

$A0+: frequency

These registers exists per channel:

YM2612 assignments for registers $A0 onward
ChannelHigh halfLow half
1st/4th$A4$A0
2nd/5th$A5$A1
3rd/6th$A6$A2

When in channel 3 special mode, the third FM channel (but not the sixth) can have its frequency set per operator. In this case, the registers for channel 3 are as follows:

Frequency registers in channel 3 special mode
OperatorHigh halfLow half
S1$AD$A9
S2$AE$AA
S3$AC$A8
S4$A6$A2

The registers format is:

YM2612 registers $A4 onward: frequency (high)
Bit 7 Bit 6 Bit 5 Bit 4 Bit 3 Bit 2 Bit 1 Bit 0
0 0 BLK:2 BLK:1 BLK:0 FREQ:10 FREQ:9 FREQ:8
YM2612 registers $A0 onward: frequency (low)
Bit 7 Bit 6 Bit 5 Bit 4 Bit 3 Bit 2 Bit 1 Bit 0
FREQ:7 FREQ:6 FREQ:5 FREQ:4 FREQ:3 FREQ:2 FREQ:1 FREQ:0

To set the frequency, first write its higher half then its lower half (frequency won't be updated until the latter write).

The block acts like the octave: frequency is doubled every time it's incremented by 1. As for the frequency, here are some approximate values (as used by Echo), though they're off by a bit depending on whether it's a NTSC or PAL system:

Approximate frequency values for each semitone
SemitoneFrequency
C644
C#681
D722
D#765
E810
F858
F#910
G964
G#1021
A1081
A#1146
B1214

$B0+: algorithm and feedback

This register exists per channel:

YM2612 assignments for registers $B0 onward
ChannelRegister
1st/4th$B0
2nd/5th$B1
3rd/6th$B2

The register format is:

YM2612 registers $B0 onward: algorithm and feedback
Bit 7 Bit 6 Bit 5 Bit 4 Bit 3 Bit 2 Bit 1 Bit 0
0 0 FEED:2 FEED:1 FEED:0 ALGO:2 ALGO:1 ALGO:0

The algorithm describes which operators modulate other operators, and which operators generate the final output. Different algorithms can generate wildly different sounds. The are eight available arrangements.

Available algorithms on the YM2612
AlgorithmArrangement
0 (000)S1 to S3 to S2 to S4, output from S4
1 (001)S1 and S3 to S2 to S4, output from S4
2 (010)S1 to S4, S3 to S2 to S4, output from S4
3 (011)S1 to S3 to S4, S2 to S4, output from S4
4 (100)S1 to S2, S3 to S4, output from S2 and S4
5 (101)S1 to S2 and S3 and S4, output from S2 and S3 and S4
6 (110)S1 to S2, output from S2 and S3 and S4
7 (111)no modulation, output from all

Operator S1 can modulate itself (on top of the algorithm's arrangement), FEED controls how much it does so. 0 is no feedback, higher values increase the self-modulation.

$B4+: panning, PMS, AMS

This register exists per channel:

YM2612 assignments for registers $B4 onward
ChannelRegister
1st/4th$B4
2nd/5th$B5
3rd/6th$B6

The register format is:

YM2612 registers $B4 onward: panning, PMS, AMS
Bit 7 Bit 6 Bit 5 Bit 4 Bit 3 Bit 2 Bit 1 Bit 0
L R AMS:1 AMS:0 0 PMS:2 PMS:1 PMS:0

Frequency and amplitude sensivity (PMS and AMS respectively) are meant to be used together with the LFO and indicate how much is the waveform affected by it.

PMS can be used as a cheap form of vibrato. The values are:

Possible values for frequency modulation
ValueModulation
000None
001±0.034 semitones
010±0.067 semitones
011±0.10 semitones
100±0.14 semitones
101±0.20 semitones
110±0.40 semitones
111±0.80 semitones

AMS only affects those operators where the AM bit has been set, and it can be used as a cheap form of tremolo. The possible values are:

Possible values for amplitude modulation
ValueModulation
00None
01±1.4 dB
10±5.9 dB
11±11.8 dB

Iwis says

PMS actually stands for "phase modulation sensivity" (since the YM2612 actually does phase modulation instead of frequency modulation). The outcome is more or less the same, aside from rounding errors.