- VERA PSG and PCM, refer to the VERA Programmer's Reference.
The Yamaha YM2151 (OPM) sound chip is an FM synthesizer ASIC in the Commander X16.
It is connected to the system bus at I/O address 0x9F40
(address register) and at 0x9F41
(data register). It has 8 independent voices with 4 FM operators each. Each
voice is capable of left/right/both audio channel output. The four operators of each channel may be connected in one of 8 pre-defined "connection algorithms" in order to produce a wide variety of timbres.
There are 3 basic operations to communicate with the YM chip: Reading its status, address select, and data write. These are performed by reading from or writing to one of the two I/O addresses as follows:
Address | Name | Read Action | Write Action |
---|---|---|---|
0x9F40 | YM_address |
Undefined (returns ?) | Selects the internal register address where data is written. |
0x9F41 | YM_data |
Returns the YM_status byte |
Writes the value into the currently-selected internal address. |
The values stored in the YM's internal registers are write-only. If you need to know the values in the registers, you must store a copy of the values somewhere in memory as you write updates to the YM.
- Ensure YM is not busy (see Write Timing below).
- Select the desired internal register address by writing it into
YM_address
. - Write the new value for this register into
YM_data
.
Note: You may write into the same register multiple times without repeating a write to YM_address
. The same register will be updated with each data write.
The YM2151 is sensitive to the speed at which you write data into it. If you make writes when it is not ready to receive them, they will be dropped and the sound output will be corrupted.
You must include a delay between writes to the address select register ($9F40) and the subsequent data write. 10 CPU cycles is the recommended minimum delay.
The YM becomes BUSY
for approximately 150 CPU cycles' (at 8Mhz) whenever it receives a data write. Any writes into YM_data during this BUSY
period will be ignored!
In order to avoid this, you can use the BUSY
flag which is bit 7 of the YM status
byte. Read the status byte from YM_data
(0x9F41). If the top bit (7) is set, the YM may not be written into at this time. Note that it is not required that you read YM_status
, only that writes occur no less than ~150 CPU cycles apart. For instance, BASIC executes slowly enough that you are in no danger of writing into the YM too quickly, so BASIC programs may skip checking YM_status
.
Lastly, the BUSY
flag sometimes takes a (very) short period before it goes high. This has only been observed when IMMEDIATELY polling the flag after a write into YM_data.
As long as your code does not do so, this quirk should not be an issue.
Assembly Language:
check_busy:
BIT YM_data ; check busy flag
BMI check_busy ; wait until busy flag is clear
LDA #$08 ; Select YM register $08 (Key-Off/On)
STA YM_addr ;
NOP ;<-+
NOP ; |
NOP ; +--slight pause before writing data
NOP ; |
NOP ;<-+
LDA #$04 ; Write $04 (Release note on channel 4).
STA YM_data
RTS
BASIC:
10 YA=$9F40 : REM YM_ADDRESS
20 YD=$9F41 : REM YM_DATA
30 POKE YA,$29 : REM CHANNEL 1 NOTE SELECT
40 POKE YD,$4A : REM SET NOTE = CONCERT A
50 POKE YA,$08 : REM SELECT THE KEY ON/OFF REGISTER
60 POKE YD,$00+1 : REM RELEASE ANY NOTE ALREADY PLAYING ON CHANNEL 1
70 POKE YD,$78+1 : REM KEY-ON VOICE 1 TO PLAY THE NOTE
80 FOR I=1 TO 100 : NEXT I : REM DELAY WHILE NOTE PLAYS
90 POKE YD,$00+1 : REM RELEASE THE NOTE
The YM register address space can be thought of as being divided into 3 ranges:
Range | Type | Description |
---|---|---|
00 .. 1F | Global Values | Affect individual global parameters such as LFO frequency, noise enable, etc. |
20 .. 3F | Channel CFG | Parameters in groups of 8, one per channel. These affect the whole channel. |
40 .. FF | Operator CFG | Parameters in groups of 32 - these map to individual operators of each voice. |
Addr | Register | Bits | Description | |||||||
---|---|---|---|---|---|---|---|---|---|---|
7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | |||
$01 | Test Register | ! | ! | ! | ! | ! | ! | LR | ! |
Bit 1 is the LFO reset bit. Setting it disables the LFO and holds the oscillator at 0. Clearing it enables the LFO. All other bits control various test functions and should not be written into. |
$08 | Key Control | . | C2 | M2 | C1 | M1 | CHA |
Starts and Releases notes on the 8 channels. Setting/Clearing bits for M1,C1,M2,C2 controls the key state for those operators on channel CHA. NOTE: The operator order is different than the order they appear in the Operator configuration registers! |
||
$0F | Noise Control | NE | . | . | NFRQ |
NE = Noise Enable NFRQ = Noise Frequency When eabled, C2 of channel 7 will use a noise waveform instead of a sine waveform. |
||||
$10 | Ta High | CLKA1 | Top 8 bits of Timer A period setting | |||||||
$11 | Ta Low | . | . | . | . | . | . | CLKA2 | Bottom 2 bits of Timer A period setting | |
$12 | Timer B | CLKB | Timer B period setting | |||||||
7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | |||
$14 | IRQ Control | CSM | . | Clock ACK | IRQ EN | Clock Start |
CSM: When a timer expires, trigger note key-on for all channels. For the other 3 fields, lower bit = Timer A, upper bit = Timer B. Clock ACK: clears the timer's bit in the YM_status byte and acknowledges the IRQ. |
|||
$18 | LFO Freq. | LFRQ | Sets LFO frequency. $00 = ~0.008Hz $FF = ~32.6Hz |
|||||||
$19 | LFO Amplitude | 0 | AMD |
AMD = Amplitude Modulation Depth PMD = Phase Modulation (vibrato) Depth Bit 7 determines which parameter is being set when writing into this register. |
||||||
1 | PMD | |||||||||
$1B | CT / LFO Waveform | CT | . | . | . | . | W |
CT: sets output pins CT1 and CT1 high or low. (not connected to anything in X16) W: LFO Waveform: 0-4 = Saw, Square, Triange, Noise For sawtooth: PM->//// AM->\\\\ |
Register Range | Register bits | Description | |||||||
---|---|---|---|---|---|---|---|---|---|
7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | ||
$20 + channel | RL | FB | CON |
|
|||||
$28 + channel | . | KC | |||||||
$30 + channel | KF | . | . | ||||||
$38 + channel | . | PMS | . | . | AMS |
Register Range |
Operator | Register Bits | Description | |||||||
---|---|---|---|---|---|---|---|---|---|---|
7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | |||
$40 | M1: $40+channel | . | DT1 | MUL |
|
|||||
M2: $48+channel | ||||||||||
C1: $50+channel | ||||||||||
C2: $58+channel | ||||||||||
$60 | M1: $60+channel | . | TL |
|
||||||
M2: $68+channel | ||||||||||
C1: $70+channel | ||||||||||
C2: $78+channel | ||||||||||
$80 | M1: $80+channel | KS | . | AR |
|
|||||
M2: $88+channel | ||||||||||
C1: $90+channel | ||||||||||
C2: $98+channel | ||||||||||
$A0 | M1: $A0+channel | A M E n a |
. | . | D1R |
|
||||
M2: $A8+channel | ||||||||||
C1: $B0+channel | ||||||||||
C2: $B8+channel | ||||||||||
$C0 | M1: $C0+channel | DT2 | . | D2R |
|
|||||
M2: $C8+channel | ||||||||||
C1: $D0+channel | ||||||||||
C2: $D8+channel | ||||||||||
$E0 | M1: $E0+channel | D1L | RR |
|
||||||
M2: $E8+channel | ||||||||||
C1: $F0+channel | ||||||||||
C2: $F8+channel |
LR (LFO Reset)
Register $01, bit 1
Setting this bit will disable the LFO and hold it at level 0. Clearing this bit allows the LFO to operate as normal. (See LFRQ for further info)
KON (KeyON)
Register $08
-
Bits 0-2: Channel_Number
-
Bits 3-6: Operator M1, C1, M2, C2 control bits:
- 0: Releases note on operator
- 0->1: Triggers note attack on operator
- 1->1: No effect
Use this register to start/stop notes. Typically, all 4 operators are triggered/released together at once. Writing a value of $78+channel_number will start a note on all 4 OPs, and writing a value of $00+channel_number will stop a note on all 4 OPs.
NE (Noise Enable)
Register $0F, Bit 7
When set, the C2 operator of channel 7 will use a noise waveform instead of a sine.
NFRQ (Noise Frequency)
Register $0F, Bits 0-4
Sets the noise frequency, $00 is the lowest and $1F is the highest. NE bit must be set in order for this to have any effect. Only affects operator C2 on channel 7.
CLKA1 (Clock A, high order bits)
Register $10, Bits 0-7
This is the high-order value for Clock A (a 10-bit value).
CLKA2 (Clock A, low order bits)
Register $11, Bits 0-1
Sets the 2 low-order bits for Clock A (a 10-bit value).
Timer A's period is Computed as (64*(1024-ClkA)) / PhiM ms. (PhiM = 3579.545Khz)
CLKB (Clock B)
Register $12, Bits 0-7
Sets the Clock B period. The period for Timer B is computed as (1024*(256-CLKB)) / PhiM ms. (PhiM = 3579.545Khz)
CSM
Register $14, Bit 7
When set, the YM2151 will generate a KeyON attack on all 8 channels whenever TimerA overflows.
Clock ACK
Register $14, Bits 4-5
Clear (acknowledge) IRQ status generated by TimerA and TimerB (respectively).
IRQ EN
Register $14, Bits 2-3
When set, enables IRQ generation when TimerA or TimerB (respectively) overflow. The IRQ status of the two timers is checked by reading from the YM2151_STATUS byte. Bit 0 = Timer A IRQ status, and Bit 1 = Timer B IRQ status. Note that these status bits are only active if the timer has overflowed AND has its IRQ_EN bit set.
Clock Start
Register $14, Bits 0-1
When set, these bits clear the TimerA and TimerB (respectively) counters and starts it running.
LFRQ (LFO Frequency)
Register $18, Bits 0-7
Sets the LFO frequency.
- $00 = ~0.008Hz
- $FF = ~32.6Hz
Note that even setting the value zero here results in a positive LFO frequency. Any channels sensitive to the LFO will still be affected by the LFO unless the LR
bit is set in register $01 to completely disable it.
AMD (Amplitude Modulation Depth)
Register $19 Bits 0-6, Bit 7 clear
Sets the peak strength of the LFO's Amplitude Modulation effect. Note that bit 7 of the value written into $19 must be clear in order to set the AMD. If bit 7 is set, the write will be interpreted as PMD.
PMD (Phase Modulation Depth)
Register $19 Bits 0-6, Bit 7 set
Sets the peak strength of the LFO's Phase Modulation effect. Note that bit 7 of the value written into $19 must be set in order to set the PMD. If bit 7 is clear, the value is interpreted as AMD.
CT (Control pins)
Register $1B, Bits 6-7
These bits set the electrical state of the two CT pins to on/off. These pins are not connected to anything in the X16 and have no effect.
W (LFO Waveform)
Register $1B, Bits 0-1
Sets the LFO waveform: 0: Sawtooth, 1: Square (50% duty cycle), 2: Triangle, 3: Noise
RL (Right/Left output enable)
Register $20 (+ channel), Bits 6-7
Setting/Clearing these bits enables/disables audio output for the selected channel. (bit6=left, bit7=right)
FB (M1 Self-Feedback)
Register $20 (+ channel), bits 3-5
Sets the amount of self feedback on operator M1 for the selected channel. 0=none, 7=max
CON (Connection Algorithm)
Register $20 (+ channel), bits 0-2
Sets the selected channel to connect the 4 operators in one of 8 arrangements.
[insert picture here]
KC (Key Code - Note selection)
Register $28 + channel, bits 0-6
Sets the octave and semitone for the selected channel. Bits 4-6 specify the octave (0-7) and bits 0-3 specify the semitone:
0 | 1 | 2 | 4 | 5 | 6 | 8 | 9 | A | C | D | E |
---|---|---|---|---|---|---|---|---|---|---|---|
c# | d | d# | e | f | f# | g | g# | a | a# | b | c |
Note that natural C is at the TOP of the selected octave, and that each 4th value is skipped. Thus if concert A (A-4, 440hz) is KC=$4A, then middle C is KC=$3E
KF (Key Fraction)
Register $30 + channel, Bits 2-7
Raises the pitch by 1/64th of a semitone * the KF value.
PMS (Phase Modulation Sensitivity)
Register $38 + channel, Bits 4-6
Sets the Phase Modulation (vibrato) sensitivity of the selected channel. The resulting vibrato depth is determined by the combination of the global PMD setting (see above) modified by each channel's PMS.
Sensitivity values: (+/- cents)
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 |
---|---|---|---|---|---|---|---|
0 | 5 | 10 | 20 | 50 | 100 | 400 | 700 |
AMS (Amplitude Modulation Sensitivity)
Register $38 + channel, Bits 0-1
Sets the Amplitude Modulation sensitivity of the selected channel. Note that each operator may individually enable or disable this effect on its output by setting/clearing the AMS-Ena bit (see below). Operators acting as outputs will exhibit a tremolo effect (varying volume) and operators acting as modulators will vary their effectiveness on the timbre when enabled for amplitude modulation.
Sensitivity values: (dB)
0 | 1 | 2 | 3 |
---|---|---|---|
0 | 23.90625 | 47.8125 | 95.625 |
Operators are arranged as follows:
name | M1 | M2 | C1 | C2 |
---|---|---|---|---|
index | 0 | 1 | 2 | 3 |
These are the names used throughout this document for consistency, but they may function as either modulators or carriers, depending on which CON
ALG is used.
The Operator Control parameters are mapped to channels/operators as follows: Register + 8*op + channel. You may also choose to think of these register addresses as using bits 0-2 = channel, bits 3-4 = operator, and bits 5-7 = parameter. This reference will refer to them using the address range, e.g. $60-$7F = TL. To set TL for channel 2, operator 1, the register address would be $6A ($60 + 1*8 + 2).
DT1 (Detune 1 - fine detune)
Registers $40-$5F, Bits 4-6
Detunes the operator from the channel's main pitch. Values 0 and 4=no detuning.
Values 1-3=detune up, 5-7 = detune down.
The amount of detuning varies with pitch. It decreases as the channel's pitch increases.
MUL (Frequency Multiplier)
Registers $40-$5F, Bits 0-3
If MUL=0, it multiplies the operator's frequency by 0.5
Otherwise, the frequency is multiplied by the value in MUL (1,2,3...etc)
TL (Total Level - attenuation)
Registers $60-$7F, Bits 0-6
This is essentially "volume control" - It is an attenuation value, so $00 = maximum level and $7F is minimum level. On output operators, this is the volume output by that operator. On modulating operators, this affects the amount of modulation done to other operators.
KS (Key Scaling)
Registers $80-$9F, Bits 6-7
Controls the speed of the ADSR progression. The KS value sets four different levels of scaling. Key scaling increases along with the pitch set in KC. 0=min, 3=max
AR (Attack Rate)
Registerss $80-$9F, Bits 0-4
Sets the attack rate of the ADSR envelope. 0=slowest, $1F=fastest
AMS-Enable (Amplitude Modulation Sensitivity Enable)
Registers $A0-$BF, Bit 7
If set, the operator's output level will be affected by the LFO according to the channel's AMS setting. If clear, the operator will not be affected.
D1R (Decay Rate 1)
Registers $A0-$BF, Bits 0-4
Controls the rate at which the level falls from peak down to the sustain level (D1L). 0=none, $1F=fastest.
DT2 (Detune 2 - coarse)
Registers $C0-$DF, Bits 6-7
Sets a strong detune amount to the operator's frequency. Yamaha suggests that this is most useful for sound effects. 0=off,
D2R (Decay Rate 2)
Registers $C0-$DF, Bits 0-4
Sets the Decay2 rate, which takes effect once the level has fallen from peak down to the sustain level (D1L). This rate continues until the level reaches zero or until the note is released.
0=none, $1F=fastest
D1L
Registers $E0-$FF, Bits 4-7
Sets the level at which the ADSR envelope changes decay rates from D1R to D2R. 0=minimum (no D2R), $0F=maximum (immediately at peak, which effectively disables D1R)
RR
Registers $E0-$FF, Bitst 0-3
Sets the rate at which the level drops to zero when a note is released. 0=none, $0F=fastest
While there is a large number of parameters that affect the sound of the YM2151, its operation can be thought of in simplified terms if you consider that there are basically three components to deal with: Instrument configuration (patch), voice pitch selection, and "pressing/releasing" the "key" to trigger (begin) and release (end) notes. It's essentially the same as using a music keyboard. Pressing an instrument button (e.g. Marimba) makes the keyboard sound like a Marimba. Once this is done, you press a key on the keyboard to play a note, and release it to stop the note. With the YM, loading a patch (pressing the Marimba button) entails setting all of the various operators' registers on the voice(s) you want the instrument to be used on. On the music keyboard, pitch and note stop/start are done with a single piano key. In the YM2151, these are two distinct actions.
For this tutorial, we will start with the simplest operation, (triggering notes) and proceed to note selection, and finally patch configuration.
Key On/Off (KON) Register ($08):
This is probably the most important single register in the YM2151. It is used to trigger and release notes. It controls the key on/off state for all 8 channels. A note is triggered whenever its key state changes from off to on, and is released whenever the state changes from on to off. Repeated writes of the same state (off->off or on->on) have no effect.
Whenever an operator is triggered, it progresses through the states of attack, decay1, and sustain/decay2. Whenever an active note is released, it enters the release state where the volume decreases until reaching zero. It then remains silent until the next time the operator is triggered. If you are familiar with the C64 SID chip, this is the same behavior as the "gate" bit on that chip.
Key state and voice selection are both contained in the value written into the KON register as follows:
- Key ON = $78 + channel number
- Key OFF = $0 + channel number
Simple Examples:
To release the note in channel 4: write $08 to YM_address
($9F40) and then write $04 ($00+4) to YM_data
($9F41).
To begin a note on channel 7, write $08 into YM_address
to select the KON register. Then write $7F ($78+7) into YM_data
If the current key state of a channel is not known, you can write key off and then key on immediately (after waiting for the YM busy period to end, of course):
POKE $9F40,$08 : REM SELECT KEY ON/OFF REGISTER
POKE $9F41,$07 : REM KEY OFF FOR VOICE 7
POKE $9F41,$7F : REM KEY ON FOR VOICE 7
Remember: BASIC is slow enough that you do not need to poll the YM_status
byte, but assembly and other languages will need to do so.
The ADSR parameters will be discussed in more detail later.
Advanced:
Each channel (voice) of the YM2151 uses 4 operators which can be gated together or independently. Independent triggering gives lots of advanced possibilities. To trigger and release operators independently, you use different values than $78 or $00. These values are composed by 4 bits which signal the on/off state for each operator.
Suppose a note is playing on channel 2 with all 4 operators active. You can release only the M1 operator by writing $72 into register $08.
The KON value format:
7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
- | C2 | M2 | C1 | M1 | Channel |
YM Registers:
KC
= $28 + channel numberKF
= $30 + channel number
For note selection, each voice has two parameters: KC
(Key Code) and KF
(Key Fraction).
These are set in register ranges $28 and $30, respectively. The KC codes correspond
directly to the notes of the chromatic scale. Each value maps to a specific octave & semitone. The KF
value can even be ignored
for basic musical playback. It is mostly useful for vibrato or pitch bend effects. KF
raises
the pitch selected in KC
in 1/64th increments of the way up to the next semitone.
Like all registers in the YM, whenever a channel's KC
or KF
value is written, it takes effect immediately. If a note is playing, its pitch immediately changes. When triggering new notes, it is not important whether you write the pitch or key the note first. This happens quickly in real-time and you will not hear any real difference. Changing the pitch without re-triggering the ADSR envelope is how to achieve pitch slides or a legato effect.
KC
codes are "conveniently" arranged so that the upper nybble is the octave (0-7) and the
lower nybble is the pitch. The pitches are arranged as follows within an octave:
Note | C# | D | D# | E | F | F# | G | G# | A | A# | B | C |
---|---|---|---|---|---|---|---|---|---|---|---|---|
Low Nybble (hex) | 0 | 1 | 2 | 4 | 5 | 6 | 8 | 9 | A | C | D | E |
(Note that every 4th value is skipped.)
Combine the above with an octave to get a note's KC
value. For instance: concert A (440hz) is (by sheer coincidence) $4A
. Middle C is $3E
, and so forth.
KF
values are written into the top 6 bits of the voice's KF
register. Basically the value is 0, 1<<2, 2<<2, .. 63<<2
The patch configuration is by far the most complicated aspect of using the YM. If you take as given that a voice has a patch loaded, then playing notes on it is fairly straightforward. For the moment, we will assume a pre-patched voice.
To get started quickly, here is some BASIC code to patch voice 0 with a marimba tone:
5 YA=$9F40 : YD=$9F41 : V=0
10 REM: MARIMBA PATCH FOR YM VOICE 0 (SET V=0..7 FOR OTHER VOICES)
20 DATA $DC,$00,$1B,$67,$61,$31,$21,$17,$1F,$0A,$DF,$5F,$DE
30 DATA $DE,$0E,$10,$09,$07,$00,$05,$07,$04,$FF,$A0,$16,$17
40 READ D
50 POKE YA,$20+V : POKE YD,D
60 FOR A=$38 TO $F8 STEP 8
70 READ D : POKE YA,A+V : POKE YD,D
80 NEXT A
Once a voice has been patched as above, you can now POKE notes into it with very few commands for each note.
Patches consist mostly of ADSR envelope parameters. A complete patch contains values for the $20 range register (LR|FB|CON), for the $38 range register (AMS|PMS), and 4 values for each of the parameter ranges starting at $40. (4 operators per voice means 4 values per parameter). Since this is a huge amount of flexibility, it is recommended to experiment with instrument creation in an application such as a chip tracker or VST, as the creative process of instrument design is very hands-on and subjective.
There is a single global LFO in the YM2151 which can affect the level (volume) and/or pitch of all 8 channels simultaneously. It has a single frequency and waveform setting which must be shared among all channels, and shared between both phase and amplitude modulation. The global parameters AMD
and PMD
act as modifiers to the sensitivity settings of the channels. While the frequency and waveform of the LFO pattern must be shared, the depths of the two types of modulation are independent of each other.
You can re-trigger the LFO by setting and then clearing the LR
bit in the test register ($01).
Use Phase Modulation on the desired channels. The PMS
parameter for each channel allows them to vary their vibrato depths individually. Channels with PMS
set to zero will have no vibrato. The values given earlier in the PMS
parameter description represent their maximum amount of affect. These values are modified by the global PMD.
A PMD
valie of $7F means 100% effectiveness, $40 means all channels' vibrato depths will be reduced by half, etc.
The vibrato speed is global, depending solely on the value set to LFRQ.
Amplitude modulation works similarly to phase modulation, except that the intensity is a combination of the per-channel AMS
value modified by the global AMD
value. Additionally, within channels having non-zero amplitude modulation sensitivity, individual operators must have their AMS-en
bit enabled in order to be affected by the modulation.
If the active operators are acting as carriers (generating output directly), then amplitude modulation will vary the volume of the sound being produced by that operator. This can be described as a "tremelo" effect. If the operators are acting as modulators, then the timbre of the voice will vary as the output level of the affected operators increases and decreases. You may simultaneously enable amplitude modulation on both types of operators.
The amplitude modulation speed is global, depending solely on the value set to LFRQ.