LA BATERÍA MIDI

LA BATERÍA MIDI

Este proyecto, consistió en el armado casero de una batería musical que trabaje con señales MIDI, utilizando un Arduino MEGA 2560 R3.

Lo primero a tener en cuenta es el tipo de parches a utilizar. Aquí existirían dos posibilidades, una simple, en la que de alguna manera al golpear el parche se cierre un circuito eléctrico, como si se tratase de un pulsador, que da lugar a que el sonido producido al golpear el parche sea siempre el mismo, sin los matices propios de expresión que brinda en la batería real el golpear más suave o más fuerte. La otra posibilidad es utilizar algún tipo de sensor que posea la capacidad de medir la intensidad del golpe y traducirlo en una señal eléctrica que transmita dicha información al sistema, para que produzca un sonido acorde a la intención del ejecutante.

En este caso, se optó por la versión más completa, que permite registrar las expresiones en función de la intensidad de los golpes. Para lograrlo, se optó por utilizar micrófonos piezoeléctricos, como el que se muestra en la siguiente imagen:

Estos micrófonos se pueden conectar en forma directa a las entradas analógicas del Arduino, con el cable que parte del disco más grande conectada a masa y la del disco menor a la entrada analógica, pero teniendo la precaución de agregar entre la masa y el punto de entrada, un resistor de 1 megaohm y un diodo zener de 5.1V (en paralelo con el elemento piezoeléctrico) para proteger la entrada analógica del Arduino contra posibles señales que excedan los 5.1 voltios.

Físicamente, se debe proporcionar un cuerpo a cada sensor para convertirlo en un parche que brinde una sensación en algo similar a la de estar tocando una batería real. En este caso, se optó por pegar los sensores a DVDs en desuso y cubrirlos con un disco de goma eva de igual tamaño pegado encima sólo en sus bordes.

El aspecto de los mismos puede verse en la siguiente imagen:

Una vez en funcionamiento la batería, se notó que los parches funcionaban sólo al golpearlos en su centro, cuando el golpe incidía en el disco central del sensor piezoeléctrico, por lo que se optó colocar en contacto con este disco algún elemento de mayor tamaño que transmita las vibraciones al mismo. Luego de probar diferentes opciones, se optó por discos de cartón duro de diámetro un centímetro menor al del DVD usado como base, y adherido al disco central del sensor mediante una tirita de material engomado a ambos lados, y sobre esta estructura, finalmente el disco de goma eva.

En este caso en particular, como puede verse en la imagen de portada, se eligieron colores en función del tipo de elemento que representa cada parche al configurar la batería en una forma estándar, utilizando parches negros para los sonidos más bajos, azules para los tambores tipo 'snare', violeta para los tambores tipo 'Tom', verde para los platillos, y un parche amarillo para el platillo de remate.

Los parches fueron montados sobre una placa de fibrofácil de 35x45 cm, separados de la misma mediante tubos de cartón (tomados de rollos de papel de cocina) en los que uno de los extremos para algunos parches, fue cortado en ángulo, para proporcionar al parche cierta inclinación para que resulte más natural acceder a ellos al tocar. Se utilizó pegamento para unir los parches a los tubos y los tubos a la placa de fibrofácil, y se pintó todo de color negro para dar al dispositivo un mejor aspecto.

Por supuesto, para golpear los parches, se utilizaron baquetas reales. En este caso en particular, se deseaba que el instrumento fuera lo más silencioso posible al golpear los parches, de modo de poder utilizarlo a altas horas de la noche, con auriculares, sin perturbar a los vecinos, lo que se logró agregando a las baquetas unos trozos de gamuza en cada punta.

La siguiente figura muestra un esquema de las conexiones efectuadas:

Por razones de espacio, en el esquema anterior se muestra un solo sensor piezoeléctrico conectado al puerto de entrada analógico 'A0' del Arduino, pero se debe repetir ese coonexionado para cada parche de la batería, utilizando los otros puertos libres ('A1', 'A2', etc).

El código utilizado para programar el Arduino es el siguiente:

#line 1 'Bateria_MIDI.ino'

#include 'Arduino.h'

// Mapeo entre las teclas o pulsadores numerados según su posición física en el equipo
// y los números identificadores de los puertos a los que se hallan conectados
#define tecla0 3
#define tecla1 4
#define tecla2 5
#define tecla3 6
#define tecla4 7

