tttapa / Control-Surface

Arduino library for creating MIDI controllers and other MIDI devices.
GNU General Public License v3.0
1.24k stars 139 forks source link

How to stop sending midi information while inside a function? #114

Open kevinagnes opened 4 years ago

kevinagnes commented 4 years ago

How are you, Tttapa?

I am working in a DIY midi controller with ten encoders. Each encoder when clicked/double-clicked/held change its CC value for a couple of seconds (this covers an EQ with freq/Gain/Q/On/Off controls). In addition, when I press another button, I change the behaviour entirely with a Program Change (using a bankable shared encoder class) employing the enable/disable function to control the DAW.

The problem is when I press the button: it sends to the new encoder control the last encoder value (sometimes, messing up the EQ slightly). One thing I think could help is to stop all midi sends until the enable/disable function is complete.

Bank<4> bank0 = {1};
Bank<4> bank1 = {1}; 
Bank<4> bank2 = {1}; 
Bank<4> bank3 = {1}; 
Bank<4> bank4 = {1}; 
Bank<4> bank5 = {1}; 
Bank<4> bank6 = {1}; 
Bank<4> bank7 = {1}; 
Bank<4> bank8 = {1}; 
Bank<4> bank9 = {1};
Bank<4> bank[10] = {bank0,bank1,bank2,bank3,bank4,bank5,bank6,bank7,bank8,bank9};      

Encoder enc0(23,22), 
        enc1(25,24),
        enc2(27,26),
        enc3(29,28),
        enc4(31,30),
        enc5(33,32),
        enc6(35,34),
        enc7(37,36),
        enc8(39,38),
        enc9(41,40);

Bankable::BorrowedCCRotaryEncoder encEQ[] = 
{
  {{bank[0], BankType::CHANGE_ADDRESS},enc0, {ccEnc[0],CHANNEL_1}, 2, 4,}, // Low Cut    (Freq,Gain,Q,OnOff)
  {{bank[1], BankType::CHANGE_ADDRESS},enc1, {ccEnc[1],CHANNEL_1}, 2, 4,}, // Low Shelf  (Freq,Gain,Q,OnOff)
  {{bank[2], BankType::CHANGE_ADDRESS},enc2, {ccEnc[2],CHANNEL_1}, 2, 4,}, // Peak 1     (Freq,Gain,Q,OnOff)
  {{bank[3], BankType::CHANGE_ADDRESS},enc3, {ccEnc[3],CHANNEL_1}, 2, 4,}, // Peak 2     (Freq,Gain,Q,OnOff)
  {{bank[4], BankType::CHANGE_ADDRESS},enc4, {ccEnc[4],CHANNEL_1}, 2, 4,}, // Peak 3     (Freq,Gain,Q,OnOff)
  {{bank[5], BankType::CHANGE_ADDRESS},enc5, {ccEnc[5],CHANNEL_1}, 2, 4,}, // Peak 4     (Freq,Gain,Q,OnOff)
  {{bank[6], BankType::CHANGE_ADDRESS},enc6, {ccEnc[6],CHANNEL_1}, 2, 4,}, // High Shelf (Freq,Gain,Q,OnOff)
  {{bank[7], BankType::CHANGE_ADDRESS},enc7, {ccEnc[7],CHANNEL_1}, 2, 4,}, // High Cut   (Freq,Gain,Q,OnOff)
  {{bank[8], BankType::CHANGE_ADDRESS},enc8, {ccEnc[8],CHANNEL_1}, 2, 4,}, 
  {{bank[9], BankType::CHANGE_ADDRESS},enc9, {ccEnc[9],CHANNEL_1}, 2, 4,},   
}; 

Bankable::BorrowedCCRotaryEncoder encGENERAL[] = 
{
  {{bank[0], BankType::CHANGE_CHANNEL}, enc0, {1, CHANNEL_1}, 2, 4,},
  {{bank[1], BankType::CHANGE_CHANNEL}, enc1, {2, CHANNEL_1}, 2, 4,},
  {{bank[2], BankType::CHANGE_CHANNEL}, enc2, {3, CHANNEL_1}, 2, 4,},
  {{bank[3], BankType::CHANGE_CHANNEL}, enc3, {4, CHANNEL_1}, 2, 4,},
  {{bank[4], BankType::CHANGE_CHANNEL}, enc4, {5, CHANNEL_1}, 2, 4,},
  {{bank[5], BankType::CHANGE_CHANNEL}, enc5, {6, CHANNEL_1}, 2, 4,},
  {{bank[6], BankType::CHANGE_CHANNEL}, enc6, {7, CHANNEL_1}, 2, 4,},
  {{bank[7], BankType::CHANGE_CHANNEL}, enc7, {8, CHANNEL_1}, 2, 4,},
  {{bank[8], BankType::CHANGE_CHANNEL}, enc8, {9, CHANNEL_1}, 2, 4,},
  {{bank[9], BankType::CHANGE_CHANNEL}, enc9, {10, CHANNEL_1}, 2, 4,},   
};

for (int j=0;j<8;j++) // CHANGE BANKS (Mainly for EQ)
  {
    if (bValue[j]==(ClickEncoder::Clicked)) 
    {
      toggle[j] = !toggle[j];
      bank[j].select(toggle[j]);
      timer[j] = millis(); 
      timerToggle[j] = 1;
    }

    if (bValue[j]==(ClickEncoder::DoubleClicked))
    {     
      bank[j].select(2);
      timer[j] = millis();   
      timerToggle[j] = 1;          
    }

    if (bValue[j]==(ClickEncoder::Held))
    {   
      bank[j].select(3);  
      timer[j] = millis()-timeBackToBankZero/4; 
      timerToggle[j] = 1;
    } 

    if ((millis()-timer[j])>timeBackToBankZero && timerToggle[j]==1) 
    {
      toggle[j] = 0;
      bank[j].select(toggle[j]);  
      timerToggle[j] = !timerToggle[j];   
    } 
  }

void programChange()
{
for (int r=0;r<10;r++)
    {
     if (encGENERAL[r].isEnabled())
     {
        encGENERAL[r].disable();
        encEQ[r].enable();
     }
     else
     {
        encEQ[r].disable();
        encGENERAL[r].enable();
     }
    } 
}
tttapa commented 4 years ago

If I understand your problem correctly, I think you should be able to solve it by resetting the offset of the encoders before enabling them:

    if (encGENERAL[r].isEnabled())
     {
        encGENERAL[r].disable();
        encEQ[r].resetPositionOffset();
        encEQ[r].enable();
     }
     else
     {
        encEQ[r].disable();
        encGENERAL[r].resetPositionOffset();
        encGENERAL[r].enable();
     }
kevinagnes commented 4 years ago

Thanks for the reply, I will try tonight! :)

kevinagnes commented 4 years ago

I got the following compilation error: class CS::Bankable::BorrowedCCRotaryEncoder has no member named resetPositionOffset.

I am using the 'Control-Surface-share-encoder' branch slightly modified. src.zip

any tips?

tttapa commented 4 years ago

The function was added here: https://github.com/tttapa/Control-Surface/commit/3daf72f0ea9ac14dc41d66a5eb3a8447f0e78aa8#diff-5dbec93aa57b14937e2b5f6981df46ebR55

You'll probably have to add it to the bankable version yourself.

kevinagnes commented 4 years ago

Thanks Pieter, I managed to get it working by editing the file _MIDIOutputs/Bankable/Abstract/MIDIRotaryEncoder.hpp adding the function: void resetPositionOffset() { previousPosition = encoder.read(); } to the class GenericMIDIRotaryEncoder.

Now, the code compiles and it works how it should.