Spaces:
Running
Running
| import pretty_midi | |
| import os | |
| import logging | |
| logger = logging.getLogger(__name__) | |
| def parse_midi_file(filepath: str) -> dict: | |
| """ | |
| Parsea un archivo MIDI (.mid o .midi) y extrae todas sus pistas, notas, tempo y clasificación GM. | |
| """ | |
| if not os.path.exists(filepath): | |
| raise FileNotFoundError(f"No se encontró el archivo MIDI en: {filepath}") | |
| try: | |
| pm = pretty_midi.PrettyMIDI(filepath) | |
| tempo = pm.estimate_tempo() | |
| duration = pm.get_end_time() | |
| tracks = [] | |
| for idx, inst in enumerate(pm.instruments): | |
| notes = [] | |
| for note in inst.notes: | |
| notes.append({ | |
| "note": pretty_midi.note_number_to_name(note.pitch), | |
| "midi": note.pitch, | |
| "start": round(note.start, 3), | |
| "duration": round(note.end - note.start, 3), | |
| "velocity": note.velocity | |
| }) | |
| # Si no tiene notas, la ignoramos para mantener el payload limpio | |
| if not notes: | |
| continue | |
| if inst.is_drum: | |
| inst_type = "drums" | |
| name = "Batería / Percusión" | |
| else: | |
| prog = inst.program | |
| if 0 <= prog <= 7: | |
| inst_type = "piano" | |
| name = f"Piano (GM {prog})" | |
| elif 24 <= prog <= 31: | |
| inst_type = "guitar" | |
| name = f"Guitarra (GM {prog})" | |
| elif 32 <= prog <= 39: | |
| inst_type = "bass" | |
| name = f"Bajo (GM {prog})" | |
| elif 16 <= prog <= 23: | |
| inst_type = "organ" | |
| name = f"Órgano (GM {prog})" | |
| elif 40 <= prog <= 55: | |
| inst_type = "strings" | |
| name = f"Cuerdas/Orquesta (GM {prog})" | |
| elif 56 <= prog <= 71: | |
| inst_type = "brass" | |
| name = f"Metales/Vientos (GM {prog})" | |
| else: | |
| inst_type = "synth" | |
| name = f"Sintetizador (GM {prog})" | |
| tracks.append({ | |
| "id": idx, | |
| "nombre": name, | |
| "program": inst.program, | |
| "is_drum": inst.is_drum, | |
| "tipo_instrumento": inst_type, | |
| "total_notas": len(notes), | |
| "notas": notes | |
| }) | |
| return { | |
| "success": True, | |
| "tempo_bpm": round(tempo, 1) if tempo > 0 else 120.0, | |
| "duracion_segundos": round(duration, 2), | |
| "total_pistas": len(tracks), | |
| "pistas": tracks | |
| } | |
| except Exception as e: | |
| logger.error(f"Error parseando archivo MIDI {filepath}: {e}") | |
| return { | |
| "success": False, | |
| "error": f"El archivo no es un MIDI válido o está dañado: {str(e)}" | |
| } | |