141 lines
3.6 KiB
C++

/****************************************************
* Arduino Sketch: Shape-Based Chord Detection + RC Filter
* - Reads 3 SoftPot sensors on A0, A1, A2 (with resistor+cap)
* - Sorts them in descending order to detect chord shape (A, D, E)
* - Outputs "ChordName|val1,val2,val3" over Serial at 9600 baud
*
* 2025-03-xx
****************************************************/
#define S1_PIN A0
#define S2_PIN A1
#define S3_PIN A2
// Toggle this to test shape detection without real sensors
#define SIMULATION_MODE true
#define CYCLE_INTERVAL 3000 // ms to switch chord in simulation
// Threshold for ignoring no-touch floating (~500)
#define NO_TOUCH_MIN 400
#define NO_TOUCH_MAX 600
// Minimal difference between High and Low for shape detection
#define MIN_DIFF 10
// For simulation
unsigned long lastSwitchTime = 0;
int currentFakeChord = 0; // cycles 0=A, 1=D, 2=E
void setup() {
Serial.begin(9600);
}
void loop() {
int s1, s2, s3;
if (SIMULATION_MODE) {
// Switch chord every 3 seconds
if (millis() - lastSwitchTime > CYCLE_INTERVAL) {
lastSwitchTime = millis();
currentFakeChord = (currentFakeChord + 1) % 3;
}
// Fake sensor values for chord shapes:
switch (currentFakeChord) {
case 0: s1 = 800; s2 = 600; s3 = 400; break; // A
case 1: s1 = 700; s2 = 200; s3 = 600; break; // D
case 2: s1 = 200; s2 = 300; s3 = 800; break; // E
}
} else {
// Real sensor reading:
s1 = analogRead(S1_PIN);
delay(5); // let RC settle
s2 = analogRead(S2_PIN);
delay(5);
s3 = analogRead(S3_PIN);
delay(5);
}
// Convert raw readings into a chord name
String chordName = detectChordShape(s1, s2, s3);
// Output e.g. "A|60,50,55"
Serial.print(chordName);
Serial.print("|");
Serial.print(s1); Serial.print(",");
Serial.print(s2); Serial.print(",");
Serial.println(s3);
delay(200);
}
/*****************************************************
* detectChordShape():
* - Filters out 'no-touch' readings
* - Sorts in descending order
* - Matches pattern for A, D, E
*****************************************************/
String detectChordShape(int raw1, int raw2, int raw3) {
int s1 = filterNoTouch(raw1);
int s2 = filterNoTouch(raw2);
int s3 = filterNoTouch(raw3);
// If all -1 => no real touches
if (s1 == -1 && s2 == -1 && s3 == -1) {
return "None";
}
// Sort them descending
int arr[3] = {s1, s2, s3};
int idx[3] = {1, 2, 3};
for(int i=0; i<2; i++) {
for(int j=0; j<2-i; j++){
if (arr[j] < arr[j+1]) {
int tempVal = arr[j];
arr[j] = arr[j+1];
arr[j+1] = tempVal;
int tempIdx = idx[j];
idx[j] = idx[j+1];
idx[j+1] = tempIdx;
}
}
}
// Check difference high-low
int diffHL = arr[0] - arr[2];
if (diffHL < MIN_DIFF) {
return "None";
}
// Pattern matching
// Example A shape => (S1=High, S2=Mid, S3=Low) => index[0]==1, index[1]==2, index[2]==3
if (idx[0] == 1 && idx[1] == 2 && idx[2] == 3) {
return "A";
}
// D shape => (S1=High, S3=Mid, S2=Low) => index[0]==1, index[1]==3, index[2]==2
if (idx[0] == 1 && idx[1] == 3 && idx[2] == 2) {
return "D";
}
// E shape => (S3=High, S2=Mid, S1=Low) => index[0]==3, index[1]==2, index[2]==1
if (idx[0] == 3 && idx[1] == 2 && idx[2] == 1) {
return "E";
}
return "None";
}
/*****************************************************
* filterNoTouch():
* Returns -1 if sensor is around 500 => no press
* Otherwise returns rawVal
*****************************************************/
int filterNoTouch(int val) {
if (val >= NO_TOUCH_MIN && val <= NO_TOUCH_MAX) {
return -1; // no-touch
}
return val;
}