Go Down

Topic: How to close/turn OFF MIDI.read(); (Read 1 time) previous topic - next topic

Grumpy_Mike

#15
Dec 21, 2018, 07:06 am Last Edit: Dec 21, 2018, 07:06 am by Grumpy_Mike
This is the way I would go about this in code. It compiles but I have not tried it out so it might need some tweaking.

Code: [Select]

#include <MIDI.h>
MIDI_CREATE_DEFAULT_INSTANCE();
// Setting up the counter
int reading = 0;
int lastReading = 0;
int lowest = 0;
int highest = 127;
int changeamnt = 1;
int ledPin = 13;
boolean moveing = false;
 
// Timing for polling the encoder
unsigned long restartTime = 0;
 
 
// Pin definitions
const int pinA = 8;
const int pinB = 9;
 
boolean encA;
boolean encB;
boolean lastA = false;
 
byte midiCh = 1; // MIDI channel to be used which is Channel 2
byte note = 36; // Lowest MIDI note
byte cc = 1; // Lowest MIDI CC
 
void setup() {
  pinMode(ledPin, OUTPUT);
  // set the two pins as inputs with internal pullups
  pinMode(pinA, INPUT_PULLUP);
  pinMode(pinB, INPUT_PULLUP);

  MIDI.begin();
  MIDI.turnThruOff();
    // Start the serial monitor for debugging
  // Serial.begin(9600); // I don't thing you can do this with the MIDI.h libiary
   MIDI.setHandleControlChange(handleControlChange); // Listens to control change
  //MIDI.setHandleNoteOn(handleNoteOn); // Listens to note ons
  //MIDI.setHandleNoteOff(handleNoteOff); // Listens to note offs
}
  
void loop()
{
  if( ! moveing ) MIDI.read(); // real MIDI read
  
  if(millis() > restartTime && moveing){ // restore call back
     MIDI.setHandleControlChange(handleControlChange); // re enable the call back function
     moveing = false;
  }
 if(readEncoder() != -1){ // a change in the reading has occoured
  {
    MIDI.disconnectCallbackFromType(midi::ControlChange);
    MIDI.sendControlChange(cc, reading, midiCh);
    restartTime = millis() + 7; // or what ever
    moveing = true;
    delay(2); // to allow time for echo
    MIDI.read(); // to flush out the buffer
    }    
  }
 
}

int readEncoder(){ // see if the encoder has moved
// read the two pins
    encA = digitalRead(pinA);
    encB = digitalRead(pinB);
    reading = lastReading;
    // check if A has gone from high to low
    if ((!encA) && (lastA))
    {    
      // check if B is high
      if (encB)
      {      
       // clockwise
        if (reading + changeamnt <= highest)
        {
          reading = reading + changeamnt;
        }
      } // end of checking 1
      else
      {
        // anti-clockwise
        if (reading - changeamnt >= lowest)
        {
          reading = reading - changeamnt;
        }
      }
    // ristrain the reading value  
    if( reading < 0) reading = 0;
    if( reading > 127) reading = 127;
    lastA = encA;
    if(reading != lastReading){
      lastReading=reading;
      return reading;
    }
    else{
      return -1;  // if there is no change
    }
  }
}
///////////////////////////////////////////
// MIDI IN
void handleControlChange(byte channel, byte number, byte value) { // channel, CC, value
reading = value;
 
 // Serial.println(value);
/* if (value != 0){
 digitalWrite(ledPin, HIGH);
 }else
 digitalWrite(ledPin, LOW);
 */
}
 
 
void handleNoteOn(byte channel, byte number, byte value) { // channel, note, velocity

}
 
 
void handleNoteOff(byte channel, byte number, byte value) { // channel, note, velocity
  
}

seby20

#16
Dec 21, 2018, 02:13 pm Last Edit: Dec 21, 2018, 02:14 pm by seby20
This is the way I would go about this in code. It compiles but I have not tried it out so it might need some tweaking.

