usbMidi: How to get information from the DAW?

Status
Not open for further replies.

postman

Member
Hi,

I am trying to create a midi controller for Logic or Mainstage. In order to start simple, I have created a project with one encoder that controls one parameter (for instance the volume). This is working fine.

But now I want to receive the current setting from Logic or Mainstage. For instance, when the channel volume is changed by another way (for instance by using the mouse), I want to receive the new setting with teensy. This way I can update the setting for the encoder, and prevent any jumping.

However, I seem not the receive any messages from Logic or Mainstage at all.

Below the code that I am currently using to check if I am receiving any midi information at all. But none so far. Still, this should be possible. I saw examples of motorized faders responding to changes in the DAW.

Any help is very much apreciated!

Code:
void MidiMessages(){
   if(usbMIDI.read()){ //true if new midi message
    Serial.println(usbMIDI.getType());
   }
   
}

It should print the message type if any message is received. But I am receiving none at all.
To be complete, below the whole code:

Code:
#include <Encoder.h>

void setMidiPos(int valChange,int scale);//calculate valid mide value for the encoder
int setencSpeedFct(int interv);//calculate speed factor based on encoder rotation speed
void myControlChange(byte channel, byte control, byte value);//event handler midi control change

Encoder myEnc(6, 5);
unsigned long previousMillis = 0;//needed to calculate speed of turning the encoder
unsigned long currentMillis = 0;//needed to calculate speed of turning the encoder
long oldPosition  = 0;//needed to calculate the position change of the encoder
long newPosition = 0;//needed to calculate the position change of the encoder
int encPosChange=0;//needed to keep track of the position change
bool encMoving=false;//flag indicates that the encoder is still being turned
int midiPos=0;//current midi value for the encoder
int encSpeedFct=1;//speed factor for multiplying the value change
const long interval = 200; // interval after which encodermovement is assumed to have stopped
const int midiCC=7; //7 is common for volume

void setup() {
  // put your setup code here, to run once:
  usbMIDI.setHandleControlChange(myControlChange);
}

void loop() {
  // put your main code here, to run repeatedly:
  MidiMessages();//read any incoming midimessages
  EncoderMovement();//respond to encoder
}

//check for incoming midi messages
void MidiMessages(){
   if(usbMIDI.read()){ //true if new midi message
    Serial.println(usbMIDI.getType());//check if anything is received
   }
}

void EncoderMovement(){
  currentMillis = millis();//keep track of time
  newPosition = myEnc.read();//check encoder movement
  if (newPosition != oldPosition) {//encoder moved
    encMoving=true;
    encPosChange=encPosChange+newPosition-oldPosition;//keep track of posisiton changes 
    //filter out multiple pos changes that happen with each click
    //otherwise you do not get a proper speed calculation   
    if(abs(encPosChange)>2) 
    {
      setencSpeedFct(currentMillis-previousMillis);//calculate speed of turning rotary
      setMidiPos(encSpeedFct*encPosChange/3,128);//calculate new midi value
      usbMIDI.sendControlChange(midiCC, midiPos, 1);//sent value
      previousMillis = currentMillis;//reset timer
      encPosChange=0;//reset position changes
    }
    oldPosition= newPosition;
  }
  else{
    if (currentMillis - previousMillis >= interval) {
       //to much time without movement: stopped moving
       if(encMoving) { //reset if it was moving
        encMoving=false;
        previousMillis = currentMillis;
        encPosChange=0;
        oldPosition= newPosition;
      }
    }
  }  
}

//calculate valid mide value
void setMidiPos(int valChange,int scale){
  midiPos=midiPos+valChange;
  if(midiPos>scale)
    midiPos=scale-1;
  if(midiPos<0)
    midiPos=0;
}

//calculate multiply factor based on speed of encoder movement
int setencSpeedFct(int interv)
{
  if(interv<100)
    encSpeedFct=4;
  else if(interv<200)
    encSpeedFct=3;
  else if(interv<400)
    encSpeedFct=2;
  else   
    encSpeedFct=1;
}

//respond to incoming control changes
void myControlChange(byte channel, byte control, byte value){
  switch(control){
    case midiCC:
      setMidiPos(value,128);
      return;
     default:
      Serial.println("Control:" + control);
      return;
  }
}
 
I ran your program here on a Teensy 3.2, with nothing connected on the pins. Then I typed a command to send a sysex message. It printed "240" in the serial monitor. Here's a screenshot.

sc.png

I can't say why your PC isn't sending messages, but hopefully this can at least to confirm your code is correctly receiving messages. When you get software on your PC to actually transmit, I'm sure you'll see numbers in the serial monitor.
 
This is a general synchronization problem often encountered with MIDI controllers. You have a parameter in your DAW you want to control with MIDI, so you map it to a particular CC. Then you setup your MIDI controller to control that parameter with one of it's knobs. When you move the knob on the hardware controller, the parameter changes in the DAW, and is reflected often by the GUI showing the parameter as a virtual knob or whatever.

Now, if you move the virtual knob, you want the corresponding MIDI value to be sent to the controller so it's aware of the update.

E.g.
1) Param is as 64.
2) Hardware knob turns one click to the right. It sends a MIDI CC to set the param to 65.
3) DAW turns the virtual knob one position further. Param is not at 66.
4) Hardware is unaware of the param value. Hardware knob turns one more click, it thinks it was at 65 still, param in the DAW is 66, so Hardware tells daw to set value to 66, instead of 67 as intended.

Now I'll admit that I've used neither Logic or Mainstage. I've only used Cubase, Amplitube and Forte. And I never found a way to send MIDI CC message out when you change a virtual knob controlled by a MIDI IN in those three programs.

