- Un teclado viejo que no se use, lo único que se rescata son los pulsadores como entradas del Arduino
- Un Arduino Uno o como finalmente descubrí que era mejor el Arduino Leonardo pues tiene interface midi, directo, esto ayuda que no tengas que hacer un programa adicional para mapear las salidas de Arduino Uno y convertirlas en midi, en concreto con Arduino Leonardo puedo usar el teclado midi hasta en mi celular (con Garage Band u otro)
- Diodos para evitar el ghosting, esto ultimo me dio dolores de cabeza pues en algunas combinaciones de teclas simplemente no sonaban juntas, ellos porque al conectarse a un mismo punto la corriente se devolvía por donde no debía.
La parte difícil creo yo es descubrir la matriz de contactos que tiene cada teclado, en mi caso tenia dos bandas de cables de 8, los cuales modele como filas y columnas en Arduino. Para eso tienen que medir con el multimetro que terminales de los dos bandas de cables se cortocircuitaban al presionar las teclas del Piano.
Ejemplo: Para la primera nota Do se unían el primer pin del cable 1 con el primer pin del cable 2. Do# con el primer pin del cable 1 y el segundo del cable 2 y asi hasta llegar al ultimo pin del cable 2.
Como este teclado solo tiene 54 teclas, pude constatar que en la fila 7 solo usaba el pin 1 de ambos cables los demás no los usaba, y en la fila 8 solo se usaban del 4 al 8 pin.
Dado que cada elemento de la matriz es una nota esto tiene un equivalente en números para sonidos midi, considerando estos se hizo la siguiente matriz de sonidos que corresponde a mi teclado.
// Matriz de teclas con los valores MIDI asignados.
int keys[ROWS][COLS] = {
{36, 37, 38, 39, 40, 41, 42, 43}, // Fila 1: Teclas 1-8
{44, 45, 46, 47, 48, 49, 50, 51}, // Fila 2: Teclas 9-16
{52, 53, 54, 55, 56, 57, 58, 59}, // Fila 3: Teclas 17-24
{60, 61, 62, 63, 64, 65, 66, 67}, // Fila 4: Teclas 25-32
{68, 69, 70, 71, 72, 73, 74, 75}, // Fila 5: Teclas 33-40
{76, 77, 78, 79, 80, 81, 82, 83}, // Fila 6: Teclas 41-48
{84, -1, -1, -1, -1, -1, -1, -1}, // Fila 7: Tecla 49 (especial)
{-1, -1, -1, 85, 86, 87, 88, 89} // Fila 8: Teclas 50-54 (especial)
};
Una vez definida la matriz se tienen que conectar a las salidas y entradas de Arduino es decir el pulsar una tecla unen los pines de Arduino Leonardo, para dicho fin use las siguientes salidas.
// Pines asignados a filas (A0-A5 y D2-D3).
byte rowPins[ROWS] = {A0, A1, A2, A3, A4, A5, 2, 3};
// Pines asignados a columnas (D4-D11).
byte colPins[COLS] = {4, 5, 6, 7, 8, 9, 10, 11};
Entonces, para conseguir Do se unen los pines A0 y D4, Do# A0 y D5 y así sucesivamente, el problema de ghosting que tenia era al comento de conectar A0 D4 y A1 D4 por lo que probablemente la corriente se devolvía por el punto D4 lo cual hacia que no sonaran las dos notas juntas, por lo que es en ese lugar donde deberían ir los diodos (8 en total). Finalmente asi me quedo el conexionado. En la parte de las bandas que están con cinta negra, se incluyó los 8 diodos en cada una para evitar el ghosting.
Este es el código final tal como resultado para este proyecto.
#include <MIDIUSB.h>
//con Arduino Leonardo: código by Edward Angelino
const byte ROWS = 8; // Número de filas.
const byte COLS = 8; // Número de columnas.
// Matriz de teclas con los valores MIDI asignados.
int keys[ROWS][COLS] = {
{36, 37, 38, 39, 40, 41, 42, 43}, // Fila 1: Teclas 1-8
{44, 45, 46, 47, 48, 49, 50, 51}, // Fila 2: Teclas 9-16
{52, 53, 54, 55, 56, 57, 58, 59}, // Fila 3: Teclas 17-24
{60, 61, 62, 63, 64, 65, 66, 67}, // Fila 4: Teclas 25-32
{68, 69, 70, 71, 72, 73, 74, 75}, // Fila 5: Teclas 33-40
{76, 77, 78, 79, 80, 81, 82, 83}, // Fila 6: Teclas 41-48
{84, -1, -1, -1, -1, -1, -1, -1}, // Fila 7: Tecla 49 (especial)
{-1, -1, -1, 85, 86, 87, 88, 89} // Fila 8: Teclas 50-54 (especial)
};
// Pines asignados a filas (A0-A5 y D2-D3).
byte rowPins[ROWS] = {A0, A1, A2, A3, A4, A5, 2, 3};
// Pines asignados a columnas (D4-D11).
byte colPins[COLS] = {4, 5, 6, 7, 8, 9, 10, 11};
// Pines para los botones de cambio de octava
const byte btnUp = 12; // Botón para subir la octava
const byte btnDown = 13; // Botón para bajar la octava
// Variables para manejar la octava
int octaveShift = 0; // Cambio de octava actual
// Variables para almacenar el estado de las teclas.
bool keyState[ROWS][COLS] = {false};
void setup() {
Serial.begin(115200); // Depuración serial.
// Configurar los pines de las filas como salidas y las columnas como entradas.
for (int i = 0; i < ROWS; i++) {
pinMode(rowPins[i], OUTPUT);
digitalWrite(rowPins[i], HIGH); // Inicializar en estado alto (no activado).
}
for (int i = 0; i < COLS; i++) {
pinMode(colPins[i], INPUT_PULLUP); // Las columnas como entradas con resistencia pull-up.
}
// Configurar los botones
pinMode(btnUp, INPUT_PULLUP);
pinMode(btnDown, INPUT_PULLUP);
}
void loop() {
// Manejar botones de octava
handleOctaveButtons();
// Recorremos todas las filas.
for (int row = 0; row < ROWS; row++) {
// Configuramos la fila actual como baja (activada) y las demás como alta.
for (int i = 0; i < ROWS; i++) {
digitalWrite(rowPins[i], (i == row) ? LOW : HIGH);
}
// Revisamos las columnas para ver si alguna tecla está presionada.
for (int col = 0; col < COLS; col++) {
if (digitalRead(colPins[col]) == LOW) { // Si la columna está baja, la tecla está presionada.
if (!keyState[row][col]) { // Si el estado anterior no era presionado.
keyState[row][col] = true; // Actualizamos el estado a presionado.
int tecla_presionada = keys[row][col];
if (tecla_presionada != -1) {
// Ajustar la nota según la octava
int adjustedNote = tecla_presionada + octaveShift;
if (adjustedNote >= 0 && adjustedNote <= 127) {
// Enviar mensaje MIDI de Note On
noteOn(0, adjustedNote, 127); // Canal 0, nota, velocidad
MidiUSB.flush();
}
}
}
} else {
if (keyState[row][col]) { // Si la tecla fue liberada.
keyState[row][col] = false; // Actualizamos el estado a liberado.
int tecla_presionada = keys[row][col];
if (tecla_presionada != -1) {
// Ajustar la nota según la octava
int adjustedNote = tecla_presionada + octaveShift;
if (adjustedNote >= 0 && adjustedNote <= 127) {
// Enviar mensaje MIDI de Note Off
noteOff(0, adjustedNote, 0); // Canal 0, nota, velocidad 0
MidiUSB.flush();
}
}
}
}
}
}
delay(10); // Retardo para evitar rebote (debouncing)
}
// Función para manejar los botones de cambio de octava
void handleOctaveButtons() {
bool upPressed = digitalRead(btnUp) == LOW;
bool downPressed = digitalRead(btnDown) == LOW;
if (upPressed && downPressed) {
// Si ambos botones están presionados, resetea la octava
octaveShift = 0;
Serial.println("Resetear octava");
delay(200); // Anti-rebote
} else if (upPressed) {
// Subir una octava
octaveShift += 12;
Serial.println("Subir octava");
delay(200); // Anti-rebote
} else if (downPressed) {
// Bajar una octava
octaveShift -= 12;
Serial.println("Bajar octava");
delay(200); // Anti-rebote
}
}
// Función para enviar mensajes MIDI Note On
void noteOn(byte channel, byte pitch, byte velocity) {
midiEventPacket_t event = {0x09, static_cast<uint8_t>(0x90 | channel), pitch, velocity};
MidiUSB.sendMIDI(event);
}
// Función para enviar mensajes MIDI Note Off
void noteOff(byte channel, byte pitch, byte velocity) {
midiEventPacket_t event = {0x08, static_cast<uint8_t>(0x80 | channel), pitch, velocity};
MidiUSB.sendMIDI(event);
}
El nuevo teclado ahora solo se conecta por usb a la PC (o celular) y ya se tiene un teclado midi, en un monitor midi en mi caso uso "midi monitor" se puede ver que nota(s) se esta(n) pulsando.