Files
notetrainer/run.py
T
2023-05-19 09:56:13 +02:00

111 lines
2.7 KiB
Python

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