Are you sure Logic/Mainstage supports that particular feature? I've always thought it was an obvious necessity but most DAWs don't seem to have it because 99% of midi controllers out there don't have MIDI inputs, output only.
 
As far far as I know the only way to get information out of Logic is by emulating a Logic Control or other control surface. I'm working on a controller for Logic optimised for controlling plugins that emulates a Logic control and a Logic control XT so I can control 16 parameters at a time.
What kind of controller do you have in mind? Rotary encoders? Motor faders? Display(s)? How many paramaters do you want to control simultaneously? Is it intended as a general controller or for specific functions, plugins or instruments?

Kind regards,

Gerrit
 
Now that I think more about it, it's not really the DAW most of the time that's the issue, it's the VST plugins. If the VST plugin supports MIDI IN control of the parameter, it's up to the VST plugin itself to generate MIDI OUT messages when someone moves a virtual control inside the VST GUI. There's no way the VST host knows that inside the plugin a parameter changed.
 
usbMidi and Mackie Control

Thanks to all for the quick and helpful responses, and special thanks to Paul for even testing my code.

I assumed that somehow this information is sent back to the controller, for two reasons:
1. Commercially available controllers like Nektar Panorama and Komplete Kontrol are able to show current settings. These are indeed Mackie (Logic) control devices, as Gerrit suggested.
2. I see examples of motorised faders that apparently respond. I downloaded the code of one of these with Arduino (see https://blog.codyhazelwood.me/midi-control-with-an-arduino-and-a-motorized-fader/). It seems to be based on Mackie as well, but I could not see anything in the code that is different from my code. So I do not understand how Mackie is playing a role here.

So I suppose I need to implement Mackie Control. If anyone with experience with Mackie on Teensy could set me in the right direction, would be very welcome. For instance, is this possible via the usbMIDI, or not?

What I am aiming to build (for who is interested like Gerrit)
I am using plug-in synthesizers a lot. I want better hardware control than possible up to now. I have been using controllers like Kore, Komplete Kontrol, Nektar Panorama. I know exactly how I would improve all these controllers to make it really work to my likings. So time to built one my self.

The first thing I want to build is what I would call a midi matrix. It will work much like the interface of a Microkorg or Blofeld, and also like the Panorama and the KK, but than better:
1. Instead of having to scroll through an (sometimes unordered) list of pages/modes, I want dedicated push buttons for direct selecting the page/mode for Oscillator, Filter, Amp, Envelope, LFO, Mix, FX, Mod Matrix.
2. The encoders and push buttons are always controlling the same parameter, whatever synth you ar controlling. For instance: in oscillator mode, encoder 1 is always controlling the waveform, encoder 2 the PW/shape, encoder 3 the coarse tuning, Encoder 4 the fine tuning, etc. If a certain parameter is not available for a certain synth, the encoder is dimmed and not used for another parameter. So, (after getting used to it) you do not have to search where a certain parameter is hidden.
3. It is important that the current settings are shown on the midi controller (either by leds or a display), and there should be no jumping. You should be able to control the plugin without looking on your computer. That is why I need to receive the current settings.

So I have started a simple project, just to learn Teensy and how this could be accomplished. I know, the final objective is far away, but you have to start somewhere, don't you?
 
There does not seem to be an official specification for Mackie Control universal (MCU) but sereral companies implement apparently interoperable products using it.

There is a PDF (available here https://web.archive.org/web/2013040...e.com/en/Logic7_DedicatedCntrlSurfaceInfo.pdf) which describes the protocol (page 239 onward).

For the related HUI protocol, look here
https://forum.cockos.com/showthread.php?t=101328

I know, these are not great sources. If someone has better ones I would like to see them.

You can use Teensy USB Host to intercept the MIDI messages sent by your controllers, log them to the Arduino console, and forward them on via the USB device port. Basically a SysEX sniffer.
 
.... It seems to be based on Mackie as well, but I could not see anything in the code that is different from my code. So I do not understand how Mackie is playing a role here.

So I suppose I need to implement Mackie Control. If anyone with experience with Mackie on Teensy could set me in the right direction, would be very welcome. For instance, is this possible via the usbMIDI, or not?

...

Only if Logic detects a Mackie control unit on one of the midi ports will it send data to that port. I don't know if you can just tell logic that there's a controller connected as I implemented the sysex handshake for automatic detection and installation.
Yes, this possible over USB.

Here's the sketch I'm working on:View attachment Zeus-DPC.ino

And here's a picture of it in operation:
Zeus-DPC-Lexicon-front.jpg

It's not finished yet but the basics are working.

Kind regards,

Gerrit
 
Hi Gerrit,
A bit late, but thanks a lot. Your Zeus code helped me a lot to get going! I do not understand it completely yet, but it definitely works. Your project is interesting as well, and probably quite similar to what I am going to try to do.
Kind regards,
Peter
 
View attachment Zeus-DPC.ino
Hi Gerrit,
A bit late, but thanks a lot. Your Zeus code helped me a lot to get going! I do not understand it completely yet, but it definitely works. Your project is interesting as well, and probably quite similar to what I am going to try to do.
Kind regards,
Peter
Glad I could help:)
Here's an updatet version of the sketch:View attachment Zeus-DPC.ino The 4D System library is not used anymore so it should work as is. There's more code as the displays are controlled directly from the sketch and some 'translations' and plugin ids are added.
The unit now identifies itself as a standard Mackie control and extension unit and the jog shuttle is also working.

Kind regards,

Gerrit
 
Status
Not open for further replies.
Back
Top