1#!/bin/python 2import gi 3gi.require_version('Gtk', '3.0') 4from gi.repository import Gtk 5from gi.repository import Pango 6import os 7import mimetypes 8import bliss 9import csv 10import sys 11import threading 12 13def analyze(url_lib, url_csv, self): 14 if self.recursive: 15 file_list = [os.path.join(dp, f) for dp, dn, fn in os.walk(os.path.expanduser(url_lib)) for f in fn] 16 else: 17 file_list = [os.path.join(url_lib, f) for f in os.listdir(url_lib) if os.path.isfile(os.path.join(url_lib, f))] 18 19 audio_files = [] 20 21 for file_n in file_list: 22 guess = mimetypes.guess_type(file_n)[0] 23 if guess is not None and "audio" in guess: 24 audio_files.append(file_n) 25 26 if not audio_files: 27 print("Please enter a valid directory containing audio files") 28 self.goBtn.set_label("Go") 29 return 30 31 32 self.label_done.hide() 33 self.progressBar.show() 34 self.progressBar.set_ellipsize(Pango.EllipsizeMode.MIDDLE) 35 self.progressBar.set_show_text(True) 36 37 with open(url_csv, "w") as csvfile: 38 library_writer = csv.writer(csvfile, delimiter='|', quotechar="'", quoting=csv.QUOTE_MINIMAL) 39 for i,file_n in enumerate(audio_files): 40 if self.e.isSet(): 41 self.e.clear() 42 break 43 44 with bliss.bl_song(file_n) as song: 45 # Test if the file has been decoded properly (ugly) 46 if song["duration"] > 0: 47 self.progressBar.set_text(song["filename"]) 48 library_writer.writerow((song["filename"], song["album"], song["force_vector"]["attack"], song["force_vector"]["tempo"], song["force_vector"]["amplitude"], song["force_vector"]["frequency"])) 49 csvfile.flush() 50 else: 51 print("Couldn't decode file '%s', skipping..." % file_n) 52 self.progressBar.set_fraction(i/(len(audio_files) - 1)) 53 54 self.progressBar.hide() 55 self.label_done.set_label("Done!") 56 self.label_done.show() 57 self.goBtn.set_label("Go") 58 print("Scan completed, data is availabe at '%s'" % url_csv) 59 60class MyWindow(Gtk.Window): 61 def __init__(self): 62 Gtk.Window.__init__(self, title="Bliss data generator") 63 self.url_csv = os.path.join(os.getcwd(), "output.csv") 64 self.url_lib = "" 65 self.th = None 66 self.recursive = False 67 self.e = threading.Event() 68 self.progressBar = Gtk.ProgressBar() 69 70 openDirBtn = Gtk.Button.new_with_label("Open...") 71 openDirBtn.connect("clicked", self.onOpenDir) 72 73 saveFileBtn = Gtk.Button.new_with_label("Save as CSV...") 74 saveFileBtn.connect("clicked", self.onSaveFile) 75 76 self.goBtn = Gtk.Button.new_with_label("Go") 77 self.goBtn.connect("clicked", self.go) 78 quitBtn = Gtk.Button.new_with_label("Quit") 79 quitBtn.connect("clicked", self.quit) 80 81 recursiveBtn = Gtk.CheckButton("Recursive scan") 82 recursiveBtn.connect("toggled", self.recursiveCheck) 83 84 self.label_open = Gtk.Label(self.url_lib) 85 self.label_open.set_ellipsize(Pango.EllipsizeMode.MIDDLE) 86 self.label_save = Gtk.Label(self.url_csv) 87 self.label_save.set_ellipsize(Pango.EllipsizeMode.MIDDLE) 88 self.label_done = Gtk.Label() 89 90 sizer = Gtk.Box(orientation=Gtk.Orientation.VERTICAL) 91 sizer_open = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL) 92 sizer_save = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL) 93 sizer_set = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL) 94 95 sizer.pack_start(sizer_open, True, True, 5) 96 sizer.pack_start(sizer_save, True, True, 5) 97 sizer.pack_start(self.progressBar, True, True, 5) 98 sizer.pack_start(self.label_done, True, True, 5) 99 sizer.pack_start(recursiveBtn, True, True, 5) 100 sizer.pack_start(sizer_set, True, True, 5) 101 102 sizer_open.pack_start(openDirBtn, False, True, 5) 103 sizer_open.pack_start(self.label_open, True, True, 5) 104 sizer_save.pack_start(saveFileBtn, False, True, 5) 105 sizer_save.pack_start(self.label_save, True, True, 5) 106 sizer_set.pack_start(quitBtn, True, True, 5) 107 sizer_set.pack_start(self.goBtn, True, True, 5) 108 109 self.add(sizer) 110 111 def quit(self, evt): 112 Gtk.main_quit() 113 114 def go(self, button): 115 if os.path.isabs(self.url_lib) and os.path.isabs(self.url_csv): 116 if self.th is None or not self.th.isAlive(): 117 self.th = threading.Thread(target=analyze, args=(self.url_lib, self.url_csv, self)) 118 button.set_label("Cancel") 119 self.th.start() 120 else: 121 button.set_label("Go") 122 self.e.set() 123 else: 124 message = Gtk.MessageDialog(parent=self, flags=0, type=Gtk.MessageType.WARNING, 125 buttons=Gtk.ButtonsType.NONE, message_format=None) 126 message.set_markup("Please enter a valid directory containing audio files") 127 message.show() 128 129 def onOpenDir(self, evt): 130 dialog = Gtk.FileChooserDialog("Please choose a folder to analyze", self, 131 Gtk.FileChooserAction.SELECT_FOLDER, 132 (Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL, "Select", Gtk.ResponseType.OK)) 133 dialog.set_default_size(800, 400) 134 response = dialog.run() 135 136 if response == Gtk.ResponseType.OK: 137 self.url_lib = dialog.get_filename() 138 self.label_open.set_label(self.url_lib) 139 140 dialog.destroy() 141 142 def recursiveCheck(self, button): 143 self.recursive = button.get_active() 144 145 def onSaveFile(self, evt): 146 dialog = Gtk.FileChooserDialog("Please choose an output CSV file", self, 147 Gtk.FileChooserAction.SAVE, 148 (Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL, "Select", Gtk.ResponseType.OK)) 149 dialog.set_default_size(800, 400) 150 response = dialog.run() 151 152 if response == Gtk.ResponseType.OK: 153 self.url_csv= dialog.get_filename() 154 self.label_save.set_label(self.url_csv) 155 156 dialog.destroy() 157 158win = MyWindow() 159win.connect("delete-event", Gtk.main_quit) 160win.show_all() 161win.progressBar.hide() 162win.label_done.hide() 163 164Gtk.main() 165