Better way to do button triggered sounds?

I'm admittedly not a really good programmer. So let me explain what I'm trying to do, because I feel like there has to be a better way than how I'm doing it now.
I built my son (almost 2) a "blast off board" basically a project box with a bunch of buttons and toggles and LEDs on it. Nine of the buttons are momentary, arcade button style, and I want them to play different beep sounds. And four of those buttons will play a dual-tone beep. So, assuming he pushes the button for just a tap, it'll play the full quarter note beep (and this much I've accomplished, though I'm using delays, and that could get hairy, more on that later). However, with my current code, if you hold down the button, it plays the quarter note beep over and over again. I would like for it to only beep once even if the button is held down, and then reset on release so the next press will beep once again. Here's the Fritzing diagram:

And here's the current code (I've slimmed it down to just 2 buttons because that gets the idea across):

/*
  Button Beep
*/

#include "pitches.h"

int b1pin = 0;   // choose the input pin (for a pushbutton)
int b1val = 0;     // variable for reading the pin status
int b2pin = 1;
int b2val = 0;
int b3pin = 2;
int b3val = 0;
int b4pin = 3;
int b4val = 0;
int b5pin = 4;
int b5val = 0;
int b6pin = 5;
int b6val = 0;
int b7pin = 6;
int b7val = 0;
int b8pin = 7;
int b8val = 0;
int b9pin = 8;
int b9val = 0;


int speakerpin = 9; // speaker connected to this pin and ground

void setup() {
  pinMode(b1pin, INPUT_PULLUP);  // declare pushbuttons as input
  pinMode(b2pin, INPUT_PULLUP);
}

void loop() {
  b1val = digitalRead(b1pin);
  if (b1val == LOW) {
    tone(speakerpin, NOTE_C6, 125);
    delay(125);
    tone(speakerpin, NOTE_B5, 125);
    delay(500);
  } 
  else {
    noTone(speakerpin);
  }

  b2val = digitalRead(b2pin);
  if (b2val == LOW) {
    tone(speakerpin, NOTE_CS6, 250);
    delay(500);
  } 
  else {
    noTone(speakerpin);
  }
}

The included pitches.h defines a long list of NOTE_ stuff, for example: #define NOTE_C6 1047.

Now, earlier I had mentioned my worry with delay(), and that's because once I get this working, I'm adding some rotary encoder code I've already finished that lights up a row of LEDs one at a time as you turn the knob. With a series of delays in button presses, the rotary encoder might not be read if turned right after a button press. Although, I can live with that so long as I can get the "beep once" issue resolved.

Thanks for any input, I really appreciate it (and so does my son)!

1 Like

There is a much easier way, with no programming required. You can get a DFplayer Mini board on eBay very cheaply. Record the notes or other sound effects, explosions, animal noises, whatever you like, onto a micro-SD card in MP3 format using your PC. Then insert the SD card into the player. Attach up to 14 buttons to play 14 sounds/tracks directly. The board can drive a small speaker directly, giving a much louder and better quality sound than you can get from an Arduino pin.

$_1 (4).JPG

$_1 (4).JPG

Hmm... That's kinda cool actually. I don't think I'll be able to get that in time to put it all together for Christmas, but the beep / delay code will suffice until it shows up. Thanks for the heads up.