Skip to content

Instantly share code, notes, and snippets.

@phuang1024
Created May 23, 2023 03:01
Show Gist options
  • Select an option

  • Save phuang1024/f976911f9e7cc34d49e9ab127fe04a67 to your computer and use it in GitHub Desktop.

Select an option

Save phuang1024/f976911f9e7cc34d49e9ab127fe04a67 to your computer and use it in GitHub Desktop.

Revisions

  1. phuang1024 created this gist May 23, 2023.
    83 changes: 83 additions & 0 deletions musiclab_piano_player.py
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,83 @@
    import argparse
    import time

    import mido
    import pyautogui


    class Player:
    keys = list("awsedftgyhuj")

    def __init__(self):
    self.midi_paths = []

    def note_to_info(self, note):
    key_ind = note + 9
    key = self.keys[key_ind % 12]
    octave = key_ind // 12
    return (key, octave)

    def play(self, init_pause=1, key_pause=0.001, speed=1, loop=False):
    pyautogui.PAUSE = key_pause
    time.sleep(init_pause)

    notes = []
    for path in self.midi_paths:
    midi = mido.MidiFile(path)

    curr_time = 0
    starts = [False] * 88
    for msg in midi:
    curr_time += msg.time
    if not msg.is_meta and msg.type == "note_on":
    note = msg.note - 21
    if msg.velocity == 0:
    notes.append([note, starts[note], curr_time, "NOT_PLAYED"])
    else:
    starts[note] = curr_time

    notes = sorted(notes, key=(lambda x: x[1]))

    curr_octave = 4
    octave = 4
    time_start = time.time()
    while True:
    elapsed = time.time() - time_start
    elapsed *= speed

    for i, info in enumerate(notes):
    note, start, end, state = info

    if state == "NOT_PLAYED" and elapsed >= start:
    key, octave = self.note_to_info(note)
    oct_diff = abs(octave - curr_octave)

    if octave > curr_octave:
    pyautogui.typewrite("x"*oct_diff)
    elif octave < curr_octave:
    pyautogui.typewrite("z"*oct_diff)

    pyautogui.typewrite(key)
    notes[i][3] = "PLAYED"
    curr_octave = octave

    if all([x[3]=="PLAYED" for x in notes]):
    break

    oct_diff = abs(octave - curr_octave)
    if octave > curr_octave:
    pyautogui.typewrite("x"*oct_diff)
    elif octave < curr_octave:
    pyautogui.typewrite("z"*oct_diff)
    if loop:
    self.play(init_pause=init_pause, key_pause=key_pause, speed=speed, loop=loop)


    if __name__ == "__main__":
    parser = argparse.ArgumentParser()
    parser.add_argument("midis", nargs="+", help="midi files to play")
    args = parser.parse_args()

    player = Player()
    player.midi_paths = args.midis
    player.play()