(!) Tips For Better Translating #4 – All Together Now

metastatik

2013-01-28 20:44:04

DISCLAIMER: Although I have used MT for many years, I have never read MT’s manual as there was no manual available when I started using it. So my approach and the tips that will follow mostly come from trial and error as well as some things I learned here on the forum (mostly from Florian’s posts). For that reason, I’d suggest using your own discretion in terms of which tips you take away from this post.

In Method to the Madness, I mentioned favoring rules over translators, gave an example relating to the Launchpad and promised to discuss that further in a future post. Well, here it is! Please note, however, that you do not need a Launchpad to follow along here. What we’ll be discussing is more about MIDI messages and, more specifically, how to elegantly deal with groups of them. In this case, we’ll be discussing a button matrix, but similar ideology can be applied to any sort of control group.

The Plan
In the example given in Method to the Madness, I mentioned setting up a page of 8 button faders, so that’s precisely what we’ll be doing here. Before implementing functionality in MT, it helps to have as clear a picture as possible of what you’re going for. Here, we’ve got a vague image so far, so let’s clarify it some more before going further.

This image shows the Launchpad’s default MIDI messages, which is our starting point.

This image shows the superimposed button fader implementation, which is our ending point.

First Attempt
As a first attempt, we might think to just use 64 separate translators. Method to the Madness discusses why this is a bad idea, but let’s take a look at it anyways.

We’d create a translator for each button. Let’s start with the first (leftmost) column. The translator for the uppermost button would look like this:

Code: Select all

Incoming: 90 00 7F
Outgoing: B0 00 7F
The next button down would look like this:

Code: Select all

Incoming: 90 10 7F
Outgoing: B0 00 6C
And we’d just continue along those lines until we had 64 translators. In summary, each translator would receive a specific note and send out a specific CC with a specific value.

Taking A Step Back
As discussed in Method to the Madness, we’d be much better off using 8 or, better yet, 1 translator to do this. To accomplish this, we need to find the logic in both our starting and ending points.

In the ending point, it’s easy to see that each column of buttons sends the same CC. Likewise, each row of buttons sends the same value. This is very simple logic so, really, we should be able to do this with just 1 translator providing that we can find a way to deal with the matrix in terms of coordinates. Instead of being concerned about which note a button sent, we’d like to know which column and row it’s on.

To accomplish this, we have to go back to the starting point and try to find the logic in terms of the way the notes are laid out. If you start with the upper leftmost button and work your way down, what is occurring with the note numbers? Does the same hold true when moving down other columns? Likewise, if you start with the upper leftmost button and work your way across, what is occurring with the note numbers? Does the same hold true when moving across other rows? Try to figure this out on your own before reading on.

You should’ve found the row numbering increases by 16 as you move down and the column numbering increases by 1 as you move across. This is the logic we needed to find.

Initial Skeleton
Before we get to working on the rules, let’s create a simple skeleton translator that will handle what we’re looking to do here. Unlike the translators used in our First Attempt, we need a translator that can receive any note in the matrix and send out any of the CCs and values needed by our button faders.

We know that all notes in the matrix use channel 1 and that all the button faders also use channel 1. So here is what our skeleton would look like.

Code: Select all

Incoming: 90 pp 7F
Outgoing: B0 oo vv
Unfortunately though, the Incoming message here won’t just receive notes from the matrix, it will also receive the notes from the 8 buttons on the right side of the Launchpad, which also send notes on channel 1. We’ll need to apply some sort of filtering in order to prevent those buttons from triggering this translator. We’ll look at how to do that in a bit, but it’s something to keep in mind and is something you’ll typically have to do when using variables in Incoming messages.

Deriving Coordinates
As mentioned in Taking A Step Back, we’d like to deal with coordinates. So, before we look at actually implementing our button faders, we need to figure out how to derive coordinates based on the notes the matrix sends. For example, if we receive note #0, we want to derive row 0/column 0. If we receive note #52, we want to derive row 3/column 4.

What sorts of rules can we use to accomplish this? I’ll give you a big hint, the general form of the rules we need are covered in Golden Rules. Try to figure this out on your own before reading on.

First, let’s look at deriving the row. As we found in Taking A Step Back, row numbering increases by 16. So what we want to do here is figure out how many 16s are in the note numbers we receive. What sort of mathematical equation can you use to figure that out? Division, right? As mentioned in Golden Rules, it’s a good idea to try out rules on paper, so give it a try and make sure it works. We’ll try a couple of examples here.

