#include <Arduino.h>
#include <Audio.h>
#include <Wire.h>
#include <SPI.h>
#include <SD.h>
// ---- AUDIO OBJECTS (2 voices per note) ----
// Note 1: C3
AudioPlaySdWav note1a;
AudioPlaySdWav note1b;
// Note 2: D3
AudioPlaySdWav note2a;
AudioPlaySdWav note2b;
// Note 3: E3
AudioPlaySdWav note3a;
AudioPlaySdWav note3b;
// Note 4: F3
AudioPlaySdWav note4a;
AudioPlaySdWav note4b;
// Note 5: G3
AudioPlaySdWav note5a;
AudioPlaySdWav note5b;
// Note 6: A3
AudioPlaySdWav note6a;
AudioPlaySdWav note6b;
// Note 7: B3
AudioPlaySdWav note7a;
AudioPlaySdWav note7b;
// Note 8: C4
AudioPlaySdWav note8a;
AudioPlaySdWav note8b;
// ---- 4 sub-mixers (AudioMixer4) for 16 total voices ----
// We'll group them in pairs: (C3,D3), (E3,F3), (G3,A3), (B3,C4).
AudioMixer4 mixerA; // for note1a, note1b, note2a, note2b
AudioMixer4 mixerB; // for note3a, note3b, note4a, note4b
AudioMixer4 mixerC; // for note5a, note5b, note6a, note6b
AudioMixer4 mixerD; // for note7a, note7b, note8a, note8b
AudioMixer4 mixerMaster;
// Output + SGTL5000 control
AudioOutputI2S i2s1;
AudioControlSGTL5000 sgtl5000_1;
// ---- PATCH CORDS ----
// mixerA (notes 1 & 2)
AudioConnection pc1 (note1a, 0, mixerA, 0);
AudioConnection pc2 (note1b, 0, mixerA, 1);
AudioConnection pc3 (note2a, 0, mixerA, 2);
AudioConnection pc4 (note2b, 0, mixerA, 3);
// mixerB (notes 3 & 4)
AudioConnection pc5 (note3a, 0, mixerB, 0);
AudioConnection pc6 (note3b, 0, mixerB, 1);
AudioConnection pc7 (note4a, 0, mixerB, 2);
AudioConnection pc8 (note4b, 0, mixerB, 3);
// mixerC (notes 5 & 6)
AudioConnection pc9 (note5a, 0, mixerC, 0);
AudioConnection pc10 (note5b, 0, mixerC, 1);
AudioConnection pc11 (note6a, 0, mixerC, 2);
AudioConnection pc12 (note6b, 0, mixerC, 3);
// mixerD (notes 7 & 8)
AudioConnection pc13 (note7a, 0, mixerD, 0);
AudioConnection pc14 (note7b, 0, mixerD, 1);
AudioConnection pc15 (note8a, 0, mixerD, 2);
AudioConnection pc16 (note8b, 0, mixerD, 3);
// Combine A, B, C, D into mixerMaster
AudioConnection pc17 (mixerA, 0, mixerMaster, 0);
AudioConnection pc18 (mixerB, 0, mixerMaster, 1);
AudioConnection pc19 (mixerC, 0, mixerMaster, 2);
AudioConnection pc20 (mixerD, 0, mixerMaster, 3);
// mixerMaster -> I2S output
AudioConnection pc21 (mixerMaster, 0, i2s1, 0);
AudioConnection pc22 (mixerMaster, 0, i2s1, 1);
// ---- SENSOR PINS & FILENAMES ----
const int sensorPins[8] = {2, 3, 4, 5, 6, 7, 8, 9};
// Filenames in ascending order from C3 to C4
const char *noteFiles[8] = {
"C3.WAV", // sensorPins[0] => pin2
"D3.WAV", // sensorPins[1] => pin3
"E3.WAV", // sensorPins[2] => pin4
"F3.WAV", // sensorPins[3] => pin5
"G3.WAV", // sensorPins[4] => pin6
"A3.WAV", // sensorPins[5] => pin7
"B3.WAV", // sensorPins[6] => pin8
"C4.WAV" // sensorPins[7] => pin9
};
// For edge detection
bool oldState[8] = {false, false, false, false, false, false, false, false};
// ---- SETUP ----
void setup() {
Serial.begin(115200);
while (!Serial) { /* wait for Serial Monitor */ }
// Configure TTP223 pins
for (int i = 0; i < 8; i++) {
pinMode(sensorPins[i], INPUT);
}
// Allocate audio memory (16 voices => at least 32 recommended)
AudioMemory(32);
// Enable the SGTL5000 codec
sgtl5000_1.enable();
sgtl5000_1.volume(0.8); // range 0.0 to 1.0
// Mixer gains: each AudioMixer4 has 4 inputs
// set them all to 1.0 (unity)
for (int ch = 0; ch < 4; ch++) {
mixerA.gain(ch, 1.0);
mixerB.gain(ch, 1.0);
mixerC.gain(ch, 1.0);
mixerD.gain(ch, 1.0);
}
// Master mixer has 4 inputs (from sub-mixers)
for (int out = 0; out < 4; out++) {
mixerMaster.gain(out, 1.0);
}
// Initialize SD card
// If your Audio Shield uses pin 10 for SD card CS, this is correct.
// If using Teensy 4.0's built-in SD slot, try SD.begin(BUILTIN_SDCARD).
if (!SD.begin(10)) {
Serial.println("SD card init failed. Check wiring or card format.");
while (1) { /* halt */ }
}
Serial.println("SD card initialized.");
}
// ---- HELPER: PLAY NOTE (2 VOICES) ----
void playNoteFile(AudioPlaySdWav &voiceA, AudioPlaySdWav &voiceB, const char* fname) {
if (!voiceA.isPlaying()) {
voiceA.play(fname);
} else if (!voiceB.isPlaying()) {
voiceB.play(fname);
} else {
// Both busy => forcibly re-trigger voiceA
voiceA.stop();
voiceA.play(fname);
}
}
// ---- MAIN LOOP ----
void loop() {
// Check each sensor, do edge detection
for (int i = 0; i < 8; i++) {
bool newState = (digitalRead(sensorPins[i]) == HIGH);
// If it changed from LOW to HIGH, trigger note
if (!oldState[i] && newState) {
Serial.print("Sensor ");
Serial.print(i);
Serial.print(" => playing ");
Serial.println(noteFiles[i]);
// Trigger the correct pair of voices based on sensor index
switch (i) {
case 0: playNoteFile(note1a, note1b, noteFiles[i]); break; // C3
case 1: playNoteFile(note2a, note2b, noteFiles[i]); break; // D3
case 2: playNoteFile(note3a, note3b, noteFiles[i]); break; // E3
case 3: playNoteFile(note4a, note4b, noteFiles[i]); break; // F3
case 4: playNoteFile(note5a, note5b, noteFiles[i]); break; // G3
case 5: playNoteFile(note6a, note6b, noteFiles[i]); break; // A3
case 6: playNoteFile(note7a, note7b, noteFiles[i]); break; // B3
case 7: playNoteFile(note8a, note8b, noteFiles[i]); break; // C4
}
}
// Save state
oldState[i] = newState;
}
// Brief delay
delay(10);
}