Code: [Select]

#include <MIDI.h>
MIDI_CREATE_DEFAULT_INSTANCE();
// Setting up the counter
int reading = 0;
int lastReading = 0;
int lowest = 0;
int highest = 127;
int changeamnt = 1;
int ledPin = 13;
boolean moveing = false;
 
// Timing for polling the encoder
unsigned long restartTime = 0;
 
 
// Pin definitions
const int pinA = 8;
const int pinB = 9;
 
boolean encA;
boolean encB;
boolean lastA = false;
 
byte midiCh = 1; // MIDI channel to be used which is Channel 2
byte note = 36; // Lowest MIDI note
byte cc = 1; // Lowest MIDI CC
 
void setup() {
  pinMode(ledPin, OUTPUT);
  // set the two pins as inputs with internal pullups
  pinMode(pinA, INPUT_PULLUP);
  pinMode(pinB, INPUT_PULLUP);

  MIDI.begin();
  MIDI.turnThruOff();
    // Start the serial monitor for debugging
  // Serial.begin(9600); // I don't thing you can do this with the MIDI.h libiary
   MIDI.setHandleControlChange(handleControlChange); // Listens to control change
  //MIDI.setHandleNoteOn(handleNoteOn); // Listens to note ons
  //MIDI.setHandleNoteOff(handleNoteOff); // Listens to note offs
}
  
void loop()
{
  if( ! moveing ) MIDI.read(); // real MIDI read
  
  if(millis() > restartTime && moveing){ // restore call back
     MIDI.setHandleControlChange(handleControlChange); // re enable the call back function
     moveing = false;
  }
 if(readEncoder() != -1){ // a change in the reading has occoured
  {
    MIDI.disconnectCallbackFromType(midi::ControlChange);
    MIDI.sendControlChange(cc, reading, midiCh);
    restartTime = millis() + 7; // or what ever
    moveing = true;
    delay(2); // to allow time for echo
    MIDI.read(); // to flush out the buffer
    }    
  }
 
}

int readEncoder(){ // see if the encoder has moved
// read the two pins
    encA = digitalRead(pinA);
    encB = digitalRead(pinB);
    reading = lastReading;
    // check if A has gone from high to low
    if ((!encA) && (lastA))
    {    
      // check if B is high
      if (encB)
      {      
       // clockwise
        if (reading + changeamnt <= highest)
        {
          reading = reading + changeamnt;
        }
      } // end of checking 1
      else
      {
        // anti-clockwise
        if (reading - changeamnt >= lowest)
        {
          reading = reading - changeamnt;
        }
      }
    // ristrain the reading value  
    if( reading < 0) reading = 0;
    if( reading > 127) reading = 127;
    lastA = encA;
    if(reading != lastReading){
      lastReading=reading;
      return reading;
    }
    else{
      return -1;  // if there is no change
    }
  }
}
///////////////////////////////////////////
// MIDI IN
void handleControlChange(byte channel, byte number, byte value) { // channel, CC, value
reading = value;
 
 // Serial.println(value);
/* if (value != 0){
 digitalWrite(ledPin, HIGH);
 }else
 digitalWrite(ledPin, LOW);
 */
}
 
 
void handleNoteOn(byte channel, byte number, byte value) { // channel, note, velocity

}
 
 
void handleNoteOff(byte channel, byte number, byte value) { // channel, note, velocity
  
}


Hi, here's the result that I got from your code.
Tks from your help
Seby
https://youtu.be/SHj61taaubY

Grumpy_Mike

OK. The minus one comes from the readEncoder function. It returns -1 when their is no change between the reading from the encoders and the reading last time.
The line
Code: [Select]
if(readEncoder() != -1)
Calls the readEncoder() function and compares it to -1. If it is NOT -1 then that means their has been a change in the value of the reading and hence sends out the data.

