initial commit
This commit is contained in:
@@ -0,0 +1,110 @@
|
|||||||
|
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
|
||||||
Reference in New Issue
Block a user