---
title: "MIDI vs MusicXML en Python: qué se pierde y qué no"
slug: midi-vs-musicxml-en-python
kind: tutorial
summary: "Un experimento con music21 y pretty_midi: la misma frase con digitación, ligadura y dinámica, exportada a MIDI y a MusicXML. Qué sobrevive en cada formato, con cifras reales."
publishedAt: 2026-08-05
---
import { Image } from "astro:assets";
import partituraEjemplo from "../../assets/blog/posts/infografias/partitura-midi-vs-musicxml.jpg";

**MIDI** es el formato que todo el mundo que ha tocado con un teclado
electrónico conoce, aunque sea de oídas. **MusicXML** lo conoce mucho menos
gente, y sin embargo hay una pregunta que aparece en cuanto se necesita algo
más que "que suene": ¿y si lo que hace falta es la *partitura*, no el sonido?
Digitación, ligaduras, matices de dinámica —todo eso que un intérprete lee y
un ordenador puede necesitar conservar—. Este tutorial no explica de nuevo
qué es cada formato —para eso están [¿Qué es MIDI?](/blog/que-es-midi) y
[¿Qué es MusicXML?](/blog/que-es-musicxml)— sino que lo demuestra: construye
la misma frase musical una sola vez, la exporta a los dos formatos y comprueba,
con datos reales, qué sobrevive en cada uno.

## El experimento

La idea es sencilla: escribir una frase corta con **music21** —digitación en
cada nota, una ligadura y una marca de dinámica incluidas— y exportarla dos
veces, una a MusicXML y otra a MIDI. Después, leer cada fichero de vuelta y
ver qué queda.

```python
from music21 import stream, note, meter, tempo, dynamics, articulations, spanner, clef

s = stream.Part()
s.append(clef.TrebleClef())
s.append(meter.TimeSignature('4/4'))
s.append(tempo.MetronomeMark(number=100))

n1 = note.Note('C5', quarterLength=1)
n1.articulations.append(articulations.Fingering(1))
n2 = note.Note('E5', quarterLength=1)
n2.articulations.append(articulations.Fingering(3))
n3 = note.Note('G5', quarterLength=0.5)
n3.articulations.append(articulations.Fingering(5))
n4 = note.Note('E5', quarterLength=0.5)
n4.articulations.append(articulations.Fingering(3))

n1.dynamic = dynamics.Dynamic('mp')
slur = spanner.Slur(n3, n4)

s.append(n1); s.append(n2); s.append(n3); s.append(n4)
s.insert(0, dynamics.Dynamic('mp'))
s.insert(0, slur)

s.write('musicxml', fp='ejemplo.musicxml')
s.write('midi', fp='ejemplo.mid')
```

Cuatro notas —Do5, Mi5, Sol5, Mi5—, cada una con su dedo indicado, las dos
últimas ligadas entre sí y toda la frase marcada *mezzopiano*. Nada exótico:
es exactamente el tipo de información que un intérprete espera ver impresa
en una partitura.

<figure>
  <Image
    src={partituraEjemplo}
    alt="Partitura de la frase de ejemplo renderizada desde el MusicXML real generado por el código: cuatro notas en clave de sol con digitación 1, 3, 5, 3, una ligadura entre las dos últimas y la indicación de dinámica mp"
    widths={[480, 768, 1200]}
    sizes="(min-width: 760px) 680px, 92vw"
    loading="lazy"
  />
  <figcaption>La frase de ejemplo tal como queda escrita en el MusicXML generado por el código anterior —digitación, ligadura y dinámica incluidas—, renderizada aquí para verla como la vería un intérprete.</figcaption>
</figure>

## Leyendo el MIDI de vuelta

Con **pretty_midi** se puede abrir `ejemplo.mid` y listar las notas tal como
quedaron codificadas:

```
pitch=72 start=0.00 end=0.60 velocity=81   (C5)
pitch=76 start=0.60 end=1.20 velocity=81   (E5)
pitch=79 start=1.20 end=1.50 velocity=81   (G5)
pitch=76 start=1.50 end=1.80 velocity=81   (E5)
```

Cuatro eventos de nota, cada uno con altura (`pitch`), instante de inicio y
fin en segundos, y una `velocity` —81 en las cuatro, resultado de traducir
la única dinámica *mp* de la frase a un valor MIDI fijo—. Es exactamente lo
que cabe esperar de MIDI: instrucciones de *cuándo suena qué, con qué
intensidad*. Ni rastro de la digitación, ni de la ligadura, ni de que hubo
alguna vez una marca "mp" en la partitura: esa información no tiene dónde
vivir en el protocolo. Se toca igual de bien, pero se ha perdido para
siempre en cuanto se guardó.

