Buscar..


Introducción

La intención de este tema es mostrar algunos programas MIDI básicos que muestran cómo operar con el protocolo y agregan progresivamente funciones útiles que requieren las aplicaciones más complejas.

Ejemplo de MIDI THRU

El MIDI Thru es simple y fácil de probar. Cuando trabaje correctamente, podrá instalar su proyecto Arduino entre dos dispositivos MIDI, MIDI IN a MIDI OUT y podrá verificar que los dos dispositivos funcionan juntos. Si tiene la capacidad de medir la latencia, verá un aumento debido a las instrucciones de captura y retransmisión del búfer en serie.

// This is a simple MIDI THRU.  Everything in, goes right out.
// This has been validate on an Arduino UNO and a Olimex MIDI Shield  

boolean byteReady; 
unsigned char midiByte;

void setup() {
    // put your setup code here, to run once:
    //  Set MIDI baud rate:
    Serial.begin(31250);
    byteReady = false;
    midiByte = 0;  
}

// The Loop that always gets called...
void loop() {
   if (byteReady) {
        byteReady = false;
        Serial.write(midiByte);
    }
}

// The little function that gets called each time loop is called.  
// This is automated somwhere in the Arduino code.
void serialEvent() {
  if (Serial.available()) {
    // get the new byte:
    midiByte = (unsigned char)Serial.read();
    byteReady = true;
  }
}

MIDI a través de la cola

// This is a more complex MIDI THRU.  This version uses a queue.  Queues are important because some
// MIDI messages can be interrupted for real time events.  If you are generating your own messages,
// you may need to stop your message to let a "real time" message through and then resume your message.


#define QUEUE_DEPTH 128

// Queue Logic for storing messages
int headQ = 0;
int tailQ = 0;
unsigned char tx_queue[QUEUE_DEPTH];

void setup() {
    // put your setup code here, to run once:
    //  Set MIDI baud rate:
    Serial.begin(31250);
}

// getQDepth checks for roll over.  Folks have told me this 
// is not required.  Feel free to experiment.
int getQDepth() {
int depth = 0;
    if (headQ < tailQ) {
        depth = QUEUE_DEPTH - (tailQ - headQ);
    } else {
        depth = headQ - tailQ;
    }
    return depth;
}

void addQueue (unsigned char myByte) {
    int depth = 0;
    depth = getQDepth();

    if (depth < (QUEUE_DEPTH-2)) {
        tx_queue[headQ] = myByte;
        headQ++;
        headQ = headQ % QUEUE_DEPTH; // Always keep the headQ limited between 0 and 127
    }
}

unsigned char deQueue() {
    unsigned char myByte;
    myByte = tx_queue[tailQ];
    tailQ++;
    tailQ = tailQ % QUEUE_DEPTH;  // Keep this tailQ contained within a limit
    // Now that we dequeed the byte, it must be sent. 
    return myByte;
}

void loop() {
   if (getQDepth>0) {
        Serial.write(deQueue());
    }
}

// The little function that gets called each time loop is called.  
// This is automated somwhere in the Arduino code.
void serialEvent() {
  if (Serial.available()) {
    // get the new byte:
    addQueue((unsigned char)Serial.read());;
  }
}

Generación de reloj MIDI

// This is a MiDI clk generator.  This takes a #defined BPM and 
// makes the appropriate clk rate.  The queue is used to let other messages 
// through, but allows a clock to go immediately to reduce clock jitter

#define QUEUE_DEPTH 128
#define BPM 121
#define MIDI_SYSRT_CLK 0xF8

// clock tracking and calculation
unsigned long lastClock;
unsigned long captClock;
unsigned long clk_period_us;

// Queue Logic for storing messages
int headQ = 0;
int tailQ = 0;
unsigned char tx_queue[QUEUE_DEPTH];

void setup() {
    //  Set MIDI baud rate:
    Serial.begin(31250);
    clk_period_us = 60000000 / (24 * BPM);
    lastClock = micros();
}

// getQDepth checks for roll over.  Folks have told me this 
// is not required.  Feel free to experiment.
int getQDepth() {
int depth = 0;
    if (headQ < tailQ) {
        depth = QUEUE_DEPTH - (tailQ - headQ);
    } else {
        depth = headQ - tailQ;
    }
    return depth;
}

void addQueue (unsigned char myByte) {
    int depth = 0;
    depth = getQDepth();

    if (depth < (QUEUE_DEPTH-2)) {
        tx_queue[headQ] = myByte;
        headQ++;
        headQ = headQ % QUEUE_DEPTH; // Always keep the headQ limited between 0 and 127
    }
}

