Replies: 1 comment
-
Hey, I've been delving deeper into MIDI over the past few days and discovered that scrolling through a MIDI song isn't straightforward due to the influence of messages preceding the current playtime. However, I figured out a workaround to start playing MIDI files from a specific point in time. It might not be the most elegant solution, but it gets the job done by skipping the wait until the desired start time and pushing all MIDI messages through until it's time to play. In this process, I disable note_on and note_off messages since I believe they aren't necessary for setting up the play from the start time. There's also a possibility that some MIDI instruments might attempt to play all these notes during this very short particular instance of time. For those interested in doing the same, here's a complete code example (utilizing pygame to play the notes). I've also incorporated tempo adjustments for timing and volume control for velocity into the function. One thing worth noting is that I use import pygame.midi
import time
from mido import MidiFile
def play_midi_file(file_path, start_time=0, tempo=100, volume=100):
"""Play a MIDI file with adjustable start time (seconds), tempo %, and volume %."""
current_time = 0
searching = False
# Check if tempo is valid
if tempo <= 0:
print('Tempo must be higher than 0 to play')
return
try:
pygame.midi.init()
player = pygame.midi.Output(0)
player.set_instrument(0)
for msg in MidiFile(file_path):
searching = current_time < start_time
# Display current time and MIDI message
print(f"[ {current_time} ]", end='')
print(msg)
# skip delay until start time is passed
if not searching:
time.sleep(msg.time * (100 / tempo))
# Process the MIDI message
if not msg.is_meta:
current_time += msg.time
# Play the note or control change
if not searching:
if msg.type == 'note_on':
scaled_velocity = int(msg.velocity * volume / 100)
scaled_velocity = max(0, min(scaled_velocity, 127))
player.note_on(msg.note, scaled_velocity, msg.channel)
elif msg.type == 'note_off':
player.note_off(msg.note, msg.velocity, msg.channel)
elif msg.type == 'control_change':
player.write_short(0xB0 + msg.channel, msg.control, msg.value)
except KeyboardInterrupt:
print("\nExiting...")
except Exception as e:
print(f"An error occurred: {e}")
finally:
pygame.midi.quit()
# Example usage:
midi_file_path = 'mario.mid'
play_midi_file(midi_file_path,0,100,100) |
Beta Was this translation helpful? Give feedback.
-
Hi, thank you for this library. I am trying to use it to build a visualizer on top of a piano to help my kid play along with midi files.
One thing I like to implement is the ability to rewind X seconds and play. Or start the song from a certain point in time. But I can't figure out how to do that using the MidiFile('song.mid').play() function.
Any idea how to solve this?
Beta Was this translation helpful? Give feedback.
All reactions