Pro Tools Rec Light

Hello!
I'm trying to make Pro Tools Rec Light. And I actually made it . But I have a strong desire that Pro Tools sends messages to Arduino through HUI protocol.

Ok.
I have Arduino Uno. Midi shield. M-audio card with MIDI Out. First I thought that there should be Sysex data mess
but (how lucky I am) it sends Control Change messages.
So PT sends messages, Arduino gets them, the Lights are ON/Off.

That's the code:

#include <MIDI.h>

MIDI_CREATE_DEFAULT_INSTANCE();

       void setup() 
{
 pinMode(13,OUTPUT);
  MIDI.begin(); 
  MIDI.setHandleControlChange(MyCC);
 
}
       void loop() {
  
       
MIDI.read();
 
 }

void MyCC(byte channel, byte controller, byte value ) {

    
  if(channel==1)

 if(controller==44)

 if(value==69) 

 digitalWrite(13,HIGH);

 if(channel==1)

 if(controller==44)

 if(value==5)  
 
  digitalWrite(13,LOW);
 

 }

Everything is perfect! Except one small thing: when I press alt/opt button ....Rec lights are also ON!
With the help of Midi Monitor I've learned that this cunning HUI sends at least two messages for all the buttons.

So : to turn the REC On PT sends

  1. channel 1, controller 12, value 14
  2. channel 1, controller 44, value 69

to turn the REC Off

  1. channel 1, controller 12, value 14
  2. channel 1, controller 44, value 5

I've got theory: first message is some kind of a name of a button and the second one is the command itself.

And ALT/OPT button (by the way I hate it for now))) sends:

  1. channel 1, controller 12, value 8
  2. channel 1, controller 44, value 69

And here is the point: I'm a beginner with Arduino and I can't figure out how I can make the board react on two messages and interpret them as one.

Please help.
Thank you! And sorry for my English it's not a native language for me.

I've got theory: first message is some kind of a name of a button and the second one is the command itself.

Officially
CC 12 is Effect Control 1
CC 44 is LSB for Control 12 (Effect control 1)

So one way to do this would have each CC message set the appropriate part of the number then combine them like this.

effectsController = (ccMessage1Value << 7) | ( ccMessage44Value & 0x7F);

Thank you!
I'll try to fight this through))

I vaguely understand but I work on it. One question before I take a deep dive into it:
effectsController = (ccMessage1Value << 7) | ( ccMessage44Value & 0x7F); - all the the values are just examples? I'm a bit confused with 0x7F (since PT doesn't send value 127, at least connected with Rec button). Sorry to bother.

I'm a bit confused with 0x7F

This value is a bit mask, it ensures that the value you are adding to the number is restricted to the range 0 to 127. It should already be in this range but just to make sure it does no harm to force it not to overflow.

all the the values are just examples?

Not sure what you mean by values? Do you mean variables? If so yes the variables have names that illustrate what sort of value they hold. It is a good idea to write your code like this so you know what sort of values these variables will contain.

I'm sorry I'm too slow at programming languages. ))
I went to the reference and read about <<, | and &. It helped a bit but not too much.

oook. I understand that I 've got a lot of questions but:
Am I right considering this: effectsController = (ccMessage1Value << 7) | ( ccMessage44Value & 0x7F); - as a math expression? And if yes should I get a resulting numeric value? And again if yes, what is the numeric value of this expression?

If we consider that:
ccMessage1Value =14
ccMessage44Value=69

Will it be correct to write it down like this:

effectsController = (14 << 7) | ( 69 & 0x7F); ?

Thank you!

Am I right considering this:
Code: [Select]

effectsController = (ccMessage1Value << 7) | ( ccMessage44Value & 0x7F);

  • as a math expression?

Not quite it is a program statement. If it were maths the = would mean "is equal to" but as a program statement the = means "make it equal to"

If we consider that:
ccMessage1Value =14
ccMessage44Value=69

Will it be correct to write it down like this:......

Yes.

So what will the value of the variable effectsController be?

Basically you are making one number from two part numbers. The one number has 14 bits and the two part numbers have 7 bits each.

Thank you! Now I got it! It's beautiful.

And of course the coding. It took me pretty long but I'm not sure if I used the idea correctly:

#include <MIDI.h>

byte ExpressionContr1;
byte ExpressionContr2;
byte ExpressionContr3;

MIDI_CREATE_DEFAULT_INSTANCE();

     void setup() 
{
pinMode(13,OUTPUT);
MIDI.begin(); 
MIDI.setHandleControlChange(MyCC);

}
     void loop() {
 
MIDI.read();
}

