Collection of tools useful for audio production
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

323 lines
9.8KB

  1. #!/usr/bin/env python3
  2. # -*- coding: utf-8 -*-
  3. # Common/Shared code
  4. # Copyright (C) 2010-2012 Filipe Coelho <falktx@falktx.com>
  5. #
  6. # This program is free software; you can redistribute it and/or modify
  7. # it under the terms of the GNU General Public License as published by
  8. # the Free Software Foundation; either version 2 of the License, or
  9. # any later version.
  10. #
  11. # This program is distributed in the hope that it will be useful,
  12. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. # GNU General Public License for more details.
  15. #
  16. # For a full copy of the GNU General Public License see the COPYING file
  17. # Imports (Global)
  18. import os, sys
  19. from unicodedata import normalize
  20. from PyQt4.QtCore import qWarning, SIGNAL, SLOT
  21. from PyQt4.QtGui import QFileDialog, QIcon, QMessageBox
  22. from codecs import open as codecopen
  23. # Set Platform
  24. if sys.platform == "darwin":
  25. from PyQt4.QtGui import qt_mac_set_menubar_icons
  26. qt_mac_set_menubar_icons(False)
  27. HAIKU = False
  28. LINUX = False
  29. MACOS = True
  30. WINDOWS = False
  31. elif "haiku" in sys.platform:
  32. HAIKU = True
  33. LINUX = False
  34. MACOS = False
  35. WINDOWS = False
  36. elif "linux" in sys.platform:
  37. HAIKU = False
  38. LINUX = True
  39. MACOS = False
  40. WINDOWS = False
  41. elif sys.platform in ("win32", "win64", "cygwin"):
  42. HAIKU = False
  43. LINUX = False
  44. MACOS = False
  45. WINDOWS = True
  46. else:
  47. HAIKU = False
  48. LINUX = False
  49. MACOS = False
  50. WINDOWS = False
  51. try:
  52. from signal import signal, SIGINT, SIGTERM, SIGUSR1, SIGUSR2
  53. haveSignal = True
  54. except:
  55. haveSignal = False
  56. # Set Version
  57. VERSION = "0.5.0"
  58. # Set Debug mode
  59. DEBUG = bool("-d" in sys.argv or "-debug" in sys.argv or "--debug" in sys.argv)
  60. # Global variables
  61. global x_gui
  62. x_gui = None
  63. # Small integrity tests
  64. HOME = os.getenv("HOME")
  65. if HOME is None:
  66. if WINDOWS:
  67. HOME = os.getenv("TMP")
  68. else:
  69. qWarning("HOME variable not set")
  70. HOME = "/tmp"
  71. elif not os.path.exists(HOME):
  72. qWarning("HOME variable set but not valid")
  73. if WINDOWS:
  74. HOME = os.getenv("TMP")
  75. else:
  76. HOME = "/tmp"
  77. PATH_env = os.getenv("PATH")
  78. if PATH_env is None:
  79. qWarning("PATH variable not set")
  80. if MACOS:
  81. PATH = ("/opt/local/bin", "/usr/local/bin", "/usr/bin", "/bin")
  82. elif WINDOWS:
  83. WINDIR = os.getenv("WINDIR")
  84. PATH = (os.path.join(WINDIR, "system32"), WINDIR)
  85. del WINDIR
  86. else:
  87. PATH = ("/usr/local/bin", "/usr/bin", "/bin")
  88. else:
  89. PATH = PATH_env.split(os.pathsep)
  90. del PATH_env
  91. # ------------------------------------------------------------------------------------------------------------
  92. MIDI_CC_LIST = (
  93. #"0x00 Bank Select",
  94. "0x01 Modulation",
  95. "0x02 Breath",
  96. "0x03 (Undefined)",
  97. "0x04 Foot",
  98. "0x05 Portamento",
  99. #"0x06 (Data Entry MSB)",
  100. "0x07 Volume",
  101. "0x08 Balance",
  102. "0x09 (Undefined)",
  103. "0x0A Pan",
  104. "0x0B Expression",
  105. "0x0C FX Control 1",
  106. "0x0D FX Control 2",
  107. "0x0E (Undefined)",
  108. "0x0F (Undefined)",
  109. "0x10 General Purpose 1",
  110. "0x11 General Purpose 2",
  111. "0x12 General Purpose 3",
  112. "0x13 General Purpose 4",
  113. "0x14 (Undefined)",
  114. "0x15 (Undefined)",
  115. "0x16 (Undefined)",
  116. "0x17 (Undefined)",
  117. "0x18 (Undefined)",
  118. "0x19 (Undefined)",
  119. "0x1A (Undefined)",
  120. "0x1B (Undefined)",
  121. "0x1C (Undefined)",
  122. "0x1D (Undefined)",
  123. "0x1E (Undefined)",
  124. "0x1F (Undefined)",
  125. #"0x20 *Bank Select",
  126. #"0x21 *Modulation",
  127. #"0x22 *Breath",
  128. #"0x23 *(Undefined)",
  129. #"0x24 *Foot",
  130. #"0x25 *Portamento",
  131. #"0x26 *(Data Entry MSB)",
  132. #"0x27 *Volume",
  133. #"0x28 *Balance",
  134. #"0x29 *(Undefined)",
  135. #"0x2A *Pan",
  136. #"0x2B *Expression",
  137. #"0x2C *FX *Control 1",
  138. #"0x2D *FX *Control 2",
  139. #"0x2E *(Undefined)",
  140. #"0x2F *(Undefined)",
  141. #"0x30 *General Purpose 1",
  142. #"0x31 *General Purpose 2",
  143. #"0x32 *General Purpose 3",
  144. #"0x33 *General Purpose 4",
  145. #"0x34 *(Undefined)",
  146. #"0x35 *(Undefined)",
  147. #"0x36 *(Undefined)",
  148. #"0x37 *(Undefined)",
  149. #"0x38 *(Undefined)",
  150. #"0x39 *(Undefined)",
  151. #"0x3A *(Undefined)",
  152. #"0x3B *(Undefined)",
  153. #"0x3C *(Undefined)",
  154. #"0x3D *(Undefined)",
  155. #"0x3E *(Undefined)",
  156. #"0x3F *(Undefined)",
  157. #"0x40 Damper On/Off", # <63 off, >64 on
  158. #"0x41 Portamento On/Off", # <63 off, >64 on
  159. #"0x42 Sostenuto On/Off", # <63 off, >64 on
  160. #"0x43 Soft Pedal On/Off", # <63 off, >64 on
  161. #"0x44 Legato Footswitch", # <63 Normal, >64 Legato
  162. #"0x45 Hold 2", # <63 off, >64 on
  163. "0x46 Control 1 [Variation]",
  164. "0x47 Control 2 [Timbre]",
  165. "0x48 Control 3 [Release]",
  166. "0x49 Control 4 [Attack]",
  167. "0x4A Control 5 [Brightness]",
  168. "0x4B Control 6 [Decay]",
  169. "0x4C Control 7 [Vib Rate]",
  170. "0x4D Control 8 [Vib Depth]",
  171. "0x4E Control 9 [Vib Delay]",
  172. "0x4F Control 10 [Undefined]",
  173. "0x50 General Purpose 5",
  174. "0x51 General Purpose 6",
  175. "0x52 General Purpose 7",
  176. "0x53 General Purpose 8",
  177. "0x54 Portamento Control",
  178. "0x5B FX 1 Depth [Reverb]",
  179. "0x5C FX 2 Depth [Tremolo]",
  180. "0x5D FX 3 Depth [Chorus]",
  181. "0x5E FX 4 Depth [Detune]",
  182. "0x5F FX 5 Depth [Phaser]"
  183. )
  184. # ------------------------------------------------------------------------------------------------------------
  185. # Remove/convert non-ascii chars from a string
  186. def asciiString(string):
  187. return normalize('NFKD', string).encode("ascii", "ignore").decode("utf-8")
  188. # Convert a ctypes c_char_p to a python string
  189. def cString(value):
  190. if not value:
  191. return ""
  192. if isinstance(value, str):
  193. return value
  194. return value.decode("utf-8", errors="ignore")
  195. # Check if a value is a number (float support)
  196. def isNumber(value):
  197. try:
  198. float(value)
  199. return True
  200. except:
  201. return False
  202. # Convert a value to a list
  203. def toList(value):
  204. if value is None:
  205. return []
  206. elif not isinstance(value, list):
  207. return [value]
  208. else:
  209. return value
  210. def uopen(filename, mode="r"):
  211. return codecopen(filename, encoding="utf-8", mode=mode)
  212. # QLineEdit and QPushButton combo
  213. def getAndSetPath(self_, currentPath, lineEdit):
  214. newPath = QFileDialog.getExistingDirectory(self_, self_.tr("Set Path"), currentPath, QFileDialog.ShowDirsOnly)
  215. if newPath:
  216. lineEdit.setText(newPath)
  217. return newPath
  218. # Get Icon from user theme, using our own as backup (Oxygen)
  219. def getIcon(icon, size=16):
  220. return QIcon.fromTheme(icon, QIcon(":/%ix%i/%s.png" % (size, size, icon)))
  221. # Custom MessageBox
  222. def CustomMessageBox(self_, icon, title, text, extraText="", buttons=QMessageBox.Yes|QMessageBox.No, defButton=QMessageBox.No):
  223. msgBox = QMessageBox(self_)
  224. msgBox.setIcon(icon)
  225. msgBox.setWindowTitle(title)
  226. msgBox.setText(text)
  227. msgBox.setInformativeText(extraText)
  228. msgBox.setStandardButtons(buttons)
  229. msgBox.setDefaultButton(defButton)
  230. return msgBox.exec_()
  231. # ------------------------------------------------------------------------------------------------------------
  232. # signal handler for unix systems
  233. def setUpSignals(self_):
  234. if not haveSignal:
  235. return
  236. global x_gui
  237. x_gui = self_
  238. signal(SIGINT, signalHandler)
  239. signal(SIGTERM, signalHandler)
  240. signal(SIGUSR1, signalHandler)
  241. signal(SIGUSR2, signalHandler)
  242. x_gui.connect(x_gui, SIGNAL("SIGUSR2()"), lambda: showWindowHandler())
  243. x_gui.connect(x_gui, SIGNAL("SIGTERM()"), SLOT("close()"))
  244. def signalHandler(sig, frame):
  245. global x_gui
  246. if sig in (SIGINT, SIGTERM):
  247. x_gui.emit(SIGNAL("SIGTERM()"))
  248. elif sig == SIGUSR1:
  249. x_gui.emit(SIGNAL("SIGUSR1()"))
  250. elif sig == SIGUSR2:
  251. x_gui.emit(SIGNAL("SIGUSR2()"))
  252. def showWindowHandler():
  253. global x_gui
  254. if x_gui.isMaximized():
  255. x_gui.showMaximized()
  256. else:
  257. x_gui.showNormal()
  258. # ------------------------------------------------------------------------------------------------------------
  259. # Shared Icons
  260. def setIcons(self_, modes):
  261. if "canvas" in modes:
  262. self_.act_canvas_arrange.setIcon(getIcon("view-sort-ascending"))
  263. self_.act_canvas_refresh.setIcon(getIcon("view-refresh"))
  264. self_.act_canvas_zoom_fit.setIcon(getIcon("zoom-fit-best"))
  265. self_.act_canvas_zoom_in.setIcon(getIcon("zoom-in"))
  266. self_.act_canvas_zoom_out.setIcon(getIcon("zoom-out"))
  267. self_.act_canvas_zoom_100.setIcon(getIcon("zoom-original"))
  268. self_.act_canvas_print.setIcon(getIcon("document-print"))
  269. self_.b_canvas_zoom_fit.setIcon(getIcon("zoom-fit-best"))
  270. self_.b_canvas_zoom_in.setIcon(getIcon("zoom-in"))
  271. self_.b_canvas_zoom_out.setIcon(getIcon("zoom-out"))
  272. self_.b_canvas_zoom_100.setIcon(getIcon("zoom-original"))
  273. if "jack" in modes:
  274. self_.act_jack_clear_xruns.setIcon(getIcon("edit-clear"))
  275. self_.act_jack_configure.setIcon(getIcon("configure"))
  276. self_.act_jack_render.setIcon(getIcon("media-record"))
  277. self_.b_jack_clear_xruns.setIcon(getIcon("edit-clear"))
  278. self_.b_jack_configure.setIcon(getIcon("configure"))
  279. self_.b_jack_render.setIcon(getIcon("media-record"))
  280. if "transport" in modes:
  281. self_.act_transport_play.setIcon(getIcon("media-playback-start"))
  282. self_.act_transport_stop.setIcon(getIcon("media-playback-stop"))
  283. self_.act_transport_backwards.setIcon(getIcon("media-seek-backward"))
  284. self_.act_transport_forwards.setIcon(getIcon("media-seek-forward"))
  285. self_.b_transport_play.setIcon(getIcon("media-playback-start"))
  286. self_.b_transport_stop.setIcon(getIcon("media-playback-stop"))
  287. self_.b_transport_backwards.setIcon(getIcon("media-seek-backward"))
  288. self_.b_transport_forwards.setIcon(getIcon("media-seek-forward"))
  289. if "misc" in modes:
  290. self_.act_quit.setIcon(getIcon("application-exit"))
  291. self_.act_configure.setIcon(getIcon("configure"))