TEENSY 2.0 Potentiometer MIDI controller, switchable channels

Status
Not open for further replies.
Hi there


I have adapted a project from the following blog, and was hoping for some help
http://little-scale.blogspot.com/2012/10/a-very-simple-diy-usb-midi-controller.html


I want the teensy to act as a midi device, and to enable a potentiometer to send MIDI data to different MIDI control channels depending upon the state of a switch. I am just putting the code together and was wondering if anyone could help me get it right?

Circuit Architecture:

I have a 10K potentiometer placed between the +5v and Ground rails, with the actuator connected to pin: A0

I have a rocker switch enabling 5V to be sent to pin: A4 when it is in one position, and 0V to A4 when in the other position

Aim

*I would like the pot to send data to MIDI Control channel 1 when the switch is in state 0 (0V to pin: A4),
*and for the pot to send data to Midi Control channel 2 when the switch is in its state 1 (5V to A4).

Code so far:


int val;
int swPin = 4; // This is the pin which recieves the 5V from the switch
int conNum; // this is the MIDI controller number that will be altered
//depending upon the state of the switch


void setup() {
pinMode (swPin, INPUT);
// define pin: A4 as an input
}

void loop() {

val = analogRead(swPin); //read the switch state
if (val = HIGH)
{conNum = 1; //If the switch is on, conNum is 2
}
else
{conNum = 2; //If the switch is off, conNum is 1
}

//The following is the standard MIDI function from...
//teensy, with the controll change lane defined...
//as the number that has been chosen from above
usbMIDI.sendControlChange(conNum, analogRead(0) / 8, 1);

//delay for stability
delay(5);

//Ignore incoming midi from computer as this is a...
//send-data controller only
while (usbMIDI.read()) {
}
}
 
You need to read it as a boolean value with digitalRead()

Code:
  if (digitalRead(swPin)) {
   conNum = 1;
  } else {
   conNum = 2;
  }

Big issue is stability of output. Your delay-only method will pump lots of similar messages; potentially 200 per second as it is sending even when unchanged.
 
Thanks Oddson, you have made some great points

I have made some changes including adding code to only send midi when there is a change in the potentiometer, and defining the switch as boolien

I would be very interested to know what you think of the following:

//Variables
bool swState; // switch val
int potState; // potentiometer val
int conNumber; //midi cc lane
int carryVal = 0; //carry over num

// Inputs
int potPin = 0;
int swPin = 4;



void setup() {
pinMode (swPin, INPUT);
// pin: A4 is switch input
pinMode (potPin, INPUT);
// pin: A0 is pot. Input
}



void loop() {
// switch determines conNum
if (digitalRead(swPin)) {
conNum = 1;
} else {
conNum = 2;
}

// compare potState to prev value
potState = analougeRead(potPin);
if (potState == carryVal){
}

// if there is a change, send MIDI
else{
usbMIDI.sendControlChange(conNum, potState / 8, 1);

// make carryVal the current pot
carryVal = potState;

}

// don’t receive midi
while (usbMIDI.read()) {
}
delay 5;
}
 
Do you think it will work?

Also, are there are no comparison arguments needed for this section:


