#include "pitches.h"
#define SPEAKER_PIN 8
// Tombol piano (8 buah)
const uint8_t buttonPins[] = {12, 11, 10, 9, 7, 6, 5, 4};
// LED untuk tiap tombol
const uint8_t ledPins[] = {2, 3, 14, 15, 16, 17, 18, 19};
// Nada dasar tiap tombol
const int baseTones[] = {
NOTE_C4, NOTE_D4, NOTE_E4, NOTE_F4,
NOTE_G4, NOTE_A4, NOTE_B4, NOTE_C5
};
// Label nada
const char* noteNames[] = {
"C4", "D4", "E4", "F4", "G4", "A4", "B4", "C5"
};
const int numTones = sizeof(buttonPins) / sizeof(buttonPins[0]);
// Tombol khusus
const uint8_t demoButton = 20;
const uint8_t recordButton = 21;
const uint8_t playButton = 22;
const uint8_t octaveUpBtn = 26;
const uint8_t octaveDnBtn = 27;
// Lagu demo
int melody[] = {
NOTE_C4, NOTE_C4, NOTE_G4, NOTE_G4, NOTE_A4, NOTE_A4, NOTE_G4,
NOTE_F4, NOTE_F4, NOTE_E4, NOTE_E4, NOTE_D4, NOTE_D4, NOTE_C4
};
const char* melodyNames[] = {
"C4","C4","G4","G4","A4","A4","G4",
"F4","F4","E4","E4","D4","D4","C4"
};
int noteDurations[] = {4,4,4,4,4,4,2, 4,4,4,4,4,4,2};
// Buffer rekaman
#define MAX_RECORD 200
int recordedNotes[MAX_RECORD];
const char* recordedNames[MAX_RECORD];
int recordedTimes[MAX_RECORD];
int recordLength = 0;
bool isRecording = false;
unsigned long lastTime;
// Variabel shifting oktaf
int octaveShift = 0; // 0 normal, ±1, ±2
// ------------------- SETUP -------------------
void setup() {
Serial.begin(115200);
for (uint8_t i = 0; i < numTones; i++) {
pinMode(buttonPins[i], INPUT_PULLUP);
pinMode(ledPins[i], OUTPUT);
}
pinMode(SPEAKER_PIN, OUTPUT);
pinMode(demoButton, INPUT_PULLUP);
pinMode(recordButton, INPUT_PULLUP);
pinMode(playButton, INPUT_PULLUP);
pinMode(octaveUpBtn, INPUT_PULLUP);
pinMode(octaveDnBtn, INPUT_PULLUP);
lastTime = millis();
Serial.println("🎹 Mini Piano Siap!");
}
// ------------------- DEMO SONG -------------------
void playDemo() {
Serial.println("▶ Memutar demo: Twinkle Twinkle Little Star");
for (int thisNote = 0; thisNote < 14; thisNote++) {
int noteDuration = 1000 / noteDurations[thisNote];
tone(SPEAKER_PIN, melody[thisNote], noteDuration);
Serial.println(melodyNames[thisNote]);
delay(noteDuration * 1.30);
}
noTone(SPEAKER_PIN);
Serial.println("⏹ Demo selesai.");
}
// ------------------- PLAY RECORDING -------------------
void playRecording() {
Serial.println("▶ Memutar hasil rekaman");
for (int i = 0; i < recordLength; i++) {
if (recordedNotes[i] > 0) {
tone(SPEAKER_PIN, recordedNotes[i], 200);
Serial.println(recordedNames[i]);
}
delay(recordedTimes[i]);
noTone(SPEAKER_PIN);
}
Serial.println("⏹ Playback selesai.");
}
// ------------------- LOOP -------------------
void loop() {
bool playing = false;
// Cek tombol piano
for (uint8_t i = 0; i < numTones; i++) {
if (digitalRead(buttonPins[i]) == LOW) {
int toneFreq = baseTones[i] * pow(2, octaveShift);
tone(SPEAKER_PIN, toneFreq);
digitalWrite(ledPins[i], HIGH);
playing = true;
// Cetak ke Serial
Serial.print("Main: ");
Serial.println(noteNames[i]);
// Rekam jika recording
if (isRecording && recordLength < MAX_RECORD) {
recordedNotes[recordLength] = toneFreq;
recordedNames[recordLength] = noteNames[i];
recordedTimes[recordLength] = millis() - lastTime;
lastTime = millis();
recordLength++;
}
delay(200); // biar nggak spam Serial
} else {
digitalWrite(ledPins[i], LOW);
}
}
// Tombol demo
if (digitalRead(demoButton) == LOW) {
playDemo();
}
// Tombol rekam
if (digitalRead(recordButton) == LOW) {
delay(200);
if (!isRecording) {
recordLength = 0;
isRecording = true;
lastTime = millis();
Serial.println("🔴 Rekaman dimulai...");
} else {
isRecording = false;
Serial.println("⏹ Rekaman berhenti.");
}
}
// Tombol playback
if (digitalRead(playButton) == LOW && !isRecording && recordLength > 0) {
playRecording();
}
// Tombol octave up
if (digitalRead(octaveUpBtn) == LOW) {
delay(200);
if (octaveShift < 2) {
octaveShift++;
Serial.print("🔼 Oktaf naik ke ");
Serial.println(octaveShift);
}
}
// Tombol octave down
if (digitalRead(octaveDnBtn) == LOW) {
delay(200);
if (octaveShift > -2) {
octaveShift--;
Serial.print("🔽 Oktaf turun ke ");
Serial.println(octaveShift);
}
}
// Kalau tidak ada tombol ditekan
if (!playing) {
noTone(SPEAKER_PIN);
}
}