Teensy LC Midi Controller for Plugins in Logic Pro X

Status
Not open for further replies.

TheSwede

Member
I am making a midi controller aiming to control Waves Pultec EQP-1A plugin version looking similar to the blue controller in this thread:
https://www.gearslutz.com/board/low-end-theory/1187323-diy-midi-controller-plugins.html

My gear:
  • Teensy LC
  • 9 potentiometers
  • 1 LED
  • 1 Toggle switch (I have yet to buy one)

The plugin looks like this:
puigtec-eqp-1a.jpg

The pots will control the different pots shown on the plugin except for the parameter "MAINS" (the real deal doesn't have that so I am skipping that one).

Now, I would like the toggle switch to bypass the plugin or make it active depending on the current status. I am thinking of getting a SPST momentary toggle switch. Since I am aiming for the controller to be used on multiple channels, I think a momentary toggle switch is the way to go.

My plan is also for the LED to receive message if the plugin is active or bypassed for the active/selected channel.

Does anyone have a code for this sort of midi controller or can guide me on how to proceed? I have very little knowledge in coding so I really appreciate all help I can get.

Cheers
 
After having taken the initial design decision to go either with DIN or USB MIDI, just have a look onto the corresponding libraries and examples which come with the Teensyduino plugin installation.
And have a look here and here.
 
As the position of the pots will not match the plugin settings when switching channels you might want to add a button to send the current position of all pots to the plugin.
 
As the position of the pots will not match the plugin settings when switching channels you might want to add a button to send the current position of all pots to the plugin.

You could also consider using motorized potentiometers such as this if you can figure out how to get Logic to send the plugin values back to your controller.
 
You could also consider using motorized potentiometers such as this if you can figure out how to get Logic to send the plugin values back to your controller.

As I understand it these motorised pots are intended for use with a simple 'up and 'down' remote control and not for use as a servo like with motorised faders. They are also quite slow as it takes several seconds to go from min to max.

If the goal is to emulate the device as best as possible you could consider using rotary switches wired as pots using resistors but you'd first have to figure out what the values are for the different settings of the plugin parameters.
In the thread on gearslutz the Logic smart controls are used to control the plugin. Smart controls do not give feedback so it will not be possible to set the LED status from the DAW this way. Just as with the position of the pots, the state of the LED will not match the plugin setting when switching channels.
 
As I understand it these motorised pots are intended for use with a simple 'up and 'down' remote control and not for use as a servo like with motorised faders. They are also quite slow as it takes several seconds to go from min to max.

If the goal is to emulate the device as best as possible you could consider using rotary switches wired as pots using resistors but you'd first have to figure out what the values are for the different settings of the plugin parameters.
In the thread on gearslutz the Logic smart controls are used to control the plugin. Smart controls do not give feedback so it will not be possible to set the LED status from the DAW this way. Just as with the position of the pots, the state of the LED will not match the plugin setting when switching channels.

I’ve yet to get one for myself to test it, but it’s listed as a “pro audio” component and has applications in mixing consoles so if I had to guess it was made to rival their own motorized faders for a similar use. But again this is only speculation it could be a good product or it might not be, I want to get a couple and test it for myself for use in a future project.
 
Thanks for all the input guys!

I have decided to stick to "normal" pots as opposed to motorized since the EQ settings won't be same for different channels and I would rather start from scratch with every channel.

I've got all the pots set up correctly, but there are two things that I have yet to solve:

  1. In Logic, does anyone know how to make the bypass plugin control assignment specific to a plugin instead of insert #1 bypass (for example)?
  • I want the LED to light up when the plugin is active and turn off when it is bypassed. Does anyone know if Logic sends a midi message when activating/bypassing plugins that I can code? It should be able to since it can read incoming messages, right?
 
Thanks for all the input guys!

I have decided to stick to "normal" pots as opposed to motorized since the EQ settings won't be same for different channels and I would rather start from scratch with every channel.

I've got all the pots set up correctly, but there are two things that I have yet to solve:

  1. In Logic, does anyone know how to make the bypass plugin control assignment specific to a plugin instead of insert #1 bypass (for example)?
  2. I want the LED to light up when the plugin is active and turn off when it is bypassed. Does anyone know if Logic sends a midi message when activating/bypassing plugins that I can code? It should be able to since it can read incoming messages, right?

  1. From looking at the way the controllers are mapped I don’t believe you can assign it to a specific plugin and only to a relative location such as Track #2 or the currently selected track and Insert #1.
  2. Logic has no way of sending midi data out unless you have a Midi Device Plug-In mapped to your controller and I haven’t figured out how to make a custom one yet or if you even can without some kind of permission or SDK from Apple. Most DAWs act in this same manner, they will not by default send any controller data back to a controller unless it has some kind of file that tells it what your controller can do and what messages to send. Along with that they don’t all allow you to make your own custom mapping file and your stuck with using the standard protocols of either HUI or Mackie/Logic Control.
 
Okay that is a bit of a downer, well then there's nothing to do about that I guess.

I am having some troubles with the potentiometers too though, I think they are rotating about 290 degrees. But reach velocity 127 after only turning 180 degrees. Can change the code so they reach 127 when they have been fully rotated?

This is my code (slightly customized using this code from "oddson", to whom I am very grateful):

Code:
//************LIBRARIES USED**************
// include the ResponsiveAnalogRead library for analog smoothing
#include <ResponsiveAnalogRead.h>
// include the Bounce library for 'de-bouncing' switches -- removing electrical chatter as contacts settle
#include <Bounce.h> 
//usbMIDI.h library is added automatically when code is compiled as a MIDI device

// ******CONSTANT VALUES******** 
// customize code behaviour here!
const int channel = 1; // MIDI channel
const int A_PINS = 9; // number of Analog PINS
const int D_PINS = 3; // number of Digital PINS
const int ON_VELOCITY = 99; // note-one velocity sent from buttons (should be 65 to  127)

// define the pins you want to use and the CC ID numbers on which to send them..
const int ANALOG_PINS[A_PINS] = {A0,A1,A2,A3,A4,A5,A6,A7,A8};
const int CCID[A_PINS] = {21,22,23,24,25,26,27,28,29};

// define the pins and notes for digital events
const int DIGITAL_PINS[D_PINS] = {0,1,2};
const int note[D_PINS] = {60,61,62};
const int BOUNCE_TIME = 7; // 5 ms is usually sufficient
const boolean toggled = true;


//******VARIABLES***********
// a data array and a lagged copy to tell when MIDI changes are required
byte data[A_PINS];
byte dataLag[A_PINS]; // when lag and new are not the same then update MIDI CC value


//************INITIALIZE LIBRARY OBJECTS**************
// not sure if there is a better way... some way run a setup loop on global array??
// use comment tags to comment out unused portions of array definitions

// initialize the ReponsiveAnalogRead objects
ResponsiveAnalogRead analog[]{
  {ANALOG_PINS[0],true},
  {ANALOG_PINS[1],true},
  {ANALOG_PINS[2],true},
  {ANALOG_PINS[3],true},
  {ANALOG_PINS[4],true},
  {ANALOG_PINS[5],true},
  {ANALOG_PINS[6],true},
  {ANALOG_PINS[7],true},
  {ANALOG_PINS[8],true}/*,
  {ANALOG_PINS[6],true},
  {ANALOG_PINS[7],true},*/
}; 

// initialize the bounce objects 
Bounce digital[] =   {
  Bounce(DIGITAL_PINS[0],BOUNCE_TIME), 
  Bounce(DIGITAL_PINS[1], BOUNCE_TIME),
  Bounce(DIGITAL_PINS[2], BOUNCE_TIME)/*,
  Bounce(DIGITAL_PINS[3], BOUNCE_TIME),
  Bounce(DIGITAL_PINS[4], BOUNCE_TIME),
  Bounce(DIGITAL_PINS[5], BOUNCE_TIME),
  Bounce(DIGITAL_PINS[6], BOUNCE_TIME),
  Bounce(DIGITAL_PINS[7], BOUNCE_TIME),*/
}; 

//************SETUP**************
void setup() {
// loop to configure input pins and internal pullup resisters for digital section
  for (int i=0;i<D_PINS;i++){
    pinMode(DIGITAL_PINS[i], INPUT_PULLUP);
  }
}

//************LOOP**************
void loop() {
  getAnalogData();
  getDigitalData();
  while (usbMIDI.read()) {
     // controllers must call .read() to keep the queue clear even if they are not responding to MIDI
  }
}


//************ANALOG SECTION**************
void getAnalogData(){  
  for (int i=0;i<A_PINS;i++){
    // update the ResponsiveAnalogRead object every loop
    analog[i].update(); 
    // if the repsonsive value has change, print out 'changed'
    if(analog[i].hasChanged()) {
      data[i] = analog[i].getValue()>>3;
      if (data[i] != dataLag[i]){
        dataLag[i] = data[i];
        usbMIDI.sendControlChange(CCID[i], data[i], channel);
      }
    }
  }
}



//************DIGITAL SECTION**************
void getDigitalData(){
  for (int i=0;i<D_PINS;i++){
  digital[i].update();
    if (digital[i].fallingEdge()) {
      usbMIDI.sendNoteOn(note[i], ON_VELOCITY, channel);  
    }
    // Note Off messages when each button is released
    if (digital[i].risingEdge()) {
      usbMIDI.sendNoteOff(note[i], 0, channel);  
    }
  }
}
 
To 5V, Analog inputs and ground.

Like this, except I am using Teensy LC and the wires have been soldered to the pots and go to the breadboard busses:
Single-Knob-Breadboard.png

Is it 5V that is the issue?
 
To 5V, Analog inputs and ground.

Like this, except I am using Teensy LC and the wires have been soldered to the pots and go to the breadboard busses:
View attachment 14039

Is it 5V that is the issue?

That is completely the issue, not only that but the Teensy LC is not 5v tolerant and it may have already damaged the pins. You want to connect it to the 3.3v regulator pin and you never want to input more than 3.3v to the Teensy LC.
 
Yes you were correct, it was the 5V that was the issue. The pots work great now though so it seems like the TLC has not been damaged!
 
UPDATE:

I decided to do a 1176 compressor controller instead of the Pultec EQ. I have everything set up except for the VU-meter.

Here's a picture so you know what I am talking about:
klark-teknik-1176-kt-533048.jpg

So there is one last problem that I would love to get some help with. My plan is to make the analog VU-meter show the audio level coming out of my audio interface. The plan is to take one headphone line out (stereo) to a mono adapter into the VU-meter, that I bought from Aliexpress. I tried to illustrate it here:
Skärmavbild 2018-07-17 kl. 23.02.49.png

The problem is that the needle only moves a little bit when audio is streaming from the interface but I would like it to move full range.

So my questions are:
1. Do I need one of those VU-meter driver boards to make it go full range?
Or
2. Can I connect the VU-meter to the Teensy and use coding to make it work?

Thanks in advance for your help!
 
Oh I forgot to add that the metering does not have to be accurate, I just want the needle to bounce more to the music!
 
Based on this meter from Adafruit it may just a need a resistor in place in order for it to get the full range. This is what they say to use when connecting it to a pwm output from a microcontroller, if I had to guess I would say that the resistor is probably important for getting the full range. I don’t have a spare vu meter that I could test for you or I would be able to say for certain.
The resistor should be = (Power supply Voltage) * 20,000. So for a 5V supply, 100Kohm. For a 3.3V supply, 66Kohm.
 
eq controller

Hello there - I posted my project on the blog project submission, which is a similar kind of idea - mine is to control the kush hammer eq, although I use cubase as my daw, which in the generic remote will send all current controller data for a plug in if set up for it. I use LED button switches in that, although I use encoders rather than pots, but the 12mm LED button switches are pretty nice :) Pdf breakdown and sketch are in the posting, I tried to make it easy to follow, but I've had no feedback as to whether that was the case yet.