if (digitalRead(swPin)) {
conNum = 1;
} else {
conNum = 2;


As in

if (digitalRead(swPin) = 1) {
conNum = 1;
}
else {
conNum = 2;
}
 
For buttons, I highly recommend using the Bounce library. It has risingEdge() and fallingEdge() functions to tell you when the button has changed from low to high and high to low. This makes MIDI much easier.

In Arduino, click File > Examples > Teensy > USB_MIDI > Buttons for code to use.
 
@Paul... switch is not used as a trigger but as a boolean-selector toggle so debounce is not an issue.

@OP digitalRead is already boolean where HIGH = True.
https://www.pjrc.com/teensy/td_digital.html

Checking if the result is different from the last send should make it usable but you may find it still flickers between values.

Checking if the raw value has changed more than some threshold before calculating new value avoids flickering when the raw reading is near a multiple of eight.

There is the ResponsiveAnalogRead libray that can handle it for you.
 
Last edited:
Thanks oddson, there are some really great ideas there so thanks for sending them. I have re-written the code which is looking a lot cleaner now. Does this look good?:




// include responsive read
#include <ResponsiveAnalogRead.h>

// define variables
const int pot_pin = A0; // pot input
int potValue; // stores pot state
int conNum; // midi cc control num

//declare responsive analog object
ResponsiveAnalogRead analog(pot_pin, true);


void setup(){
//define switch as input
pinMode(PIN_D4, INPUT_PULLUP);
}

void loop(){

// update the analog value each
//cycle
analog.update();
// send analog value to potVal
potValue = analog.getValue();

// switch condition sets midi cc
// to ether 1 or 2
if (digitalRead(PIN_D4)) {
conNum = 1;
} else {
conNum = 2;
}

// if the responsive analog read
// function returns a new value
// then send the change to MIDI
if(analog.hasChanged()) {
usbMIDI.sendControlChange(conNum, potValue / 8, 1);
} // divided by 8 to get correct
// midi value

// ignore incoming MIDI
while (usbMIDI.read()) {
}

// Delay for stability
delay 5;
}



Does this look like it is going to work, or is there anything I have missed?
 
Last edited:
On a quick look it seems you are on track but I didn't compile it... have you tried it?

The delay may not be required now. You will still send a few redundant messages where different readings send the same CC value with rounding in the division.

You can double up and check that the calculated value has changed before sending but it's not essential.
 
Thanks oddson
Its all theory based so far so I will have to check with a serial.print function to see what happens
Is there a better way to get midi 127 from 1024 than rounding off?
 
How about this:


// include responsive read
#include <ResponsiveAnalogRead.h>

// define variables
const int pot_pin = A0; // pot input
int potValue; // stores pot state
int conNum; // midi cc control num
Int carryVal = 0;

//declare responsive analog object
ResponsiveAnalogRead analog(pot_pin, true);


void setup(){
//define switch as input
pinMode(PIN_D4, INPUT_PULLUP);
}

void loop(){

// update the analog value each
//cycle
analog.update();
// send analog value to potVal
potValue = analog.getValue();

// switch condition sets midi cc
// to ether 1 or 2
if (digitalRead(PIN_D4)) {
conNum = 1;
} else {
conNum = 2;
}

// if the analog read
// function returns a new value
// compared-to carry value
// then send the change to MIDI
if(potValue == carryValue){
} else {
usbMIDI.sendControlChange(conNum, potValue / 8, 1);
} // divided by 8 to get correct
// midi value

// Update carry value
carryValue = potValue;

// ignore incoming MIDI
while (usbMIDI.read()) {
}

// Delay for stability
delay 5;
}
 
...Is there a better way to get midi 127 from 1024 than rounding off?
Wondering that myself.
I just keep lagged values and compare and send if changed.

I'm not sure conNum isn't reversed as your comments seem to contradict your code.
 
How about this:...
You only need to set to the lagged value when it changes so you can move carryValue assignment next to the midi send.

Btw - please use the [C0DE][/CODE] tags for any code you post. It's the number-sign button in the blog editor. It retains indents with monospacing.
 
Thanks for the heads up, unfortunately I can’t get the display as code option here because i am replying on my phone. I will try to copy it to my computer and resubmit tonight.

In the meantime, here is an alteration that is based on what you suggested. Hope this is better



// include responsive read
#include <ResponsiveAnalogRead.h>

// define variables
const int pot_pin = A0; // pot input
int potValue; // stores pot state
int potMidiValue; // above dev by 8
int conNum; // midi cc control num
Int carryVal = 0;


//declare responsive analog object
ResponsiveAnalogRead analog(pot_pin, true);


void setup(){
//define switch as input
pinMode(PIN_D4, INPUT_PULLUP);
}

void loop(){

// update the analog value each
//cycle
analog.update();
// send analog value to potVal
potValue = analog.getValue();
potMidiValue = potValue / 8;

// switch condition sets midi cc
// to ether 1 or 2
if (digitalRead(PIN_D4)) {
conNum = 2;
} else {
conNum = 1;
}

// if the analog read
// function returns a new value
// and the midi value is different
// compared-to carry value
// then send the change to MIDI
if((analog.hasChanged()) && (midiControlValue != carryValue)){
usbMIDI.sendControlChange(conNum, potMidiValue, 1);
}

// Update carry value
carryValue = potMidiValue;

// ignore incoming MIDI
while (usbMIDI.read()) {
}

// Delay for stability
delay 5;
}
 
Here we are, I have compiled the following and there seems to be no errors. Do you think the if && statement will solve any unwanted values?

Code:
// include the ResponsiveAnalogRead library
#include <ResponsiveAnalogRead.h>

// define variables
const int pot_pin = A0; // pot input
int potValue; // Stores Pot State
int potMidiValue; // Stores Pot State devided by 8 for MIDI
int conNum; // midi cc control number
int carryVal = 0;

// make a ResponsiveAnalogRead object, pass in the pin, and either true or false depending on if you want sleep enabled
// enabling sleep will cause values to take less time to stop changing and potentially stop changing more abruptly,
//   where as disabling sleep will cause values to ease into their correct position smoothly and more accurately
ResponsiveAnalogRead analog(pot_pin, true);


void setup() {
  pinMode(PIN_D4, INPUT_PULLUP);
}

void loop() {
  analog.update();   //update the analouge reading in each pass
  potValue = analog.getValue(); // store current state in variable
  potMidiValue = potValue / 8; // Makes potVale in to MIDI friendly code

  //switch condition
  if (digitalRead(PIN_D4)) {
    conNum = 2; // if switch is in this state the conNum variable is set to 2
  } else {
    conNum = 1; // as above except varable is set to 1
  }
  //If the analog read function returns a new value, and the 
  //potMidiValue calculation is different to the prefious run
  //then data of the pot's current state will be sent as 
  //midi data, along with the cc channel which was
  //decided by the switch condition
  if ((analog.hasChanged()) && (potMidiValue != carryVal)){
    usbMIDI.sendControlChange(conNum, potMidiValue, 1);
  }

  // Update carry value
  carryVal = potMidiValue;

  // ignore incoming midi
  while (usbMIDI.read()) {
  }

  delay(5);


  

}
 
I have also made a version for serial.print for checking the thing works:

Code:
// include the ResponsiveAnalogRead library
#include <ResponsiveAnalogRead.h>

// define variables
const int pot_pin = A0; // pot input
int potValue; // Stores Pot State
int potMidiValue; // Stores Pot State devided by 8 for MIDI
int conNum; // midi cc control number
int carryVal = 0;

// make a ResponsiveAnalogRead object, pass in the pin, and either true or false depending on if you want sleep enabled
// enabling sleep will cause values to take less time to stop changing and potentially stop changing more abruptly,
//   where as disabling sleep will cause values to ease into their correct position smoothly and more accurately
ResponsiveAnalogRead analog(pot_pin, true);


void setup() {
  pinMode(PIN_D4, INPUT_PULLUP); // pin D4 is a pullup switch
  Serial.begin(9600);      // open the serial port at 9600 bps
}

void loop() {
  analog.update();   //update the analouge reading in each pass
  potValue = analog.getValue(); // store current state in variable
  potMidiValue = potValue / 8; // Makes potVale in to MIDI friendly code

  //switch condition
  if (digitalRead(PIN_D4)) {
    conNum = 2; // if switch is in this state the conNum variable is set to 2
  } else {
    conNum = 1; // as above except varable is set to 1
  }
  
  
  //If the analog read function returns a new value, and the 
  //potMidiValue calculation is different to the prefious run
  //then data of the pot's current state will be sent as 
  //midi data, along with the cc channel which was
  //decided by the switch condition
  if ((analog.hasChanged()) && (potMidiValue != carryVal)){
    usbMIDI.sendControlChange(conNum, potMidiValue, 1);
    Serial.println(potMidiValue);
  }

  // Update carry value
  carryVal = potMidiValue;

  // ignore incoming midi
  while (usbMIDI.read()) {
  }

  delay(5);

}
 
Hmm ... I uploaded the programme to the teensy and that seemed to go ok, but when I try to open
the serial window in Arduino I get the following error message:

Board at /dev/cu.usbmodem1411 is not available
 
OK I have tested the serial monitor for midi and the data is looking lovely: The ease in and out functions are working great when I add 5V to A0 and then release the 5V:

(about 4 seconds for the following after 5V release)

127
126
125
124
123
122
121
120
119
118
117
116
115
114
113
112
111
110
109
108
107
106
105
104
103
102
101
100
99
98
97
96
95
94
93
92
91
90
89
88
87
86
85
84
83
82
81
80
79
78
77
76
75
74
73
72
71
70
69
68
67
66
65
64
63
62
61
60
59
58
57
56
55
54
53
52
51
50
49
48
47
46
45
44
43
42
41
40
39
38
37
36
35
34
 
Last edited:
Success

Hi Oddson

I just wanted to say a massive thank you for your help and guidance on this project, you have made it in to something much better than it was originally and I am thrilled with the results.

It is rare to be able to claim complete success first time round, but the first time I plugged this in today it was fantastic.

 
9CE3491D-D349-40AD-8929-38A6E6D28C95.jpg
E9BA4633-BB85-4A8B-B8BB-02F0891931ED.jpg
 
Status
Not open for further replies.
Back
Top