From c55da23e2d2a7819a962342fcf3d49f7e25e1aea Mon Sep 17 00:00:00 2001 From: Patrick Marsee Date: Tue, 11 May 2021 23:47:07 -0400 Subject: [PATCH] Multiple files can now be loaded. Fixed GUI becoming unresponsive while a song is playing. --- main.py | 59 +++++++++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 53 insertions(+), 6 deletions(-) diff --git a/main.py b/main.py index a345cb1..08c040b 100644 --- a/main.py +++ b/main.py @@ -25,8 +25,10 @@ from tkinter import * from tkinter import ttk from tkinter import filedialog as fd +from tkinter import messagebox as mb import subprocess as sp import os +import threading class MidiPort: @@ -45,6 +47,11 @@ class App(ttk.Frame): self.devices = self.get_midi_list() self.create_widgets() 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): 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.grid(column=0, row=1) 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_button = ttk.Button(self, text="Open...", - command=lambda: self.midi_file_var.set(fd.askopenfilename(defaultextension=".mid", filetypes=[("MIDI", ".mid")], initialdir=os.environ['HOME']))) - self.midi_file_button.grid(column=2, row=1, sticky=(E, W)) + command=self.open_file) + 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.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) @staticmethod @@ -79,14 +94,46 @@ class App(ttk.Frame): 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:]] + 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): - 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): - initial_dir = os.pwd() + initial_dir = os.getcwd() if 'HOME' in os.environ: 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): root = Tk()