// Asignación de un nombre a cada instrumento del banco MIDI
#define primerInstrumento 13
#define _13_TaikoDrum     13
#define _14_TaikoDrum     14
#define _15_FilterSnap    15
#define _16_NoiseSlap     16
#define _17_ScratchHi     17
#define _18_ScratchHi     18
#define _21_MetClick1     21
#define _22_MetClick2     22
#define _23_MetClick2     23
#define _24_MetClick2     24
#define _25_OrchSnare     25
#define _26_BrushSwirl    26
#define _27_FilterSnap    27
#define _28_NoiseSlap     28
#define _29_ScratchLo     29
#define _30_ScratchHi     30
#define _31_Sticks        31
#define _32_Sinetick      32
#define _33_MetClick1     33
#define _34_MetClick2     34
#define _35_Kick1         35
#define _36_Kick2         36
#define _37_Rim           37
#define _38_Snare1        38
#define _39_Clap          39
#define _40_Snare2        40
#define _41_LowFloorTom   41
#define _42_HiHatClosed   42
#define _43_LowFloorTom   43
#define _44_HiHatFoot     44
#define _45_LowTom        45
#define _46_HiHatOpen     46
#define _47_LowMidTom     47
#define _48_LowMidTom     48
#define _49_CrashCymbal   49
#define _50_HighTom       50
#define _51_RideCymbal    51
#define _52_ChinaCrash    52
#define _53_MRideBell     53
#define _54_Tambourine    54
#define _55_SplashCymbal  55
#define _56_CowBell       56
#define _57_SplashCymbal  57
#define _58_VibraSlap     58
#define _59_SplashCymbal  59
#define _60_BongoRim      60
#define _61_LowBongo      61
#define _62_ClosedSlap    62
#define _63_HighConga     63
#define _64_LowTumba      64
#define _65_TimbaleHi     65
#define _66_TimbaleLo     66
#define _67_HighAgogo     67
#define _68_LowAgogo      68
#define _69_Cabasa        69
#define _70_Maracas       70
#define _71_ShortWhistle  71
#define _72_ShortWhistle  72
#define _73_GuiroDown     73
#define _74_GuiroUp       74
#define _75_Clave         75
#define _76_HighWoodBlock 76
#define _77_LowWoodblock  77
#define _78_CuicaHi       78
#define _79_CuicaLo       79
#define _80_Triangle      80
#define _81_Triangle      81
#define _82_SmallShaker   82
#define _83_SleighBells   83
#define _84_BellTree      84
#define _85_Castanet      85
#define _86_TaikoDrum     86
#define _87_TaikoDrum     87
#define ultimoInstrumento 87

// Umbral de sensibilidad de los sensores piezoeléctricos, se utiliza para evitar falsas activaciones
const int umbral = 100;

// Definición de las funciones a implementar
void setup();
void loop();
void noteOn(byte nota, byte velocidad);
void noteOff(byte nota, byte velocidad);
void enviarMensajeMIDI(byte comando, byte dato1, byte dato2);

// Variables globales
uint8_t i, item, estado = 1;
uint8_t parche[11] = {_51_RideCymbal, _49_CrashCymbal, _46_HiHatOpen, _42_HiHatClosed, _35_Kick1, _45_LowTom, _47_LowMidTom, _40_Snare2, _38_Snare1, _41_LowFloorTom, _41_LowFloorTom};
uint16_t lectura[11] = {0,0,0,0,0,0,0,0,0,0,0};
uint16_t velocidad[11] = {0,0,0,0,0,0,0,0,0,0,0};
uint8_t activo[11] = {0,0,0,0,0,0,0,0,0,0,0};
uint8_t anterior[11] = {0,0,0,0,0,0,0,0,0,0,0};
uint8_t modoProgramacion = 0;
uint8_t parcheElegido = 0;
uint8_t instrumentoElegido = primerInstrumento;

