| @@ -23,23 +23,27 @@ from PyQt4.QtCore import qWarning, SIGNAL, SLOT | |||||
| from PyQt4.QtGui import QIcon, QMessageBox, QFileDialog | from PyQt4.QtGui import QIcon, QMessageBox, QFileDialog | ||||
| # Set Platform | # Set Platform | ||||
| if (sys.platform == "darwin"): | |||||
| from PyQt4.QtGui import qt_mac_set_menubar_icons | |||||
| qt_mac_set_menubar_icons(False) | |||||
| LINUX = False | |||||
| WINDOWS = False | |||||
| elif ("linux" in sys.platform): | |||||
| LINUX = True | |||||
| WINDOWS = False | |||||
| elif ("win" in sys.platform): | |||||
| LINUX = False | |||||
| WINDOWS = True | |||||
| if sys.platform == "darwin": | |||||
| from PyQt4.QtGui import qt_mac_set_menubar_icons | |||||
| qt_mac_set_menubar_icons(False) | |||||
| LINUX = False | |||||
| MACOS = True | |||||
| WINDOWS = False | |||||
| elif "linux" in sys.platform: | |||||
| LINUX = True | |||||
| MACOS = False | |||||
| WINDOWS = False | |||||
| elif "win" in sys.platform: | |||||
| LINUX = False | |||||
| MACOS = False | |||||
| WINDOWS = True | |||||
| else: | else: | ||||
| LINUX = False | |||||
| WINDOWS = False | |||||
| LINUX = False | |||||
| MACOS = False | |||||
| WINDOWS = False | |||||
| if (not WINDOWS): | |||||
| from signal import signal, SIGINT, SIGTERM, SIGUSR1, SIGUSR2 | |||||
| if LINUX or MACOS: | |||||
| from signal import signal, SIGINT, SIGTERM, SIGUSR1, SIGUSR2 | |||||
| # Set Version | # Set Version | ||||
| VERSION = "0.5.0" | VERSION = "0.5.0" | ||||
| @@ -53,152 +57,171 @@ x_gui = None | |||||
| # Small integrity tests | # Small integrity tests | ||||
| HOME = os.getenv("HOME") | HOME = os.getenv("HOME") | ||||
| if (HOME == None): | |||||
| qWarning("HOME variable not set") | |||||
| HOME = "/tmp" | |||||
| elif (not os.path.exists(HOME)): | |||||
| qWarning("HOME variable set but not valid") | |||||
| HOME = "/tmp" | |||||
| if HOME == None: | |||||
| if WINDOWS: | |||||
| HOME = os.getenv("TMP") | |||||
| else: | |||||
| qWarning("HOME variable not set") | |||||
| HOME = "/tmp" | |||||
| elif not os.path.exists(HOME): | |||||
| qWarning("HOME variable set but not valid") | |||||
| if WINDOWS: | |||||
| HOME = os.getenv("TMP") | |||||
| else: | |||||
| HOME = "/tmp" | |||||
| PATH_env = os.getenv("PATH") | PATH_env = os.getenv("PATH") | ||||
| if (PATH_env == None): | |||||
| qWarning("PATH variable not set") | |||||
| PATH = ("/bin", "/sbin", "/usr/local/bin", "/usr/local/sbin", "/usr/bin", "/usr/sbin", "/usr/games") | |||||
| if PATH_env == None: | |||||
| qWarning("PATH variable not set") | |||||
| if LINUX: | |||||
| PATH = ("/bin", "/sbin", "/usr/local/bin", "/usr/local/sbin", "/usr/bin", "/usr/sbin", "/usr/games") | |||||
| elif MACOS: | |||||
| PATH = ("TODO",) | |||||
| elif WINDOWS: | |||||
| PATH = ("TODO",) | |||||
| else: | |||||
| PATH = ("/bin", "/usr/local/bin", "/usr/bin") | |||||
| else: | else: | ||||
| PATH = PATH_env.split(os.pathsep) | |||||
| PATH = PATH_env.split(os.pathsep) | |||||
| del PATH_env | del PATH_env | ||||
| MIDI_CC_LIST = ( | MIDI_CC_LIST = ( | ||||
| #"0x00 Bank Select", | |||||
| "0x01 Modulation", | |||||
| "0x02 Breath", | |||||
| "0x03 (Undefined)", | |||||
| "0x04 Foot", | |||||
| "0x05 Portamento", | |||||
| #"0x06 (Data Entry MSB)", | |||||
| "0x07 Volume", | |||||
| "0x08 Balance", | |||||
| "0x09 (Undefined)", | |||||
| "0x0A Pan", | |||||
| "0x0B Expression", | |||||
| "0x0C FX Control 1", | |||||
| "0x0D FX Control 2", | |||||
| "0x0E (Undefined)", | |||||
| "0x0F (Undefined)", | |||||
| "0x10 General Purpose 1", | |||||
| "0x11 General Purpose 2", | |||||
| "0x12 General Purpose 3", | |||||
| "0x13 General Purpose 4", | |||||
| "0x14 (Undefined)", | |||||
| "0x15 (Undefined)", | |||||
| "0x16 (Undefined)", | |||||
| "0x17 (Undefined)", | |||||
| "0x18 (Undefined)", | |||||
| "0x19 (Undefined)", | |||||
| "0x1A (Undefined)", | |||||
| "0x1B (Undefined)", | |||||
| "0x1C (Undefined)", | |||||
| "0x1D (Undefined)", | |||||
| "0x1E (Undefined)", | |||||
| "0x1F (Undefined)", | |||||
| #"0x20 *Bank Select", | |||||
| #"0x21 *Modulation", | |||||
| #"0x22 *Breath", | |||||
| #"0x23 *(Undefined)", | |||||
| #"0x24 *Foot", | |||||
| #"0x25 *Portamento", | |||||
| #"0x26 *(Data Entry MSB)", | |||||
| #"0x27 *Volume", | |||||
| #"0x28 *Balance", | |||||
| #"0x29 *(Undefined)", | |||||
| #"0x2A *Pan", | |||||
| #"0x2B *Expression", | |||||
| #"0x2C *FX *Control 1", | |||||
| #"0x2D *FX *Control 2", | |||||
| #"0x2E *(Undefined)", | |||||
| #"0x2F *(Undefined)", | |||||
| #"0x30 *General Purpose 1", | |||||
| #"0x31 *General Purpose 2", | |||||
| #"0x32 *General Purpose 3", | |||||
| #"0x33 *General Purpose 4", | |||||
| #"0x34 *(Undefined)", | |||||
| #"0x35 *(Undefined)", | |||||
| #"0x36 *(Undefined)", | |||||
| #"0x37 *(Undefined)", | |||||
| #"0x38 *(Undefined)", | |||||
| #"0x39 *(Undefined)", | |||||
| #"0x3A *(Undefined)", | |||||
| #"0x3B *(Undefined)", | |||||
| #"0x3C *(Undefined)", | |||||
| #"0x3D *(Undefined)", | |||||
| #"0x3E *(Undefined)", | |||||
| #"0x3F *(Undefined)", | |||||
| #"0x40 Damper On/Off", # <63 off, >64 on | |||||
| #"0x41 Portamento On/Off", # <63 off, >64 on | |||||
| #"0x42 Sostenuto On/Off", # <63 off, >64 on | |||||
| #"0x43 Soft Pedal On/Off", # <63 off, >64 on | |||||
| #"0x44 Legato Footswitch", # <63 Normal, >64 Legato | |||||
| #"0x45 Hold 2", # <63 off, >64 on | |||||
| "0x46 Control 1 [Variation]", | |||||
| "0x47 Control 2 [Timbre]", | |||||
| "0x48 Control 3 [Release]", | |||||
| "0x49 Control 4 [Attack]", | |||||
| "0x4A Control 5 [Brightness]", | |||||
| "0x4B Control 6 [Decay]", | |||||
| "0x4C Control 7 [Vib Rate]", | |||||
| "0x4D Control 8 [Vib Depth]", | |||||
| "0x4E Control 9 [Vib Delay]", | |||||
| "0x4F Control 10 [Undefined]", | |||||
| "0x50 General Purpose 5", | |||||
| "0x51 General Purpose 6", | |||||
| "0x52 General Purpose 8", | |||||
| "0x53 General Purpose 9", | |||||
| "0x54 Portamento Control", | |||||
| "0x5B FX 1 Depth [Reverb]", | |||||
| "0x5C FX 2 Depth [Tremolo]", | |||||
| "0x5D FX 3 Depth [Chorus]", | |||||
| "0x5E FX 4 Depth [Detune]", | |||||
| "0x5F FX 5 Depth [Phaser]" | |||||
| ) | |||||
| #"0x00 Bank Select", | |||||
| "0x01 Modulation", | |||||
| "0x02 Breath", | |||||
| "0x03 (Undefined)", | |||||
| "0x04 Foot", | |||||
| "0x05 Portamento", | |||||
| #"0x06 (Data Entry MSB)", | |||||
| "0x07 Volume", | |||||
| "0x08 Balance", | |||||
| "0x09 (Undefined)", | |||||
| "0x0A Pan", | |||||
| "0x0B Expression", | |||||
| "0x0C FX Control 1", | |||||
| "0x0D FX Control 2", | |||||
| "0x0E (Undefined)", | |||||
| "0x0F (Undefined)", | |||||
| "0x10 General Purpose 1", | |||||
| "0x11 General Purpose 2", | |||||
| "0x12 General Purpose 3", | |||||
| "0x13 General Purpose 4", | |||||
| "0x14 (Undefined)", | |||||
| "0x15 (Undefined)", | |||||
| "0x16 (Undefined)", | |||||
| "0x17 (Undefined)", | |||||
| "0x18 (Undefined)", | |||||
| "0x19 (Undefined)", | |||||
| "0x1A (Undefined)", | |||||
| "0x1B (Undefined)", | |||||
| "0x1C (Undefined)", | |||||
| "0x1D (Undefined)", | |||||
| "0x1E (Undefined)", | |||||
| "0x1F (Undefined)", | |||||
| #"0x20 *Bank Select", | |||||
| #"0x21 *Modulation", | |||||
| #"0x22 *Breath", | |||||
| #"0x23 *(Undefined)", | |||||
| #"0x24 *Foot", | |||||
| #"0x25 *Portamento", | |||||
| #"0x26 *(Data Entry MSB)", | |||||
| #"0x27 *Volume", | |||||
| #"0x28 *Balance", | |||||
| #"0x29 *(Undefined)", | |||||
| #"0x2A *Pan", | |||||
| #"0x2B *Expression", | |||||
| #"0x2C *FX *Control 1", | |||||
| #"0x2D *FX *Control 2", | |||||
| #"0x2E *(Undefined)", | |||||
| #"0x2F *(Undefined)", | |||||
| #"0x30 *General Purpose 1", | |||||
| #"0x31 *General Purpose 2", | |||||
| #"0x32 *General Purpose 3", | |||||
| #"0x33 *General Purpose 4", | |||||
| #"0x34 *(Undefined)", | |||||
| #"0x35 *(Undefined)", | |||||
| #"0x36 *(Undefined)", | |||||
| #"0x37 *(Undefined)", | |||||
| #"0x38 *(Undefined)", | |||||
| #"0x39 *(Undefined)", | |||||
| #"0x3A *(Undefined)", | |||||
| #"0x3B *(Undefined)", | |||||
| #"0x3C *(Undefined)", | |||||
| #"0x3D *(Undefined)", | |||||
| #"0x3E *(Undefined)", | |||||
| #"0x3F *(Undefined)", | |||||
| #"0x40 Damper On/Off", # <63 off, >64 on | |||||
| #"0x41 Portamento On/Off", # <63 off, >64 on | |||||
| #"0x42 Sostenuto On/Off", # <63 off, >64 on | |||||
| #"0x43 Soft Pedal On/Off", # <63 off, >64 on | |||||
| #"0x44 Legato Footswitch", # <63 Normal, >64 Legato | |||||
| #"0x45 Hold 2", # <63 off, >64 on | |||||
| "0x46 Control 1 [Variation]", | |||||
| "0x47 Control 2 [Timbre]", | |||||
| "0x48 Control 3 [Release]", | |||||
| "0x49 Control 4 [Attack]", | |||||
| "0x4A Control 5 [Brightness]", | |||||
| "0x4B Control 6 [Decay]", | |||||
| "0x4C Control 7 [Vib Rate]", | |||||
| "0x4D Control 8 [Vib Depth]", | |||||
| "0x4E Control 9 [Vib Delay]", | |||||
| "0x4F Control 10 [Undefined]", | |||||
| "0x50 General Purpose 5", | |||||
| "0x51 General Purpose 6", | |||||
| "0x52 General Purpose 8", | |||||
| "0x53 General Purpose 9", | |||||
| "0x54 Portamento Control", | |||||
| "0x5B FX 1 Depth [Reverb]", | |||||
| "0x5C FX 2 Depth [Tremolo]", | |||||
| "0x5D FX 3 Depth [Chorus]", | |||||
| "0x5E FX 4 Depth [Detune]", | |||||
| "0x5F FX 5 Depth [Phaser]" | |||||
| ) | |||||
| # Check if an object is a number (float support) | |||||
| # Convert a ctypes c_char_p to a python string | |||||
| def c_string(value): | |||||
| if value: | |||||
| return value.decode("utf-8", errors="ignore") | |||||
| else: | |||||
| return "" | |||||
| # Remove/convert non-ascii chars from a string | |||||
| def unicode2ascii(string): | |||||
| return normalize('NFKD', string).encode("ascii", "ignore").decode("utf-8") | |||||
| # Check if a value is a number (float support) | |||||
| def isNumber(value): | def isNumber(value): | ||||
| try: | |||||
| float(value) | |||||
| return True | |||||
| except: | |||||
| return False | |||||
| try: | |||||
| float(value) | |||||
| return True | |||||
| except: | |||||
| return False | |||||
| # Convert a value to a list | # Convert a value to a list | ||||
| def toList(value): | def toList(value): | ||||
| if value is None: | |||||
| return [] | |||||
| if value == None: | |||||
| return [] | |||||
| elif not isinstance(value, list): | elif not isinstance(value, list): | ||||
| return [value] | |||||
| return [value] | |||||
| else: | else: | ||||
| return value | |||||
| return value | |||||
| # Convert a ctypes char_p to a string | |||||
| def toString(value): | |||||
| if (value): | |||||
| return value.decode("utf-8", errors="ignore") | |||||
| else: | |||||
| return "" | |||||
| # Remove/convert non-ascii chars from a string | |||||
| def unicode2ascii(string): | |||||
| return normalize('NFKD', string).encode("ascii", "ignore").decode("utf-8") | |||||
| # QLineEdit and QPushButton combo | |||||
| def getAndSetPath(self_, currentPath, lineEdit): | |||||
| newPath = QFileDialog.getExistingDirectory(self_, self_.tr("Set Path"), currentPath, QFileDialog.ShowDirsOnly) | |||||
| if newPath: | |||||
| lineEdit.setText(newPath) | |||||
| return newPath | |||||
| # Get Icon from user theme, using our own as backup (Oxygen) | # Get Icon from user theme, using our own as backup (Oxygen) | ||||
| def getIcon(icon, size=16): | def getIcon(icon, size=16): | ||||
| return QIcon.fromTheme(icon, QIcon(":/%ix%i/%s.png" % (size, size, icon))) | |||||
| return QIcon.fromTheme(icon, QIcon(":/%ix%i/%s.png" % (size, size, icon))) | |||||
| # QLineEdit and QPushButtom combo | |||||
| def getAndSetPath(self_, currentPath, lineEdit): | |||||
| newPath = QFileDialog.getExistingDirectory(self_, self_.tr("Set Path"), currentPath, QFileDialog.ShowDirsOnly) | |||||
| if (newPath): | |||||
| lineEdit.setText(newPath) | |||||
| return newPath | |||||
| # Get short filename from full filename (/a/b.c -> b.c) | |||||
| def getShortFileName(filename): | |||||
| if os.sep in filename: | |||||
| return filename.rsplit(os.sep, 1)[1] | |||||
| return filename | |||||
| # Custom MessageBox | # Custom MessageBox | ||||
| def CustomMessageBox(self_, icon, title, text, extraText="", buttons=QMessageBox.Yes|QMessageBox.No, defButton=QMessageBox.No): | def CustomMessageBox(self_, icon, title, text, extraText="", buttons=QMessageBox.Yes|QMessageBox.No, defButton=QMessageBox.No): | ||||
| @@ -212,68 +235,66 @@ def CustomMessageBox(self_, icon, title, text, extraText="", buttons=QMessageBox | |||||
| return msgBox.exec_() | return msgBox.exec_() | ||||
| # signal handler for unix systems | # signal handler for unix systems | ||||
| def set_up_signals(_gui): | |||||
| if (WINDOWS): | |||||
| return | |||||
| global x_gui | |||||
| x_gui = _gui | |||||
| signal(SIGINT, signal_handler) | |||||
| signal(SIGTERM, signal_handler) | |||||
| signal(SIGUSR1, signal_handler) | |||||
| signal(SIGUSR2, signal_handler) | |||||
| def set_up_signals(self_): | |||||
| if LINUX or MACOS: | |||||
| global x_gui | |||||
| x_gui = self_ | |||||
| signal(SIGINT, signal_handler) | |||||
| signal(SIGTERM, signal_handler) | |||||
| signal(SIGUSR1, signal_handler) | |||||
| signal(SIGUSR2, signal_handler) | |||||
| x_gui.connect(x_gui, SIGNAL("SIGUSR2()"), lambda gui=x_gui: showWindow(gui)) | |||||
| x_gui.connect(x_gui, SIGNAL("SIGTERM()"), SLOT("close()")) | |||||
| x_gui.connect(x_gui, SIGNAL("SIGUSR2()"), lambda gui=x_gui: showWindow(gui)) | |||||
| x_gui.connect(x_gui, SIGNAL("SIGTERM()"), SLOT("close()")) | |||||
| def signal_handler(sig, frame): | def signal_handler(sig, frame): | ||||
| global x_gui | |||||
| if (sig in (SIGINT, SIGTERM)): | |||||
| x_gui.emit(SIGNAL("SIGTERM()")) | |||||
| elif (sig == SIGUSR1): | |||||
| x_gui.emit(SIGNAL("SIGUSR1()")) | |||||
| elif (sig == SIGUSR2): | |||||
| x_gui.emit(SIGNAL("SIGUSR2()")) | |||||
| global x_gui | |||||
| if sig in (SIGINT, SIGTERM): | |||||
| x_gui.emit(SIGNAL("SIGTERM()")) | |||||
| elif sig == SIGUSR1: | |||||
| x_gui.emit(SIGNAL("SIGUSR1()")) | |||||
| elif sig == SIGUSR2: | |||||
| x_gui.emit(SIGNAL("SIGUSR2()")) | |||||
| def showWindow(self_): | def showWindow(self_): | ||||
| if (self_.isMaximized()): | |||||
| self_.showMaximized() | |||||
| else: | |||||
| self_.showNormal() | |||||
| if self_.isMaximized(): | |||||
| self_.showMaximized() | |||||
| else: | |||||
| self_.showNormal() | |||||
| # Shared Icons | # Shared Icons | ||||
| def setIcons(self_, modes): | def setIcons(self_, modes): | ||||
| if ("canvas" in modes): | |||||
| self_.act_canvas_arrange.setIcon(getIcon("view-sort-ascending")) | |||||
| self_.act_canvas_refresh.setIcon(getIcon("view-refresh")) | |||||
| self_.act_canvas_zoom_fit.setIcon(getIcon("zoom-fit-best")) | |||||
| self_.act_canvas_zoom_in.setIcon(getIcon("zoom-in")) | |||||
| self_.act_canvas_zoom_out.setIcon(getIcon("zoom-out")) | |||||
| self_.act_canvas_zoom_100.setIcon(getIcon("zoom-original")) | |||||
| self_.act_canvas_print.setIcon(getIcon("document-print")) | |||||
| self_.b_canvas_zoom_fit.setIcon(getIcon("zoom-fit-best")) | |||||
| self_.b_canvas_zoom_in.setIcon(getIcon("zoom-in")) | |||||
| self_.b_canvas_zoom_out.setIcon(getIcon("zoom-out")) | |||||
| self_.b_canvas_zoom_100.setIcon(getIcon("zoom-original")) | |||||
| if "canvas" in modes: | |||||
| self_.act_canvas_arrange.setIcon(getIcon("view-sort-ascending")) | |||||
| self_.act_canvas_refresh.setIcon(getIcon("view-refresh")) | |||||
| self_.act_canvas_zoom_fit.setIcon(getIcon("zoom-fit-best")) | |||||
| self_.act_canvas_zoom_in.setIcon(getIcon("zoom-in")) | |||||
| self_.act_canvas_zoom_out.setIcon(getIcon("zoom-out")) | |||||
| self_.act_canvas_zoom_100.setIcon(getIcon("zoom-original")) | |||||
| self_.act_canvas_print.setIcon(getIcon("document-print")) | |||||
| self_.b_canvas_zoom_fit.setIcon(getIcon("zoom-fit-best")) | |||||
| self_.b_canvas_zoom_in.setIcon(getIcon("zoom-in")) | |||||
| self_.b_canvas_zoom_out.setIcon(getIcon("zoom-out")) | |||||
| self_.b_canvas_zoom_100.setIcon(getIcon("zoom-original")) | |||||
| if ("jack" in modes): | |||||
| self_.act_jack_clear_xruns.setIcon(getIcon("edit-clear")) | |||||
| self_.act_jack_configure.setIcon(getIcon("configure")) | |||||
| self_.act_jack_render.setIcon(getIcon("media-record")) | |||||
| self_.b_jack_clear_xruns.setIcon(getIcon("edit-clear")) | |||||
| self_.b_jack_configure.setIcon(getIcon("configure")) | |||||
| self_.b_jack_render.setIcon(getIcon("media-record")) | |||||
| if "jack" in modes: | |||||
| self_.act_jack_clear_xruns.setIcon(getIcon("edit-clear")) | |||||
| self_.act_jack_configure.setIcon(getIcon("configure")) | |||||
| self_.act_jack_render.setIcon(getIcon("media-record")) | |||||
| self_.b_jack_clear_xruns.setIcon(getIcon("edit-clear")) | |||||
| self_.b_jack_configure.setIcon(getIcon("configure")) | |||||
| self_.b_jack_render.setIcon(getIcon("media-record")) | |||||
| if ("transport" in modes): | |||||
| self_.act_transport_play.setIcon(getIcon("media-playback-start")) | |||||
| self_.act_transport_stop.setIcon(getIcon("media-playback-stop")) | |||||
| self_.act_transport_backwards.setIcon(getIcon("media-seek-backward")) | |||||
| self_.act_transport_forwards.setIcon(getIcon("media-seek-forward")) | |||||
| self_.b_transport_play.setIcon(getIcon("media-playback-start")) | |||||
| self_.b_transport_stop.setIcon(getIcon("media-playback-stop")) | |||||
| self_.b_transport_backwards.setIcon(getIcon("media-seek-backward")) | |||||
| self_.b_transport_forwards.setIcon(getIcon("media-seek-forward")) | |||||
| if "transport" in modes: | |||||
| self_.act_transport_play.setIcon(getIcon("media-playback-start")) | |||||
| self_.act_transport_stop.setIcon(getIcon("media-playback-stop")) | |||||
| self_.act_transport_backwards.setIcon(getIcon("media-seek-backward")) | |||||
| self_.act_transport_forwards.setIcon(getIcon("media-seek-forward")) | |||||
| self_.b_transport_play.setIcon(getIcon("media-playback-start")) | |||||
| self_.b_transport_stop.setIcon(getIcon("media-playback-stop")) | |||||
| self_.b_transport_backwards.setIcon(getIcon("media-seek-backward")) | |||||
| self_.b_transport_forwards.setIcon(getIcon("media-seek-forward")) | |||||
| if ("misc" in modes): | |||||
| self_.act_quit.setIcon(getIcon("application-exit")) | |||||
| self_.act_configure.setIcon(getIcon("configure")) | |||||
| if "misc" in modes: | |||||
| self_.act_quit.setIcon(getIcon("application-exit")) | |||||
| self_.act_configure.setIcon(getIcon("configure")) | |||||