joshnishikawa / MIDIcontroller

A library for creating Teensy MIDI controllers with support for hold or latch buttons, potentiometers, encoders, capacitive sensors, Piezo transducers and other velocity sensitive inputs with aftertouch.
223 stars 19 forks source link

Encoder count limit? #17

Closed jabberwalky1 closed 2 years ago

jabberwalky1 commented 2 years ago

Forgive the likely noob question, but I'm using your library for a box that controls FX sends.

My misunderstanding of encoders is this. When the encoder is turned past the range of CC (127 in this case), it keeps track of these turns. Oftentimes it means (that many turns beyond 127) counter-clockwise turns are required to start sending negative CC values. Is there a way to stop it from counting beyond the CC range? So it begins counting down immediately from a counter-clockwise turn, and vice versa?

Thanks!

joshnishikawa commented 2 years ago

I think Teensy's Encoder class has a range of -9999 to 9999 but you can set the value to anything using myEncoder.write(myValue). The MIDIenc class keeps track of its own value. It reads the value of the Encoder only until it detects a -1 or 1. Then it increments or decrements the MIDIenc value until it reaches 0 or 127 and then writes the Encoder back to 0. If the MIDIenc value is 0, negitive Encoder values are ignored and if the MIDIenc value is 127, positive Encoder values are ignored. So, to answer your question, it already does this so that you don't have to keep turning the knob.

You can also pass PER_DETENT as a 4th argument to the MIDIenc constructor. That will read Encoder values from -4 to 4 before writing back to 0. This allows you to increment or decrement one MIDI value per detent (if your encoder has detents).

jabberwalky1 commented 2 years ago

Ahh ok thank you Josh. I'm understanding what you mean I think.

The problem I'm encountering is that I'm using the encoders in a banked situation. So Bank A changes certain CC values, and Bank B changes other values. So if I was to increase the encoder in Bank A, then switch to bank B, the encoder is still at that value from A. Is there a way to reset the encoder somehow? I tried myEnc.write();, but it said that it has "no member".

I'd ideally like to stop the encoder from remembering how many turns it goes beyond the CC range 0,127. I'd like it to hit 127, then if any turns beyond that are ignored, so a counter-clockwise turn would immediately decrease the CC values.

Thank you for your help!!

joshnishikawa commented 2 years ago

Well, there is a small problem and a big problem. The small problem is that the new PER_DETENT thing simply wasn't implemented correctly. Before my previous comment, I made the noob mistake of testing on a device that was using a previous version of the library. I've fixed it (again) and tested it properly. Please update to version 2.4.3 and encoders should work as expected provided they each have their own set of pins.

This is the where the big problem lies. I believe the same set of pins on the Teensy can only ever be attached to a single Encoder object. Each time you create a new MIDIenc, it attaches a new Encoder object to those pins overwriting the previous one. So, only the most recently instantiated MIDIenc will work. This is a limitation of the Encoder class (not the MIDIenc class) and is beyond my ability to change. If you can figure out a hack, let me know.

As for myEnc.write(), if myEnc is a MIDIenc object, it wouldn't have worked because that class didn't have a write() function. But since you mentioned it, I thought it would be useful to have one. Now you can call myEnc.write(32) for example and it will set the encoder's value to 32 and send a NOTE ON message of 32 for whatever CC and channel meEnc is set to.

#include "MIDIcontroller.h"

byte MIDIchannel = 5;

const int encPinA = 12;
const int encPinB = 11;
const int buttonPin = 10;
MIDIenc myEnc(encPinA, encPinB, 24);
Bounce myButton = Bounce(buttonPin, 50);

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

void loop(){
  myEnc.send();
  myButton.update();
  if ( myButton.fallingEdge() ){
    myEnc.write(32);
  }

// This prevents crashes that happen when incoming usbMIDI is ignored.
  while(usbMIDI.read()){}

// Also uncomment this if compiling for standard MIDI
//  while(MIDI.read()){}
} 

I also made PER_DETENT the default because it's less erratic and probably more useful to more people.

jabberwalky1 commented 2 years ago

Wow! Thank you Josh! Your changes have corrected the errors perfectly! I also am enjoying the ability to write a value to the encoder. I may forego the idea of bankable encoders, and just implement a knob per function in my design to get around the pin limitations. Thanks again for the wonderful library!

joshnishikawa commented 2 years ago

Thanks for the bug report and the idea for the write() function!