Driver Technical Information
Note: Since this is Z80 code, all words are little-endian unless otherwise stated.
Memory Layout
Address |
Size |
Description
|
$DD00
|
Byte
|
Unused
|
$DD01
|
Byte
|
Global speed counter
|
$DD02
|
Byte
|
Global speed counter reset
|
$DD03
|
Byte
|
Sound ID Main Trigger
|
$DD04
|
Byte
|
Sound ID Queue, Slot 1
|
$DD05
|
Byte
|
Sound ID Queue, Slot 2
|
$DD06
|
Byte
|
Sound ID Queue, Slot 3
|
$DD07
|
Byte
|
Unused
|
$DD08
|
Byte
|
Pause Mode (00 - off, 01-7F - paused, 80-FF - do unpause)
|
$DD09
|
Byte
|
Fade-out countdown - major value
|
$DD0A
|
Byte
|
Fade-out countdown - minor value
|
$DD0B
|
Byte
|
Fade-out countdown - minor reset value
|
$DD0C
|
Byte
|
Unused
|
$DD0D
|
Byte
|
Current sound effect number
|
$DD0E
|
Byte
|
Unused
|
$DD0F
|
Byte
|
Current Sound priority
|
$DD10
|
Byte
|
Unused (Game Gear Stereo bits in later drivers)
|
$DD11
|
Byte
|
Current PSG noise mode
|
$DD12-14
|
3 Bytes
|
Unused
|
$DD15
|
Byte
|
Unknown (modifies noise mode, never written and should always be 0)
|
$DD16
|
Byte
|
Noise channel attenuation
|
$DD17
|
41 Bytes
|
Unused
|
$DD40
|
48 Bytes
|
Music Channel 1 RAM (PSG 1)
|
$DD70
|
48 Bytes
|
Music Channel 2 RAM (PSG 2)
|
$DDA0
|
48 Bytes
|
Music Channel 3 RAM (PSG 3)
|
$DDD0
|
48 Bytes
|
Music Channel 4 RAM (PSG Noise)
|
$DE00
|
48 Bytes
|
SFX Channel 1 RAM (PSG 2)
|
$DE30
|
48 Bytes
|
SFX Channel 2 RAM (PSG 3)
|
$DE60
|
48 Bytes
|
SFX Channel 3 RAM (PSG Noise)
|
Channel Structures
Each channel occupies 48 bytes of RAM:
Offset |
Type |
Description
|
$00
|
Byte
|
Control flags
|
$01
|
Byte
|
PSG channel number
|
$02
|
Unsigned Byte
|
Note length multiplier
|
$03
|
Word
|
Data pointer
|
$05
|
Signed Byte
|
Transposition (added to note value)
|
$06
|
Signed Byte
|
Volume
|
$07
|
Byte
|
Pitch Envelope
|
$08
|
Byte
|
Volume Envelope
|
$09
|
Unsigned Byte
|
Channel branch "stack" pointer
|
$0A
|
Unsigned Byte
|
Note duration counter
|
$0B
|
Unsigned Word
|
PSG tone register value (i.e. the value written to the PSG to generate the note)
|
$0D
|
Unsigned Byte
|
Note duration reset value
|
$0E
|
Byte
|
Note Stop counter (number of frames after the note gets turned off)
|
$0F
|
Byte
|
Note Stop reset value
|
$10
|
Word
|
Data pointer for pitch bend effect.
|
$12
|
Signed Word
|
Pitch bend effect adjustment value. Added to word at $0B before writing to the PSG.
|
$14
|
Unsigned Byte
|
Number of ticks to wait before starting pitch bend.
|
$15
|
Unsigned Byte
|
Number of ticks to wait before increasing the pitch bend. Also used as the pitch envelope index.
|
$16
|
Signed Byte
|
Pitch bend step size.
|
$17
|
Unsigned Byte
|
Number of pitch bend steps before negating step value.
|
$18
|
5 Bytes
|
Unused.
|
$1D
|
Byte
|
Volume effect flags
|
$1E
|
Byte
|
Volume effect mode (00 - normal, 08 - repeat Attack/Decay phase)
|
$1F
|
Unsigned Byte
|
Volume effect value / Volume envelope index
|
$20
|
Signed Byte
|
Volume Effects - Adjustment value
|
$21
|
4 Bytes.
|
Volume effect memory
|
$25
|
Signed Byte
|
Detune value (added to raw PSG frequency)
|
$26
|
Byte
|
Unused (Channel Stereo Bits in later drivers)
|
$27
|
3 Bytes
|
Loop counters
|
$2A
|
3 Words
|
Branch return address stack
|
Channel Control Flags
Bit |
Description
|
0
|
Unknown.
|
1
|
Maintain effect state across notes
|
2
|
Suppress PSG writes (i.e. music channel that is overridden by SFX)
|
3
|
Triggers literal read mode
|
4
|
Suppress writes to the PSG volume register (channel plays a rest)
|
5
|
Unknown
|
6
|
Allow PSG volume updates only
|
7
|
Channel active flag
|
Pitch Effect Flags
Bit |
Description
|
0-6
|
If bit 7 = 0: pitch envelope number otherwise unused.
|
7
|
Set = pitch bend; Reset = pitch envelope.
|
Literal Read Mode
If bit 3 of the channel's control byte is set the driver enters literal read mode. This changes the way that data is read from the channel's stream: instead of reading bytes, the driver starts reading big-endian words (command bytes are still processed). These words are interpreted as PSG tone register values and are copied into offset $0B. The pitch adjustment at $05 is sign-extended to 16-bits and treated as a detune value which is added to the word before copying to the offset. Each word must be followed by a duration byte.
Module Editing
Offset |
Size |
Description
|
$00
|
Word
|
Unused. Was probably intended as a pointer to volume envelope data but the driver ignores it.
|
$02
|
Byte
|
Number of channels.
|
$03
|
Byte
|
Unused. Skipped by the driver.
|
$04
|
Byte
|
Note length multiplier. Copied into offset $02 of each channel structure.
|
$05
|
Byte
|
Global speed. Copied into $DD01 and $DD02
|
Following the module header are the channel headers. The number of channel headers must match the value at offset $02 in the module header.
Offset |
Size |
Description
|
$00
|
Word
|
Channel data pointer (absolute).
|
$02
|
Byte
|
Pitch adjustment. (transposition)
|
$03
|
Byte
|
Volume adjustment.
|
Commands
Command |
Description
|
$00 - $7F
|
Duration values
|
$80 - $DF
|
Notes ($80 = rest)
|
$E0vvwwxxyyzz
|
Volume effect / ADSR envelope (Attack, Decay, Sustain, Release)
- vv - Attack Rate (volume starts at silence and increases with this speed until it reaches the maximum)
- ww - Decay Rate (how fast the volume decreases after the Attack Phase)
- xx - Decay Level (volume level where the Decay Phase ends)
- yy - Sustain Rate (how fast the volume decreases after the Decay Phase)
- zz - Release Rate (how fast the volume decreases after being turned off)
|
$E1xx
|
Detune - xx = amount (signed)
|
$E2xx
|
Adjust volume - same as $E6
|
$E3xx
|
Nothing (empty slot)
|
$E4xx
|
Adjust noise volume - xx = amount (signed)
|
$E5xx
|
Change ADSR Mode. 00 - normal, 01-FF - repeat Attack/Decay phases
|
$E6xx
|
Adjust volume - xx = amount (signed)
|
$E7
|
Maintain effect state (sets bit 1 of channel control)
|
$E8xx
|
set Note Stop timeout (number of frames after that the note is turned off forcibly, 0 - off)
|
$E9xx
|
Nothing (empty slot)
|
$EAxx
|
Nothing (empty slot)
|
$EBxx
|
Nothing (empty slot)
|
$ECxx
|
Nothing (empty slot)
|
$EDxx
|
Set global speed - xx = new speed
|
$EExx
|
Nothing (empty slot)
|
$EF
|
Invalid command (points into data)
|
$F0wwxxyyzz
|
Pitch Bend
- ww - Number of ticks to wait.
- xx - Number of ticks before increasing pitch bend.
- yy - Pitch bend step size.
- zz - Number of ticks before negating step size.
|
$F1
|
Invalid command (points into data)
|
$F2
|
Stop channel playback
|
$F3??
|
Unknown
|
$F4xx
|
Pitch envelope - xx = envelope number
|
$F5xx
|
Volume envelope - xx = envelope number
|
$F6xxxx
|
Jump - xxxx = absolute address
|
$F7xxyyzzzz
|
Loop
- xx - Slot number
- yy - Loop count
- zzzz - Absolute address
|
$F8xxxx
|
Subroutine branch - xxxx = absolute address
|
$F9
|
Return from subroutine
|
$FAxx
|
Set channel speed - xx = new speed
|
$FBxx
|
Transpose channel by xx (added to current transpose value, which is added to all notes before looking up the PSG frequency)
|
$FCxx
|
Nothing (empty slot)
|
$FDxx
|
Set read literal mode. Turned on if xx == $01, otherwise off.
|
$FExx
|
Nothing (empty slot)
|
$FFxx
|
Nothing (empty slot)
|