#include <Keypad.h>
#include "pitches.h"
uint8_t const ROWS = 4;
uint8_t const COLS = 3;
char keys[ROWS][COLS] = {
{ '1', '2', '3', },
{ '4', '5', '6', },
{ '7', '8', '9', },
{ 'r', '0', 's', },
};
int keyToTone[] = {
0, NOTE_C4, NOTE_D4, NOTE_E4,
NOTE_F4, NOTE_G4, NOTE_A4,
NOTE_B4, NOTE_C5, NOTE_D5,
};
uint8_t rowPins[ROWS] = { 8, 7, 6, 5 }; // Pins connected to R1, R2, R3, R4
uint8_t colPins[COLS] = { 4, 3, 2 }; // Pins connected to C1, C2, C3
Keypad keypad = Keypad(makeKeymap(keys), rowPins, colPins, ROWS, COLS);
uint8_t buzzerPin = 13;
float const tone_factor = .6;
enum {HALT, RECORDING, PLAYING} state = HALT;
int const MAX_NOTES = 255;
uint8_t nr_notes = 0;
uint8_t sliderPin = A0;
int bpm;
int track[MAX_NOTES];
int tick = 0;
void setup() {
Serial.begin(9600);
pinMode(buzzerPin, OUTPUT);
}
static void play(int index) {
if (track[index] != 0) {
int quaver_duration = 60000 / bpm / 4 * tone_factor;
tone(buzzerPin, keyToTone[track[index]], quaver_duration);
}
}
static void clear_track() {
for (int i = 0; i < MAX_NOTES; i++) {
track[i] = 0;
}
nr_notes = 0;
Serial.println("Track cleared");
}
static void record(char key) {
if (nr_notes == MAX_NOTES) {
clear_track();
}
track[nr_notes] = key - '0';
play(nr_notes);
nr_notes++;
Serial.print("Recorded ");
Serial.print(nr_notes);
Serial.print("/");
Serial.print(MAX_NOTES);
Serial.println(" notes");
if (nr_notes == MAX_NOTES) {
Serial.println("Track full");
}
}
static void reset_tick() {
tick = 0;
}
static void next_tick() {
if (nr_notes == 0) {
tick = 0;
return;
}
tick = (tick + 1) % nr_notes;
}
static void delay_quaver() {
delay(60000 / bpm / 4);
}
void loop() {
bpm = map(analogRead(sliderPin), 0, 1023, 30, 120);
char key = keypad.getKey();
switch (key) {
case NO_KEY:
break;
case 'r':
if (state == RECORDING) {
Serial.println("Halt");
state = HALT;
} else {
Serial.println("Recording mode");
state = RECORDING;
}
break;
case 's':
if (state == PLAYING) {
Serial.println("Halt");
state = HALT;
} else {
Serial.println("Playing mode");
state = PLAYING;
reset_tick();
}
break;
default:
if (state == HALT && key == '0') {
clear_track();
}
if (state == RECORDING) {
record(key);
}
}
if (state == PLAYING) {
play(tick);
next_tick();
delay_quaver();
}
}