creatiVision BIOS Music Player Song format
Posted: Sat Feb 12, 2022 6:24 pm
Here's a breakdown of the creatiVision Music Player Song format.
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
The songstream length is used to seed the Y register for indirect indexing.
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.
Reading backwards you get
Decoded to BASIC it would be
When you try to play in BASIC there's an obvious timing issue. This is due to the note length.
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
The note length is hard coded to be $12. A quick patch would make it sound better
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
The code which kills this little trick in BASIC is
Any attempt to use frequency duration 1 is returned to 0.
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!
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!