Code: Select all

0=0/16

Code: Select all

3=52/16
Good, but it doesn’t hurt to try more, so please feel free. Anyhow, our first rule will look like this:

Code: Select all

rr=pp/16
Next, we need to derive the column, which is a bit trickier. As we found in Taking A Step Back, column numbering increases by 1. Of course, dividing by 1 isn’t going to work. What we really want to do is figure out how far away from the beginning of a row are the note numbers we receive. To do that, we need to figure out the note number at the beginning of the row. We’ve already done part of the work in our first rule. If we multiply that result by 16, we get the note number at the beginning of the row. Let’s try a couple of examples here.

Code: Select all

0=0/16
0=0*16

Code: Select all

3=52/16
48=3*16
Good, so now we’ve got our first two rules.

Code: Select all

rr=pp/16
ss=rr*16
Now we simply need to subtract the ss value from the note number we received and this will tell us how far away from the beginning of the row it is. Let’s try a couple of examples here:

Code: Select all

0=0/16
0=0*16
0=0-0

Code: Select all

3=52/16
48=3*16
4=52-48
And now we’ve got all the rules we need to derive row number (rr) and column number (oo). By the way, this should look familiar as it’s The Modulo Rule covered in Golden Rules.

Code: Select all

rr=pp/16
ss=rr*16
oo=pp-ss
Filtering
As mentioned in Initial Skeleton, we’ll need to apply some filtering to prevent the 8 buttons on the right side of the Launchpad from triggering our translator. Typically, you want to do your filtering in the first rule(s). However, in this case, it would be impractical as we’d need a bunch of rules to do that. Now that we’ve derived coordinates, we can simply filter out that entire column with just one rule.

Code: Select all

if oo==8 then exit rules, skip Outgoing Action
Implementing The Faders
Up until this point, everything we’ve discussed is the general way you’d deal with the Launchpad’s matrix regardless of what functionality you were implementing. Now, we’ll get into discussing implementing the functionality we’re after, which is our 8 button faders.

Part of the work is already done. The column value (oo) is equal to the CC# our button faders send, so we’ll simply pass that to the Outgoing message. The CC value is a bit trickier.

First of all, our row value (rr) increases as you move down while our button faders are supposed to increase as you move up. How do we fix this? With another one of the Golden Rules, The Inversion Rule.

Code: Select all

vv=7-rr
So that fixes the orientation, but the values are wrong. Our row value is in the range of 7 - 0 while our button faders are supposed to be in the range of 127 – 0. We can fix this with multiplication, but unfortunately the values don’t equally scale. If we multiply vv by 18 that will get us close, but the highest value will be 126 instead of 127. So we’ll need to employ a minor hack to fix that.

Code: Select all

vv=vv*18
if vv==126 then vv=127
Putting It All Together
Our finalized translator will look like this.

Code: Select all

Incoming: 90 pp 7F
Rules:
rr=pp/16
ss=rr*16
oo=pp-ss
if oo==8 then exit rules, skip Outgoing Action
vv=7-rr
vv=vv*18
if vv==126 then vv=127
Outgoing: B0 oo vv
Although it’s a bit more difficult to understand conceptually as compared to using 64 translators, it’s far easier to deal with in the long run. Also, most of the rules here are re-useable in that they can be used as the basis of implementing other functionality such as note modes and functionality that requires splitting the matrix up into quadrants.

Of course, the logic of the Launchpad’s layout that we used to derive coordinates is specific to it, but other controllers (such as the APC40) are logically laid out as well and can be expressed mathematically just as we did here. The take home point here is to take a look at what you’re starting with and what you want to end up with, try to figure out the logic at both ends and use rules to express it.

psamek

2013-03-27 03:54:43

Many, many thanks for this tutorial in structured BMT programming.

rifter

2016-02-06 19:15:08

Hi metastatik your tutorial is awesome.
Could you please update the two reference images for the Launchpad’s default MIDI messages and superimposed ones to correclty follow your explanation?
Thank you.

metastatik

2016-03-27 20:49:49

Sorry about that. It looks like imageshack (the host I was using) made some changes and some things were lost in the mix. I'll redo the images and post them on another host ASAP.

metastatik

2016-03-28 13:06:49

Fixed.

rifter

2016-03-29 14:52:41

Thank you very much!