## Leyendo el MusicXML de vuelta

Con `music21.converter.parse` sobre `ejemplo.musicxml`, la misma frase
devuelve mucho más:

```
C5: digitación=[1]
E5: digitación=[3]
G5: digitación=[5]
E5: digitación=[3]
Ligaduras (slurs) codificadas explícitamente: 2
Marcas de dinámica: ['mp']
```

Las cuatro digitaciones están intactas, la ligadura sigue codificada como tal
—no como una coincidencia de tiempos, sino como un elemento `<slur>`
explícito— y la marca "mp" sigue siendo "mp", no un número de velocidad. Todo
lo que MIDI no tenía dónde guardar, MusicXML lo conserva porque describe la
partitura, no la interpretación.

Un fragmento del XML generado deja ver por qué: cada uno de esos elementos es
una etiqueta legible, no un número de protocolo.

```xml
<dynamics default-x="-36" default-y="-80">
  <mp />
</dynamics>
...
<fingering alternate="no" substitution="no">1</fingering>
...
<slur number="1" type="start" />
```

## Lo que dicen los bytes

La diferencia también se ve, literalmente, en el tamaño y la forma de cada
fichero. `ejemplo.mid` pesa **99 bytes**; `ejemplo.musicxml`, **3560 bytes**
—36 veces más para la misma frase de cuatro notas—. No es ineficiencia: es
la diferencia entre guardar solo instrucciones de reproducción y guardar una
descripción completa de la notación escrita.

Los primeros bytes del MIDI, en hexadecimal, son binario puro:

```
4d54 6864 0000 0006 0001 0002 2760 4d54
726b 0000 0014 00ff 5103 0927 c000 ff58
```

Sin un parser de por medio, esto no dice nada. El MusicXML, en cambio, es
texto XML que cualquier persona puede abrir en un editor y leer —los
fragmentos de arriba (`<dynamics>`, `<fingering>`, `<slur>`) se entienden sin
más contexto que el propio nombre de la etiqueta—.

## Tabla comparativa del experimento

| | MIDI (`ejemplo.mid`) | MusicXML (`ejemplo.musicxml`) |
|---|---|---|
| Notas (altura, tiempo) | ✔ Conservadas | ✔ Conservadas |
| Digitación | ✘ Perdida | ✔ Conservada (`[1]`, `[3]`, `[5]`, `[3]`) |
| Ligadura | ✘ Perdida (solo tiempos contiguos) | ✔ Conservada como `<slur>` explícito |
| Dinámica ("mp") | Aproximada a `velocity=81` | ✔ Conservada como texto (`mp`) |
| Tamaño | 99 bytes | 3560 bytes |
| Legible por una persona | ✘ Binario | ✔ Texto XML |

## Por qué importa en la práctica

Esto no es una curiosidad de formato: decide qué herramienta usar según lo
que se necesite conservar. Para reproducir, secuenciar o controlar un
sintetizador, MIDI sobra y es más ligero. Para notación, pedagogía —una
digitación que un alumno necesita ver impresa— o archivo de una partitura
que se quiere editar más adelante, MIDI se queda corto por diseño, no por
descuido: nunca prometió guardar eso.

Es también la razón de que un sistema de [transcripción automática de
música](/blog/que-es-amt) tenga que elegir con cuidado su formato de salida
según el uso final: MIDI si el objetivo es que la transcripción suene,
MusicXML si el objetivo es que alguien la lea, la corrija o la use para
enseñar. En mi propia investigación doctoral trabajo con **piano** como
corpus, y esta misma disyuntiva aparece en cuanto un sistema de AMT termina
de decidir qué notas sonaron: el siguiente paso es en qué formato entregar
ese resultado, y no es una decisión neutra.

## Bibliografía

Las referencias en las que se apoya este artículo y por dónde seguir leyendo:

- The MIDI Association. [*The Official MIDI Specifications* (MIDI 1.0, General MIDI, MIDI 2.0)](https://midi.org).
- W3C Music Notation Community Group. (2021). [*MusicXML 4.0*](https://www.w3.org/2021/06/musicxml40/).
- Cuthbert, M. S., & Ariza, C. (2010). [music21: A Toolkit for Computer-Aided Musicology and Symbolic Music Data](https://web.mit.edu/music21/). *Proceedings of the 11th International Society for Music Information Retrieval Conference (ISMIR)*.
- Raffel, C., & Ellis, D. P. W. [pretty_midi: A Python Library for Handling MIDI Data](https://github.com/craffel/pretty-midi) — repositorio y documentación oficial.
