oddson
Well-known member
Here is a version retaining the array of ResponsiveAnalogRead (RAR) objects (thanks to Christoph for sorting me out on this!).
It's now very similar to the analog section of my example code and was very easy to implement the other changes once I had my head straight on how to get an RAR array when the pin is always the same.
As an added benefit you can leave your MUX pins float if you point their initialization at a grounded Teensy pin... RAR will read that (stable) value and you won't see 'noise' messages flying everywhere.
It also allows me to test a bit more... By having only 1 RAR object point at the pin where I have a control and the rest at a grounded pin I can get a better idea of how it's working because I only see messages generated for that MUX CC.
So I think I've tested everything except the MUX logic and timing which require the hardware.
And the timing is everything... With RAR and three-bits of reduction stability should be very easy to achieve and hardware filtering never seems to really be needed at seven bits.
That is if you can live with whatever trade-off between responsiveness and stability that the additional processing and timing issues with controlling a MUX entail. Of hardware changes lower resistance on your pots (if you can afford the current and not really below 10KOhm) and better quality pots likely have the best payoff. That and some care with signal paths.
It's now very similar to the analog section of my example code and was very easy to implement the other changes once I had my head straight on how to get an RAR array when the pin is always the same.
Code:
//************LIBRARIES USED**************
// include the ResponsiveAnalogRead library for analog smoothing
#include <ResponsiveAnalogRead.h>
//usbMIDI.h library is added automatically when code is compiled as a MIDI device
// ******CONSTANT VALUES********
// customize code behaviour here!
const int muxTimeMin = 500; // minimum micro-seconds between MUX reads
const int channel = 1; // MIDI channel
const int MUX_PINS = 16; // number of MUX Channnels
// define the CC ID numbers on which to send them..
const int CCID[MUX_PINS] = {21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36};
//******VARIABLES***********
// a data array and a lagged copy to tell when MIDI changes are required
byte data[MUX_PINS];
byte dataLag[MUX_PINS]; // when lag and new are not the same then update MIDI CC value
byte i=0; // global index for MUX channel reads
//mapping of mux to teensy digital pins
int pin_Out_S0 = 0;
int pin_Out_S1 = 1;
int pin_Out_S2 = 2;
int pin_Out_S3 = 3;
int pin_In_Mux1 = A1;
//****** TIMER VARIABLE *** change scale here!
elapsedMicros mux1Updated; // switch to micros to run at speed and tune with muxTimeMin setting above
//elapsedMillis mux1Updated; // switch to millis to troubleshoot
//************INITIALIZE LIBRARY OBJECTS**************
// initialize the ReponsiveAnalogRead objects
ResponsiveAnalogRead analog[]{
{pin_In_Mux1 ,true},
{pin_In_Mux1 ,true},
{pin_In_Mux1 ,true},
{pin_In_Mux1 ,true},
{pin_In_Mux1 ,true},
{pin_In_Mux1 ,true},
{pin_In_Mux1 ,true},
{pin_In_Mux1 ,true},
{pin_In_Mux1 ,true},
{pin_In_Mux1 ,true},
{pin_In_Mux1 ,true},
{pin_In_Mux1 ,true},
{pin_In_Mux1 ,true},
{pin_In_Mux1 ,true},
{pin_In_Mux1 ,true},
{pin_In_Mux1 ,true}
};
//************SETUP**************
void setup() {
//! don't forget to set for output!
pinMode(pin_Out_S0, OUTPUT);
pinMode(pin_Out_S1, OUTPUT);
pinMode(pin_Out_S2, OUTPUT);
pinMode(pin_Out_S3, OUTPUT);
}
//************LOOP**************
void loop() {
nextMUXpin();
while (usbMIDI.read()) {
// controllers must call .read() to keep the queue clear even if they are not responding to MIDI
}
}
//************MUX SECTION**************
void nextMUXpin(){
if (mux1Updated>muxTimeMin) {
// 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);
serialPringMIDIdata(); // use to troublshoot
}
}
//reset timer
mux1Updated = 0;
//increment index
i++;
if (i>15) {i=0;}
// set mux control pins for next pass
digitalWrite(pin_Out_S0, HIGH && (i & B00000001));
digitalWrite(pin_Out_S1, HIGH && (i & B00000010));
digitalWrite(pin_Out_S2, HIGH && (i & B00000100));
digitalWrite(pin_Out_S3, HIGH && (i & B00001000));
}
}
// **useful for debugging, comment out function call to run full speed
void serialPringMIDIdata(){
Serial.print(i,DEC);
Serial.print(" :");
Serial.print(HIGH && (i & B00000001),BIN);
Serial.print(HIGH && (i & B00000010),BIN);
Serial.print(HIGH && (i & B00000100),BIN);
Serial.print(HIGH && (i & B00001000),BIN);
Serial.print(" MUX_PIN: ");
Serial.print(i,DEC);
Serial.print(" CC: ");
Serial.print(CCID[i],DEC);
Serial.print(" DATA HEX: ");
Serial.println(data[i],HEX);
}
As an added benefit you can leave your MUX pins float if you point their initialization at a grounded Teensy pin... RAR will read that (stable) value and you won't see 'noise' messages flying everywhere.
It also allows me to test a bit more... By having only 1 RAR object point at the pin where I have a control and the rest at a grounded pin I can get a better idea of how it's working because I only see messages generated for that MUX CC.
So I think I've tested everything except the MUX logic and timing which require the hardware.
And the timing is everything... With RAR and three-bits of reduction stability should be very easy to achieve and hardware filtering never seems to really be needed at seven bits.
That is if you can live with whatever trade-off between responsiveness and stability that the additional processing and timing issues with controlling a MUX entail. Of hardware changes lower resistance on your pots (if you can afford the current and not really below 10KOhm) and better quality pots likely have the best payoff. That and some care with signal paths.
Last edited: