I mainly deal with lower-level stuff, and making tools to help others make great stuff out of them.
I'm a regular over at gbdev, if you're interested in making a game on a retro platform for fun, this might be worth checking out!
I'm the main maintainer of RGBDS, the main toolchain for programming on the Game Boy.
If you're interested in contributing, we have some beginner-friendly tasks!
Pattern break Dxx seems to under fO, jump to the specified row on the pattern it's already playing. Under hD, it skips to the next pattern (unless overridden using a Bxx command).
There seems to be something not quite right with Fxx Set Tempo. For example, playing the first pattern of the sample song The Murderous Funk Machine (intro), it has a discrepancy. I've attached recordings displaying the difference, with the first channel isolated.
When a channel is unmuted, the driver refrains from using it until a note is next played. The reason is that FX might write to the channel while NRxy still contain leftover values, but not the song's; this would produce corrupt sounds. When a note is played, all NRxy registers are initialised, avoiding the issue.
However, the current condition is wrong: all registers may not be written if a note is played, only if an instrument is specified on that cell as well.
This would require moving the AllowedChannels write inside of the "instrument writes" block. Preferably early, as e (the channel mask) eventually gets overwritten from register pressure.
Add a new option (in main.rs); I'm thinking something like -O -trim_patterns,+prune_instruments. (-O is a common "optimisation" flag, e.g. in C compilers.) The argument would be a comma-separated list of pass toggles, with the + or - prefix indicating whether to enable or disable the pass.
For each pass, if it's disabled, then replace it with a dummy operation that doesn't perform any optimisations. (For example, the "row overlap" pass would instead return some arbitrary order, and no overlap.)
Rationale
This would be useful for people doing tricks with the song data (e.g. using routines to manipulate the song pointer).
I'm guessing this was missed when testing because only one song is played at a time, but when the song changes the wave channel will linger for a bit until the new song uses it.
Attached song works fine in hUGETracker 1.0.1, but trying to parse it with teNOR-v1.0.0-x86_64 throws an error:
Error: Unable to parse a UGE song from "Prologue_test_new05a.uge": There was an error parsing the UGE file!
(0x6001 bytes into the data) Length out of range (000000e3)
(0x5efd bytes into the data) parsing v3 instrument from here
(0x542b bytes into the data) Error in parser "Count"
(0x542b bytes into the data) parsing v3 instrument bank from here
(0x304 bytes into the data) parsing v3 instr collection from here
(0x4 bytes into the data) parsing v6 song from here
(Either the file is corrupted, or our UGE parser has a bug. If the latter, please attach your UGE file and the above in your bug report!)
This has been requested by a few people: allow "absolute" offsets in subpatterns.
Proposed implementation: repurpose a FX otherwise incompatible with subpatterns, that would signal the offset must instead be interpreted as a note ID. Possibly, make the FX param be an additional offset to add to that note's period?
Look for ; TODO: have tracker do this comments (or similar, the regex TODO.+tracker should find them all). These mark computations that can be done statically, which would not only save some cycles, but also some bytes in the especially "jr-tight" FX code.
@SuperDisk has commented that the textual output format is not to be changed, for "debuggability" purposes (fair enough); however, the binary format can be modified.
Fortunately, macros can give us the best of both worlds:
This is trivial on the RGBDS side, since the macro can be essentially as complex as we want (though keeping the complexity low is preferable), but more annoying on the C side, since the macro has to be expressions—and unlike 🦀, we can't really do conditionals besides ternaries, likely turning that macro into ternary soup in the long run.
A possibility for the C thing is to "pre-process" that C file (from a more maintainable hUGEDriver.h.in). This however complicates the integration process slightly, though we can instead rely on releases for this. Maybe.
I don't really now how to describe it properly. Just listen to the example for a number of loops (at least 20 or so) and it seems like the beat changes - likely a note is missed or something.
Help is wanted because I do not have the motivation to implement this; I am however willing to provide guidance to anyone having that motivation. Feel free to contact me.
Context / Motivation
Currently, the biggest problem with using fO over hD is the dreaded Error: The song has NNN unique cells, the max is 256! error.
In the interest of size, fO collects cells (note+instr+FX) into a "catalog", and stores cells as indices into this catalog; in the interest of size and speed (again), those indices are single bytes, which inherently forbid more than 256 entries in the "catalog".
Implementation
A way to relax the limitation is to split the catalog in two1: one for the "main grid", and one for subpatterns. Then the limitation only applies to each one individually, which should be productive considering that typical cells for patterns and subpatterns are quite different.
As far as fO itself is concerned, this is really simple: duplicate the pointer to .cellCatalog, and change the variable being loaded from in TickSubpattern.
Issues
Song export
First off, teNOR currently assumes that it can compute the "overlap" optimisation by comparing the cells themselves; this wouldn't become true anymore, because nothing guarantees a given cell would have the same ID across both catalogs.
Therefore, cells should instead be compared via some kind of IDs, of three kinds: shared, main only, and subpattern only. Then, the shared cells would get the same indices across both catalogs (so the first few, for simplicity).
Output size
There is also a size problem: there is already somewhat considerable padding within a cell catalog2, and splitting the catalog in two like that would multiply the padding by 2.5!
This could be mitigated by fusing the two catalogs like they currently are if that's possible; then both labels are identical, and only a single header byte is wasted—but that increases the implementation's complexity significantly.
Footnotes
Other options have been considered for splitting, such as one catalog per channel; but these are very impractical to implement, at least with fO in its current form. ↩
The size of the catalog is 512 + nb_cells bytes, which can be a lot compared to the theoretical minimum size of 3 × nb_cells. ↩