Multiple files can now be loaded. Fixed GUI becoming unresponsive while a song is playing.

This commit is contained in:
Patrick Marsee 2021-05-11 23:47:07 -04:00
parent 66a3b9f542
commit c55da23e2d

59
main.py
View file

@ -25,8 +25,10 @@
from tkinter import * from tkinter import *
from tkinter import ttk from tkinter import ttk
from tkinter import filedialog as fd from tkinter import filedialog as fd
from tkinter import messagebox as mb
import subprocess as sp import subprocess as sp
import os import os
import threading
class MidiPort: class MidiPort:
@ -45,6 +47,11 @@ class App(ttk.Frame):
self.devices = self.get_midi_list() self.devices = self.get_midi_list()
self.create_widgets() self.create_widgets()
self.midi_port_var.set(str(self.devices[0])) self.midi_port_var.set(str(self.devices[0]))
# play control
self.play_mutex = threading.Lock()
self.is_playing = False
self.stop_after = False
self.files = ()
def create_widgets(self): def create_widgets(self):
self.midi_port_label = ttk.Label(self, text="Midi Device") self.midi_port_label = ttk.Label(self, text="Midi Device")
@ -58,16 +65,24 @@ class App(ttk.Frame):
self.midi_file_label = ttk.Label(self, text="File") self.midi_file_label = ttk.Label(self, text="File")
self.midi_file_label.grid(column=0, row=1) self.midi_file_label.grid(column=0, row=1)
self.midi_file_var = StringVar() self.midi_file_var = StringVar()
self.midi_file_text = ttk.Entry(self, textvariable=self.midi_file_var, width=80) self.midi_file_text = Listbox(self, listvariable=self.midi_file_var, width=80, height=20, selectmode="extended")
self.midi_file_text.grid(column=1, row=1) self.midi_file_text.grid(column=1, row=1)
self.midi_file_button = ttk.Button(self, self.midi_file_button = ttk.Button(self,
text="Open...", text="Open...",
command=lambda: self.midi_file_var.set(fd.askopenfilename(defaultextension=".mid", filetypes=[("MIDI", ".mid")], initialdir=os.environ['HOME']))) command=self.open_file)
self.midi_file_button.grid(column=2, row=1, sticky=(E, W)) self.midi_file_button.grid(column=3, row=1, sticky=(E, W))
self.midi_file_scroll = ttk.Scrollbar(self, orient=VERTICAL, command=self.midi_file_text.yview)
self.midi_file_text.configure(yscrollcommand=self.midi_file_scroll.set)
self.midi_file_scroll.grid(column=2, row=1, sticky=(N, S, W))
self.play_button = ttk.Button(self, text="Play", command=self.play_midi) self.play_button = ttk.Button(self, text="Play", command=self.play_midi)
self.play_button.grid(column=1, row=2) self.play_button.grid(column=1, row=2)
self.stop_after_var = StringVar()
self.stop_after_var.set("go")
self.stop_after_button = ttk.Checkbutton(self, text="Stop after current", command=self.stop_after_current, variable=self.stop_after_var, onvalue="stop", offvalue="go")
self.stop_after_button.grid(column=2, row=2, columnspan=2)
self.columnconfigure(1, weight=1) self.columnconfigure(1, weight=1)
@staticmethod @staticmethod
@ -79,14 +94,46 @@ class App(ttk.Frame):
port_name_start = devices[0].find("Port name") port_name_start = devices[0].find("Port name")
return [MidiPort(i[port_start:client_name_start].strip(), i[client_name_start:port_name_start].strip(), i[port_name_start:].strip()) for i in devices[1:]] return [MidiPort(i[port_start:client_name_start].strip(), i[client_name_start:port_name_start].strip(), i[port_name_start:].strip()) for i in devices[1:]]
def stop_after_current(self):
self.play_mutex.acquire()
self.stop_after = self.stop_after_var.get() == "stop"
self.play_mutex.release()
def play_midi(self): def play_midi(self):
sp.run(["aplaymidi", "-p", self.devices[self.midi_port_selector.current()].port, self.midi_file_var.get()]) self.play_mutex.acquire()
if self.is_playing:
self.play_mutex.release()
mb.showinfo(message="Another song cannot play until the previous song is finished playing.")
else:
self.play_mutex.release()
port = self.devices[self.midi_port_selector.current()].port
midis = [self.files[f] for f in self.midi_file_text.curselection()]
if len(midis) == 0:
midis = self.files
play_thread = threading.Thread(target=self.play_thread, args=(port, midis))
play_thread.start()
def play_thread(self, port: str, midis: list):
self.play_mutex.acquire()
self.is_playing = True
self.play_mutex.release()
for midi in midis:
sp.run(["aplaymidi", "-p", port, midi])
self.play_mutex.acquire()
if self.stop_after:
self.play_mutex.release()
break;
self.play_mutex.release()
self.play_mutex.acquire()
self.is_playing = False
self.play_mutex.release()
def open_file(self): def open_file(self):
initial_dir = os.pwd() initial_dir = os.getcwd()
if 'HOME' in os.environ: if 'HOME' in os.environ:
initial_dir = os.environ['HOME'] initial_dir = os.environ['HOME']
self.midi_file_var.set(fd.askopenfilename(defaultextension=".mid", filetypes=[("MIDI", ".mid")], initialdir=initial_dir)) self.files = fd.askopenfilename(defaultextension=".mid", filetypes=[("MIDI", ".mid")], initialdir=initial_dir, multiple=True)
self.midi_file_var.set(self.files)
def main(args): def main(args):
root = Tk() root = Tk()