Button State Switching

Status
Not open for further replies.
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.
 
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
        

        }

        
      
       
        }
        

        
}
}
 
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);
			}
		}
[COLOR="#FF0000"]		msec = 0;
		state = 2;[/COLOR]
		return;
 
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.
 
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.
 
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).
 
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
        

      }    
    }    
  }
 
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.
 
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
 
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;
}
 
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");
                        [COLOR="#FF0000"]// this is where it was... [/COLOR]
			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{			[COLOR="#FF0000"]//this is where it only happens with no mods[/COLOR]
[COLOR="#005500"]					pgcNum++;
					if (pgcNum > 127) {
						pgcNum = 127
					}[/COLOR]
				}
			}
			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.
 
Status
Not open for further replies.
Back
Top