Hello,
I'm a beginner in the field of microcontrollers and I'm working on a project to create a piano that generates MIDI notes for audio output. I've successfully implemented MIDI note generation, but now I want to extend the functionality to save the MIDI output to MIDI files for playback. It's important to maintain accurate timing, pitch, and note durations in the saved MIDI files.
For my setup, I'm using an ESP32 microcontroller along with a microSD card module for storage. The audio output is handled by a UDA1334A module connected to a JBL speaker, and for the button matrix, I'm using an SX1509.
The Code right now:
#include <Wire.h>
#include <SparkFunSX1509.h>
#include "AudioTools.h"
#include "StkAll.h"
#define KEY_ROWS 8
#define KEY_COLS 8
const byte SX1509_ADDRESS = 0x3E;
SX1509 io;
I2SStream i2s;
ArdStreamOut output(i2s, 1);
BlowBotl blowbotl ;
Voicer voicer;
int group = 1;
float amplitude = 30;
int note = 0;
const byte gedrueckt = LOW;
const byte losgelassen = HIGH;
// Array für die MIDI-Notenwerte
const byte midiNotes[KEY_ROWS][KEY_COLS] = {
{ 0, 52, 44, 36, 28, 20, 12, 0 },
{ 0, 53, 45, 37, 29, 21, 13, 0 },
{ 0, 54, 46, 38, 30, 22, 14, 0 },
{ 0, 55, 47, 39, 31, 23, 15, 0 },
{ 0, 56, 48, 40, 32, 24, 16, 0 },
{ 0, 57, 49, 41, 33, 25, 17, 0 },
{ 0, 58, 50, 42, 34, 26, 18, 0 },
{ 0, 59, 51, 43, 35, 27, 19, 0 }
};
void setup() {
Serial.begin(115200);
while (!Serial);
Serial.println("Setup-Start");
Wire.begin();
Serial.println("Wire.begin() done");
if (io.begin(SX1509_ADDRESS) == false) {
Serial.println("Failed to communicate. Check wiring and address of SX1509.");
while (1);
}
voicer.addInstrument(&blowbotl, group);
auto cfg = i2s.defaultConfig(TX_MODE);
cfg.bits_per_sample = 16;
cfg.sample_rate = Stk::sampleRate();
cfg.channels = 1;
cfg.pin_bck = 27; //#define I2S_BCLK 27
cfg.pin_ws = 26; //#define I2S_LRC 26
cfg.pin_data = 25; //#define I2S_DOUT 25
i2s.begin(cfg);
for (int c = 0; c < 8; c++) {
io.pinMode(c, OUTPUT); //8er-Leiste ist OUTPUT
Serial.print("io.pinMode(");
Serial.print(c);
Serial.println("), OUTPUT");
// Serial.print("8er Leiste auf Output: ");
Serial.println(io.digitalRead(c));
}
for (int r = 8; r < 16; r++) {
io.pinMode(r, INPUT_PULLUP);
Serial.println(io.digitalRead(r));
Serial.print("io.pinMode(");
Serial.print(r);
Serial.println("), INPUT_PULLUP");
}
}
void loop() {
int col = 0;
int row = 0;
int rowx = 0;
long endTime = millis() + 500;
for ( row = 0; row < 8; row++) {
io.digitalWrite(row, HIGH);
}
for ( rowx = 0; rowx < 8; rowx++) {
io.digitalWrite(rowx, LOW);
for ( col = 8; col < 16; col++) {
while (io.digitalRead(col) == gedrueckt) {
byte midiNote = midiNotes[rowx][col - 8];
voicer.noteOn(midiNote, amplitude, group);
while (millis() < endTime) {
output.tick( voicer.tick() );
}
Serial.print("Note: ");
Serial.println(midiNote);
}
}
io.digitalWrite(rowx, HIGH);
}
}
That is my Harware right now (except the battery):
I'd appreciate any advice or experiences you may have with implementing MIDI file saving in this context.
Thank you in advance!