Relative rotary encoders & Control_Surface.h Help Needed

My current project is a row of 8 relative rotary encoders passing MIDI to my DAW, I have been using the brilliant Control_Surface.h library by Pieter P.

All is working well, but I have come to need a variation in the optional multiplier control, and I don’t understand how to implement the change required.
Rather than have a fixed multiplier rate, I wish to press a toggle button to choose between a fast rate, and a slow one. As some instances require more detail when using, but become cumbersome in general use.

The Arduino is currently the Uno using Hairless MIDI as the serial bridge.

The code below is a quick shortening of the actual code used, as it is the principle required that I’m most interested in.

Thanks in advance :smiley:

#include <Encoder.h>   // This must be done before the Control Surface library.
#include <Control_Surface.h>     // Include the Control Surface library
HairlessMIDI_Interface midi;


const int encbut1 = 10;  // button to trigger action
int encbutval = 5;       // starting value

CCRotaryEncoder enc = {

  {3, 2},       // pins
  MCU:: V_POT_1, // MIDI address (CC number + optional channel)
  encbutval,    // this is the multiplier variable I would like to control 
};


// Variables to debounce Rotary Encoder
long TimeOfLastDebounce = 0;
int DelayofDebounce = 0.01;

void setup() {

  RelativeCCSender::setMode(relativeCCmode::TWOS_COMPLEMENT);
  Control_Surface.begin();
  Serial.begin(115200);

  pinMode(encbut1, INPUT_PULLUP);

}

void loop() {

  Control_Surface.loop(); // Update the Control Surface

  // If enough time has passed check the rotary encoder
  if ((millis() - TimeOfLastDebounce) > DelayofDebounce) {
    TimeOfLastDebounce = millis(); // Set variable to current millis() timer

  }
      if (digitalRead(encbut1) == LOW) {  // button press detection
    encbutval = 1; //change of value
    
  }
}
    encbutval = 1; //change of value

Changing the value of the variable won't help when what you want to change is the field in the 'enc' structure. That field has a name (see the declaration of "CCRotaryEncoder") and using that name you can say:

    enc.name = 1;

Thanks, John for the reply

Unfortunately, although I’m sure you are correct, I could not make this work.
Maybe it’s my handling of the function, or my syntax? Either way, the closest I could get to anything was:

#include <Encoder.h>   // This must be done before the Control Surface library.
#include <Control_Surface.h>     // Include the Control Surface library
HairlessMIDI_Interface midi;


const int encbut1 = 10;  // button to trigger action
int speedMultiply  = 5;       // starting value

CCRotaryEncoder enc = {

  {3, 2},       // pins
  MCU:: V_POT_1, // MIDI address (CC number + optional channel)
  speedMultiply ,    // this is the multiplier variable I would like to control 

};


// Variables to debounce Rotary Encoder
long TimeOfLastDebounce = 0;
int DelayofDebounce = 0.01;

void setup() {

  RelativeCCSender::setMode(relativeCCmode::TWOS_COMPLEMENT);
  Control_Surface.begin();
  Serial.begin(115200);

  pinMode(encbut1, INPUT_PULLUP);

}

void loop() {



  Control_Surface.loop(); // Update the Control Surface

  // If enough time has passed check the rotary encoder
  if ((millis() - TimeOfLastDebounce) > DelayofDebounce) {
    TimeOfLastDebounce = millis(); // Set variable to current millis() timer
  }

          if (digitalRead(encbut1) == LOW) {  // button press detection
    enc.speedMultiply  = 1; //change of value
    
  }

}

Which gives me the error:
exit status 1
‘const int8_t CS::MIDIRotaryEncoderCS::RelativeCCSender::speedMultiply’ is private within this context

Needless to say, I just don’t know where to begin to utilise this code.

Sorry but it looks like the library does not allow you to change the speedMultiply value after the object has been created. To use a different value you have to create a different object.

To work around that you would have to change the library:

Control-Surface/src/MIDI_Outputs/Bankable/Abstract/MIDIRotaryEncoder.hpp

Thank you for your comments :slight_smile:

But I think that redefining the library is currently way above my level of understanding!

Cheers for the input though :slight_smile:

It probably is not above your level. All you have to do is add a public function in the class that takes an argument and assigns it to that value.

blh64:
It probably is not above your level. All you have to do is add a public function in the class that takes an argument and assigns it to that value.

I'll get some research done, and see if I can get my head around it. :slight_smile:

It seems that this will not be the only problem I will have to try to overcome. As I have been building and coding this project, it has made me think about the next project, which would be to build a bank of 30 encoders using a Mega 2560 ( pretty much taking up all of its pins ) and as far as I can tell so far, the Control_Surface library restricts me to 8. Can anyone confirm this?

Cheers

johnwasser:
Sorry but it looks like the library does not allow you to change the speedMultiply value after the object has been created. To use a different value you have to create a different object.

To work around that you would have to change the library:

Control-Surface/src/MIDI_Outputs/Bankable/Abstract/MIDIRotaryEncoder.hpp

Indeed. OP seems to be using the non-bankable version, so the file to edit would be src/MIDI_Outputs/Abstract/MIDIRotaryEncoder.hpp.

You could do something like this:

template <class Sender>
class MIDIRotaryEncoder : public MIDIOutputElement {
  protected:
    /**
     * @brief   Construct a new MIDIRotaryEncoder.
     *
     * @todo    Documentation
     */
    MIDIRotaryEncoder(const EncoderPinList &pins,
                      const MIDIAddress &address,
                      int8_t speedMultiply, uint8_t pulsesPerStep,
                      const Sender &sender)
        : encoder{pins.A, pins.B}, address(address),
          speedMultiply(speedMultiply),
          pulsesPerStep(pulsesPerStep), sender(sender) {}

// For tests only
#ifndef ARDUINO
    MIDIRotaryEncoder(const Encoder &encoder,
                      const MIDIAddress &address,
                      int8_t speedMultiply, uint8_t pulsesPerStep,
                      const Sender &sender)
        : encoder{encoder}, address(address), speedMultiply(speedMultiply),
          pulsesPerStep(pulsesPerStep), sender(sender) {}
#endif

  public:
    void begin() final override {}
    void update() final override {
        long currentPosition = encoder.read();
        long difference = (currentPosition - previousPosition) / pulsesPerStep;
        if (difference) {
            sender.send(difference * speedMultiply, address);
            previousPosition += difference * pulsesPerStep;
        }
    }
    
    int8_t getMultiplier() const { 
        return speedMultiply; 
    }
    void setMultiplier(int8_t speedMultiply) {
        this->speedMultiply = speedMultiply; 
    }

  private:
    Encoder encoder;
    const MIDIAddress address;
    int8_t speedMultiply;
    const uint8_t pulsesPerStep;
    long previousPosition = 0;

  public:
    Sender sender;
};

I removed the const qualifier from the speedMultiply member and added a getter and setter for it.

guitarman66:
It seems that this will not be the only problem I will have to try to overcome. As I have been building and coding this project, it has made me think about the next project, which would be to build a bank of 30 encoders using a Mega 2560 ( pretty much taking up all of its pins ) and as far as I can tell so far, the Control_Surface library restricts me to 8. Can anyone confirm this?

The Control Surface library uses the PJRC Encoder library for handling encoders. You are limited by the number of interrupt pins your microcontroller has. If you use a non-interrupt pin, the Encoder library falls back to polling, which works for a small number of encoders if the CPU isn’t too busy with other things.

Here are some discussions on GitHub about expanding the number of encoders:
Encoders through multiplexer
Too many encoders on an Arduino MEGA

Pieter

Thank you Pieter... I'll look into that straight away!