void MyCC( byte channel, byte controller, byte value ) {

if (ExpressionContr1=(channel==1<<7)|(channel==1&15 ))
if (ExpressionContr2=(controller==0xC <<7) | (controller==0x2C&0x7F ))
if (ExpressionContr3=(value ==0xE <<7) | (value ==0x45&0x7F ))

digitalWrite(13,HIGH);

if (ExpressionContr1=(channel==1<<7)|(channel==1&15 ))
if (ExpressionContr2=(controller==0xC <<7) | (controller==0x2C&0x7F ))
if (ExpressionContr3=(value ==0xE <<7) | (value ==0x5&0x7F ))
digitalWrite(13,LOW);

}

Since it still works as before (i.e. alt/opt also turns the lights on) something is wrong. May be I shouldn't declare "ExpressionContrs" as bytes?
Thank you!

1 Like

May be I shouldn't declare "ExpressionContrs" as bytes?

That's right.

As the variables ExpressionContr are trying to hold a 14 bit number then bytes will not be big enough. While the value variables can be bytes ( a byte is 8 bits ) when you combine the two you need a type of variable with more bits. Use a int type variable, this will hold a maximum of 16 bits. The fact you only need 14 of them is not important because an int is the smallest variable type that will fit your number.

I changed "bytes" to "ints" but "alt/opt" still lights the Led. I suppose that there is something wrong with my "if" statements. Somehow the board can't differ the messages.

#include <MIDI.h>

int ExpressionContr1;
int ExpressionContr2;
int ExpressionContr3;

MIDI_CREATE_DEFAULT_INSTANCE();

    void setup() 
{
pinMode(13,OUTPUT);
MIDI.begin(); 
MIDI.setHandleControlChange(MyCC);

}
    void loop() {

MIDI.read();
}

void MyCC( byte channel, byte controller, byte value ) {

if (ExpressionContr1=(channel==1<<7)|(channel==1 & 15 ))
if (ExpressionContr2=(controller==0xC <<7) | (controller==0x2C & 0x7F ))
if (ExpressionContr3=(value ==0xE <<7) | (value ==0x45 & 0x7F ))

digitalWrite(13,HIGH);

if (ExpressionContr1=(channel==1<<7)|(channel==1 & 15 ))
if (ExpressionContr2=(controller==0xC <<7) | (controller==0x2C & 0x7F ))
if (ExpressionContr3=(value ==0xE <<7) | (value ==0x5 & 0x7F ))
digitalWrite(13,LOW);

}

Yes they are all wrong. First off you need a double equal sign in them to compare anything. But the big mistake is that you first fill your Expression control variable with a value you device from the MIDI messages and then you test it with an if statement to see if it is the number you are looking for.
When you find that it is that number then you do something about it like controlling your LED. The if statement when true will execute the statement following or the block following defined in curly braces.

You need to post all the code you have not just a part as I suspect more of it is totally wrong like this.

Grumpy_Mike:
You need to post all the code you have not just a part as I suspect more of it is totally wrong like this.

That is all code I've got. I just want to make this rec light to shine and nothing more. :slight_smile:

Grumpy_Mike:
First off you need a double equal sign in them to compare anything. But the big mistake is that you first fill your Expression control variable with a value you device from the MIDI messages and then you test it with an if statement to see if it is the number you are looking for.
When you find that it is that number then you do something about it like controlling your LED. The if statement when true will execute the statement following or the block following defined in curly braces.

I changed the code a bit and again I'm not sure I did it correctly:

#include <MIDI.h>

int ExpressionContr1 = 1;
int ExpressionContr2 = (0xC, 0x2C) ;
int ExpressionContr3 = (0xE ,0x45) ;
int ExpressionContr4 = (0xE,0x5);
MIDI_CREATE_DEFAULT_INSTANCE();

     void setup() 
{
pinMode(13,OUTPUT);
MIDI.begin(); 
MIDI.setHandleControlChange(MyCC);

}
     void loop() {
 
MIDI.read();
}

void MyCC( byte channel, byte controller, byte value ) {
 

if (ExpressionContr1==(channel==1<<7)|(channel==1 & 15 ))
if (ExpressionContr2==(controller==0xC <<7) | (controller==0x2C & 0x7F ))
if (ExpressionContr3==(value ==0xE <<7) | (value ==0x45 & 0x7F ))

digitalWrite(13,HIGH);

if (ExpressionContr1==(channel==1<<7)|(channel==1 & 15 ))
if (ExpressionContr2==(controller==0xC <<7) | (controller==0x2C & 0x7F ))
if (ExpressionContr4==(value ==0xE <<7) | (value ==0x5 ))
digitalWrite(13,LOW);

}