Paul Hesketh.
 
The problem is that the needle only moves a little bit when audio is streaming from the interface but I would like it to move full range.

Details matter. We can't see the specs for this analog meter, and we don't know anything about the "Stereo to mono adapter" you used. Perhaps the adapter is passive resistors where the output impedance is too high (too weak) for the current that analog needle needs? But that's just a blind guess.
 
I tried to make it easy to follow, but I've had no feedback as to whether that was the case yet.

We currently have just under 100 projects in the queue to go onto the website blog. At 1 every 2 days, the queue is the better part of a year.

But we don't necessarily post them in any particular order. If there's something time sensitive about your project (especially a crowdfunding campaign or some other way you'll be selling them) please send Robin a message. Especially on days where she's pressed for time, a good write-up that's ready to go (explaining what the project does, not so much *how*, but *what*) really helps!
 
Update: I am finally getting closer to finishing the project. I just need help putting two sets of code together:

I got one for MIDI and one for the VU meter. Anyone know how to put these into one code?

Thanks in advance!

MIDI:

Code:
//************LIBRARIES USED**************
// include the ResponsiveAnalogRead library for analog smoothing
#include <ResponsiveAnalogRead.h>
// include the Bounce library for 'de-bouncing' switches -- removing electrical chatter as contacts settle
#include <Bounce.h> 
//usbMIDI.h library is added automatically when code is compiled as a MIDI device

// ******CONSTANT VALUES******** 
// customize code behaviour here!
const int channel = 1; // MIDI channel
const int A_PINS = 4; // number of Analog PINS
const int D_PINS = 9; // number of Digital PINS
const int ON_VELOCITY = 99; // note-one velocity sent from buttons (should be 65 to  127)

// define the pins you want to use and the CC ID numbers on which to send them..
const int ANALOG_PINS[A_PINS] = {A0,A1,A2,A3};
const int CCID[A_PINS] = {21,22,23,24};

// define the pins and notes for digital events
const int DIGITAL_PINS[D_PINS] = {0,1,2,3,4,5,6,7,8};
const int note[D_PINS] = {60,61,62,63,64,65,66,67,68};
const int BOUNCE_TIME = 15; // 5 ms is usually sufficient
const boolean toggled = true;


//******VARIABLES***********
// a data array and a lagged copy to tell when MIDI changes are required
byte data[A_PINS];
byte dataLag[A_PINS]; // when lag and new are not the same then update MIDI CC value


//************INITIALIZE LIBRARY OBJECTS**************
// not sure if there is a better way... some way run a setup loop on global array??
// use comment tags to comment out unused portions of array definitions

// initialize the ReponsiveAnalogRead objects
ResponsiveAnalogRead analog[]{
  {ANALOG_PINS[0],true},
  {ANALOG_PINS[1],true},
  {ANALOG_PINS[2],true},
  {ANALOG_PINS[3],true}/*,
  {ANALOG_PINS[4],true},
  {ANALOG_PINS[5],true},
  {ANALOG_PINS[6],true},
  {ANALOG_PINS[7],true},
  {ANALOG_PINS[8],true}/*,
  {ANALOG_PINS[6],true},
  {ANALOG_PINS[7],true},*/
}; 

// initialize the bounce objects 
Bounce digital[] =   {
  Bounce(DIGITAL_PINS[0], BOUNCE_TIME), 
  Bounce(DIGITAL_PINS[1], BOUNCE_TIME),
  Bounce(DIGITAL_PINS[2], BOUNCE_TIME),
  Bounce(DIGITAL_PINS[3], BOUNCE_TIME),
  Bounce(DIGITAL_PINS[4], BOUNCE_TIME),
  Bounce(DIGITAL_PINS[5], BOUNCE_TIME),
  Bounce(DIGITAL_PINS[6], BOUNCE_TIME),
  Bounce(DIGITAL_PINS[7], BOUNCE_TIME),
  Bounce(DIGITAL_PINS[8], BOUNCE_TIME)/*,,*/
}; 

//************SETUP**************
void setup() {
// loop to configure input pins and internal pullup resisters for digital section
  for (int i=0;i<D_PINS;i++){
    pinMode(DIGITAL_PINS[i], INPUT_PULLUP);
  }
}

//************LOOP**************
void loop() {
  getAnalogData();
  getDigitalData();
  while (usbMIDI.read()) {
     // controllers must call .read() to keep the queue clear even if they are not responding to MIDI
  }
}


//************ANALOG SECTION**************
void getAnalogData(){  
  for (int i=0;i<A_PINS;i++){
    // update the ResponsiveAnalogRead object every loop
    analog[i].update(); 
    // if the repsonsive value has change, print out 'changed'
    if(analog[i].hasChanged()) {
      data[i] = analog[i].getValue()>>3;
      if (data[i] != dataLag[i]){
        dataLag[i] = data[i];
        usbMIDI.sendControlChange(CCID[i], data[i], channel);
      }
    }
  }
}



//************DIGITAL SECTION**************
void getDigitalData(){
  for (int i=0;i<D_PINS;i++){
  digital[i].update();
    if (digital[i].fallingEdge()) {
      usbMIDI.sendNoteOn(note[i], ON_VELOCITY, channel);  
    }
    // Note Off messages when each button is released
    if (digital[i].risingEdge()) {
      usbMIDI.sendNoteOff(note[i], 0, channel);  
    }
  }
}



VU meter:

Code:
#include "Wire.h"

int leftMeter = 20;       // left meter (hours) is attached to pin 5 (PWM)
int leftChannel = 0;     // left channel of audio (analog 1)
int sensitivity = 0;     // 10k pot sensitivity control (analog 0)
int rightLevel = 0;      // position of the right meter
int leftLevel = 0;       // position of the left meter 
// rtc - SDA to A4 - SCL to A5
 
void setup()  { 
  Wire.begin();
  // Serial.begin(9600); Un-comment to view time in serial monitor
  
  pinMode(leftMeter, OUTPUT);      // Initialize Outputs 
  
  digitalWrite(leftMeter, HIGH);   // Test meters on startup
  digitalWrite(13, HIGH);
  delay (1000);
  digitalWrite(leftMeter, LOW);
  digitalWrite(13, LOW);
  delay(1000);
 } 


void loop()  { 
  
  sensitivity = (analogRead(A8) / 3 + 1); // potentiometer sensitivity control
{
     analogWrite(leftMeter, leftLevel); // adjust left meter level
    }
     
     leftChannel = analogRead(A4); // read left channel of audio 
   
  // Below is the code to set meter levels based on sound levels: 
  // If you change the values, remember to make sure that the Left and Right channels are matching.
  // leftLevel and rightLevel can be set from 0 to 255 (PWM)
  
    if (leftChannel >= sensitivity && leftLevel < 20){   
   leftLevel = 20; 
      }
    
    if (leftChannel >= sensitivity + 5 && leftLevel < 41){   
   leftLevel = 41;
      }
        
    if (leftChannel >= sensitivity + 10 && leftLevel < 62){   
   leftLevel = 62;
      }
      
    if (leftChannel >= sensitivity + 15 && leftLevel < 83){   
   leftLevel = 83;
      }
      
    if (leftChannel >= sensitivity + 20 && leftLevel < 104){   
   leftLevel = 104;
      }
        
    if (leftChannel >= sensitivity + 25 && leftLevel < 125){
   leftLevel = 125;
      }
    
     if (leftChannel >= sensitivity + 30 && leftLevel < 146){   
   leftLevel = 146;
      }
      
    if (leftChannel >= sensitivity + 35 && leftLevel < 167){
   leftLevel = 167;
       } 
       
    if (leftChannel >= sensitivity + 37 && leftLevel < 188){
   leftLevel = 188;
       } 
     
    if (leftChannel >= sensitivity + 40 && leftLevel < 209){
    leftLevel = 209;
       }  
       
    if (leftChannel >= sensitivity + 42 && leftLevel < 230){
    leftLevel = 230;
       }  
 
    if (leftChannel >= sensitivity + 45 && leftLevel < 255){
    leftLevel = 255;
       }

 // Fade the meters out to 0
   if (leftChannel < sensitivity && leftLevel > 0){   
     leftLevel = --leftLevel;  // left meter                       
     delayMicroseconds(1000); // can be increased and decreased to adjust smoothness 
   }                          // (how long it takes to get back to 0)
    
}
 
Cubase generoc remote

  1. From looking at the way the controllers are mapped I don’t believe you can assign it to a specific plugin and only to a relative location such as Track #2 or the currently selected track and Insert #1.
  2. Logic has no way of sending midi data out unless you have a Midi Device Plug-In mapped to your controller and I haven’t figured out how to make a custom one yet or if you even can without some kind of permission or SDK from Apple. Most DAWs act in this same manner, they will not by default send any controller data back to a controller unless it has some kind of file that tells it what your controller can do and what messages to send. Along with that they don’t all allow you to make your own custom mapping file and your stuck with using the standard protocols of either HUI or Mackie/Logic Control.

Hello there - Hmm, don't know if logic has an equivalent, but the cubase generic remote sends MIDI data out, if in the settings it is set to transmit as well as receive. You're quite right, though - its not default, is dependent on the vst parameters that are made available from the plugin, and the generic remote can be a bit clunky to work with. Way I have it set up is to have the same vst plugin in the same insert slots on every track, then define a generic remote to control set to selected, and power off any unused plugins. That way, when a track is selected, it transmits the parameter data from the plugins, and updates the values on controllers. A compressor controller is something I've though about building at some point - the sticking point for me too has been metering. The only compressor plugin I've found that outputs gain reduction/compression data over MIDI is the blue cat audio dynamics, so I'll probably base it on that when I get round to it :) Interesting idea to use an unused audio output, though.

Paul.
 
Can anyone help? Plz :D

Update: I am finally getting closer to finishing the project. I just need help putting two sets of code together:

I got one for MIDI and one for the VU meter. Anyone know how to put these into one code?

Thanks in advance!

MIDI:

Code:
//************LIBRARIES USED**************
// include the ResponsiveAnalogRead library for analog smoothing
#include <ResponsiveAnalogRead.h>
// include the Bounce library for 'de-bouncing' switches -- removing electrical chatter as contacts settle
#include <Bounce.h> 
//usbMIDI.h library is added automatically when code is compiled as a MIDI device

// ******CONSTANT VALUES******** 
// customize code behaviour here!
const int channel = 1; // MIDI channel
const int A_PINS = 4; // number of Analog PINS
const int D_PINS = 9; // number of Digital PINS
const int ON_VELOCITY = 99; // note-one velocity sent from buttons (should be 65 to  127)

// define the pins you want to use and the CC ID numbers on which to send them..
const int ANALOG_PINS[A_PINS] = {A0,A1,A2,A3};
const int CCID[A_PINS] = {21,22,23,24};

// define the pins and notes for digital events
const int DIGITAL_PINS[D_PINS] = {0,1,2,3,4,5,6,7,8};
const int note[D_PINS] = {60,61,62,63,64,65,66,67,68};
const int BOUNCE_TIME = 15; // 5 ms is usually sufficient
const boolean toggled = true;


//******VARIABLES***********
// a data array and a lagged copy to tell when MIDI changes are required
byte data[A_PINS];
byte dataLag[A_PINS]; // when lag and new are not the same then update MIDI CC value


//************INITIALIZE LIBRARY OBJECTS**************
// not sure if there is a better way... some way run a setup loop on global array??
// use comment tags to comment out unused portions of array definitions

// initialize the ReponsiveAnalogRead objects
ResponsiveAnalogRead analog[]{
  {ANALOG_PINS[0],true},
  {ANALOG_PINS[1],true},
  {ANALOG_PINS[2],true},
  {ANALOG_PINS[3],true}/*,
  {ANALOG_PINS[4],true},
  {ANALOG_PINS[5],true},
  {ANALOG_PINS[6],true},
  {ANALOG_PINS[7],true},
  {ANALOG_PINS[8],true}/*,
  {ANALOG_PINS[6],true},
  {ANALOG_PINS[7],true},*/
}; 

// initialize the bounce objects 
Bounce digital[] =   {
  Bounce(DIGITAL_PINS[0], BOUNCE_TIME), 
  Bounce(DIGITAL_PINS[1], BOUNCE_TIME),
  Bounce(DIGITAL_PINS[2], BOUNCE_TIME),
  Bounce(DIGITAL_PINS[3], BOUNCE_TIME),
  Bounce(DIGITAL_PINS[4], BOUNCE_TIME),
  Bounce(DIGITAL_PINS[5], BOUNCE_TIME),
  Bounce(DIGITAL_PINS[6], BOUNCE_TIME),
  Bounce(DIGITAL_PINS[7], BOUNCE_TIME),
  Bounce(DIGITAL_PINS[8], BOUNCE_TIME)/*,,*/
}; 

//************SETUP**************
void setup() {
// loop to configure input pins and internal pullup resisters for digital section
  for (int i=0;i<D_PINS;i++){
    pinMode(DIGITAL_PINS[i], INPUT_PULLUP);
  }
}

//************LOOP**************
void loop() {
  getAnalogData();
  getDigitalData();
  while (usbMIDI.read()) {
     // controllers must call .read() to keep the queue clear even if they are not responding to MIDI
  }
}


//************ANALOG SECTION**************
void getAnalogData(){  
  for (int i=0;i<A_PINS;i++){
    // update the ResponsiveAnalogRead object every loop
    analog[i].update(); 
    // if the repsonsive value has change, print out 'changed'
    if(analog[i].hasChanged()) {
      data[i] = analog[i].getValue()>>3;
      if (data[i] != dataLag[i]){
        dataLag[i] = data[i];
        usbMIDI.sendControlChange(CCID[i], data[i], channel);
      }
    }
  }
}



//************DIGITAL SECTION**************
void getDigitalData(){
  for (int i=0;i<D_PINS;i++){
  digital[i].update();
    if (digital[i].fallingEdge()) {
      usbMIDI.sendNoteOn(note[i], ON_VELOCITY, channel);  
    }
    // Note Off messages when each button is released
    if (digital[i].risingEdge()) {
      usbMIDI.sendNoteOff(note[i], 0, channel);  
    }
  }
}



VU meter:

Code:
#include "Wire.h"

int leftMeter = 20;       // left meter (hours) is attached to pin 5 (PWM)
int leftChannel = 0;     // left channel of audio (analog 1)
int sensitivity = 0;     // 10k pot sensitivity control (analog 0)
int rightLevel = 0;      // position of the right meter
int leftLevel = 0;       // position of the left meter 
// rtc - SDA to A4 - SCL to A5
 
void setup()  { 
  Wire.begin();
  // Serial.begin(9600); Un-comment to view time in serial monitor
  
  pinMode(leftMeter, OUTPUT);      // Initialize Outputs 
  
  digitalWrite(leftMeter, HIGH);   // Test meters on startup
  digitalWrite(13, HIGH);
  delay (1000);
  digitalWrite(leftMeter, LOW);
  digitalWrite(13, LOW);
  delay(1000);
 } 


void loop()  { 
  
  sensitivity = (analogRead(A8) / 3 + 1); // potentiometer sensitivity control
{
     analogWrite(leftMeter, leftLevel); // adjust left meter level
    }
     
     leftChannel = analogRead(A4); // read left channel of audio 
   
  // Below is the code to set meter levels based on sound levels: 
  // If you change the values, remember to make sure that the Left and Right channels are matching.
  // leftLevel and rightLevel can be set from 0 to 255 (PWM)
  
    if (leftChannel >= sensitivity && leftLevel < 20){   
   leftLevel = 20; 
      }
    
    if (leftChannel >= sensitivity + 5 && leftLevel < 41){   
   leftLevel = 41;
      }
        
    if (leftChannel >= sensitivity + 10 && leftLevel < 62){   
   leftLevel = 62;
      }
      
    if (leftChannel >= sensitivity + 15 && leftLevel < 83){   
   leftLevel = 83;
      }
      
    if (leftChannel >= sensitivity + 20 && leftLevel < 104){   
   leftLevel = 104;
      }
        
    if (leftChannel >= sensitivity + 25 && leftLevel < 125){
   leftLevel = 125;
      }
    
     if (leftChannel >= sensitivity + 30 && leftLevel < 146){   
   leftLevel = 146;
      }
      
    if (leftChannel >= sensitivity + 35 && leftLevel < 167){
   leftLevel = 167;
       } 
       
    if (leftChannel >= sensitivity + 37 && leftLevel < 188){
   leftLevel = 188;
       } 
     
    if (leftChannel >= sensitivity + 40 && leftLevel < 209){
    leftLevel = 209;
       }  
       
    if (leftChannel >= sensitivity + 42 && leftLevel < 230){
    leftLevel = 230;
       }  
 
    if (leftChannel >= sensitivity + 45 && leftLevel < 255){
    leftLevel = 255;
       }

 // Fade the meters out to 0
   if (leftChannel < sensitivity && leftLevel > 0){   
     leftLevel = --leftLevel;  // left meter                       
     delayMicroseconds(1000); // can be increased and decreased to adjust smoothness 
   }                          // (how long it takes to get back to 0)
    
}
 
Code:
//************SETUP**************
void setup() {
[COLOR="#FF0000"]// loop to configure input pins and internal pullup resisters for digital section
  for (int i=0;i<D_PINS;i++){
    pinMode(DIGITAL_PINS[i], INPUT_PULLUP);
  }[/COLOR]
}

//************LOOP**************
void loop() {
  [COLOR="#FF0000"]getAnalogData();
  getDigitalData();
  while (usbMIDI.read()) {
     // controllers must call .read() to keep the queue clear even if they are not responding to MIDI
  }[/COLOR]
}
To move the midi into your code add the red bits to the setup and loop structures and put the rest elseswhere in the code.

Setup is run once while loop is run over and over.
 
To move the midi into your code add the red bits to the setup and loop structures and put the rest elseswhere in the code.

Setup is run once while loop is run over and over.

I did what you said but get an error message: 'D_PINS' was not declared in this scope

Here's the code when put together:

Code:
#include "Wire.h"

int leftMeter = 20;       // left meter (hours) is attached to pin 5 (PWM)
int leftChannel = 0;     // left channel of audio (analog 1)
int sensitivity = 0;     // 10k pot sensitivity control (analog 0)
int rightLevel = 0;      // position of the right meter
int leftLevel = 0;       // position of the left meter 
// rtc - SDA to A4 - SCL to A5
 
void setup()  { 
  Wire.begin();
  // Serial.begin(9600); Un-comment to view time in serial monitor
  
  pinMode(leftMeter, OUTPUT);      // Initialize Outputs 
  
  digitalWrite(leftMeter, HIGH);   // Test meters on startup
  digitalWrite(13, HIGH);
  delay (1000);
  digitalWrite(leftMeter, LOW);
  digitalWrite(13, LOW);
  delay(1000);

// loop to configure input pins and internal pullup resisters for digital section
  for (int i=0;i<D_PINS;i++){
    pinMode(DIGITAL_PINS[i], INPUT_PULLUP);
  }
 
 } 


void loop()  { 
  
  sensitivity = (analogRead(A8) / 3 + 1); // potentiometer sensitivity control
{
     analogWrite(leftMeter, leftLevel); // adjust left meter level
    }
     
     leftChannel = analogRead(A4); // read left channel of audio 
   
  // Below is the code to set meter levels based on sound levels: 
  // If you change the values, remember to make sure that the Left and Right channels are matching.
  // leftLevel and rightLevel can be set from 0 to 255 (PWM)
  
    if (leftChannel >= sensitivity && leftLevel < 20){   
   leftLevel = 20; 
      }
    
    if (leftChannel >= sensitivity + 5 && leftLevel < 41){   
   leftLevel = 41;
      }
        
    if (leftChannel >= sensitivity + 10 && leftLevel < 62){   
   leftLevel = 62;
      }
      
    if (leftChannel >= sensitivity + 15 && leftLevel < 83){   
   leftLevel = 83;
      }
      
    if (leftChannel >= sensitivity + 20 && leftLevel < 104){   
   leftLevel = 104;
      }
        
    if (leftChannel >= sensitivity + 25 && leftLevel < 125){
   leftLevel = 125;
      }
    
     if (leftChannel >= sensitivity + 30 && leftLevel < 146){   
   leftLevel = 146;
      }
      
    if (leftChannel >= sensitivity + 35 && leftLevel < 167){
   leftLevel = 167;
       } 
       
    if (leftChannel >= sensitivity + 37 && leftLevel < 188){
   leftLevel = 188;
       } 
     
    if (leftChannel >= sensitivity + 40 && leftLevel < 209){
    leftLevel = 209;
       }  
       
    if (leftChannel >= sensitivity + 42 && leftLevel < 230){
    leftLevel = 230;
       }  
 
    if (leftChannel >= sensitivity + 45 && leftLevel < 255){
    leftLevel = 255;
       }

 // Fade the meters out to 0
   if (leftChannel < sensitivity && leftLevel > 0){   
     leftLevel = --leftLevel;  // left meter                       
     delayMicroseconds(1000); // can be increased and decreased to adjust smoothness 
   }                          // (how long it takes to get back to 0)


  getAnalogData();
  getDigitalData();
  while (usbMIDI.read()) {
     // controllers must call .read() to keep the queue clear even if they are not responding to MIDI
  }
}
   
 
//************LIBRARIES USED**************
// include the ResponsiveAnalogRead library for analog smoothing
#include <ResponsiveAnalogRead.h>
// include the Bounce library for 'de-bouncing' switches -- removing electrical chatter as contacts settle
#include <Bounce.h> 
//usbMIDI.h library is added automatically when code is compiled as a MIDI device

// ******CONSTANT VALUES******** 
// customize code behaviour here!
const int channel = 1; // MIDI channel
const int A_PINS = 4; // number of Analog PINS
const int D_PINS = 9; // number of Digital PINS
const int ON_VELOCITY = 99; // note-one velocity sent from buttons (should be 65 to  127)

// define the pins you want to use and the CC ID numbers on which to send them..
const int ANALOG_PINS[A_PINS] = {A0,A1,A2,A3};
const int CCID[A_PINS] = {21,22,23,24};

// define the pins and notes for digital events
const int DIGITAL_PINS[D_PINS] = {0,1,2,3,4,5,6,7,8};
const int note[D_PINS] = {60,61,62,63,64,65,66,67,68};
const int BOUNCE_TIME = 15; // 5 ms is usually sufficient
const boolean toggled = true;


//******VARIABLES***********
// a data array and a lagged copy to tell when MIDI changes are required
byte data[A_PINS];
byte dataLag[A_PINS]; // when lag and new are not the same then update MIDI CC value


//************INITIALIZE LIBRARY OBJECTS**************
// not sure if there is a better way... some way run a setup loop on global array??
// use comment tags to comment out unused portions of array definitions

// initialize the ReponsiveAnalogRead objects
ResponsiveAnalogRead analog[]{
  {ANALOG_PINS[0],true},
  {ANALOG_PINS[1],true},
  {ANALOG_PINS[2],true},
  {ANALOG_PINS[3],true}/*,
  {ANALOG_PINS[4],true},
  {ANALOG_PINS[5],true},
  {ANALOG_PINS[6],true},
  {ANALOG_PINS[7],true},
  {ANALOG_PINS[8],true}/*,
  {ANALOG_PINS[6],true},
  {ANALOG_PINS[7],true},*/
}; 

// initialize the bounce objects 
Bounce digital[] =   {
  Bounce(DIGITAL_PINS[0], BOUNCE_TIME), 
  Bounce(DIGITAL_PINS[1], BOUNCE_TIME),
  Bounce(DIGITAL_PINS[2], BOUNCE_TIME),
  Bounce(DIGITAL_PINS[3], BOUNCE_TIME),
  Bounce(DIGITAL_PINS[4], BOUNCE_TIME),
  Bounce(DIGITAL_PINS[5], BOUNCE_TIME),
  Bounce(DIGITAL_PINS[6], BOUNCE_TIME),
  Bounce(DIGITAL_PINS[7], BOUNCE_TIME),
  Bounce(DIGITAL_PINS[8], BOUNCE_TIME)/*,,*/
}; 

//************ANALOG SECTION**************
void getAnalogData(){  
  for (int i=0;i<A_PINS;i++){
    // update the ResponsiveAnalogRead object every loop
    analog[i].update(); 
    // if the repsonsive value has change, print out 'changed'
    if(analog[i].hasChanged()) {
      data[i] = analog[i].getValue()>>3;
      if (data[i] != dataLag[i]){
        dataLag[i] = data[i];
        usbMIDI.sendControlChange(CCID[i], data[i], channel);
      }
    }
  }
}



//************DIGITAL SECTION**************
void getDigitalData(){
  for (int i=0;i<D_PINS;i++){
  digital[i].update();
    if (digital[i].fallingEdge()) {
      usbMIDI.sendNoteOn(note[i], ON_VELOCITY, channel);  
    }
    // Note Off messages when each button is released
    if (digital[i].risingEdge()) {
      usbMIDI.sendNoteOff(note[i], 0, channel);  
    }
  }
}
 
Status
Not open for further replies.
Back
Top