Spaces:
Running
Running
| import io | |
| def transpose_midi(midi_bytes: bytes | None) -> bytes | None: | |
| """ | |
| Transpose all MIDI notes by +2 semitones (clamped to 0-127). | |
| Args: | |
| midi_bytes: Raw MIDI file bytes from the frontend | |
| Returns: | |
| Transposed MIDI file bytes | |
| """ | |
| if midi_bytes is None: | |
| return None | |
| try: | |
| import mido | |
| # Parse the MIDI file from bytes | |
| midi_file = mido.MidiFile(file=io.BytesIO(midi_bytes)) | |
| # Create a new MIDI file with transposed notes | |
| new_midi = mido.MidiFile(ticks_per_beat=midi_file.ticks_per_beat) | |
| for track in midi_file.tracks: | |
| new_track = mido.MidiTrack() | |
| for msg in track: | |
| if msg.type in ('note_on', 'note_off'): | |
| # Transpose by +2 semitones, clamped to valid MIDI range | |
| new_note = min(127, max(0, msg.note + 2)) | |
| new_msg = msg.copy(note=new_note) | |
| new_track.append(new_msg) | |
| else: | |
| # Copy non-note messages as-is | |
| new_track.append(msg.copy()) | |
| new_midi.tracks.append(new_track) | |
| # Write to bytes | |
| output = io.BytesIO() | |
| new_midi.save(file=output) | |
| return output.getvalue() | |
| except Exception as e: | |
| print(f"Error processing MIDI: {e}") | |
| return midi_bytes # Return original on error | |