from __future__ import print_function import logging import sys import time from random import randrange import subprocess import tkinter as tk from PIL import Image, ImageTk from rtmidi.midiutil import open_midiinput log = logging.getLogger('midiin_callback') logging.basicConfig(level=logging.INFO) notes_sharp = ["c", "cis", "d", "dis", "e", "f", "fis", "g", "gis", "a", "ais", "b"] lilypond = ''' \paper { #(set-paper-size "a10landscape") indent = 0\mm line-width = 110\mm oddHeaderMarkup = "" evenHeaderMarkup = "" oddFooterMarkup = "" evenFooterMarkup = "" } ''' window = tk.Tk() class Trainer(): def __init__(self): self.secret = 0 self.lb = 60 self.ub = 84 # 108 self.image = None self.image_label = tk.Label(window) self.image_label.pack() self.newNote() # Gets a new random note, outputs it to file def newNote(self): self.secret = randrange(self.lb, self.ub) self.print() ly = lilypond + f"{{{self.convertNote(self.secret)}}}" with open("lily.txt", "w") as f: f.write(ly) f.close() wait_for = subprocess.Popen(["lilypond", "-dpreview", "-dbackend=eps", "-dresolution=600", "--png", "lily.txt"]) self.refreshImage(wait_for) def refreshImage(self, wait_for=None): if wait_for: wait_for.wait() if self.image: self.image.close() self.image = Image.open("lily.png") photo = ImageTk.PhotoImage(self.image) self.image_label.configure(image=photo) self.image_label.image = photo def guess(self, note): guess = (note == self.secret) if guess: self.newNote() return guess # Convert midi pitch to lilypond notation def convertNote(self, pitch): octave = int(pitch / 12) - 4 oct_str = -octave*"," if octave < 0 else octave*"'" note = notes_sharp[(pitch % 12)] return f"{note}{oct_str}" def print(self): print(f"Current midi note: {self.secret}") print(self.convertNote(self.secret)) t = Trainer() class MidiInputHandler(object): def __init__(self, port): self.port = port def __call__(self, event, data=None): message, deltatime = event (ev, note, vel) = message if ev == 144: # note on print(f"Pressed note {note}") print(t.convertNote(note)) t.guess(note) # Prompts user for MIDI input port, unless a valid port number or name given port = sys.argv[1] if len(sys.argv) > 1 else None try: midiin, port_name = open_midiinput(port) except (EOFError, KeyboardInterrupt): sys.exit() midiin.set_callback(MidiInputHandler(port_name)) window.mainloop() midiin.close_port() del midiin