Audio: Remove the 8K track size limit.
3 files changed, 40 insertions(+), 17 deletions(-)

M src/audio/Audio.asm
M src/audio/AudioTrack.asm
M tools/audio.js
M src/audio/Audio.asm +21 -16
@@ 6,19 6,19 @@ 
 	INCLUDE "MSXMusic.asm"
 
 Audio: MACRO
-	; Modifies: af, bc, hl
+	; Modifies: af, bc, de, hl
 	Tick:
 	playing: ret
-		ld a,0
-	bank: equ $ - 1
-		ld (ROM_mapper.page8000.BANK_SELECT),a
 		ld hl,0
 	address: equ $ - 2
-		ld a,1
+		ld de,1 >> 8
+	bank: equ $ - 2
 	wait: equ $ - 1
-		dec a
+		ld a,e
+		ld (ROM_mapper.page8000.BANK_SELECT),a
+		dec d
 		call z,Audio_Process
-		ld (wait),a
+		ld (bank),de
 		ld (address),hl
 		ld a,(ROM_mapper.page8000.bank)
 		ld (ROM_mapper.page8000.BANK_SELECT),a

          
@@ 97,9 97,9 @@ Audio_Stop:
 Audio_Tick:
 	jp ix
 
-; hl = command list
-; a <- wait
-; hl <- next command
+; ehl = command list
+; d <- wait
+; ehl <- next command
 Audio_Process:
 	ld a,(hl)
 	cp 40H

          
@@ 108,11 108,12 @@ Audio_Process:
 	jr c,Audio_ProcessOPLL
 	jr z,Audio_ProcessJump
 	sub 80H
+	ld d,a
 	inc hl
 	ret
 
-; hl = command list
-; hl <- next command
+; ehl = command list
+; ehl <- next command
 Audio_ProcessPSG:
 	ld c,PSG_DATA
 	inc hl

          
@@ 120,8 121,8 @@ Audio_ProcessPSG:
 	outi
 	jr Audio_Process
 
-; hl = command list
-; hl <- next command
+; ehl = command list
+; ehl <- next command
 Audio_ProcessOPLL:
 	sub 40H
 	inc hl

          
@@ 130,12 131,16 @@ Audio_ProcessOPLL:
 	outi                      ; wait 84 cycles
 	jr Audio_Process
 
-; hl = command list
-; hl <- next command
+; ehl = command list
+; ehl <- next command
 Audio_ProcessJump:
 	inc hl
+	ld e,(hl)
+	inc hl
 	ld a,(hl)
 	inc hl
 	ld h,(hl)
 	ld l,a
+	ld a,e
+	ld (ROM_mapper.page8000.BANK_SELECT),a
 	jr Audio_Process

          
M src/audio/AudioTrack.asm +1 -1
@@ 34,5 34,5 @@ AudioCommandJump: MACRO ?address
 	command:
 		AudioCommand 80H
 	address:
-		dw ?address & 1FFFH | 8000H
+		ROMAddress ?address, 8000H
 	ENDM

          
M tools/audio.js +18 -0
@@ 33,25 33,43 @@ class AudioTrack {
 		lines.push("\tSECTION ROM_DATA");
 		lines.push("\tALIGN 2000H");
 		lines.push(`${this.name}_commands:`);
+		let size = 0;
+		const increaseSize = amount => {
+			const space = 0x2000 - (size & 0x1FFF);
+			if (space - amount < 4) {
+				lines.push(`\tAudioCommandJump ${this.name}_commands_${(size + space).toString(16).toUpperCase()}`);
+				for (let i = 4; i < space; i++) {
+					lines.push(`\tAudioCommandWait 1`);
+				}
+				lines.push(`${this.name}_commands_${(size + space).toString(16).toUpperCase()}:`);
+				size += space;
+			}
+			size += amount;
+		}
 		let time = 0.5 / 44100 * frameRate;  // slight offset to avoid rounding errors
 		for (const command of this.commands) {
 			if (command instanceof AudioCommandPSG) {
+				increaseSize(2);
 				lines.push(`\tAudioCommandPSG ${toAsmHex(command.address)}, ${toAsmHex(command.value)}`);
 			} else if (command instanceof AudioCommandOPLL) {
+				increaseSize(2);
 				lines.push(`\tAudioCommandOPLL ${toAsmHex(command.address)}, ${toAsmHex(command.value)}`);
 			} else if (command instanceof AudioCommandWait) {
 				const lastTime = time;
 				time += command.time * frameRate;
 				for (let frames = Math.floor(time) - Math.floor(lastTime); frames > 0; frames -= 0x7F) {
+					increaseSize(1);
 					lines.push(`\tAudioCommandWait ${Math.min(frames, 0x7F)}`);
 				}
 			} else if (command instanceof AudioCommandLoop) {
 				lines.push(`${this.name}_commands_loop:`);
 			} else if (command instanceof AudioCommandEnd) {
 				if (this.loop < 0) {
+					increaseSize(1);
 					lines.push(`${this.name}_commands_loop:`);
 					lines.push(`\tAudioCommandWait 1`);
 				}
+				increaseSize(4);
 				lines.push(`\tAudioCommandJump ${this.name}_commands_loop`);
 			} else {
 				throw new Error("Unrecognised command.");