El Estándar Web MIDI API y Baja Latencia: Conectando Instrumentos Físicos a Salas Colaborativas

Cómo funciona el protocolo binario MIDI en el navegador mediante navigator.requestMIDIAccess, síntesis polifónica y transmisión de eventos musicales en tiempo real.

En la sala de Música & Creatividad de Roomly, los participantes pueden tocar un piano polifónico interactivo utilizando tanto el teclado de su computadora o pantalla táctil como un controlador o piano MIDI físico conectado por USB, escuchando e interpretando piezas en vivo junto a otros usuarios conectados en la misma sala. Lograr que la pulsación de una tecla física se traduzca instantáneamente en sonido local y remoto requiere dominar la Web MIDI API y la programación de voces polifónicas.

1. El Protocolo MIDI: Eficiencia Extrema en 3 Bytes

Diseñado originalmente en 1983 y vigente hasta hoy por su extraordinaria simplicidad, un mensaje de nota MIDI estándar no transmite ondas de audio (que pesarían cientos de kilobits por segundo), sino instrucciones de control compactas de exactamente 3 bytes:

  • Byte 0 (Status Byte): Define el comando y el canal (del 1 al 16). En hexadecimal, 0x90 (144 en decimal) indica Note On en el canal 1, mientras que 0x80 (128 en decimal) indica Note Off.
  • Byte 1 (Data Byte 1 - Pitch): El número de nota musical entre 0 y 127, donde 60 corresponde al Do central (Middle C / C4 = 261.63 Hz) y 69 al La de afinación estándar (A4 = 440.00 Hz).
  • Byte 2 (Data Byte 2 - Velocity): La fuerza o velocidad con la que se presionó la tecla, de 0 a 127. Un mensaje Note On con velocity = 0 equivale por convención a soltar la tecla (Note Off).

2. Captura de Eventos Hardware con navigator.requestMIDIAccess()

El navegador expone el acceso a los controladores MIDI del sistema operativo mediante una promesa asíncrona que enumera todas las entradas (inputs) y permite reaccionar a la conexión en caliente (hot-plugging) de teclados USB:

async function initMidiController(onNoteOn, onNoteOff) {
  if (!navigator.requestMIDIAccess) return;
  const midiAccess = await navigator.requestMIDIAccess({ sysex: false });

  const bindInputs = () => {
    for (const input of midiAccess.inputs.values()) {
      input.onmidimessage = (event) => {
        const [status, midiNote, velocity] = event.data;
        const command = status & 0xf0; // Ignorar los 4 bits del canal MIDI

        if (command === 0x90 && velocity > 0) {
          onNoteOn(midiNote, velocity / 127);
        } else if (command === 0x80 || (command === 0x90 && velocity === 0)) {
          onNoteOff(midiNote);
        }
      };
    }
  };

  bindInputs();
  midiAccess.onstatechange = () => bindInputs();
}

3. Conversión de Nota MIDI a Frecuencia Acústica (Temperamento Igual)

Para sintetizar cualquier nota en la Web Audio API, convertimos el número de nota MIDI $n$ a su frecuencia fundamental en Hercios ($f$) utilizando la fórmula matemática del temperamento igual de 12 semitonos por octava referenciada a $A_4 = 440\text{ Hz}$:

function midiNoteToFrequency(midiNote) {
  return 440 * Math.pow(2, (midiNote - 69) / 12);
}

4. Gestión de Turnos, Polifonía y Prevención de Saturación en Salas Grupales

Si 20 usuarios en una sala de chat presionaran teclas al mismo tiempo sin coordinación, el resultado sería cacofónico y saturaría el bus de mezcla de audio (clipping). Por ello, en Roomly diseñamos un sistema de Escenario y Cola de Turnos en Tiempo Real acompañado de un compresor dinámico (DynamicsCompressorNode) a la salida del sintetizador:

  • Los usuarios pueden practicar en modo local silencioso o unirse a la cola del escenario para interpretar una pieza frente a la sala durante su turno activo.
  • Cada evento enviado por WebSocket transporta únicamente el identificador de nota, la velocidad normalizada y la marca de tiempo relativa, ocupando menos de 60 bytes en JSON o 4 bytes en binario.
  • Un límite de polifonía máxima de 16 voces simultáneas recicla automáticamente la nota más antigua (voice stealing) para garantizar un consumo de CPU constante incluso en teléfonos móviles de gama media.
IX

Escrito por Equipo Multimedia Inovaxsoft

El equipo de ingeniería de Inovaxsoft investiga, desarrolla y documenta arquitecturas web de baja latencia, sistemas distribuidos sobre Kubernetes ARM64 y herramientas de productividad como PomoTask y Roomly.