You could try something like this:
#include <Arduino_Helpers.h> // https://github.com/tttapa/Arduino-Helpers
#include <AH/Hardware/Button.hpp> // Button
#include <AH/Hardware/ExtendedInputOutput/AnalogMultiplex.hpp> // CD74HC4051
#include <AH/Containers/ArrayHelpers.hpp> // cat, copyAs
// Pin with speaker connected:
const uint8_t tonePin = 13;
// Instantiate an array of multiplexers.
CD74HC4051 muxes[] = {
{
10, // Input pin
{2, 3, 4}, // Address pins S0, S1, S2
}, {
11, // Input pin
{2, 3, 4}, // Address pins S0, S1, S2
}, {
12, // Input pin
{2, 3, 4}, // Address pins S0, S1, S2
},
};
// Convert arrays of pins of the muxes to one big array of buttons:
Array<Button, 24> buttons = copyAs<Button>(cat(muxes[0].pins(),
cat(muxes[1].pins(),
muxes[2].pins())));
// Explanation:
//
// "muxes[i].pins()" returns the array of pin numbers of the i-th
// multiplexer.
// "cat" concatenates two arrays.
// "copyAs<Button>" converts an array of pin numbers to an array
// of Button objects.
//
// The internal pull-up resistors will be used, so connect all buttons
// between a pin of the multiplexer and ground.
// Frequencies in Hz:
Array<unsigned int, 24> tones = {
440, 466, 494, 523, 554, 587, 622, 659,
698, 740, 784, 831, 880, 932, 988, 1047,
1109, 1175, 1245, 1319, 1397, 1480, 1568, 1661,
};
void setup() {
// Initialize multiplexers and buttons
for (auto &mux : muxes)
mux.begin();
for (auto &button : buttons)
button.begin();
}
void loop() {
static_assert(buttons.length == tones.length,
"Need the same number of buttons as tones");
static uint8_t activeTone = 0;
// Loop over all buttons
for (uint8_t i = 0; i < buttons.length; ++i) {
// Read the button
switch (buttons[i].update()) {
// If it's pressed, play a tone
case Button::Falling:
tone(tonePin, tones[i]);
activeTone = i;
break;
// If it's released, stop the tone
case Button::Rising:
if (activeTone == i)
noTone(tonePin);
break;
default: break;
}
}
}