But something is still wrong.
Tried different ways to write the variables:

int ExpressionContr2 = 0xC| 0x2C ;
int ExpressionContr2 = (0xC)| (0x2C) ;

Alt/opt still disturbs.

I experimented with the code: when I change the placements of notes ("reversed sequence") alt/opt is out of the game, but now the "play" button turns the light on(for a short time). Argh!

OK that code it totally screwed in many many ways.
This is something on the right track. I have not tested it but it does compile. See if you can understand what it is doing. The "magic numbers" might not be right.

#include <MIDI.h>
// I assume these are the right magic numbers
int ExpressionContr1 = 1;
int ExpressionContr2 = (0xC << 7) | 0x2C ;
int ExpressionContr3 = (0xE<< 7) | 0x45 ;
int ExpressionContr4 = (0xE<<7) | 0x5;
int controlRecieved;
byte ccMessage12Value;
byte ccMessage44Value;
boolean ledState;

MIDI_CREATE_DEFAULT_INSTANCE();

void setup(){
pinMode(13,OUTPUT);
MIDI.begin();
MIDI.setHandleControlChange(MyCC);
}

void loop() {
MIDI.read();
}

void MyCC( byte channel, byte controller, byte value ) {
 // build up your full message
  if(controller == 44){
  ccMessage44Value = value;
  ccMessage12Value = 0; // blank MSB of message to stop rapid on / off of LEDs
 }

 if(controller == 12){
  ccMessage12Value = value;

// now put them together into one variable
controlRecieved = (ccMessage12Value << 7) | ( ccMessage44Value & 0x7F);
// now see if you have anything of intrest
// here you seem to test the same thing to turn it on or off so you need a variable to hold the state you last put the LED
if( (ledState == false) && (controlRecieved == ExpressionContr1 || controlRecieved == ExpressionContr2 ||controlRecieved == ExpressionContr3) ){
      digitalWrite(13,HIGH);
      ledState = true;
    } else {
if( (ledState == true) && (controlRecieved == ExpressionContr1 || controlRecieved == ExpressionContr2 ||controlRecieved == ExpressionContr4) ){
      digitalWrite(13,LOW);
      ledState = false;
     }
    }
  }
}

Please come back with questions about it.

If I could I would hug you!
Thank you million times for your patience and knowledge.
For these three days I've learned much more than for the last 6 months.
It works! :slight_smile:

Looking at the code it seems easy and everything is clear now. But I understand that it would take me a year or two (or may be never) to write it!

Thank you!

If I'm right this code will work with any DAW. Will check it tomorrow with Cubase and will post here. ))

I have just edited the code in reply #12. I just realised that when receiving the LSB in CC 44 it would use the last version of what was in the MSB from CC 12. This could result in a rapid on / off of the LED due to a false message being generated. Therefore I wiped out the old number in ccMessage12Value when ever CC 44 arrived.

There may well be other wrinkles like that, as I said I have no hardware to try this on.

If I'm right this code will work with any DAW.

Yes if it sends the same numbers.

Grumpy_Mike:
I have just edited the code in reply #12.

There is a problem with new edition since the "ARM TRACK" button sends 12 CC message with value 0. So when the tack is armed everything is messed up )).

Sorry I am not understanding you. What do you mean by 12 CC messages?
Is this
A CC message for controller 12? Or
Twelve messages of the CC type?

I think it is time to specify each group of messages, what you get and what you want to do when you get them.

I know you did this in the first post but it looks like things have changed.

Grumpy_Mike:
A CC message for controller 12?

Yes it's a CC message for controller 12 with value 0.
Sorry! Sometimes my English and the knowledge of programming makes me unclear))

Grumpy_Mike:
I think it is time to specify each group of messages, what you get and what you want to do when you get them.

Thing are the same!! Since ProTools uses HUI protocol to communicate with control surfaces it will take long enough to spy down all its messages. As I was interested in Rec button I "spied" on HUI with MIDI Monitor. I've just found the REC "pattern". As for other messages its unpredictable how many of them in HUI. Though it could be interesting to do that.

Still not sure about the problem but try changing

ccMessage12Value = 0;

To

ccMessage12Value = -1;