tildearrow / furnace

a multi-system chiptune tracker compatible with DefleMask modules
GNU General Public License v2.0
2.23k stars 198 forks source link

Arpeggio Scheme #280

Closed 0x5066 closed 2 years ago

0x5066 commented 2 years ago

Forks of FamiTracker (starting with 0CC I believe) have this "Scheme" feature in it's Arpeggio section, where you could input 0 0 x x y y or 0 0 12+x x y y or 0 0 -12+x x y y as a valid command, which would take whatever 0xy parameter was in the tracker view, skipping the arpeggio's own implementation, screenshot attached for clarity:

image

tildearrow commented 2 years ago

Wooooooow that will require a rewrite of the playback routine, dropping Defle compatibility in the process. I might implement it using another way, but this looks too difficult.

Toonlink8101 commented 2 years ago

It's important to note that, for 0cc compatibility (#478), implementing arp schemes is necessary.

Deflemask compatibility could be maintained, but since Defle doesn't support arp schemes, files using the feature would need to consider this fact when attempting a dmf export.

Files with arp schemes would have to convert each use of the arps into a separate instrument, which would use many extra instruments; convert itself into a 1-speed dmf, which brings up more issues; or simply not allow dmf export when arp schemes are used.

tildearrow commented 2 years ago

The problem with arp schemes is that it would require a restructuring of the way macros are stored in order to make space for a "formula" value, and it would require me to add a formula (or even script/Lisp?) parser to Furnace...

Toonlink8101 commented 2 years ago

@tildearrow, I had trouble finding the code that handles the parsing of macros in the source code, but from what I can discern from the software itself, it seems that Furnace already supports some parsing of non-integer values. For example, the looping and release commands are already represented (and stored?) in the macro as a '|' and '/' symbol respectively. If this is the case, parsing characters such as 'x', 'y', or '+' should also be possible.

'+' is probably the easiest of these as the parser only needs to check ahead by one slot to see if a '+' is present. Then, if it is present, it just needs to add the values before and after the '+' and pass that on to whatever executes the macro's values.

For the 'x' and 'y', it would be a bit harder to discern feasibility without seeing the source. Depending on the current implementation of arpeggio macros, it might be possible to have the parser check the values of the current arpeggio effect command and store those values so that it can replace any occurrence of 'x' or 'y' to match the current arpeggio effect.

Or, a more passive approach might be to have the stored replacement values of 'x' or 'y' be set by the effect command handler. That way, the values only need to be reset when an arpeggio effect command is made.

Again, I couldn't find the code that currently parses the arpeggio macro, so I can't speak with much certainty.

Is something like this possible, or have I made false assumptions about the engine?

tildearrow commented 2 years ago

Storage. Furnace represents the loop and release positions as variables in a DivInstrumentMacro:

// this is getting out of hand
struct DivInstrumentMacro {
  String name;
  int val[256];
  unsigned int mode;
  bool open;
  unsigned char len;
  signed char loop;
  signed char rel;

  // the following variables are used by the GUI and not saved in the file
  int vScroll, vZoom;

  explicit DivInstrumentMacro(const String& n, bool initOpen=false):
    name(n),
    mode(0),
    open(initOpen),
    len(0),
    loop(-1),
    rel(-1),
    vScroll(0),
    vZoom(-1) {
    memset(val,0,256*sizeof(int));
  }
};

Macros are stored in raw format rather than an MML string when saving to a file.

The problem here is how would we store a formula? This would require changes to the format which may bring huge slowdowns to the engine (see yky.fur).

tildearrow commented 2 years ago

Additionally, we run into another issue: differing arpeggio macro implementations. Furnace treats most macros equally - the same code is used to run these and they don't take any parameters. What 0CC is doing requires binding the macro interpreter close to the playback driver, but this is not how Furnace works.

I should rephrase that. Furnace is able to run both arpeggio effect (00xy) and arpeggio macro at the same time. The arpeggio is handled by the DivEngine (sending DIV_CMD_LEGATO to the dispatch) and the arpeggio macro is handled by the DivDispatch. On the other hand, 0CC-FamiTracker apparently cannot run arpeggio effect and arpeggio macro concurrently, which means.... arpeggio macro overrides arpeggio effect...

Implementing arpeggio schemes the 0CC way would require a complete rewrite of the dispatch strategy, breaking DefleMask (and old Furnace) compatibility in the process, and potentially making things messier.

The only way to implement arp schemes in Furnace would be by storing these in the song rather than in the instrument, and adding an effect to select the current arp scheme, but then this is not how 0CC works...

Toonlink8101 commented 2 years ago

@tildearrow Firstly, thank you for taking the time to thoroughly explain things. I know that some people would rather be dismissive than have to explain everything.

So, from what I understand, it seems that full 0CC compatibility is off the table, at least to the same extent as Deflemask. With this being the case, it might be more feasible and even more practical to instead add an 0CC import*, similar to the current mod file support.

The only way to implement arp schemes in Furnace would be by storing these in the song rather than in the instrument, and adding an effect to select the current arp scheme, but then this is not how 0CC works...

If arp schemes were implemented in this way, as an effect with some kind of separate interface, similar to wavetables or samples, then 0CC files could be converted into Furnace. Since 0CC (and all versions of Famitracker) only support four effects columns, one of the additional columns supported by Furnace could be used to call the arp scheme command as necessary.

Would this be possible?

*Sidenote: it might be more practical to do the same for other file formats, such as ftm and dnm, or even crazier formats like ahx, midi, xm, or s3m. But, I'm getting ahead of myself...

tildearrow commented 2 years ago

Firstly, thank you for taking the time to thoroughly explain things. I know that some people would rather be dismissive than have to explain everything.

It's rather difficult for me to explain but I try.

So, from what I understand, it seems that full 0CC compatibility is off the table, at least to the same extent as Deflemask. With this being the case, it might be more feasible and even more practical to instead add an 0CC import*, similar to the current mod file support.

Actually, worse than DefleMask. Full DefleMask compatibility is one of Furnace's goals, whereas other tracker compatibility is not. .0cc import is definitely possible (just like .ftm import), but will have its limitations due to drastic differences, like the previously discussed arp schemes.

If arp schemes were implemented in this way, as an effect with some kind of separate interface, similar to wavetables or samples, then 0CC files could be converted into Furnace. Since 0CC (and all versions of Famitracker) only support four effects columns, one of the additional columns supported by Furnace could be used to call the arp scheme command as necessary.

This could be a possibility, but then 0CC's arp schemes have loop and release points (which Furnace's won't).

Would this be possible?

Partially.

*Sidenote: it might be more practical to do the same for other file formats, such as ftm and dnm, or even crazier formats like ahx, midi, xm, or s3m. But, I'm getting ahead of myself...

This is technically already done by MOD and Future Composer import.

tildearrow commented 2 years ago

Whoops

tildearrow commented 2 years ago

I am going to close this suggestion as won't fix because I am changing the arpeggio code in a way that may or may not be further incompatible with 0CC's arp schemes.

Apologies.