Saturday, June 13, 2020

Modul8 / Modul8 Module Best Practices

Best Practices for Writing Modul8 Modules:

  • Variables are camelCase
  • Put all your code in Init(). Define functions like handleKeyword(keyword, param, layer) and the only code in the KeywordEvent() block should be to call your handleKeyword() function. Keeping all the code on one screen makes it easy to audit, rename variables, and understand what the code is doing. You can also use "return" to skip code, instead of indenting the rest of the method.
  • Add a "module active" toggle button which defaults to off and auto-serializes. If this button is off, your module does nothing. Modul8 does not save which modules are active on a per-project basis. So if users have a lot of different projects using different modules, it is a common problem that an old project won't work until they figure out which modules to turn on and off. Adding an active toggle to your module lets them save that information as part of the project and there is no need to actually turn off the modules at the modul8 level. This is especially important for modules that have periodical, direct event, or keyword actions, because those might screw up someone's project. But it is also nice for performance reasons, if your module does a lot of GUI updates, to be able to skip them when the module is turned off.
  • Use versions on your modules, and put a changelog in the description. You can use option-Enter to add newlines to the description box.
  • Use the names of GUI elements rather then the messages. Specifically, in MessageEvent() ignore 'msg' and use param['NAME'] instead. The names are easier to find in the GUI editor, and you have to use name when modifying the GUI from the code. Having different values for the message in the "Script Connect" area, or having to keep the messages and names in sync is bothersome and an easy source of bugs. You do have to put something in the "script connect" box, but as long as you ignore the 'msg' variable in your code it doesn't matter what it is.
  • Logging script output is very CPU-intensive, so comment out all your debug message when done. If your module outputs to console as part of its feature, then it should have a "module active" button that defaults to False
  • If your module will have a (global) and (layer) version, define a variable "global = False" and write your code to handle both modes. Anytime you update the code, copy it from the (layer) module into the (global) module and change the value to True. Alternately, copy the .m8m file on disk which will include the layout as well as the code. Then you only need to update the 'global' variable to True.
  • Consider ignoring GUI changes during startup. If you have a fader that drives some keywords, but might be out of sync because the user changed those keywords through the main modul8 GUI, then you should ignore the fader position on load. Otherwise, you will override the values in the stored project: "hey, why are these values different than I left them??". This is especially important if your module doesn't have an [active] button which defaults to off. Define "finishedInit = False" in Init() and then set it true in PeriodicalEvent(); empirically, MessageEvent of saved state will run before PeriodicalEvent, so if not finishedInit you know it is due to project load and not an explicit user interaction. Turning off auto-serialize for certain GUI elements is another way to address this, although you will then lose the information about that element's value at time of save.
Best Practices for Modul8:
  • Use LB Notes and write down how your projects are structured, which modules are being used, and which MIDI and keyboard bindings you use.

No comments: