Trouble with state changing and buttons

I'm making an Arduino based MIDI controller that is going to control an effect pedal.

There are 4 buttons I'm going to be controlling that vary what they do depending on the state of the button.

For example, button1 is either record or overdub. button2 is play or stop. And they are codependent. If button2 is playing and I press button1 it goes into overdub instead of record.

Ok, that's the basic code requirement.

Before my horrible state changing logic code, I'm also having a hard time managing debounce for multiple (4) switches. I stuck some debounce code into each 'if' of the loop. Is that the best place to put debounce delay?
In the code below its debounce1 (and current 40ms). "debounce" is for the 4way button code below it all that isn't in use yet.

I've separated each possible function into its own 'if' loop, so I can troubleshoot and eventually add LED functionality too, without having to sift through 'elses' (I'm still new to coding).

When I start the code up, it almost works once, but then I think I break the state logic and nothing works anymore.

SWITCH1, SWITCH2, and SWITCH3 are the only buttons I'm using at the moment, and I'm using 2 variables for state changing.
state1 is for notrecording(0),recording(1), or overdubbing(2), and state2 is for not playing(0), and playing(1).

What am I doing wrong here?

// ======= SWITCHES
#define SWITCH1 8             // record/overdub
#define SWITCH2 9             // play/stop
#define SWITCH3 10            // play once

// ======= STATE variables
int val1 = 0;                 // record/overdub button press
int val2 = 0;                 // play/stop button press
int val3 = 0;                 // play once button press
int state1 = 0;               // state of notrecording(0),record(1),overdub(2)
int state2 = 0;               // state of stop(0),play(1)

// ======= TIMING variables
int debounce1 = 40;           // ms debounce for record/overdub/play/stop switches

//=================================================

void setup() 
{
// ======= BUTTONS
pinMode(SWITCH1, INPUT);         // record/overdub
pinMode(SWITCH2, INPUT);         // play/stop
pinMode(SWITCH3, INPUT);         // play once

// ======= MIDI
Serial.begin(31250);
}

//=================================================