// función de configuración inicial del Arduino
void setup() {
  // En los puertos digitales se debe indicar si son entrada o salida
  pinMode(1,INPUT);
  pinMode(3,INPUT);
  pinMode(4,INPUT);
  pinMode(5,INPUT);
  pinMode(6,INPUT);
  pinMode(7,INPUT);

  // Apertura del puerto serie al que está acoplado el conector MIDI
  // las interfaces MIDI trabajan siempre a 31.250 baudios
  Serial.begin(31250);

  // Apagado de todas las notas de los 16 canales del MIDI
  // Para asegurar que inicialmente haya silencio
  for (i=0; i<16; i++)  {
    enviarMensajeMIDI(176+i,123,0);
  }
}

// Función que se ejecuta constantemente una vez iniciado el Arduino
void loop() {
  // Este lazo se encarga de barrer todos los 11 sensores utilizados
  for(item=0; item<11; item++){
    if ( digitalRead(tecla1) == HIGH ) { // Primer tecla
      noteOn(22,90);
      noteOff(22,90);
      if ( modoProgramacion == 0 ) {
        modoProgramacion = 1;
      } else {
        modoProgramacion = 0;
      }
      delay(300);
    }
    if ( modoProgramacion == 1 ) {           // PROGRAMACIÓN ON/OFF
      if( analogRead(item) > umbral ) {
        parcheElegido = item;
        instrumentoElegido = parche[item];
      }
      if ( digitalRead(tecla2) == HIGH ) {  // ELEGIR INSTRUMENTO ANTERIOR
        if ( instrumentoElegido != primerInstrumento ) {
          instrumentoElegido--;
        }
        noteOn(instrumentoElegido,90);
        noteOff(instrumentoElegido,90);
        delay(300);
      }
      if ( digitalRead(tecla3) == HIGH ) {  // ELEGIR SIGUIENTE INSTRUMENTO
        if ( instrumentoElegido != ultimoInstrumento ) {
          instrumentoElegido++;
        }
        noteOn(instrumentoElegido,90);
        noteOff(instrumentoElegido,90);
        delay(300);
      }
      if ( digitalRead(tecla4) == HIGH ) {  // ASIGNAR EL INSTRUMENTO ELEGIDO
        noteOn(24,90);
        noteOff(24,90);
        delay(300);
        parche[parcheElegido] = instrumentoElegido;
        modoProgramacion = 0;
      }
    } else {
      // El pulsador 'tecla0' permite seleccionar entre los parches estándar de batería
      // y otra configuración con bongos e instrumentos afines, se pueden agregar más
      // configuraciones preestablecidas
      if ( digitalRead(tecla0) == HIGH ) {
        estado++;
        if (estado>2) {
          estado = 1;
        }
        if ( estado == 1) {
          parche[0] = _51_RideCymbal;
          parche[1] = _49_CrashCymbal;
          parche[2] = _46_HiHatOpen;
          parche[3] = _42_HiHatClosed;
          parche[4] = _35_Kick1;
          parche[5] = _45_LowTom;
          parche[6] = _47_LowMidTom;
          parche[7] = _40_Snare2;
          parche[8] = _38_Snare1;
          parche[9] = _41_LowFloorTom;
        }
        if ( estado == 2) {
          parche[0] = _54_Tambourine;
          parche[1] = _53_MRideBell;
          parche[2] = _56_CowBell;
          parche[3] = _39_Clap;
          parche[4] = _35_Kick1;
          parche[5] = _64_LowTumba;
          parche[6] = _60_BongoRim;
          parche[7] = _61_LowBongo;
          parche[8] = _63_HighConga;
          parche[9] = _41_LowFloorTom;
        }
      }
      if( analogRead(item) > umbral ) {
        anterior[item] = millis()+30;
        if ( millis() > anterior[item] ) {
          velocidad[item] = analogRead(item) / 8;
          activo[item] = 1;
        }
        if ( activo[item] == 1) {
          noteOn(parche[item], velocidad[item]);
          noteOff(parche[item], velocidad[item]);
          activo[item] = 0;
        }
      }
    }
  }
}

void noteOn(unsigned char nota, unsigned char velocidad) {
  enviarMensajeMIDI(0x99, nota, velocidad);
}

void noteOff(unsigned char nota, unsigned char velocidad) {
  enviarMensajeMIDI(0x89, nota, velocidad);
}

void enviarMensajeMIDI(unsigned char comando, unsigned char dato1, unsigned char dato2) {
  Serial.write(comando);
  Serial.write(dato1);
  Serial.write(dato2);
}