The fact that the readEncoder at first sight appears not to be sending back -1 would suggest that there is something wrong with that function. I just took the code you wrote and moved it into a function to make the code a lot tidier. I must admit I did not understand your logic with this code. I did add code to prevent it going above 127, the MIDI maximum and below 0 the MIDI minimum value for the number you sent.
As a test replace
Code: [Select]
return reading;
with
Code: [Select]
return -1;
If that doesn't stop the continuous send then the problem is elsewhere.

Using 9600 baud for hairless is a bit slow, set this to 11520 baud at both ends. This will not immediately solve the current problem but will prevent problems further down the line.

Grumpy_Mike

I just had a quick look at the readEncoder function and I think there is a misplaced bracket. Try using this one:-
Code: [Select]
int readEncoder(){ // see if the encoder has moved
// read the two pins
    encA = digitalRead(pinA);
    encB = digitalRead(pinB);
    reading = lastReading;
    // check if A has gone from high to low
    if ((!encA) && (lastA))
    {   
      // check if B is high
      if (encB)
      {       
       // clockwise
        if (reading + changeamnt <= highest)
        {
          reading = reading + changeamnt;
        }
      } // end of checking 1
      else
      {
        // anti-clockwise
        if (reading - changeamnt >= lowest)
        {
          reading = reading - changeamnt;
        }
      }
     
    // ristrain the reading value 
    if( reading < 0) reading = 0;
    if( reading > 127) reading = 127;
    lastA = encA;
    }
    if(reading != lastReading){
      lastReading=reading;
      return reading;
    }
    else{
      return -1;  // if there is no change
    }
}

seby20

I just had a quick look at the readEncoder function and I think there is a misplaced bracket. Try using this one:-
Code: [Select]
int readEncoder(){ // see if the encoder has moved
// read the two pins
    encA = digitalRead(pinA);
    encB = digitalRead(pinB);
    reading = lastReading;
    // check if A has gone from high to low
    if ((!encA) && (lastA))
    {   
      // check if B is high
      if (encB)
      {       
       // clockwise
        if (reading + changeamnt <= highest)
        {
          reading = reading + changeamnt;
        }
      } // end of checking 1
      else
      {
        // anti-clockwise
        if (reading - changeamnt >= lowest)
        {
          reading = reading - changeamnt;
        }
      }
     
    // ristrain the reading value 
    if( reading < 0) reading = 0;
    if( reading > 127) reading = 127;
    lastA = encA;
    }
    if(reading != lastReading){
      lastReading=reading;
      return reading;
    }
    else{
      return -1;  // if there is no change
    }
}

Ok, tks again, I change my code for the one above, now, the problem, is when I turn the encoder, nothing is happening. But no more loop.

Grumpy_Mike

So you are going to have to send me a diagram of how you have connected up the encoder's pins.

seby20

So you are going to have to send me a diagram of how you have connected up the encoder's pins.
Hi, here's my connected uno with the encoder, the only difference I have is that on the other side of my encoder, I have 2 more pins, but not connected.
Seby

Grumpy_Mike

Thanks for that.

Unfortunately when I wire up my rotary encoder your code to count the pulses will not work. This is because there are two types of rotary encoder, one that produces a steady state of the encoder sequence each click, and the other that produces a steady state of zero and only outputs the steps of the encoder during the click. I have the latter type.
So that meant I had to write my own code for reading the encoder.

When I did, unfortunately what I had in mind to flush the buffer didn't work. The buffer was not flushed and it held onto the CC message until the handling routine was enabled again.

My second idea was to switch the CC handling function between a real one and a dummy one. This only worked intermittently and I have not been able to make it consistently use the dummy routine, despite a lot of fiddling with delays.

So after working on it all afternoon I have come to the conclusion that what you want can't be done, sorry. 

seby20

Thanks for that.