void loop()
{
// Get Switch Values
val1 = digitalRead(SWITCH1); // record/overdub button press
val2 = digitalRead(SWITCH2); // play/stop button press
val3 = digitalRead(SWITCH3); // play once button press

// ======= RECORD NEW LOOP
if ((val1 == HIGH) && (state1 == 0) && (state2 == 0)) {
  state1 = 1;
  Serial.print(0xb0,BYTE);
  Serial.print(50,BYTE);
  Serial.print(127,BYTE);
  delay(debounce1);
}

// ======= OVERDUB (FROM RECORD STATE)
if ((val1 == HIGH) && (state1 == 1) && (state2 == 0)) {
  state1 = 2;
  state2 = 1;
  Serial.print(0xb0,BYTE);
  Serial.print(50,BYTE);
  Serial.print(0,BYTE);
  delay(debounce1);
}

// ======= OVERDUB (TO PLAY STATE)
if ((val1 == HIGH) && (state1 == 2) && (state2 == 1)) {
  state1 = 0;
  Serial.print(0xb0,BYTE);
  Serial.print(50,BYTE);
  Serial.print(0,BYTE);
  delay(debounce1);
}

// ======= OVERDUB (FROM PLAY STATE)
if ((val1 == HIGH) && (state1 == 0) && (state2 == 1)) {
  state1 = 2;
  Serial.print(0xb0,BYTE);
  Serial.print(50,BYTE);
  Serial.print(0,BYTE);
  delay(debounce1);
}

// ======= PLAY
if ((val2 == HIGH) && (state2 == 0)) {
  state2 = 1;
  Serial.print(0xb0,BYTE);
  Serial.print(28,BYTE);
  Serial.print(127,BYTE);
  delay(debounce1);
}

// ======= STOP
if ((val2 == HIGH) && (state2 == 1)) {
  state2 = 0;
  Serial.print(0xb0,BYTE);
  Serial.print(28,BYTE);
  Serial.print(0,BYTE);
  delay(debounce1);
}

// ======= PLAY ONCE
if (val3 == HIGH) {
  Serial.print(0xb0,BYTE);
  Serial.print(80,BYTE);
  Serial.print(127,BYTE);
  delay(debounce1);
}

Any reason for not using the button library?

No?

Would the button library help here?
And which button library, theres several of them isn't there?

I am trying to go 'library free' as I'm going to make the code openly available to people so they can make their own version of the MIDI pedal, so the less people have to do the better. I started with a MIDI library, but figured out how to work with it directly with the Serial.print.

No problem if you don't want to depend on a library. But the library is available, and you can look at the source code to figure out things are done.

Looked through the library and it's kind of confusing.

If I copy/paste the contents of the .h and .cpp files into the bottom of the code, would that function the same as having installed the library?

It took a bit of work to avoid using the MIDI library, it would suck to jump right into another library.

Is there a better way than using delay(20) in the 'if' loop other than using a library?

The delay(20) is delaying 20 microseconds. That's like the blink of an eye. I that causing problems for you?

The delay(20) is delaying 20 microseconds.

The delay(20) is delaying 20 milliseconds, one thousand times longer than 20 microseconds. Still short (a 50th of a second).

I tried up to 80ms at some point and was still getting some crappy switching (those tiny breadboard switches). I'm eventually going to wire it with some large/sturdy momentaries, but I was trying to sort out the code first.

Is the debounce code just fancy delay(), while keeping track of button state?

What happens when a switch is pressed, or released? There is a mass of material that is pushed about, with a spring to return the mass of material when the activator is released. There are contacts on the base of the switch and on the movable part. Contact and release is not instantaneous and complete. Contact may be made and broken many times as a switch is pressed.

To assure that the switch press or release is only counted once, you wait a short period of time after first learning of contact or release, and then check again to see if contact is still being made, or still not being made.

The delay statement is how that waiting is done. Typically, 20 milliseconds is plenty of time for the bouncing to die out.

I'll test my code some more but with 'real' buttons, as these things were freaking out like crazy.

Edited.

I didn't realize that was offensive.

People freak out. Switches behave rationally. If the switch is not behaving in the fashion you expect, perhaps it's your code that is at issue. It might be time to post your code.

My code is in the first post (I edited out the irrelevant bits).

When the Arduino resets, loop is called.

If no buttons are pressed, nothing happens, and loop gets called again.

You press button 3. 0xB0, 80, and 127 are written to the serial port, a 40 millisecond delay occurs, and loop is called again.

Unless you are very fast, your finger is still on button 3, so 0xB0, 80, and 127 are written to the serial port, a 40 millisecond delay occurs, and loop is called again.

This happens over and over until you get your finger off the button.

That's not exactly what I think of as "Play Once", whatever that means.

No buttons are pressed, so loop runs a few million times, doing nothing.

You press button 1. val1 is HIGH, and state1 and state2 are 0, so state1 is set to 1, 0xB0, 50, and 127 are written to the serial port, and a 40 millisecond delay occurs.

Now, val1 is HIGH, state1 is 1 and state2 is 0, so state1 is set to 2, state1 is set to 1, 0xB0, 50, and 0 are written to the serial port, and a 40 millisecond delay occurs.

Now, val1 is HIGH, state1 is 2 and state2 is 1, so state1 is set to 0, 0xB0, 50, and 0 are written to the serial port, and a 40 millisecond delay occurs.

Now, val1 is HIGH, state1 is 0, and state2 is 1, so state1 is set to 2, 0xB0, 50, and 0 are written to the serial port, and a 40 millisecond delay occurs.

Now, val1 is HIGH, state1 is 2, and state2 is 1, and 160 milliseconds (about 1/6 of a second) have elapsed.

No other buttons are pressed, so loop ends, and is called again.

If your finger is still on button 1, val1 is HIGH, state1 is 2 and state1 is 1, so state1 is set to 0, 0xB0, 50, and 0 are written to the serial port, and a 40 millisecond delay occurs.

Now, val1 is HIGH, state1 is 0, and state2 is 1, so state1 is set to 2, 0xB0, 50, and 0 are written to the serial port, and a 40 millisecond delay occurs.

Does this story, so far, match what you are expecting to have happen?

Yeah that makes sense about the 'play once' (it restarts the current audio loop from the beginning and plays it once).

In order to manage that should I add state changes to that? So when I press the button it sets a value 1, if the value is currently 0,it sends the serial data, but if the value is still 1 when it senses the button is still pressed, nothing happens. When the button is released, it sets the state to 0, and is ready for a new press.

As for the rest, my state changes, I'm sure, are part of the problem as to why it's not working right. So I'll try to restate what the functions are.

There are 2 main buttons, each serve dual functions. Button 1 does record and overdub, button 2 does play and stop.

If nothing is happening, pressing button1 sends a record message, and creates a new loop. If that button is pressed again, it sends an overdub message, which also lights up the LED associated with the play function (no LEDs in mine yet). If the first button is pressed yet again, it turns off overdub and goes into regular play mode. If I press button 2 while the loop is playing, or overdubbing, it stops the loop. If I press button 2 while it is simply recording, it goes directly into play mode, with no overdub.
Once a loop has been recorded, if nothing is happening and button 2 is pressed, the last loop begins playing back.

So its 2 multi function buttons that are somewhat tied together.

I tried managing that with 2 sets of state changes (it started off as boolean, but I went to regular ints as I thought I needed 3 states for button one).

I think part of whats going wrong is my debounce coding. When I press the button, the loop runs again before I pick my finger up, and it changes states into 'impossible' ones, so that no button press after that will satisfy the criteria for the 'if loops'.

You are mixing button state changes with debouncing. They are related, in that when the button is bouncing, the state is changing frequently. The delay function causes the state of the button not to be read so frequently, but it does nothing about the "I want something to happen only once when the button is pressed, no matter how long it is held down" problem that seems to be the root of your problem.

AlphaBeta contributed a very nice button library.
http://www.arduino.cc/playground/Code/Button

The library has a method, uniquePress(), that will return true only once when the button is pressed, no matter how long it is held down.

I'd strongly encourage you to use this library, so you can concentrate on the functionality you want to provide, without having to worry about button states and debouncing.

I probably am confusing states and bouncing, but the bouncing problems I'm having is complicating the state changes I'm managing too.

That library looks good. I saw another button library that was more debounce based.

Is it possible to 'de-library' code after the fact? Like, can I code everything using the library, then when I'm done, convert it to a self-standing version of the code?

The main reason is that I'd want to do that is that this would be something others would want to do (add functionality to this certain guitar pedal). So I plan on doing a guide/writeup so people can do this on their own. Installing libraries is a bit more complicated than setting up the Arduino environment.

I think that you really should approach this a little differently. Make free use of the libraries. Get your program working. Get a product that you can demonstrate, that people will want.

Then, put some instructions together for someone else to install the IDE, your sketch, and dependent libraries. Get someone to follow the instructions. If they are successful, you're done.

If not, discuss with your victim whether the instructions need improving or if the number of libraries that need to be installed needs to be reduced.

Only if you decide that removing all libraries is needed should you revise your code. Fortunately, this won't be all that hard, since a library consists of a header file and the source file, so you can see how a library did what it is you needed it to do.

I'll go that route.

It just took a while to figure out how to ditch the MIDI library, the main thing I thought I was going to need a library for, so it sucks to have to use a library for something that's 'seemingly' simple. Although I'm sure it's more complicated than I think, which is why my code isn't working right.