unsigned char deQueue() {
    unsigned char myByte;
    myByte = tx_queue[tailQ];
    tailQ++;
    tailQ = tailQ % QUEUE_DEPTH;  // Keep this tailQ contained within a limit
    // Now that we dequeed the byte, it must be sent. 
    return myByte;
}

void loop() {
    captClock = micros();
    
    if (lastClock > captClock) {
        // we have a roll over condition - Again, maybe we don't need to do this.
        if (clk_period_us <= (4294967295 - (lastClock - captClock))) {
            // Add a the ideal clock period for this BPM to the last measurement value
            lastClock = lastClock + clk_period_us;
            // Send a clock, bypasing the transmit queue
            Serial.write(MIDI_SYSRT_CLK);
        }
    } else if (clk_period_us <= captClock-lastClock) {
        // Basically the same two commands above, but not within a roll over check
        lastClock = lastClock + clk_period_us;
        // Send a clock, bypasing the transmit queue
        Serial.write(MIDI_SYSRT_CLK);
    }

    if (getQDepth>0) {
        Serial.write(deQueue());
    }
}

// The little function that gets called each time loop is called.  
// This is automated somwhere in the Arduino code.
void serialEvent() {
  if (Serial.available()) {
    // get the new byte:
    addQueue((unsigned char)Serial.read());;
  }
}

Mensajes MIDI definidos

En general, el protocolo MIDI se divide en "mensajes". Hay 4 clases generales de mensajes:

  • Canal de voz
  • Modo de canal
  • Sistema Común
  • Mensajes en tiempo real del sistema

Los mensajes comienzan con un valor de byte por encima de 0x80. Cualquier valor por debajo de 0x7F se considera datos. Lo que significa efectivamente que 127 es el valor máximo que se puede codificar en un solo byte de datos MIDI. Para codificar valores más grandes, se requieren dos o más bytes de datos MIDI.

Debe señalarse que los mensajes deben enviarse de principio a fin sin interrupción ... EXCEPTO ... Los mensajes del sistema en tiempo real, que son un solo byte, que se pueden inyectar en medio de cualquier mensaje.

Mensajes de voz del canal

Estado D7..D0 Bytes de datos Descripción
1000nnnn 0kkkkkkk 0vvvvvvvv Evento Note Off. Este mensaje se envía cuando se suelta una nota (finaliza). (kkkkkkk) es el número clave (nota). (vvvvvvv) es la velocidad.
1001nnnn 0kkkkkkk 0vvvvvvvv Nota sobre el evento. Este mensaje se envía cuando se presiona una nota (inicio). (kkkkkkk) es el número clave (nota). (vvvvvvv) es la velocidad.
1010nnnn 0kkkkkkk 0vvvvvvvv Presión de tecla polifónica (aftertouch). Este mensaje se envía con mayor frecuencia presionando la tecla hacia abajo después de que "toque fondo". (kkkkkkk) es el número clave (nota). (vvvvvvv) es el valor de presión.
1011nnnn 0ccccccc 0vvvvvvvv Control de cambio. Este mensaje se envía cuando un valor de controlador cambia. Los controladores incluyen dispositivos tales como pedales y palancas. Los números de controlador 120-127 están reservados como "Mensajes de modo de canal" (abajo). (ccccccc) es el número del controlador (0-119). (vvvvvvv) es el valor del controlador (0-127).
1100nnnn 0ppppppp Cambio de programa. Este mensaje enviado cuando el número de parche cambia. (ppppppp) es el nuevo número de programa.
1101nnnn 0vvvvvvvv Presión del canal (After-touch). Este mensaje se envía con mayor frecuencia presionando la tecla hacia abajo después de que "toque fondo". Este mensaje es diferente del post-toque polifónico. Use este mensaje para enviar el valor de presión máximo individual (de todas las teclas presionadas actuales). (vvvvvvv) es el valor de presión.
1110nnnn 0lllllll 0mmmmmmm Cambio de Pitch Bend. Este mensaje se envía para indicar un cambio en el doblador de tono (rueda o palanca, típicamente). El doblador de tono se mide por un valor de catorce bits. El centro (sin cambio de tono) es 2000H. La sensibilidad es una función del receptor, pero se puede configurar utilizando RPN 0. (lllllll) son los 7 bits menos significativos. (mmmmmmm) son los 7 bits más significativos.

Mensajes de modo de canal