Unfortunately when I wire up my rotary encoder your code to count the pulses will not work. This is because there are two types of rotary encoder, one that produces a steady state of the encoder sequence each click, and the other that produces a steady state of zero and only outputs the steps of the encoder during the click. I have the latter type.
So that meant I had to write my own code for reading the encoder.

When I did, unfortunately what I had in mind to flush the buffer didn't work. The buffer was not flushed and it held onto the CC message until the handling routine was enabled again.

My second idea was to switch the CC handling function between a real one and a dummy one. This only worked intermittently and I have not been able to make it consistently use the dummy routine, despite a lot of fiddling with delays.

So after working on it all afternoon I have come to the conclusion that what you want can't be done, sorry. 
Ok, tks, I really appreciate. Have a nice day
Seby

Grumpy_Mike

#24
Dec 21, 2018, 10:27 pm Last Edit: Dec 21, 2018, 10:28 pm by Grumpy_Mike
OK, I have done a bit more fiddling and just used flags, and that seems to be more reliable.
By using the moving variable I have used this to change the action of the handleControlChange function. Use it like this:-
Code: [Select]
void handleControlChange(byte channel, byte number, byte value) { // channel, CC, value
 if( moveing ){ // ignore any echo
    digitalWrite(ledPin, HIGH);
    delay(20);
    digitalWrite(ledPin, LOW);
   }
 else {
  // do what you would normally do with a control mesage
   digitalWrite(ledPin2, HIGH);
   delay(20);
  digitalWrite(ledPin2, LOW);
 }
}
}

Where ledPin2 is the pin driving another LED

With the loop function looking like this:-
Code: [Select]
void loop() {
  MIDI.read();
  if(millis() > restartTime && moveing){
     moveing = false;  // stop ignoring cc messages
  }
 if(readEncoder() != -1){ // a change in the reading has occoured
    MIDI.sendControlChange(cc, reading, midiCh);
    restartTime = millis() + 30; // or what ever
    moveing = true;      // switch action of the handleControlChange function
  }
}


Then control change messages sent out and then echoed are diverted to the top part of the handleControlChange function and messages originating from your DAW are handled by the bottom half of the function.

So messages from the DAW flash LED2 and from the rotary encoder flash the on board LED.

seby20

OK, I have done a bit more fiddling and just used flags, and that seems to be more reliable.
By using the moving variable I have used this to change the action of the handleControlChange function. Use it like this:-
Code: [Select]
void handleControlChange(byte channel, byte number, byte value) { // channel, CC, value
 if( moveing ){ // ignore any echo
    digitalWrite(ledPin, HIGH);
    delay(20);
    digitalWrite(ledPin, LOW);
   }
 else {
  // do what you would normally do with a control mesage
   digitalWrite(ledPin2, HIGH);
   delay(20);
  digitalWrite(ledPin2, LOW);
 }
}
}

Where ledPin2 is the pin driving another LED

With the loop function looking like this:-
Code: [Select]
void loop() {
  MIDI.read();
  if(millis() > restartTime && moveing){
     moveing = false;  // stop ignoring cc messages
  }
 if(readEncoder() != -1){ // a change in the reading has occoured
    MIDI.sendControlChange(cc, reading, midiCh);
    restartTime = millis() + 30; // or what ever
    moveing = true;      // switch action of the handleControlChange function
  }
}


Then control change messages sent out and then echoed are diverted to the top part of the handleControlChange function and messages originating from your DAW are handled by the bottom half of the function.

So messages from the DAW flash LED2 and from the rotary encoder flash the on board LED.
Hi, sorry to ask you this, but i'm a little lost now lol, is it possible to copy and paste the full code with the new changes please?
tks
Seby

Grumpy_Mike

