nephitejnf / muse2pokecrystal

GNU Affero General Public License v3.0
6 stars 2 forks source link

Optimize ASM Output #3

Open hyperdriveguy opened 5 years ago

hyperdriveguy commented 5 years ago

The with the output of even some of the most simple and repetitive songs being so long, it would be really nice if we implemented some kind of algorithm to reduce bloat.

First of all, output of sequential rests are 1:1 with input. Musescore does not automatically compress rests when they are deleted. This means that we get a lot of output like this for example:

note __, 2
note __, 2
note __, 2
note __, 2
note __, 1
note __, 8

This can be optimized to:

note __, 16
note __, 1

This optimization alone would save several bytes. The length just can't exceed 16.

There is also a much more daunting optimization using callchannel that could potentially save even more space. My proposed algorithm would happen post-conversion, be toggled by a flag, and likely be in a separate file:

  1. The raw asm output is read into an array.
  2. The algorithm selects at least 4 or 5 notes/octaves/commands and stores them in a new two dimensional array: the search array.
  3. The file array is copied to a backup array.
  4. It iterates through the file array comparing it to the active array within the search array. If a match is found, the algorithm replaces the matching lines with a line storing the word "break" followed by the index of the search array.
  5. If there is more than one match for the searched block the algorithm overwrites the current index of the search array, increasing it by one line.
  6. If the first or second search yields less matches or only one match, the search block is shifted either back to its previous position or iterates forward. The backup array is restored if it reverts to the previous position.
  7. After the entire file is iterated through, each "break" in the file array is given a matching label, in the format of callchannel Music_<SongName>_Branch<index>. The search array is formatted and appended to the array as well.
  8. The file array is written to the output.

This one is gonna be while before its properly implemented.

nephitejnf commented 5 years ago

Yeah, I've thought about the optimization like this, this is still a little out there, at least for the call channel optimization. The rests are gonna a ton easier to handle for, though. Might be an idea to delegate the optimization to a separate script, that way any by-hand changes can be made for any added flare someone may add.

nephitejnf commented 5 years ago

And then optimizations can then be made afterward.

hyperdriveguy commented 5 years ago

That's why I thought giving optimizations their own file would be a good idea: it can be done at conversion time by muse2pokecrystal with a flag by importing optimizations or the optimizations script can be run alone at after hand tweaking is done.

nephitejnf commented 5 years ago

Okay, misunderstood part of that bit.

hyperdriveguy commented 5 years ago

Here's the mess I've come up with so far. It's far from working and I feel like I'm doing something terribly wrong:

def optimize_callchannel(musicfilein):
    asmfilein = open(musicfilein, "r")
    asmfilearray = asmfilein.readlines()
    # This assumes the name of the song is in the first line of the file
    songname = asmfilearray[0][:-2]
    currentsearch = 0
    searchbeginindex = 0
    # Not inclusive of ending index. To get the "real" end index, this value must be subtracted by 1
    searchendindex = 5
    searcharray = [[]]
    searcharray[currentsearch] = asmfilearray[searchbeginindex:searchendindex]
    asmfilearraybackup = asmfilearray.copy()
    # Contains indexes where matches were found
    blockmatch = []
    for line in range(0, len(asmfilearray) - 1):
        for searchline in range(line, line + len(searcharray[currentsearch]) - 1):
            if not asmfilearray[searchline] == searcharray[currentsearch][searchline - line]:
                print(asmfilearray[searchline][:-1] + " does not match " + searcharray[currentsearch][searchline - line][:-1])
                break
nephitejnf commented 5 years ago

The optimization code is gonna be interesting, I feel like some good regex will be of use with it, though. Still not quite sure on how to be implement it though.

hyperdriveguy commented 4 years ago

SS's Megalovania is a great example of what optimization output should look like.

megalovania.asm.txt

nephitejnf commented 4 years ago

There's a good reason for that

hyperdriveguy commented 4 years ago

:open_mouth:

hyperdriveguy commented 4 years ago

So I'm going to readdress this issue from a new angle. Since the refactor, music commands are added to a list before they are output which will make this whole lot of just a list manipulation and iteration.

Something I made sure to do in the refactor is change the loopchannel 0, Channel_Loop to jumpchannel Channel_Loop because loopchannel cannot be nested. I will work on loopchannel optimizations after the callchannel optimiztations.

hyperdriveguy commented 3 years ago

28 added callchannel optimizations