Commander CX16 Wiki
Advertisement

VERA PSG[]

The PSG on the VERA chip provides 16 channels, accessible through VRAM addresses $1F9C0 through $1F9FF, and consequently very easy to use with VPOKE. For now, we'll analyze channel 0, which uses VRAM addresses $1F9C0 through $1F9C3.

The registers of channel 0 look as follows:

Register Bit 7 Bit 6 Bit 5 Bit 4 Bit 3 Bit 2 Bit 1 Bit 0
$1F9C0 Frequency word (7:0)
$1F9C1 Frequency word (15:8)
$1F9C2 Right Left Volume
$1F9C3 Waveform Pulse width

Frequency word specifies the frequency of the wave, in intervals of 0.373 Hz (derived as 25 MHz / 226). To convert from MIDI note to frequency word, use the following formula:

FW = INT(EXP(N*0.0577622651)*21.9467431+0.5)

(derived as exp(n * ln 2 / 12) * (1 / exp(69 * ln 2 / 12) * 440 * 226 / 2.5e7))

Left and Right specify whether you want to use the left channel, right channel or both.

Volume is a simple volume slider going from 0 to 63.

Waveform controls the waveform of the sound:

Waveform Description
0 Pulse
1 Sawtooth
2 Triangle
3 Noise

Pulse width only matters when the waveform is 0 (pulse), and controls the duty cycle of the pulse waveform. A value of 63 will give a 50% duty cycle or square wave, 0 will give a very narrow pulse.

The very basic requirements to play sound on the VERA PSG are:

  1. Load the properties of the note into VRAM ($1F9C0, $1F9C1, $1F9C3)
  2. Load the volume into VRAM ($1F9C2)
  3. (wait)
  4. Reset the volume to 0 in VRAM ($1F9C2)

Example program that plays Twinkle Twinkle Little Star, and demonstrates how you would do things such as tempo control and volume decay in BASIC:

10 REM SINGLE CHANNEL PLAYBACK DEMO
20 REM MAIN FLOW - WHICH SEGMENTS TO PLAY AND HOW FAST
30 TEMPO = 120
40 RESTORE : S = 0 : GOSUB 500
50 RESTORE : S = 1 : GOSUB 500
60 RESTORE : S = 1 : GOSUB 500
70 RESTORE : S = 0 : GOSUB 500
80 END
500 REM SUBROUTINE FOR PLAYING A SEGMENT
510 TD = 7272/TEMPO-14
520 CS = 0
530 READ SL
540 FOR NL = 1 TO SL
550 READ N
560 READ VOL
570 READ ND
580 IF CS = S THEN GOSUB 1000 : REM SKIPS UNWANTED SEGMENTS
590 NEXT NL
600 IF CS = S THEN RETURN
610 CS = CS + 1
620 GOTO 530
1000 REM SUBROUTINE FOR PLAYBACK OF A SINGLE NOTE
1010 REM ARGUMENTS
1020 REM N - MIDI VALUE OF NOTE TO PLAY FROM 0 TO 127 ($7F)
1030 REM VOL - VOLUME OF NOTE TO PLAY FROM 0 TO 63 ($3F)
1040 REM ND - DURATION OF NOTE TO PLAY IN SIXTEENTHS
1100 REM CONVERT MIDI NOTE TO FREQWORD
1110 FW = INT(EXP(N*0.0577622651)*21.9467431+0.5)
1120 REM SPLIT FREQWORD TO HIGH AND LOW BYTES
1130 HB = INT(FW/$100)
1140 LB = FW-HB*$100
1150 REM SPECIFY THE FREQWORD AND INSTRUMENT WE WANT
1160 VPOKE 1,$F9C0,LB
1170 VPOKE 1,$F9C1,HB
1180 VPOKE 1,$F9C3,$80 : REM TRIANGLE AS DEMO
1190 REM PLAY THE NOTE
1200 FOR I = 0 TO ND*8-1
1210 VPOKE 1,$F9C2,VOL+$C0
1220 VOL = VOL - INT((VOL+$F)/$10) : REM CONTROLS VOLUME DECAY
1230 FOR J = 0 TO TD : NEXT J
1240 NEXT I
1250 VPOKE 1,$F9C2,$00
1260 RETURN
1500 REM DATA POWERING PLAYBACK - TWINKLE TWINKLE LITTLE STAR
2000 DATA 14 : REM SEGMENT 0
2010 DATA 60,$3F,4
2020 DATA 60,$3F,4
2030 DATA 67,$3F,4
2040 DATA 67,$3F,4
2050 DATA 69,$3F,4
2060 DATA 69,$3F,4
2070 DATA 67,$3F,8
2080 DATA 65,$3F,4
2090 DATA 65,$3F,4
2100 DATA 64,$3F,4
2110 DATA 64,$3F,4
2120 DATA 62,$3F,4
2130 DATA 62,$3F,4
2140 DATA 60,$3F,8
2500 DATA 7 : REM SEGMENT 1
2510 DATA 67,$3F,4
2520 DATA 67,$3F,4
2530 DATA 65,$3F,4
2540 DATA 65,$3F,4
2550 DATA 64,$3F,4
2560 DATA 64,$3F,4
2570 DATA 62,$3F,8

