A little background
The BIOS Music Player uses the following tables to decode a song stream.
$FC79 - 8 element note duration table (BASIC Manual Page 103 for reference)
$FC80 - 42 element frequency table higher 4 bits (BASIC Manual Page 102 for reference)
$FCAA - 42 element frequency table lower 7 bits (BASIC Manual Page 102 for reference)
$FCD5 - 17 element volume decay table
$FCE6 - 17 element volume maximum table used by SONIC INVADERS
It's no surprise that BASIC uses the same tables, with a few interesting exceptions.
Song Pointers
The game ROMs have structure pointers, which are referenced at $BF00 + X
Pointer Structure
Code: Select all
WORD Songstream pointer
BYTE Songstream length
The first byte of the songstream (last as Y decrements - so reading backwards!) is the note length.
Subsequent bytes are encoded as frequency table index shift left 3, plus the duration.
Air/Sea Attack Intro
Ok - here's the whole intro tune from Air/Sea Attack.
Code: Select all
77 4F 37 4B 05 BB 4F 27 83 93 9B 93 17 4F 96 AB 17 4F 0E
Code: Select all
$0E - Note length
$4F - Frequency index 9, duration 7
$17 - Frequency index 2, duration 7
$AB - Frequency index 21, duration 3
and so on
Code: Select all
10 SOUND 9;7,2;7,21;3
20 SOUND 18;6,9;7,2;7
30 SOUND 18;3,19;3,18;3
40 SOUND 16;3,4;7,9;7
50 SOUND 23;3,0;5,9;3
60 SOUND 6;7,9;7,14;7
BASIC has it preset to $12, Air/Sea attack has it set to $0E.
The problem is caused by this code, which is the same in all versions of BASIC
Code: Select all
7BF9: lda #$12
7BFB: ldy $D1
7BFD: sta $0210,y
7C00: jsr $7C14
at least - and maybe help when composing your own tunes in a different timing.
What is BASIC Frequency 1 Rest?
In the manual, 1 and 32 are defined as rests. This is not actually the case for frequency code 1 - in the player it has a special meaning!
When the player encounters a frequency code of 1 - it means take the next byte in the song stream and use it as a literal index.
This is how game ROMs access the missing upper elements in the frequency tables.
So a stream of $1F, $0B is decoded to
Code: Select all
$0B - frequency code 1, duration 3
$1F - Impossible from BASIC - used by several games
Code: Select all
7BBA: lda $CF
7BBC: and #$1F
7BBE: cmp #$01
7BC0: bne $7BC4
7BC2: lda #$00
7BC4: sta $D0
By making a couple of patches to BASIC, you can use it to compose your next in game masterpiece in an emulator!
File offsets for patching are (same for all BASIC8xx.BIN)
$2BC3 - Change 0 to 1 - thus putting back the literal byte command
$2BFA - Change note length
Cheers!