In this post, we’ll talk about guidelines. I think it’s extremely important to determine a set of guidelines for yourself that you’ll use for every project. The reason for this is that if you start every project with no guidelines, you’ll have to make a lot of ancillary decisions that will get in your way when you’re trying to be creative/solve problems with MT. It will also make it difficult for you to revisit projects you created in the past as each project will be different.
Following are the guidelines I use in no particular order.
Favor rules over translators.
Most problems can be solved by using either an assortment of translators or fewer translators with rules. Favor rules over translators because it helps keep project size minimal, makes editing/debugging/searching much easier and generally allows you to do more complex things.
As an example, when working with a button matrix such as the 8x8 matrix on the Launchpad, many times you’ll use the entire matrix as one big element (or possibly split it up into 2, 4 or 8 elements). For example, let’s say you wanted to create a page of 8 button faders. That could be considered 8 separate elements or even 1 big element depending on how you look at it. Either way, it’s not 64 separate elements.
You could use 64 translators to accomplish this, but this is not a good idea for a variety of reasons.
- If you make a mistake, which all of us do, it will be hard to find because it only exists in one of 64 places.
- If you want to make a change, such as changing the MIDI channel the faders send out on, you’ve got to make that change in 64 places. Of course, you can make a mistake while doing this, so now we’re looking at the possibility of compound mistakes.
- This approach doesn’t lend itself to experimentation because you’ll have to make lots of changes to try anything out.
- This approach doesn’t scale well. If you use this approach for all the problems you try to solve, you’ll end up with projects with lots and lots of translators that will be difficult to manage.
Track your global variables.
This may not be an issue in the future but, for now, we don’t get to choose names for our variables or create variables arbitrarily. We’re given a set of named global variables and this is all we have. For this reason, it’s important to track your usage of global variables. I track them in the following 3 ways, all of which are important.
- In the translator that sets the value of the variable, the variable’s name is included in parentheses at the end of the translator’s name.
- In an Always Active preset, I’ll have a translator named init that is triggered on project load. The rules in this translator will list every variable the project uses and assign a default value to each, even if the value is 0. As a side note, it’s sometimes sensible to use -1 as a default value so that you can see in the log if a variable has been assigned a value yet.
- In a document (I make mine in Word) with the same name as the project and in the same directory as the project, I’ll have a list of each used variable and a description of its purpose. MT has a handy feature that will ask you if you want to open this document upon opening the project.
In a lot of programming documentation and tutorials, you’ll find phrases such as “Global variables are evil”. One of the primary reasons for this is that global variables can be changed from anywhere and that’s not a great thing. In MT, it’s no different. If you’re changing the value of a global variable in multiple translators, it makes it very difficult to discern how/when/where/why a global variable was assigned to a particular value.
For this reason, it’s a good idea to get in the habit of only changing/setting the value of a global variable in 1 translator. Of course, there are cases where exceptions can and should be made, but it should be made very clear why the exception was made. Personally, if I need to set the value of a global variable from multiple translators, I’ll create a preset that only contains translators that affect that variable.
As an aside, this goes hand in hand with tracking your global variables. If you don’t track them, you could end up using the same global variable for different purposes, which could result in problems.
Favor local variables (like pp) over global variables (like ga).
The same local variable can be used by every translator as they lose their value as soon as the translator finishes. Unless you actually need persistent storage, which global variables provide, you should use local variables. Of course, there are a limited number of local variables and sometimes you have to resort to using global variables as local variables. For example, if you’re dealing with long SysEx messages with many variable bytes from a single translator, there may not be enough local variables to use for all of the variable bytes. In those cases, you should try to re-use those global variables whenever possible as described in the next tip.
Re-use global variables when possible.
Since the number of global variables is limited, it makes sense to re-use global variables whenever possible. For example, say you create a couple of presets that set up buttons to send out notes and the notes they send can be changed on-the-fly. Typically, to avoid hung notes, you’ll need to implement some sort of strategy. One of those strategies would be to track the number of buttons that are currently pressed and only allow notes to be changed when no buttons are pressed. You’d do that with a global variable, but you only need to store this info while the preset is actually in use. You could easily re-use that same variable in your other note sending preset and even other presets.
Avoid changing the value of a local variable that is used in both the Incoming and Outgoing message.
For example, say you have a translator that looks like this:
Code: Select all
Incoming: 90 00 vv Rules: if vv!=0 then vv=1 Outgoing: B0 00 vv
Code: Select all
Incoming: 90 00 vv Rules: oo=0 if vv!=0 then oo=1 Outgoing: B0 00 oo
Favor project/preset routing over translator-specific routing and use a similar routing scheme in all projects.
It’s sometimes handy to have translators that use their own specific routing, but this makes it more difficult to see what routing is going on in the project because (at least on the Windows version), you actually have to go in and edit the translator in order to see its routing. So use this feature sparingly and document your usage of it.
Also, it helps to use similar routing schemes in all projects so that you know where to look for things when it comes time to revisit an old project.
Personally, since almost all of my projects involve a controller and at least one virtual port, my project routing is set up so that the controller is the input and the primary virtual port is the output. If I need to send data back to the controller (to handle LEDs and such) or send data to a different virtual port, I’ll create a preset that does that and set up the routing at the preset level. I very rarely use routing on the translator level.