Forum Rule: Always post complete source code & details to reproduce any issue!
Page 2 of 2 FirstFirst 1 2
Results 26 to 37 of 37

Thread: Button State Switching

  1. #26
    Senior Member oddson's Avatar
    Join Date
    Feb 2013
    Location
    Isle in the Salish Sea
    Posts
    1,318
    You're in the default case ...where you would send note off if you are also sending note values under case 1.

    Case 1 is where the note event in Paul's method is sent. It's where you have identified that a hit occurred.

  2. #27
    Member
    Join Date
    Nov 2019
    Location
    Johnson City TN
    Posts
    28
    Ooooops !!!


    Still chiseling away ... hopefully things are at least in the right case.


    Code:
    // ControlPad Message WIP
    
    
    #include <Bounce.h>
    
    
    const int channel = 1;
    int ledPin = 13;
    byte pgcNum = 0; 
    const int analogPin = A0;
    const int thresholdMin = 80;  // minimum reading, avoid noise and false starts
    const int peakTrackMillis = 12;
    const int aftershockMillis = 25; // aftershocks & vibration reject
    bool Mod0 = digitalRead(0);
    bool Mod1 = digitalRead(1);
    
    
    
    Bounce button0 = Bounce(0, 5);
    Bounce button1 = Bounce(1, 5);
    
    
    void setup() {
    
      pinMode(13, OUTPUT);
      pinMode(0, INPUT_PULLUP);
      pinMode(1, INPUT_PULLUP);
      
    
    }
    
    
    void loop() {
    
    
      
      button0.update();
      button1.update();
      
    
    
    
     if (button0.fallingEdge() && pgcNum < 127) {  //FootSwitch 1
        pgcNum++;
        usbMIDI.sendProgramChange(pgcNum,channel);
        Serial.print("FSInc");
        digitalWrite(ledPin, HIGH);
        delay(10);
        digitalWrite(ledPin, LOW);
        
      }
      
    
     if (button1.fallingEdge()) { // FootSwitch 2
        usbMIDI.sendRealTime(usbMIDI.Stop);
        Serial.print("FSStop");
        digitalWrite(ledPin, HIGH);
        delay(10);
        digitalWrite(ledPin, LOW);
      }
    
      
      int piezo = analogRead(analogPin);
      peakDetect(piezo);
    
      
      while (usbMIDI.read()) {
        // ignore incoming messages
      }
    }
    
    
    void peakDetect(int voltage) {
      static int state;  // 0=idle, 1=looking for peak, 2=ignore aftershocks
      static int peak;   // remember the highest reading
      static elapsedMillis msec; // timer to end states 1 and 2
    
    
    
             switch (state) {
        // IDLE state: wait for any reading is above threshold.  Do not set
        // the threshold too low.  You don't want to be too sensitive to slight
        // vibration.
        case 0:
          if (voltage > thresholdMin) {
            peak = voltage;
            msec = 0;
            state = 1;
    
            
          }
          return;
    
        // Peak Tracking state: capture largest reading
        case 1:
    
             
          if (voltage > peak) {
            peak = voltage;    
          }
         
           
          if (msec >= peakTrackMillis && pgcNum < 127 );  {  // ControlPad
             Serial.print("PadInc");
             pgcNum++;
             usbMIDI.sendProgramChange(pgcNum,channel);
             msec = 0;
             state = 2;
    
          }
    
          if (Mod0) {
             Serial.print("PadDec");     
             pgcNum--;
             usbMIDI.sendProgramChange(pgcNum,channel);
             msec = 0;
             state = 2;
          }
    
          else {
    
          if (Mod1) {
             Serial.print("PadMidiStart");
             usbMIDI.sendRealTime(usbMIDI.Start);
             msec = 0;
             state = 2;
                  
          }
          return;
    
        // Ignore Aftershock state: wait for things to be quiet again.
          default:
          if (voltage > thresholdMin) {
            msec = 0; // keep resetting timer if above threshold
           } else if (msec > aftershockMillis) {
            state = 0; // go back to idle when
            
    
            }
    
            
          
           
            }
            
    
            
    }
    }

  3. #28
    Senior Member oddson's Avatar
    Join Date
    Feb 2013
    Location
    Isle in the Salish Sea
    Posts
    1,318
    I haven't looked at the details yet but will mention it's hard to read without the indenting being done carefully to match the braces.

    Also, you shouldn't repeat code unnecessarily. The stuff that happens in each 'if" branch can be moved until after
    Code:
    	case 1:
    
    		if (voltage > peak) {
    			peak = voltage;    
    		}
    
    
    		if (msec >= peakTrackMillis && pgcNum < 127 );  {  // ControlPad
    			Serial.print("PadInc");
    			pgcNum++;
    			usbMIDI.sendProgramChange(pgcNum,channel);
    		}
    
    		if (Mod0) {
    			Serial.print("PadDec");     
    			pgcNum--;
    			usbMIDI.sendProgramChange(pgcNum,channel);
    		}else{
    			if (Mod1) {
    				Serial.print("PadMidiStart");
    				usbMIDI.sendRealTime(usbMIDI.Start);
    			}
    		}
    		msec = 0;
    		state = 2;
    		return;

  4. #29
    Member
    Join Date
    Nov 2019
    Location
    Johnson City TN
    Posts
    28
    Understood .... I started to realize that maybe some of this code should be indented but, My knowledge of the best way to do this is next to nothing.

  5. #30
    Senior Member oddson's Avatar
    Join Date
    Feb 2013
    Location
    Isle in the Salish Sea
    Posts
    1,318
    I've only picked up something like the default style for C code and the object.model stuff from context... But as long as the eye can see what you mean it's ok.

    While the code I've posted should function like yours I don't think it's correct. We only want to reset the timer after it runs out... so it actually ONLY where msec is tested

    I think it's like this:
    Code:
    	// Peak Tracking state: capture largest reading
    	case 1:
    
    		if (voltage > peak) {
    			peak = voltage;    
    		}
    		if (msec >= peakTrackMillis && pgcNum < 127 );  {  // ControlPad
    			Serial.print("PadInc");
    			pgcNum++;
    			usbMIDI.sendProgramChange(pgcNum,channel);
    			msec = 0;
    			state = 2;
    		}
    		if (Mod0) {
    			Serial.print("PadDec");     
    			pgcNum--;
    			usbMIDI.sendProgramChange(pgcNum,channel);
    		}else{
    			if (Mod1) {
    				Serial.print("PadMidiStart");
    				usbMIDI.sendRealTime(usbMIDI.Start);
    			}
    		}
    		return;
    The indent is exaggerated not for your benefit but from my text editor. But this example does show the importance of indent - especially in C where the lack of 'end if' and the braces everywhere can get visually confusing.

  6. #31
    Senior Member oddson's Avatar
    Join Date
    Feb 2013
    Location
    Isle in the Salish Sea
    Posts
    1,318
    STOP! -- this is just wrong... the Mod0 and Mod1 code will test every time the averaging section of the code is run...

    You really only want to fire stuff from exactly where it was in Paul's code... with the msec test...

    Code:
    	// Peak Tracking state: capture largest reading
    	case 1:
    
    		if (voltage > peak) {
    			peak = voltage;    
    		}
    		if (msec >= peakTrackMillis && pgcNum < 127 );  {  // ControlPad
    			Serial.print("PadInc");
    			pgcNum++;
    			usbMIDI.sendProgramChange(pgcNum,channel);
    			if (Mod0) {
    				Serial.print("PadDec");     
    				pgcNum--;
    				usbMIDI.sendProgramChange(pgcNum,channel);
    			}else{
    				if (Mod1) {
    					Serial.print("PadMidiStart");
    					usbMIDI.sendRealTime(usbMIDI.Start);
    				}
    			}
    			msec = 0;
    			state = 2;
    		}
    		return;
    More like this but you might want the increment to fire only if the others don't?

    If that's what you want then I think you would add an 'else' inside the nested conditional after testing Mod1 (for the False case, and since it's nested it would mean Mod0 was False too).

  7. #32
    Member
    Join Date
    Nov 2019
    Location
    Johnson City TN
    Posts
    28
    Thank Oddson,


    I've added your adjustments to the code ... I've also changed the Serial print messages so they read better and print to single lines.
    For some reason, I have yet to get the code to recognize the Footswicth Presses. Mod0 - press and hold = PGC Dec when the Pad is Struck Mod1 -press and hold = Midi Start when the pad is struck. Below is the entire code with our adjustments so far.


    Code:
    // ControlPad Message WIP
    
    
    #include <Bounce.h>
    
    
    const int channel = 1;
    int ledPin = 13;
    byte pgcNum = 0; 
    const int analogPin = A0;
    const int thresholdMin = 80;  // minimum reading, avoid noise and false starts
    const int peakTrackMillis = 12;
    const int aftershockMillis = 25; // aftershocks & vibration reject
    bool Mod0 = digitalRead(0);
    bool Mod1 = digitalRead(1);
    
    
    
    Bounce button0 = Bounce(0, 10);
    Bounce button1 = Bounce(1, 10);
    
    
    void setup() {
    
      pinMode(13, OUTPUT);
      pinMode(0, INPUT_PULLUP);
      pinMode(1, INPUT_PULLUP);
      
    
    }
    
    
    void loop() {
    
    
      
      button0.update();
      button1.update();
      
      
    
    // Foot Switches
    
     if (button0.fallingEdge() && pgcNum < 127) {  //FootSwitch 1
        pgcNum++;
        usbMIDI.sendProgramChange(pgcNum,channel);
        Serial.println("FS_PGC_Inc");
        digitalWrite(ledPin, HIGH);
        delay(10);
        digitalWrite(ledPin, LOW);
        
      }
      
    
     if (button1.fallingEdge()) { // FootSwitch 2
        usbMIDI.sendRealTime(usbMIDI.Stop);
        Serial.println("FS_MidiStop");
        digitalWrite(ledPin, HIGH);
        delay(10);
        digitalWrite(ledPin, LOW);
      }
    
      
      int piezo = analogRead(analogPin);
      peakDetect(piezo);
    
     
      
      // ControlPad
    
    
      
      while (usbMIDI.read()) {
        // ignore incoming messages
      }
    }
    
    
    void peakDetect(int voltage) {
      static int state;  // 0=idle, 1=looking for peak, 2=ignore aftershocks
      static int peak;   // remember the highest reading
      static elapsedMillis msec; // timer to end states 1 and 2
    
    
    
             switch (state) {
        // IDLE state: wait for any reading is above threshold.  Do not set
        // the threshold too low.  You don't want to be too sensitive to slight
        // vibration.
    
        
                        case 0:
                        
                        if (voltage > thresholdMin) {
                          peak = voltage;
                          msec = 0;
                          state = 1;
                   
                          }
                          return;
            
                // Peak Tracking state: capture largest reading
                         case 1:
              
                 if (voltage > peak) {
                    peak = voltage;    
                  }
                  if (msec >= peakTrackMillis && pgcNum < 127 );  {  // ControlPad
                    Serial.println("Pad_PGC_Inc");
                    pgcNum++;
                    usbMIDI.sendProgramChange(pgcNum,channel);
                    if (Mod0 && pgcNum >= 1 ) {
                      Serial.println("Pad_PGC_Dec");     
                      pgcNum--;
                      usbMIDI.sendProgramChange(pgcNum,channel);
                    }else{
                      if (Mod1) {
                        Serial.println("Pad_MidiStart");
                        usbMIDI.sendRealTime(usbMIDI.Start);
                      }
                    }
                    msec = 0;
                    state = 2;
                  }
                  return;
          
        
    
        // Ignore Aftershock state: wait for things to be quiet again.
          default:
          if (voltage > thresholdMin) {
            msec = 0; // keep resetting timer if above threshold
           } else if (msec > aftershockMillis) {
            state = 0; // go back to idle when
            
    
          }    
        }    
      }

  8. #33
    Senior Member oddson's Avatar
    Join Date
    Feb 2013
    Location
    Isle in the Salish Sea
    Posts
    1,318
    Well at some point there's bound to be a bit of debugging and some error is likely to be in my code too... (usually my code doesn't compile without a bunch tweaks and add-semi-colons).

    I could try to build a test rig with a pot standing in for the rectified piezo values (will work even though the signal is completely different) but in all honesty I'm not likely to get to it for a while... I have a few minutes here or there to check in on the internet but I'm not really able to track down problems.

    I've been meaning to say... you may want to rethink using 'and' with pgcNum constraint. Once the constraint is passed it cannot reset the timer.

    You likely want another test just around the increment lines... or if you move it to the nested 'else' as suggested that would work too.

  9. #34
    Member
    Join Date
    Nov 2019
    Location
    Johnson City TN
    Posts
    28
    Hey Oddson .. Understood .. I am constantly debugging and experimenting. The IDE helps me a lot when there is an error and gives me a clue to what might be missing. I really do appreciate the time you've given me. But I also understand that your time is limited. I'm certainly open to changing the "and" with the pgcNum.
    It's really only there to avoid wrapping at the top and bottom values and keep track of the pgcNum Value. It's the first thing I came up with that seemed to work early on with the foot switches. .. I will keep hammering away at things. and try and add the nested else.

    Kind Regards,

    Chris

  10. #35
    Senior Member oddson's Avatar
    Join Date
    Feb 2013
    Location
    Isle in the Salish Sea
    Posts
    1,318
    It's really only there to avoid wrapping at the top and bottom values and keep track of the pgcNum Value.
    Then it really should not be added to an existing and crucial test.

    You should spit it off as I believe it will interfere with functionality when the counter is at max.

    Code:
    pgcNum++
    if (pgcNum >= 128){
      pgcNum = 127;
    }

  11. #36
    Senior Member oddson's Avatar
    Join Date
    Feb 2013
    Location
    Isle in the Salish Sea
    Posts
    1,318
    Code:
    void peakDetect(int voltage) {
      static int state;  // 0=idle, 1=looking for peak, 2=ignore aftershocks
      static int peak;   // remember the highest reading
      static elapsedMillis msec; // timer to end states 1 and 2
    
    
    
    	switch (state) {
        // IDLE state: wait for any reading is above threshold.  Do not set
        // the threshold too low.  You don't want to be too sensitive to slight
        // vibration.
    
    
    	case 0:
    
    		if (voltage > thresholdMin) {
    			peak = voltage;
    			msec = 0;
    			state = 1;
    
    		}
    	  return;
    
    	// Peak Tracking state: capture largest reading
    	case 1:
    
    		if (voltage > peak) {
    			peak = voltage;
    		}
    		if (msec >= peakTrackMillis );  {  
    			Serial.println("Pad_PGC_Inc");
                            // this is where it was... 
    			usbMIDI.sendProgramChange(pgcNum,channel);
    			if (Mod0 && pgcNum >= 1 ) {
    				Serial.println("Pad_PGC_Dec");
    				pgcNum--;
    				usbMIDI.sendProgramChange(pgcNum,channel);
    			}else{
    				if (Mod1) {
    					Serial.println("Pad_MidiStart");
    					usbMIDI.sendRealTime(usbMIDI.Start);
    				}else{			//this is where it only happens with no mods
    					pgcNum++;
    					if (pgcNum > 127) {
    						pgcNum = 127
    					}
    				}
    			}
    			msec = 0;
    			state = 2;
    		}
    		return;
    
    
    
    	// Ignore Aftershock state: wait for things to be quiet again.
    	default:
    		if (voltage > thresholdMin) {
    		msec = 0; // keep resetting timer if above threshold
    		} else if (msec > aftershockMillis) {
    		state = 0; // go back to idle when
    
    
    		}
    	}
    }
    This is what I think you might be after.

  12. #37
    Member
    Join Date
    Nov 2019
    Location
    Johnson City TN
    Posts
    28
    Thanks so much Oddson : ) ... I'll have a go right away !

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •