I used apultra to pack everything, including players. Players and music data were packed separately, so players get reused. I also tested some even better packers, but they would take like half a minute to decompress in the worst case, which is unacceptable.
Even with the best packing, I needed a large buffer for the largest unpacked song, it was nearly 19K. At this point it couldn't fit at all.
I had to:
- Place my code as low as #5b00, disabling the BASIC interrupt handler completely
- Overwrite the screen drawing code with the song buffer
- Decrease the two largest songs
In order to decrease the largest songs size, which happened to be Freezing Point and Geostorm, I first made a function that optimizes out the empty rows by reducing the speed of a row before (recursively, as long as row speeds allows). This optimization can be applied to any song in 1tracker now. This helped a bit, but still wasn't enough. So I also had to modify wtbeep and SquatM formats.
In the wtbeep, I now omit the 0 byte for rows without a drum (it is now triggered by the bit 6 of the control word). Saves a bit of room.
In the SquatM, I reworked the way how the dividers stored. Instead of the normal LSB/MSB order that is easy to read with POP I stored them in the MSB/LSB order, and used bit 7 of the MSB as the note rest flag. The LSB is omited for note rests. This of course made the song data parser very suboptimal, but the Sqeeker-like design does not suffer from row transition noise much, and I gained the remaining bits of the RAM.
The largest songs remained the same, but I saved a couple K this way. Freezing point is 16714 now, and Geostorm is 15809 (2768 and 2500 packed).