OK it is here but please note that the rotary encoder software while being functional is not robust. It has a tendency to randomly swap the direction it thinks the knob is being turned in. This is due to contact bounce and quick and dirty coding so I would strongly emphasise to anyone reading this later that the encoder code is not to be used as any sort of example of how a rotary encoder code should be written.
Also because your rotary encoder is different to the one I have this code will not work with the hardware you have so don't expect it to.
Code: [Select]
#include <MIDI.h>
MIDI_CREATE_DEFAULT_INSTANCE();
// Setting up the counter
int reading = 0;
int lastReading = 0;
int lowest = 0;
int highest = 127;
int changeIncrement = 1;
int ledPin = 13;
int ledPin2 = 12; // extra green LED
boolean moving = false;
 
// Timing for polling the encoder
unsigned long restartTime = 0;
 
// Pin definitions
const int pinA = 8;
const int pinB = 9;
 
boolean encA, last_encA;
boolean encB, last_encB;
 
byte midiCh = 1; // MIDI channel to be used
byte note = 36; // Lowest MIDI note
byte cc = 1; // Lowest MIDI CC
 
void setup() {
  pinMode(ledPin, OUTPUT);
  pinMode(ledPin2, OUTPUT);
  // set the two pins as inputs with internal pullups
  pinMode(pinA, INPUT_PULLUP);
  pinMode(pinB, INPUT_PULLUP);
  MIDI.begin();
  MIDI.turnThruOff();
    // Start the serial monitor for debugging
   Serial.begin(115200);
   MIDI.setHandleControlChange(handleControlChange); // Listens to control change
  //MIDI.setHandleNoteOn(handleNoteOn); // Listens to note ons
  //MIDI.setHandleNoteOff(handleNoteOff); // Listens to note offs
}
 
void loop() {
  MIDI.read();
  if(millis() > restartTime && moving){
     moving = false;  // stop ignoring cc messages
  }
 if(readEncoder() != -1){ // a change in the reading has occurred
    MIDI.sendControlChange(cc, reading, midiCh);
    restartTime = millis() + 30; // or what ever
    moving = true;      // switch action of the handleControlChange function
  }
}

int readEncoder(){ // see if the encoder has moved
// read the two pins
    static boolean dir = true; // direction
    encA = digitalRead(pinA);
    encB = digitalRead(pinB);
    lastReading = reading;
    //if(encA != encB){ Serial.print(encA);Serial.print(" ");Serial.println(encB);} // test print
    // check if A has gone from high to low
    if (encA != encB) {
    if( last_encA == encA && last_encB == encB) dir = ! dir; // reverse direction
     
      last_encA = encA;
      last_encB = encB; 
      if (dir)
      {       
       // clockwise
          reading += changeIncrement;
        }
      else
      {
        // anti-clockwise
          reading -= changeIncrement;
      }
     
    // restrain the reading value 
    if( reading < 0) reading = 0;
    if( reading > 127) reading = 127;

    //Serial.print("reading  "); // test
    //Serial.println(reading);   // test
    while(encA != encB){    // wait until transitory condition has passed
      delay(20);   // debounce delay
      encA = digitalRead(pinA);
      encB = digitalRead(pinB);
      }
    }
    if(reading != lastReading){
      lastReading = reading;
      return reading;
    }
    else{
      return -1;  // if there is no change
    }
}

///////////////////////////////////////////
// MIDI IN
void handleControlChange(byte channel, byte number, byte value) { // channel, CC, value
 if( moving ){ // ignore any echo
    // just indicate that a CC message has been put into a sink by flashing the onboard LED
    digitalWrite(ledPin, HIGH);
    delay(20);
    digitalWrite(ledPin, LOW);
   }
 else {
  // do what you would normally do with a control message
   // just indicate that a CC message has been received by flashing an external LED
   digitalWrite(ledPin2, HIGH);
   delay(20);
   digitalWrite(ledPin2, LOW);
 }
}
 
void handleNoteOn(byte channel, byte number, byte value) { // channel, note, velocity

}
 
 
void handleNoteOff(byte channel, byte number, byte value) { // channel, note, velocity
 
}

 

Go Up