YM2151[]

The very basic requirements to play sound on the YM2151 chip are:

  1. Load a patch into the YM2151 registers for one of the 8 voices (channels).
  2. Set the note value for the channel
  3. Send a KeyDown message to play the note
  4. (wait)
  5. Send a KeyUP message to release the note when it has played for the intended duration

When playing multiple notes, if you have not released the previous note (KeyUP) yet, then sending a second KeyDN will NOT play the new note. This would be like trying to press a piano key that you're already holding down.

To talk to the YM2151, you POKE information into one of its two I/O memory locations:

  • Address Register ($9FE0) - tells the YM2151 which of its internal register addresses to use
  • Data Register ($9FE1) - send the actual values to this register
  • NOTE: These I/O addresses are very likely to change in the future, as they correspond to expansion port addresses, and if the YM2151 is approved for the system, it is likely to be built into the mainboard directly and will use a different IO address range than the expansion slots.

Example program to play two chime sounds in an ascending tone, which might serve as a positive audible feedback tone:

10 S=600               : REM NOTE SPEED
20 YA=$9FE0 : YD=$9FE1 : REM YM2151 ADDRESS/DATA PORTS
30 LN=$3A : HN=$44     : REM LN/HN = LO NOTE / HI NOTE
40 REM --- LOAD PATCH INTO VOICE 0 ---
50 FOR I=1 TO 5
60 READ A : READ D
70 POKE YA,A   : POKE YD,D
80 NEXT I
100 REM --- PLAY HAPPY SOUND ---
110 POKE YA,$28 : REM $28 IS VOICE 0 FREQ. SETTING
120 POKE YD,LN  : REM SET THE FREQ. TO LO NOTE VALUE
130 POKE YA,$08 : REM SELECT THE KEYUP/DN REGISTER
140 POKE YD,0   : REM RELEASE ANY PREVIOUS NOTE
150 POKE YD,$40 : REM PLAY THE NOTE
160 FOR I = 1 TO S : NEXT
170 POKE YD,0   : REM RELEASE THE NOTE
180 FOR I = 1 TO S : NEXT
190 POKE YA,$28
200 POKE YD,HN	: REM SET NEXT NOTE FREQ. TO HI-NOTE
210 POKE YA,$08
220 POKE YD,0
230 POKE YD,$40
240 FOR I = 1 TO S : NEXT
250 POKE YD,0   : REM RELEASE THE SECOND NOTE
260 END
1000 REM --- PATCH DATA ---
1010 DATA $20, $C0
1020 DATA $58, $01
1030 DATA $98, $1F
1040 DATA $B8, $0D
1050 DATA $F8, $F6

The patch data lines are arranged to make it easy to play around with them and see what they do.

The settings mean the following:

$20 = master channel configuration: $C0 = L & R volume ON, No Feedback, Use OP algorithm 0.

$58 = fine detuning / phase multiplier: $01 = no detune (hi nybble) / multiplier=1 (normal)

$98 = Key-scale / Attack Rate: $1F = no keyscale / max attack rate (keyscale = 3 MSB, attack = 5 LSB)

$B8 = Amplitude Mod ENA / 1st Decay Rate: $0D = no AM / Decay=13 (AM-ENA is 1 MSB / decay is 5 LSB)

$F8 = Sustain Level / Release Rate: $F6 = max sustain (0-F in hi nybble / release=6 .. 0-F in lo nybble)

Note that this patch is very simple, and only utilizes the 4th operator of voice 0. More advanced patches would require more settings to be made for each voice, which is beyond the scope of a simple "hello world" example for sound.

Advertisement