MIDI con Arduino
Miembros del Equipo (Grupo 8)
- Antonio Cao Belinchón
- Aaron Tejedor Llorente
- Jiarong Tang
Introduccion
Este proyecto tiene la intención de realizar un dispositivo capaz de procesar la interfaz de audio MIDI (Musical Instrument Digital Interface).
La idea es que al conectar vía USB el dispositivo a cualquier ordenador (siempre y cuando
el sistema operativo lo permita), se pueda trabajar con cualquier software de creación de
música.
El dispositivo cuenta con botones para las notas: DO, RE, MI, FA, SOL, LA, SI.
Además, tambien cuenta con 1 potenciómetro para modificar el «pitch» de la nota que está sonando, y 3 botones adicionales, los cuales sirven para grabar, reproducir la grabacion, y reproducir la grabación en orden inverso.
Materiales
Placa Arduino | – |
Breadboard | – |
Potenciometro x1 | – |
Interruptores x11 | 0.25€ |
Cables para realizar las conexiones | – |
Cable USB | – |
Hardware
En primer lugar se ha conectado el potenciómetro al pin analógico 0, a la vcc de 5V del
arduino y a ground.
Luego los 11 botones utilizados se han conectado por una pata a los pines digitales del 2 al
12, ambos incluidos y por la otra a la toma de tierra.
En el pin digital 2 se ha conectado el botón que sirve para cambiar la velocidad de
reproducción de las grabaciones. La velocidad por defecto será normal, pudiendo cambiar
a lenta, rápida y nuevamente a normal de forma cíclica pulsando el botón.
Entre el pin digital 3 y el pin digital 9 se encuentran los botones correspondientes a las
notas musicales. En el pin 3 se encuentra la nota musical DO y en los 6 pines siguientes se
localizan las demás notas musicales de manera ascendente, terminando en el pin digital 9
con la nota SI.
En el pin digital 10 se ha conectado el botón que permite tanto iniciar una grabación como
finalizarla.
El botón conectado al pin digital 11 reproduce la canción guardada con la funcionalidad de
la grabadora al revés, es decir en orden inverso a como se guardó. Siempre que la
grabación se haya empleado anteriormente, de no darse este caso no reproducirá ningún
sonido.
En el pin digital 12 se encuentra el botón que reproduce la canción guardada en orden
normal. Al igual que con el pin digital 11, si la grabadora no ha guardado ninguna canción
este botón no reproducirá sonido alguno.
Software
Para hacer funcionar nuestro Arduino, hemos utilizado una herramienta llamada HIDUINO.
Esta herramienta debemos flashearla en nuestro Arduino justo despues de instalar el codigo del siguiente apartado.
Entre otras cosas, HIDUINO hace que nuestro sistema operativo detecte el Arduino como un dispositivo MIDI, simplificando un montón trabajar con él.
A continuacion incluimos el código:
#include <MIDI.h> // Incluimos la libreria MIDI
const int numBotones=11; // Número de botones totales que tiene el dispositivo
const int numBotonesNotas=7; // Número de botones correspondientes a las notas
int valorLeido[numBotones]; // Array con los valores leidos de cada boton
int valorAnterior[numBotones]; // Array con el valor anterior leido
const int maximoGrabacion=50; // Tamaño máximo para las grabaciones
int grabacion[maximoGrabacion]; // Array para las grabaciones
MIDI_CREATE_DEFAULT_INSTANCE();
int potencia = 0; // Pin analógico deonde se conecta el potenciometro
int valorPitch = 0;
boolean inicializado = false; // Variable booleana que indica si se ha guardado alguna canción con la función de la grabadora
int velocidad = 750; // Variable que indica la velocidad de reproducción de las grabaciones
void setup() {
MIDI.begin(); // Inicializamos la comunicacion midi (realmente es serial)
Serial.begin(31250);
for(int i=0; i<numBotones; i++){
pinMode(i+2, INPUT_PULLUP); // Recorremos cada pin y lo ponemos como entrada
valorAnterior[i]=1; // Inicializamos el valor anterior a 1 (no pulsado)
}
// Inicializamos el array de grabación como si estuviese vacio
for (int j=0; j<maximoGrabacion; j++) {
grabacion[j]=-1;
}
}
void loop(){
// Leemos el potenciómetro
potencia = analogRead(0);
valorPitch = map(potencia,0,1023,-8192,8191);
MIDI.sendPitchBend(valorPitch,4);
// Comprobamos si se pulsa algún botón correspondiente a las notas musicales,
// ubicadas en los pines digitales del 3 al 9
for(int i=1; i<=numBotonesNotas; i++){
valorLeido[i]=digitalRead(i+2); // Leer valor
// Solo enviamos cuando ha existido un cambio
if((valorLeido[i]==0) && (valorLeido[i]!=valorAnterior[i])){
MIDI.sendNoteOn(47+i, 127, 1); //48 corresponde a C es decir DO.
}
else if ((valorLeido[i]==1) && (valorLeido[i]!=valorAnterior[i])){
MIDI.sendNoteOff(47+i, 0, 1);
}
valorAnterior[i]=valorLeido[i]; // El valor anterior es el nuevo valor para la siguiente iteracion
}
// Comprobamos si se pulsa el botón para grabar conectado al pin digital 10
valorLeido[8] = digitalRead(10);
if ((valorLeido[8]==0) && (valorLeido[8]!=valorAnterior[8])) {
// Si se pulsa y ya se había pulsado anteriormente se borra la canción que había guardada
if (inicializado) {
for (int l = 0; l < maximoGrabacion; l++) {
grabacion[l] = -1;
}
}
delay(500);
grabadora();
}
// Comprobamos si se pulsa el botón para reproducir la canción conectado al pin digital 12
valorLeido[10]=digitalRead(12);
// Si no hay ninguna canción guardada no entra en el if y no reproduce nada
if ((valorLeido[10]==0) && (valorLeido[10]!=valorAnterior[10]) && (inicializado)) {
reproducir();
valorAnterior[10]=valorLeido[10];
}
// Una vez reproducida la canción cambiamos el estado del botón a su fase original
else if ((valorLeido[10]==1) && (valorLeido[10]!=valorAnterior[10]) && (inicializado)) {
valorAnterior[10]=valorLeido[10];
}
// Comprobamos si se ha pulsado el botón para rebobinar la canción,
// es decir reproducirla pero al revés de como se guardó, conectado al pin digital 12
valorLeido[9]=digitalRead(11);
if ((valorLeido[9]==0) && (valorLeido[9]!=valorAnterior[9]) && (inicializado)) {
rebobinar();
valorAnterior[9]=valorLeido[9];
}
// Volvemos al estado original del botón
else if ((valorLeido[9]==1) && (valorLeido[9]!=valorAnterior[9]) && (inicializado)) {
valorAnterior[9]=valorLeido[9];
}
// Comprobamos si se pulsa el botón para cambiar la velocidad de reproducción
// de las canciones guardadas, conectado al pin digital 2
valorLeido[0]=digitalRead(2);
if ((valorLeido[0]==0) && (valorLeido[0]!=valorAnterior[0])) {
cambiarVelocidad();
valorAnterior[0]=valorLeido[0];
}
// Vuelta a la fase original del botón
else if ((valorLeido[0]==1) && (valorLeido[0]!=valorAnterior[0])) {
valorAnterior[0]=valorLeido[0];
}
}
// Función para grabar canciones
void grabadora() {
int j=0;
// Mientras no se pulse el boton para dejar de grabar conectado al pin digital 10 y el tamaño de la grabacion sea menor al máximo
// Nótese que el botón conectado al pin digital 10 sirve para empezar a grabar como para finalizar la grabación
while ((digitalRead(10)==1) && (j<maximoGrabacion)) {
for(int i=1; i<=numBotonesNotas; i++){
valorLeido[i]=digitalRead(i+2); // Leer valor
if ((valorLeido[i]==0) && (valorLeido[i]!=valorAnterior[i])) {
if((valorLeido[i]==0) && (valorLeido[i]!=valorAnterior[i])){
MIDI.sendNoteOn(47+i, 127, 1); //48 corresponde a C es decir DO.
}
else if ((valorLeido[i]==1) && (valorLeido[i]!=valorAnterior[i])){
MIDI.sendNoteOff(47+i, 0, 1);
}
grabacion[j]=i; //Añadir la nota a la grabación
j++;
delay(1000); // Retardo para poder pulsar los botones de las notas
}
}
}
delay(500);
inicializado = true;
}
// Función para reproducir la canción grabada
void reproducir() {
int i = 0;
// Mientras en el array haya valores para notas lógicos (no vacios) o se alcance el tamaño del array
while((i<maximoGrabacion) && (grabacion[i]!=-1)) {
MIDI.sendNoteOn(47+grabacion[i], 127, 1); // 48 corresponde a C es decir DO.
delay(velocidad); // Velocidad de reproducción
MIDI.sendNoteOff(47+grabacion[i], 0, 1);
i++;
}
}
// Función para reproducir la canción al revés
void rebobinar() {
int cont = maximoGrabacion-1;
// Nos colocamos en la última nota de la canción guardada
while((cont>=0) && (grabacion[cont]==-1)) {
cont--;
}
// Reproduce la canción desd el final hasta llegar al comienzo del array
while (cont>=0) {
MIDI.sendNoteOn(47+grabacion[cont], 127, 1); //48 corresponde a C es decir DO.
delay(velocidad); // Velocidad de reproducción
MIDI.sendNoteOff(47+grabacion[cont], 0, 1);
cont--;
}
}
// Función para cambiar la velocidad de reproducción de las grabaciones,
// tanto en modo normal como al revés con un cambio ciclo de tres fases
void cambiarVelocidad() {
//Si la velocidad es normal pasar a lento
if (velocidad==750) {
velocidad=2000;
}
//Si la velocidad es lento pasar a rápido
else if (velocidad==2000) {
velocidad=250;
}
//Si la velocidad es rápido pasar a normal
else if (velocidad==250) {
velocidad=750;
}
}
Para más informacion sobre HIDUINO, os dejamos un enlace a su repositorio en GitHub: https://github.com/ddiakopoulos/hiduino
Funcionamiento
A continuacion podreis ver como funciona :
https://drive.google.com/file/d/1L2UCjwu3wQffYIkRzDvZM4fBvyYFEqWG/view?usp=sharing