Is there some kind of reference for rules?

NiDBiLD

2016-02-17 01:24:20

I've looked around in the manual, but it seems to not include a reference for the rules language.

I'm basically looking for a document describing the syntax, structure and keywords that may be used within BMT. I find a lot of helpful examples here in different forum posts, but no reference sheet with everything in the same spot.

Could someone please point me in the right direction?

DvlsAdvct

2016-02-22 22:36:50

I can't remember off the top of my head, but the Rules wizard, in the rules panel should give you all of the available options for the rules.

Local variables are pp qq rr ss tt uu vv ww xx

Global variables are
g0-g9, ga-gz, and apply to g, h, i, j, k, l, m, n, y, z

I think that should be everything. If you need more clarification, or specific questions, let me know. :)
Jared

NiDBiLD

2016-02-22 23:25:40

Thanks! I think I've managed to get a grip on most of the options by now. I've fiddled around and managed to work most of these things out.

I do have a few questions, though:

First: Is there a reasonably straightforward way to trigger multiple events from a single incoming message? This one has me thinking in circles so far.

Another question: Is there a way to assign a variable to more than one byte at a time? Right now I'm sending text by sysex, and I'm using up quite a few global variables for this. One for each letter I'm sending at a given time, so at maximum it's 14 at this moment. There are not enough local variables to cover my needs. (Also, when I try to send more than two 16 byte sysex messages at a time, behavior of the knob I'm turning becomes erratic. It jumps all over the place. Is this some sign I should be careful with the amounts of data I send, or am I doing something wrong?)

It's all happening inside of a preset, and I'm considering reusability while building. But still. It feels like I'm missing something, and there might be a better way.

And the last one: I've built functionality for switching between scales, octaves and keys from knobs. I've got 16 playable pads, and they all behave correctly. But I'm up to two translators with 799 rows of rules each for this functionality. One translator for Note On, the other for Note Off. I'm now thinking of boiling it down a bit.

Right now I change scales as in this example:

Code: Select all

Label "Hungarian Minor"
rr=pp
if pp==60 then rr=60
if pp==61 then rr=62
if pp==62 then rr=63
if pp==63 then rr=66
if pp==64 then rr=67
if pp==65 then rr=68
if pp==66 then rr=71
if pp==67 then rr=72
if pp==68 then rr=74
if pp==69 then rr=75
if pp==70 then rr=78
if pp==71 then rr=79
if pp==72 then rr=80
if pp==73 then rr=83
if pp==74 then rr=84
if pp==75 then rr=86
pp=rr
Goto "Key"
First, I reassign every note according to scale pattern. (16 pads on a Maschine) Then it's quite simple: Octave is pp +/- some multitude of 12. And key is just +0-11 depending on which note you want.

Is there a better way? could I somehow handle every instance of the note C, for example, in one move, and make assignments like (faux code incoming) if pp==[C#] then rr=[D], where I have a single identifier for every instance of a note across the keyboard?

I really do appreciate how friendly you guys are, and how incredibly good your support is. Just wanna say that! Thanks a lot for your tips on sniffing for sysex earlier, in the other thread as well. It helped me get over a big threshold.

DvlsAdvct

2016-02-23 01:17:19

Alright, so let's break this down
First: Is there a reasonably straightforward way to trigger multiple events from a single incoming message? This one has me thinking in circles so far.
In the outgoing message, if you select MIDI Message | Raw MIDI / System Exclusive you can type the messages you want to send in hex. You can type as much as you want and they will all trigger as one. Just type them completely. So if you wanted an incoming message to trigger multiple outgoing messages, your outgoing message would simply say

Code: Select all

90 30 7F 90 31 7F 90 32 7F 
And they will all trigger when the incoming message and rules are processed.
Is there a way to assign a variable to more than one byte at a time?
No. But how many screens are you driving? And how many different commands do you need to drive? How are the sysex commands structured? Maybe we can trim the kinds of messages and how they are structured to free up variables.
I've built functionality for switching between scales, octaves and keys from knobs.
This gets a little more complicated, but is doable also. What I would do, personally, is have a translator record the knob position as a global variable, and then have a different translator for each scale. So, you'd have one global variable reference the key, and a translator for each scale type, with labels for the octave. You could also break this down in different ways based on your needs. But I'd find it more organized this way, personally. Also, for octave you can do a few other clever pieces. So here's an example.

Code: Select all

Translator 1: Scale Type Set
Incoming Message: //whatever your CC message is, position variable set to pp
Rules: if pp<10 then g0=0
if pp<20 then g0=1
[i]//and however you need to set up the range for your rules to get all of your keys. The important part is that there is one global variable set to dictate what key you're in. If you have a specific number of keys we can also run some math to simplify this[/i]
Outgoing: None

Translator 2: Octave Set
Incoming Message: //whatever your CC message is, position variable set to pp
Rules: rr=pp*100
oo=rr/1280
g1=oo
[i]//I'm assuming you're using just 7 octaves. 0 being the lowest octave, 6 being the highest[/i]
Outgoing: None

Translator 3: Hungarian Minor Key On
Incoming Message: //whatever your note commands are, with pp being note and qq being velocity
Rules: if g0!=//whatever variable you have set to Hungarian Minor then exit rules, skip outgoing action
if pp==60 then rr=60
if pp==61 then rr=62
if pp==62 then rr=63
if pp==63 then rr=66
if pp==64 then rr=67
if pp==65 then rr=68
if pp==66 then rr=71
if pp==67 then rr=72
if pp==68 then rr=74
if pp==69 then rr=75
if pp==70 then rr=78
if pp==71 then rr=79
if pp==72 then rr=80
if pp==73 then rr=83
if pp==74 then rr=84
if pp==75 then rr=86
if g1==0 then ss=rr-60
if g1==1 then ss=rr-48
if g1==2 then ss=rr-36
if g1==3 then ss=rr-24
if g1==4 then ss=rr-12
if g1==5 then ss=rr
if g1==6 then ss=rr+12
if g1==7 then ss=rr+24
if g1==8 then ss=rr+36
if g1==9 then ss=rr+48
//and realistically, there's more math you could do to simplify this as well
Outgoing Message: Channel 0 - Channel 1
Note: ss
Velocity: qq
And I think that should handle it. THen have one translator for each scale type, and it should simplify your process and make it look cleaner.

Hope that helps
J

NiDBiLD

2016-02-23 03:09:34

DvlsAdvct wrote: In the outgoing message, if you select MIDI Message | Raw MIDI / System Exclusive you can type the messages you want to send in hex. You can type as much as you want and they will all trigger as one. Just type them completely. So if you wanted an incoming message to trigger multiple outgoing messages, your outgoing message would simply say

Code: Select all

90 30 7F 90 31 7F 90 32 7F 
And they will all trigger when the incoming message and rules are processed.
Aaaaah, of course! Thanks!
No. But how many screens are you driving? And how many different commands do you need to drive? How are the sysex commands structured? Maybe we can trim the kinds of messages and how they are structured to free up variables.
If this is not possible, then I think I'll just have to conserve variables. I only need them for this purpose when I send the messages text anyway, which happens in quite isolated cases. I think I can manage through some controlled recycling of variables.

Anyway, the screens have the following structure:

Two rows.

Row 1 is a single section of 55 chars.
Row 2 is split into eight sections with 7 chars each, except for the last one, that has 6.

The format of the sysex message for row 1 is [7 byte header][up to 55 bytes of letters][F7]
or row 2 is [7 byte header][1 byte lower screen section destination][7 bytes of letters][F7]

Right now, I'm for example printing the name of the current scale. Whatever scale I pick, I just assign new letter codes to the 14 global variables I use. If I wanted to use more screens, I'd need up to 55 of them. A theoretical maximum is 110 variables/characters, if I am for some bizarre reason required to fill the entire display with arbitrary letters simultaneously, and I can't just hard-code any of them.
This gets a little more complicated, but is doable also. What I would do, personally, is have a translator record the knob position as a global variable, and then have a different translator for each scale. So, you'd have one global variable reference the key, and a translator for each scale type, with labels for the octave. You could also break this down in different ways based on your needs. But I'd find it more organized this way, personally. Also, for octave you can do a few other clever pieces. So here's an example.
Wouldn't this approach require me to write the code for changing the key and octave separately in every scale translator? If so, would this be preferrable, architecture-wise? This instinctively feels a bit redundant to me, and there'll be a lot of different places to change the code if I need to alter something.

As it stands now, I just pass the variable through three different stages using tags. I have three global variables setting the value for scale, octave and key respectively. In the Note In translator, I first check for scale, then send it to octave, and last, key. So even though the translator is longer, I only have to write the code for octave and key once.

Is this, in your opinion a better or worse approach than what you're proposing? I don't really know which way to go about it. I'm kind of new at BMT, so feel free to educate me.

If there is a way to pass messages through multiple translators, then I imagine this would be optimal. This would allow me to both partition the massive pile of rules that handle scales, so I can have one for each, and I could at the same time keep the code for octave and key DRY.

DvlsAdvct

2016-02-23 15:21:21

For the sysex messages, 55 characters makes this a lot harder since you need to conserve the variables to make sure they always trigger. But it's still 110 global variables, and you have access to 360ish (36 per letter g, h, i, j, k, l, m, n, y, z) so you may still be okay with 250 to play with.

Let me do some thinking on the last piece. I actually think there may be a better way to do it, but I'm not 100% sure yet.

You wouldn't need to write the code for changing the key and octave separately, though. You would have one translator to set the Scale value, one to set the Octave, and then one to set the key. Actually, realistically, you could tie each of those values to a global variable, and then have a single translator to process all of the notes. Possibly? I'm trying to think this through.

The order should probably be Scale - Key - Octave - Note, right? So you set the scale, and that will dictate the kinds of notes. The Key will dictate what notes are being used, Octave is where those notes sit, and the notes fire. Let me do some more thinking and I'll try and draft up some ideas tonight. :)

The code for octave will always be the same, since it will always increase or decrease the notes by some multiplier of 12. And you can always use the same global variable, so the math never needs to be re-run. In fact, you could effectively have the same note translator for every scale and key. The only thing that matters is how the notes change in the rules, but beyond that if the first global variable for the key doesn't line up the translators won't trigger at all. I like having more translators with fewer rules, because going through them is easier.

In fact, you could break down the scales into presets, which might be more efficient for troubleshooting with the with the log window. Then you only really need to worry about key/octave/note as translators within the presets. At this point it's really all preference.

Let me do some more thinking at work and get back to this tonight. Feel free to put more ideas in here.

NiDBiLD

2016-02-23 15:58:51

For the sysex messages, 55 characters makes this a lot harder since you need to conserve the variables to make sure they always trigger. But it's still 110 global variables, and you have access to 360ish (36 per letter g, h, i, j, k, l, m, n, y, z) so you may still be okay with 250 to play with.
Who needs more than 250 global variables anyway? Also, I plan on encasing these things in togglable presets, so it might not even be a problem.

What is a problem, though, is that I can't seem to send more than two 16 byte messages at the same time without the knob starting to flip out. If I attempt to write to three of four screen sections simultaneously, the knob sending the scale name sysex behaves erratically, and the text starts blinking in and out.

My interpretation is that I'm sending too much data at the same time. Maybe if I somehow delay half of the sysex messages a few milliseconds?
Actually, realistically, you could tie each of those values to a global variable, and then have a single translator to process all of the notes. Possibly? I'm trying to think this through.

The order should probably be Scale - Key - Octave - Note, right? So you set the scale, and that will dictate the kinds of notes. The Key will dictate what notes are being used, Octave is where those notes sit, and the notes fire.
This is exactly what I'm doing at the moment. This is why I have 799 rows of rules for note on, and 799 for note off, in a single translator. I set the note to pp and send it through scale -> key -> octave using labels. First it checks the value of the scale variable, and goes to the corresponding label. Then, when the note values are recalculated according to the scale, it goes to octave, and checks the variable for that parameter. Then the same thing goes for key. Then it sends out the resulting note as an outgoing message.

If this is the preferred method I'll just roll with it. I'm just thinking there might be some way to split this up into smaller "functions" or translators, and somehow pass stuff between them.

Breaking scales into presets is an interesting idea. Can I have nested presets? Because right now all of this rests within a "pad mode" preset that can be toggled on and off with the press of a button. I want to use the same pads for non-note things as well when in other "modes", so I encapsuled all of this stuff.

NiDBiLD

2016-02-23 17:33:21

I just had another thought.

I am just now creating a script for creating chords from a root note. I want this to play nicely with the other modifiers for a note.

As I am thinking about it, it'd be really simple:

IF chords are enabled, a knob controls which chord is played. So it's really just doing this after the chord, octave and key are set:

qq = pp + [some value, depending on the chord]
ss = pp + [some value, depending on the chord]

and then I send pp, qq and ss in the outgoing message:

Code: Select all

Outgoing Message:
9f pp oo 9f qq oo 9f ss oo 
(oo is velocity)

And then, of course I'll do the same thing for note off messages.

However, what do I do when chords are turned off? Is it reasonable to send the two additional notes anyway, with a velocity of zero? Or should I make an additional translator with the same 799 lines I already got, plus the code for chords, and toggle between them with a global variable?

One method sends unnecessary messages at times. One method forces me to use the same code in two different spots. Which would you prefer? Or is there a third way? Maybe use a timer with zero delay to trigger the multiple notes? Maybe such a method would be preferrable, and easier to build an arpeggiator from later?

Just considering the options here.

DvlsAdvct

2016-02-24 02:23:44

What is a problem, though, is that I can't seem to send more than two 16 byte messages at the same time without the knob starting to flip out. If I attempt to write to three of four screen sections simultaneously, the knob sending the scale name sysex behaves erratically, and the text starts blinking in and out.
I don't think this is from too much data. My guess is there's something wrong with the logic of your rules or translators, or something. MT Pro can handle some extremely robust messages. It should be fixable, though.
This is exactly what I'm doing at the moment.
No, that's not what I mean. If you have all of the variables dictated in separate translators, you would have individual translators to separate them out. So you'd have more translators, but fewer rules. So, for example, if you divide everything up into presets, you'd have all of the logic dictated in an "always on" preset. In that preset you'd have your translators that select the correct scale (activate other presets), select the correct key, octave, etc. And then you'd have different presets which would house all of the messages. You could "nest" them using activate and deactivate messages, but that's super complicated, and might make things worse.

If you are going to be switching between modes, though, presets are a really clean way to go.

If you want chords to work along with the key/scale thing we are talking about, I'd make it an extra preset, where only the chords are triggered based on the value of the notes you're pressing. In fact, if you turn Chords on, I'd have the pad you press, or whatever the outgoing message ends up being after all the translation be stored as a global variable, and have the chord translators just reference that. So you'd only need two translators, one for on and off, and only rules to process what the extra two notes are. Then, when you don't need chords, you deactivate that individual preset and they won't trigger anymore.

Does that make sense?

NiDBiLD

2016-02-24 02:51:44

I don't think this is from too much data. My guess is there's something wrong with the logic of your rules or translators, or something. MT Pro can handle some extremely robust messages. It should be fixable, though.
I think I might be able to fix it. I found out it's possible to send longer messages in one piece. I thought there were eight predetermined columns on-screen, because the data I sniffed to figure this out had that layout.

However, after some experimenting, I now have found out that the destination byte can have any value between 0 and 109, and that the messages can be any length. So I can target any of the 110 spaces of the screen as a starting point for the message - and then send a message of any length.

If characters spill over at the end of a row, the message is truncated at that point. This enables me to send all the text I want in a single message. I imagine this will solve the problem with the erratic knobs, but I have not tried it out yet.
No, that's not what I mean. If you have all of the variables dictated in separate translators, you would have individual translators to separate them out. So you'd have more translators, but fewer rules. So, for example, if you divide everything up into presets, you'd have all of the logic dictated in an "always on" preset. In that preset you'd have your translators that select the correct scale (activate other presets), select the correct key, octave, etc. And then you'd have different presets which would house all of the messages. You could "nest" them using activate and deactivate messages, but that's super complicated, and might make things worse.

If you are going to be switching between modes, though, presets are a really clean way to go.
Damn, I really have to sit down and plan the architecture of this thing. I'll get back to you about this.
If you want chords to work along with the key/scale thing we are talking about, I'd make it an extra preset, where only the chords are triggered based on the value of the notes you're pressing. In fact, if you turn Chords on, I'd have the pad you press, or whatever the outgoing message ends up being after all the translation be stored as a global variable, and have the chord translators just reference that. So you'd only need two translators, one for on and off, and only rules to process what the extra two notes are. Then, when you don't need chords, you deactivate that individual preset and they won't trigger anymore.
Would I, in this case, have the chord translator trigger on note on / note off as well? I mean, if I set the global variable in translator A, which triggers on note on, could I use the same variable in translator B, which triggers on the same incoming message?

How do I know the variable is set to a new value at this point? Is there not a risk they would fall out of sync, so I get chord notes based on the previous assignment for the variable instead of the one for the current note on message?

DvlsAdvct

2016-02-24 19:07:41

For chords, this can get really complex, depending on how you play.

You need to decide how many chords you want to trigger at a time, and how you are going to play them. if you are only ever going to play one pad at a time to trigger chords, then you will only need one translator. Every time you press Pad A, the global variable will reset to whatever that pad is. And then you assign a global variable to lock it, so only one note can process at a time. (something like, on press h0=1, and when h0=1 no other pad will send chords).
How do I know the variable is set to a new value at this point? Is there not a risk they would fall out of sync, so I get chord notes based on the previous assignment for the variable instead of the one for the current note on message?
As long as your translators are set up correctly, this won't ever be an issue. Define the variable on pad press and then trigger the chords, and the chords won't ever trigger unless a pad is pressed, which is when their value is defined.
Would I, in this case, have the chord translator trigger on note on / note off as well? I mean, if I set the global variable in translator A, which triggers on note on, could I use the same variable in translator B, which triggers on the same incoming message?
You would have two translators, one for on and one for off, but the off translators would piggyback on the on translators. You need two translators, and timers, to respond to on and off messages separately, but realistically, the off message is listening for the same rules, and is just using the current variable values. So if Translator A sets all of the global variables for the chords for Note On, Translator B only cares what those variables are currently set to, so you don't really need to duplicate the math.