Found more info.
All songs start with "FF 00 __ __ 01 __ __ 02 __ __ 03 __ __ FF"
00-03 seem to be channel indexes, and the 2 bytes after them are the bigendian addresses of those channel streams relative to the song's root address. That's super important.
After the song header comes the header of the first channel, which is a series of opcodes and values that I hope tummai can figure out (I'm pretty sure "D8 __" sets the pitch shift). Then there's the actual melody block (notes, note lengths and rests), followed by the D0 repeat byte.
This is already in my notes.
The bad news is, I calculate we only have enough room for about 3 or 4 more songs (about 400-500 bytes each). I'm all for destroying a few present songs to fit in better ones, even if they're truncated versions.
It may be possible to introduce a new opcode to place in the channel headers (or even just the first channel header) that can indicate a bank and an address, and then we can write some code for that opcode that will:
1)dynamically write some copy code to RAM (so that it can be executed after we've bankswitched away from the sound engine bank)
2)switch banks to the bank specified in the opcode
3)go to the address specified in the opcode and copy the song data to RAM
4)switch back to the sound engine and reroute pointers to the song data in RAM.
If we can pull something like this off, then we can scatter songs all across the ROM in any open space we find.
This will require:
1) enough RAM to hold the data for one song at a time.
2) enough RAM to hold the song-copying code (which should be quite short).
3) enough ROM space in the sound engine bank to hold the new opcode code (shouldn't be a problem)
If we don't have the RAM, we'll have to find another solution. But we might have it! Is the RAM in $7000-7999 used by the game at all?