← Diario de Construcción

MIDI para Programadores: Entendiendo el Protocolo que Conecta Música y Código

Una introducción técnica al protocolo MIDI desde la perspectiva del desarrollador: estructura binaria de mensajes, comunicación serial y cómo interactuar con hardware musical usando código.

Para quienes están acostumbrados a lidiar con APIs JSON de alta abstracción, interactuar con hardware físico a veces parece un misterio. Sin embargo, cuando entramos en el mundo de la música electrónica, los sintetizadores y los controladores, descubrimos un protocolo creado en la década de 1980 que resuelve la comunicación de hardware de una manera extremadamente elegante, ligera y rápida: el MIDI (Musical Instrument Digital Interface).

Si sabes programar y te gusta la música, entender el MIDI te abre las puertas para crear tus propios controladores personalizados, automatizar instrumentos reales y construir sistemas de audio interactivos.

¿Qué es realmente el MIDI?

Un error común es pensar que el MIDI transporta audio (el sonido físico de un instrumento). En realidad, el MIDI es solo un protocolo de datos de rendimiento. Describe lo que hace un músico en el instrumento, no el sonido que produce el instrumento.

Cuando presionas una tecla en un teclado controlador MIDI, este no envía una onda sonora a la computadora; envía un pequeño paquete de datos que dice: “La tecla número 60 (Do central) fue presionada en el canal 1 con una fuerza (velocity) de 100”. Corresponde al receptor (un software en la computadora u otro sintetizador) leer este mensaje y generar el sonido apropiado.

Esta distinción hace que el flujo de datos sea minúsculo, permitiendo que la transmisión ocurra en tiempo real sin una latencia perceptible.

La anatomía binaria de los mensajes MIDI

Como programadores, nos encanta analizar estructuras de datos. MIDI 1.0 utiliza mensajes binarios cortos de 1 a 3 bytes enviados en serie.

La mayoría de los mensajes de canal se componen de:

  1. Status Byte (1 byte): Define el tipo de comando (Note On, Note Off, Control Change, etc.) y el canal MIDI (del 1 al 16). El bit más significativo (MSB) de un Status Byte es siempre 1 (valores decimales del 128 al 255).
  2. Data Bytes (0, 1 o 2 bytes): Contienen los parámetros del comando. El bit más significativo de un Data Byte es siempre 0 (valores decimales del 0 al 127).

Ejemplo práctico: El comando Note On (Tocar Nota)

Un mensaje estándar de “Note On” tiene 3 bytes:

  • Byte 1 (Status): 0x90 (donde 9 representa Note On y 0 representa el canal 1).
  • Byte 2 (Nota): 0x3C (valor decimal 60, que se mapea al Do central - C4).
  • Byte 3 (Velocidad/Fuerza): 0x64 (valor decimal 100, indicando la intensidad del toque).

Para dejar de tocar la nota, el controlador envía un mensaje de Note Off (0x80, 0x3C, 0x00) o un Note On con fuerza cero (0x90, 0x3C, 0x00).

Comunicação serial e latência

El MIDI tradicional utiliza una comunicación serial simple y asíncrona que opera a una velocidad de transmisión fija de 31.250 bits por segundo (baud rate).

Aunque esta velocidad parece extremadamente lenta para los estándares actuales (donde los gigabits son la norma), está perfectamente equilibrada para el hardware de bajo consumo de los microcontroladores y para el tamaño de los mensajes. Enviar un mensaje de Note On de 3 bytes (24 bits en total) toma menos de 1 milisegundo, lo que está muy por debajo del umbral de latencia perceptible para el oído humano (unos 10ms).

Actualmente, el MIDI también se encapsula a través de USB (USB-MIDI), viajando a la velocidad estándar de los puertos USB modernos con un ancho de banda aún mayor.

Interactuando con MIDI mediante código (Python y C++)

Conectar tu código al mundo MIDI es sencillo gracias a bibliotecas listas en prácticamente todos los lenguajes modernos.

Lectura de MIDI con Python (Mido)

Usando la biblioteca mido, puedes abrir puertos MIDI en tu computadora e imprimir los mensajes recibidos en tiempo real con muy pocas líneas de código:

import mido

# Muestra los puertos de entrada disponibles
print(mido.get_input_names())

# Abre el primer puerto y escucha los mensajes
with mido.open_input('Nombre de tu teclado MIDI') as inport:
    for msg in inport:
        if msg.type == 'note_on':
            print(f"Nota presionada: {msg.note} | Fuerza: {msg.velocity}")

Generación de MIDI con Arduino (ESP32 / Arduino Uno)

Si estás construyendo tu propio pedalboard o controlador con botones físicos y potenciómetros, puedes utilizar la biblioteca MIDI en C++ para enviar comandos a tus sintetizadores:

#include <MIDI.h>

MIDI_CREATE_DEFAULT_INSTANCE();

void setup() {
  MIDI.begin(MIDI_CHANNEL_OFF);
}

void loop() {
  // Envía la nota C4 (60) en el canal 1 con fuerza 100
  MIDI.sendNoteOn(60, 100, 1);
  delay(1000);
  
  // Envía Note Off para detener el sonido
  MIDI.sendNoteOff(60, 0, 1);
  delay(1000);
}

Conclusión

El MIDI demuestra que los protocolos simples y enfocados en la eficiencia de transmisión duran décadas. Al comprender la arquitectura binaria de sus mensajes y el funcionamiento de la comunicación serial, puedes programar soluciones que expandan la creatividad musical, integrando el software que escribes con el hardware físico que utilizas en el escenario o en el estudio.

Tecnologías y Conceptos