Estado D7..D0 Bytes de datos Descripción
1011nnnn 0ccccccc 0vvvvvvvv Mensajes de modo de canal. Este es el mismo código que el Cambio de control (arriba), pero implementa el control de Modo y el mensaje especial al usar los números de controlador reservados 120-127. Los comandos son:
Todo el sonido apagado. Cuando se recibe Todo el sonido apagado, todos los osciladores se apagan y sus envolventes de volumen se ponen a cero tan pronto como sea posible. c = 120, v = 0: Todo el sonido apagado
Restablecer todos los controladores. Cuando se recibe Restablecer todos los controladores, todos los valores del controlador se restablecen a sus valores predeterminados. (Ver las prácticas recomendadas específicas para los valores predeterminados).
c = 121, v = x: el valor solo debe ser cero a menos que se permita lo contrario en una práctica recomendada específica.
Control local. Cuando el control local está desactivado, todos los dispositivos en un canal dado responderán solo a los datos recibidos a través de MIDI. Los datos reproducidos, etc. serán ignorados. Control local activado restaura las funciones de los controladores normales.
c = 122, v = 0: Control local desactivado
c = 122, v = 127: Control local activado
Todas las notas desactivadas. Cuando se reciben todas las notas desactivadas, todos los osciladores se apagarán.
c = 123, v = 0: todas las notas desactivadas (consulte el texto para obtener una descripción de los comandos del modo real).
c = 124, v = 0: Modo Omni desactivado
c = 125, v = 0: Modo Omni activado
c = 126, v = M: Modo mono activado (Poli apagado) donde M es el número de canales (Omni apagado) o 0 (Omni encendido)
c = 127, v = 0: Modo poli activado (Mono apagado) (Nota: estos cuatro mensajes también causan todas las notas desactivadas)

Mensajes comunes del sistema

Estado D7..D0 Bytes de datos Descripción
11110000 0iiiiiii [0iiiiiii 0iiiiiii] 0ddddddd --- --- 0ddddddd 11110111 Exclusivo del sistema. Este tipo de mensaje permite a los fabricantes crear sus propios mensajes (como volcados masivos, parámetros de parches y otros datos no especificados) y proporciona un mecanismo para crear mensajes de Especificación MIDI adicionales. El código de identificación del fabricante (asignado por MMA o AMEI) es 1 byte (0iiiiiii) o 3 bytes (0iiiiiii 0iiiiiii 0iiiiiii). Dos de las ID de 1 byte están reservadas para extensiones denominadas mensajes exclusivos universales, que no son específicos del fabricante. Si un dispositivo reconoce el código de ID como propio (o como un mensaje universal compatible) escuchará el resto del mensaje (0ddddddd). De lo contrario, el mensaje será ignorado. (Nota: solo los mensajes en tiempo real se pueden intercalar con un sistema exclusivo).
11110001 0nnndddd Código de tiempo MIDI Quarter Frame. nnn = Tipo de mensaje dddd = Valores
11110010 0lllllll 0mmmmmmm Puntero de posición de la canción. Este es un registro interno de 14 bits que contiene el número de tiempos MIDI (1 tiempo = seis relojes MIDI) desde el inicio de la canción. l es el LSB, m el MSB.
11110011 0sssssss Seleccione la canción. La Selección de canción especifica qué secuencia o canción se reproducirá.
11110100 Indefinido (Reservado)
11110101 Indefinido (Reservado)
11110110 Solicitud de melodía Al recibir una solicitud de sintonización, todos los sintetizadores analógicos deben sintonizar sus osciladores.
11110111 Fin de Exclusivo. Se utiliza para terminar un volcado exclusivo del sistema (ver arriba).

Mensajes en tiempo real del sistema

Estado D7..D0 Bytes de datos Descripción
11111000 Reloj de tiempo Se envía una nota de 24 veces por trimestre cuando se requiere sincronización (ver texto).
11111001 Indefinido (Reservado)
11111010 Comienzo. Inicia la secuencia actual de reproducción. (Este mensaje será seguido con los relojes de tiempo).
11111011 Continuar. Continuar en el punto en que se detuvo la secuencia.
11111100 Detener. Detener la secuencia actual.
11111101 Indefinido (Reservado)
11111110 Detección activa Este mensaje está destinado a enviarse repetidamente para indicar al receptor que una conexión está activa. El uso de este mensaje es opcional. Cuando se recibe inicialmente, el receptor esperará recibir otro mensaje de detección activa cada 300 ms (máx.), Y si no lo hace, asumirá que la conexión ha finalizado. En la terminación, el receptor apagará todas las voces y volverá a la operación normal (detección no activa).
11111111 Reiniciar. Restablecer todos los receptores en el sistema al estado de encendido. Esto debe usarse con moderación, preferiblemente bajo control manual. En particular, no debe enviarse en el encendido.


Modified text is an extract of the original Stack Overflow Documentation
Licenciado bajo CC BY-SA 3.0
No afiliado a Stack Overflow