Audio plugin host https://kx.studio/carla
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.

carla_shared.py 31KB

11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
10 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
10 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
7 years ago
7 years ago
10 years ago
7 years ago
7 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
9 years ago
9 years ago
9 years ago
11 years ago
10 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
10 years ago
10 years ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886
  1. #!/usr/bin/env python3
  2. # -*- coding: utf-8 -*-
  3. # Common Carla code
  4. # Copyright (C) 2011-2021 Filipe Coelho <falktx@falktx.com>
  5. #
  6. # This program is free software; you can redistribute it and/or
  7. # modify it under the terms of the GNU General Public License as
  8. # published by the Free Software Foundation; either version 2 of
  9. # the License, or 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 doc/GPL.txt file.
  17. # ------------------------------------------------------------------------------------------------------------
  18. # Imports (Global)
  19. import os
  20. import sys
  21. from math import fmod
  22. # ------------------------------------------------------------------------------------------------------------
  23. # Imports (Signal)
  24. from signal import signal, SIGINT, SIGTERM
  25. try:
  26. from signal import SIGUSR1
  27. haveSIGUSR1 = True
  28. except:
  29. haveSIGUSR1 = False
  30. # ------------------------------------------------------------------------------------------------------------
  31. # Imports (PyQt5)
  32. from PyQt5.Qt import PYQT_VERSION_STR
  33. from PyQt5.QtCore import qFatal, QT_VERSION, QT_VERSION_STR, qWarning, QDir, QSettings
  34. from PyQt5.QtGui import QIcon
  35. from PyQt5.QtWidgets import QFileDialog, QMessageBox
  36. # ------------------------------------------------------------------------------------------------------------
  37. # Imports (Custom)
  38. from carla_backend import (
  39. kIs64bit, HAIKU, LINUX, MACOS, WINDOWS,
  40. MAX_DEFAULT_PARAMETERS,
  41. ENGINE_PROCESS_MODE_MULTIPLE_CLIENTS,
  42. ENGINE_PROCESS_MODE_PATCHBAY,
  43. ENGINE_TRANSPORT_MODE_INTERNAL,
  44. ENGINE_TRANSPORT_MODE_JACK
  45. )
  46. # ------------------------------------------------------------------------------------------------------------
  47. # Config
  48. # These will be modified during install
  49. X_LIBDIR_X = None
  50. X_DATADIR_X = None
  51. # ------------------------------------------------------------------------------------------------------------
  52. # Platform specific stuff
  53. if WINDOWS:
  54. WINDIR = os.getenv("WINDIR")
  55. # ------------------------------------------------------------------------------------------------------------
  56. # Set Version
  57. VERSION = "2.4.1"
  58. # ------------------------------------------------------------------------------------------------------------
  59. # Set TMP
  60. envTMP = os.getenv("TMP")
  61. if envTMP is None:
  62. if WINDOWS:
  63. qWarning("TMP variable not set")
  64. TMP = QDir.tempPath()
  65. else:
  66. TMP = envTMP
  67. if not os.path.exists(TMP):
  68. qWarning("TMP does not exist")
  69. TMP = "/"
  70. del envTMP
  71. # ------------------------------------------------------------------------------------------------------------
  72. # Set HOME
  73. envHOME = os.getenv("HOME")
  74. if envHOME is None:
  75. if LINUX or MACOS:
  76. qWarning("HOME variable not set")
  77. HOME = QDir.toNativeSeparators(QDir.homePath())
  78. else:
  79. HOME = envHOME
  80. if not os.path.exists(HOME):
  81. qWarning("HOME does not exist")
  82. HOME = TMP
  83. del envHOME
  84. # ------------------------------------------------------------------------------------------------------------
  85. # Set PATH
  86. envPATH = os.getenv("PATH")
  87. if envPATH is None:
  88. qWarning("PATH variable not set")
  89. if MACOS:
  90. PATH = ("/opt/local/bin", "/usr/local/bin", "/usr/bin", "/bin")
  91. elif WINDOWS:
  92. PATH = (os.path.join(WINDIR, "system32"), WINDIR)
  93. else:
  94. PATH = ("/usr/local/bin", "/usr/bin", "/bin")
  95. else:
  96. PATH = envPATH.split(os.pathsep)
  97. del envPATH
  98. # ------------------------------------------------------------------------------------------------------------
  99. # Static MIDI CC list
  100. MIDI_CC_LIST = (
  101. "01 [0x01] Modulation",
  102. "02 [0x02] Breath",
  103. "04 [0x04] Foot",
  104. "05 [0x05] Portamento",
  105. "07 [0x07] Volume",
  106. "08 [0x08] Balance",
  107. "10 [0x0A] Pan",
  108. "11 [0x0B] Expression",
  109. "12 [0x0C] FX Control 1",
  110. "13 [0x0D] FX Control 2",
  111. "16 [0x10] General Purpose 1",
  112. "17 [0x11] General Purpose 2",
  113. "18 [0x12] General Purpose 3",
  114. "19 [0x13] General Purpose 4",
  115. "70 [0x46] Control 1 [Variation]",
  116. "71 [0x47] Control 2 [Timbre]",
  117. "72 [0x48] Control 3 [Release]",
  118. "73 [0x49] Control 4 [Attack]",
  119. "74 [0x4A] Control 5 [Brightness]",
  120. "75 [0x4B] Control 6 [Decay]",
  121. "76 [0x4C] Control 7 [Vib Rate]",
  122. "77 [0x4D] Control 8 [Vib Depth]",
  123. "78 [0x4E] Control 9 [Vib Delay]",
  124. "79 [0x4F] Control 10 [Undefined]",
  125. "80 [0x50] General Purpose 5",
  126. "81 [0x51] General Purpose 6",
  127. "82 [0x52] General Purpose 7",
  128. "83 [0x53] General Purpose 8",
  129. "84 [0x54] Portamento Control",
  130. "91 [0x5B] FX 1 Depth [Reverb]",
  131. "92 [0x5C] FX 2 Depth [Tremolo]",
  132. "93 [0x5D] FX 3 Depth [Chorus]",
  133. "94 [0x5E] FX 4 Depth [Detune]",
  134. "95 [0x5F] FX 5 Depth [Phaser]"
  135. )
  136. MAX_MIDI_CC_LIST_ITEM = 95
  137. # ------------------------------------------------------------------------------------------------------------
  138. # PatchCanvas defines
  139. CANVAS_ANTIALIASING_SMALL = 1
  140. CANVAS_EYECANDY_SMALL = 1
  141. # ------------------------------------------------------------------------------------------------------------
  142. # Carla Settings keys
  143. CARLA_KEY_MAIN_PROJECT_FOLDER = "Main/ProjectFolder" # str
  144. CARLA_KEY_MAIN_USE_PRO_THEME = "Main/UseProTheme" # bool
  145. CARLA_KEY_MAIN_PRO_THEME_COLOR = "Main/ProThemeColor" # str
  146. CARLA_KEY_MAIN_REFRESH_INTERVAL = "Main/RefreshInterval" # int
  147. CARLA_KEY_MAIN_CONFIRM_EXIT = "Main/ConfirmExit" # bool
  148. CARLA_KEY_MAIN_CLASSIC_SKIN = "Main/ClassicSkin" # bool
  149. CARLA_KEY_MAIN_SHOW_LOGS = "Main/ShowLogs" # bool
  150. CARLA_KEY_MAIN_SYSTEM_ICONS = "Main/SystemIcons" # bool
  151. CARLA_KEY_MAIN_EXPERIMENTAL = "Main/Experimental" # bool
  152. CARLA_KEY_CANVAS_THEME = "Canvas/Theme" # str
  153. CARLA_KEY_CANVAS_SIZE = "Canvas/Size" # str "NxN"
  154. CARLA_KEY_CANVAS_USE_BEZIER_LINES = "Canvas/UseBezierLines" # bool
  155. CARLA_KEY_CANVAS_AUTO_HIDE_GROUPS = "Canvas/AutoHideGroups" # bool
  156. CARLA_KEY_CANVAS_AUTO_SELECT_ITEMS = "Canvas/AutoSelectItems" # bool
  157. CARLA_KEY_CANVAS_EYE_CANDY = "Canvas/EyeCandy2" # bool
  158. CARLA_KEY_CANVAS_FANCY_EYE_CANDY = "Canvas/FancyEyeCandy" # bool
  159. CARLA_KEY_CANVAS_USE_OPENGL = "Canvas/UseOpenGL" # bool
  160. CARLA_KEY_CANVAS_ANTIALIASING = "Canvas/Antialiasing" # enum
  161. CARLA_KEY_CANVAS_HQ_ANTIALIASING = "Canvas/HQAntialiasing" # bool
  162. CARLA_KEY_CANVAS_INLINE_DISPLAYS = "Canvas/InlineDisplays" # bool
  163. CARLA_KEY_CANVAS_FULL_REPAINTS = "Canvas/FullRepaints" # bool
  164. CARLA_KEY_ENGINE_DRIVER_PREFIX = "Engine/Driver-"
  165. CARLA_KEY_ENGINE_AUDIO_DRIVER = "Engine/AudioDriver" # str
  166. CARLA_KEY_ENGINE_PROCESS_MODE = "Engine/ProcessMode" # enum
  167. CARLA_KEY_ENGINE_TRANSPORT_MODE = "Engine/TransportMode" # enum
  168. CARLA_KEY_ENGINE_TRANSPORT_EXTRA = "Engine/TransportExtra" # str
  169. CARLA_KEY_ENGINE_FORCE_STEREO = "Engine/ForceStereo" # bool
  170. CARLA_KEY_ENGINE_PREFER_PLUGIN_BRIDGES = "Engine/PreferPluginBridges" # bool
  171. CARLA_KEY_ENGINE_PREFER_UI_BRIDGES = "Engine/PreferUiBridges" # bool
  172. CARLA_KEY_ENGINE_MANAGE_UIS = "Engine/ManageUIs" # bool
  173. CARLA_KEY_ENGINE_UIS_ALWAYS_ON_TOP = "Engine/UIsAlwaysOnTop" # bool
  174. CARLA_KEY_ENGINE_MAX_PARAMETERS = "Engine/MaxParameters" # int
  175. CARLA_KEY_ENGINE_RESET_XRUNS = "Engine/ResetXruns" # bool
  176. CARLA_KEY_ENGINE_UI_BRIDGES_TIMEOUT = "Engine/UiBridgesTimeout" # int
  177. CARLA_KEY_OSC_ENABLED = "OSC/Enabled"
  178. CARLA_KEY_OSC_TCP_PORT_ENABLED = "OSC/TCPEnabled"
  179. CARLA_KEY_OSC_TCP_PORT_NUMBER = "OSC/TCPNumber"
  180. CARLA_KEY_OSC_TCP_PORT_RANDOM = "OSC/TCPRandom"
  181. CARLA_KEY_OSC_UDP_PORT_ENABLED = "OSC/UDPEnabled"
  182. CARLA_KEY_OSC_UDP_PORT_NUMBER = "OSC/UDPNumber"
  183. CARLA_KEY_OSC_UDP_PORT_RANDOM = "OSC/UDPRandom"
  184. CARLA_KEY_PATHS_AUDIO = "Paths/Audio"
  185. CARLA_KEY_PATHS_MIDI = "Paths/MIDI"
  186. CARLA_KEY_PATHS_LADSPA = "Paths/LADSPA"
  187. CARLA_KEY_PATHS_DSSI = "Paths/DSSI"
  188. CARLA_KEY_PATHS_LV2 = "Paths/LV2"
  189. CARLA_KEY_PATHS_VST2 = "Paths/VST2"
  190. CARLA_KEY_PATHS_VST3 = "Paths/VST3"
  191. CARLA_KEY_PATHS_SF2 = "Paths/SF2"
  192. CARLA_KEY_PATHS_SFZ = "Paths/SFZ"
  193. CARLA_KEY_WINE_EXECUTABLE = "Wine/Executable" # str
  194. CARLA_KEY_WINE_AUTO_PREFIX = "Wine/AutoPrefix" # bool
  195. CARLA_KEY_WINE_FALLBACK_PREFIX = "Wine/FallbackPrefix" # str
  196. CARLA_KEY_WINE_RT_PRIO_ENABLED = "Wine/RtPrioEnabled" # bool
  197. CARLA_KEY_WINE_BASE_RT_PRIO = "Wine/BaseRtPrio" # int
  198. CARLA_KEY_WINE_SERVER_RT_PRIO = "Wine/ServerRtPrio" # int
  199. CARLA_KEY_EXPERIMENTAL_PLUGIN_BRIDGES = "Experimental/PluginBridges" # bool
  200. CARLA_KEY_EXPERIMENTAL_WINE_BRIDGES = "Experimental/WineBridges" # bool
  201. CARLA_KEY_EXPERIMENTAL_JACK_APPS = "Experimental/JackApplications" # bool
  202. CARLA_KEY_EXPERIMENTAL_EXPORT_LV2 = "Experimental/ExportLV2" # bool
  203. CARLA_KEY_EXPERIMENTAL_PREVENT_BAD_BEHAVIOUR = "Experimental/PreventBadBehaviour" # bool
  204. CARLA_KEY_EXPERIMENTAL_LOAD_LIB_GLOBAL = "Experimental/LoadLibGlobal" # bool
  205. # if pro theme is on and color is black
  206. CARLA_KEY_CUSTOM_PAINTING = "UseCustomPainting" # bool
  207. # ------------------------------------------------------------------------------------------------------------
  208. # Carla Settings defaults
  209. # Main
  210. CARLA_DEFAULT_MAIN_PROJECT_FOLDER = HOME
  211. CARLA_DEFAULT_MAIN_USE_PRO_THEME = True
  212. CARLA_DEFAULT_MAIN_PRO_THEME_COLOR = "Black"
  213. CARLA_DEFAULT_MAIN_REFRESH_INTERVAL = 20
  214. CARLA_DEFAULT_MAIN_CONFIRM_EXIT = True
  215. CARLA_DEFAULT_MAIN_CLASSIC_SKIN = False
  216. CARLA_DEFAULT_MAIN_SHOW_LOGS = bool(not WINDOWS)
  217. CARLA_DEFAULT_MAIN_SYSTEM_ICONS = False
  218. CARLA_DEFAULT_MAIN_EXPERIMENTAL = False
  219. # Canvas
  220. CARLA_DEFAULT_CANVAS_THEME = "Modern Dark"
  221. CARLA_DEFAULT_CANVAS_SIZE = "3100x2400"
  222. CARLA_DEFAULT_CANVAS_SIZE_WIDTH = 3100
  223. CARLA_DEFAULT_CANVAS_SIZE_HEIGHT = 2400
  224. CARLA_DEFAULT_CANVAS_USE_BEZIER_LINES = True
  225. CARLA_DEFAULT_CANVAS_AUTO_HIDE_GROUPS = True
  226. CARLA_DEFAULT_CANVAS_AUTO_SELECT_ITEMS = False
  227. CARLA_DEFAULT_CANVAS_EYE_CANDY = True
  228. CARLA_DEFAULT_CANVAS_FANCY_EYE_CANDY = False
  229. CARLA_DEFAULT_CANVAS_USE_OPENGL = False
  230. CARLA_DEFAULT_CANVAS_ANTIALIASING = CANVAS_ANTIALIASING_SMALL
  231. CARLA_DEFAULT_CANVAS_HQ_ANTIALIASING = False
  232. CARLA_DEFAULT_CANVAS_INLINE_DISPLAYS = False
  233. CARLA_DEFAULT_CANVAS_FULL_REPAINTS = False
  234. # Engine
  235. CARLA_DEFAULT_FORCE_STEREO = False
  236. CARLA_DEFAULT_PREFER_PLUGIN_BRIDGES = False
  237. CARLA_DEFAULT_PREFER_UI_BRIDGES = True
  238. CARLA_DEFAULT_MANAGE_UIS = True
  239. CARLA_DEFAULT_UIS_ALWAYS_ON_TOP = False
  240. CARLA_DEFAULT_MAX_PARAMETERS = MAX_DEFAULT_PARAMETERS
  241. CARLA_DEFAULT_RESET_XRUNS = False
  242. CARLA_DEFAULT_UI_BRIDGES_TIMEOUT = 4000
  243. CARLA_DEFAULT_AUDIO_BUFFER_SIZE = 512
  244. CARLA_DEFAULT_AUDIO_SAMPLE_RATE = 44100
  245. CARLA_DEFAULT_AUDIO_TRIPLE_BUFFER = False
  246. if WINDOWS:
  247. CARLA_DEFAULT_AUDIO_DRIVER = "DirectSound"
  248. elif MACOS:
  249. CARLA_DEFAULT_AUDIO_DRIVER = "CoreAudio"
  250. elif os.path.exists("/usr/bin/jackd") or os.path.exists("/usr/bin/jackdbus"):
  251. CARLA_DEFAULT_AUDIO_DRIVER = "JACK"
  252. else:
  253. CARLA_DEFAULT_AUDIO_DRIVER = "PulseAudio"
  254. if CARLA_DEFAULT_AUDIO_DRIVER == "JACK":
  255. CARLA_DEFAULT_PROCESS_MODE = ENGINE_PROCESS_MODE_MULTIPLE_CLIENTS
  256. CARLA_DEFAULT_TRANSPORT_MODE = ENGINE_TRANSPORT_MODE_JACK
  257. else:
  258. CARLA_DEFAULT_PROCESS_MODE = ENGINE_PROCESS_MODE_PATCHBAY
  259. CARLA_DEFAULT_TRANSPORT_MODE = ENGINE_TRANSPORT_MODE_INTERNAL
  260. # OSC
  261. CARLA_DEFAULT_OSC_ENABLED = not (MACOS or WINDOWS)
  262. CARLA_DEFAULT_OSC_TCP_PORT_ENABLED = True
  263. CARLA_DEFAULT_OSC_TCP_PORT_NUMBER = 22752
  264. CARLA_DEFAULT_OSC_TCP_PORT_RANDOM = False
  265. CARLA_DEFAULT_OSC_UDP_PORT_ENABLED = True
  266. CARLA_DEFAULT_OSC_UDP_PORT_NUMBER = 22752
  267. CARLA_DEFAULT_OSC_UDP_PORT_RANDOM = False
  268. # Wine
  269. CARLA_DEFAULT_WINE_EXECUTABLE = "wine"
  270. CARLA_DEFAULT_WINE_AUTO_PREFIX = True
  271. CARLA_DEFAULT_WINE_FALLBACK_PREFIX = os.path.expanduser("~/.wine")
  272. CARLA_DEFAULT_WINE_RT_PRIO_ENABLED = True
  273. CARLA_DEFAULT_WINE_BASE_RT_PRIO = 15
  274. CARLA_DEFAULT_WINE_SERVER_RT_PRIO = 10
  275. # Experimental
  276. CARLA_DEFAULT_EXPERIMENTAL_PLUGIN_BRIDGES = False
  277. CARLA_DEFAULT_EXPERIMENTAL_WINE_BRIDGES = False
  278. CARLA_DEFAULT_EXPERIMENTAL_JACK_APPS = False
  279. CARLA_DEFAULT_EXPERIMENTAL_LV2_EXPORT = False
  280. CARLA_DEFAULT_EXPERIMENTAL_PREVENT_BAD_BEHAVIOUR = False
  281. CARLA_DEFAULT_EXPERIMENTAL_LOAD_LIB_GLOBAL = False
  282. # ------------------------------------------------------------------------------------------------------------
  283. # Default File Folders
  284. CARLA_DEFAULT_FILE_PATH_AUDIO = []
  285. CARLA_DEFAULT_FILE_PATH_MIDI = []
  286. # ------------------------------------------------------------------------------------------------------------
  287. # Default Plugin Folders (get)
  288. DEFAULT_LADSPA_PATH = ""
  289. DEFAULT_DSSI_PATH = ""
  290. DEFAULT_LV2_PATH = ""
  291. DEFAULT_VST2_PATH = ""
  292. DEFAULT_VST3_PATH = ""
  293. DEFAULT_SF2_PATH = ""
  294. DEFAULT_SFZ_PATH = ""
  295. if WINDOWS:
  296. splitter = ";"
  297. APPDATA = os.getenv("APPDATA")
  298. PROGRAMFILES = os.getenv("PROGRAMFILES")
  299. PROGRAMFILESx86 = os.getenv("PROGRAMFILES(x86)")
  300. COMMONPROGRAMFILES = os.getenv("COMMONPROGRAMFILES")
  301. COMMONPROGRAMFILESx86 = os.getenv("COMMONPROGRAMFILES(x86)")
  302. # Small integrity tests
  303. if not APPDATA:
  304. qFatal("APPDATA variable not set, cannot continue")
  305. sys.exit(1)
  306. if not PROGRAMFILES:
  307. qFatal("PROGRAMFILES variable not set, cannot continue")
  308. sys.exit(1)
  309. if not COMMONPROGRAMFILES:
  310. qFatal("COMMONPROGRAMFILES variable not set, cannot continue")
  311. sys.exit(1)
  312. DEFAULT_LADSPA_PATH = APPDATA + "\\LADSPA"
  313. DEFAULT_LADSPA_PATH += ";" + PROGRAMFILES + "\\LADSPA"
  314. DEFAULT_DSSI_PATH = APPDATA + "\\DSSI"
  315. DEFAULT_DSSI_PATH += ";" + PROGRAMFILES + "\\DSSI"
  316. DEFAULT_LV2_PATH = APPDATA + "\\LV2"
  317. DEFAULT_LV2_PATH += ";" + COMMONPROGRAMFILES + "\\LV2"
  318. DEFAULT_VST2_PATH = PROGRAMFILES + "\\VstPlugins"
  319. DEFAULT_VST2_PATH += ";" + PROGRAMFILES + "\\Steinberg\\VstPlugins"
  320. if kIs64bit:
  321. DEFAULT_VST2_PATH += ";" + COMMONPROGRAMFILES + "\\VST2"
  322. DEFAULT_VST3_PATH = COMMONPROGRAMFILES + "\\VST3"
  323. DEFAULT_SF2_PATH = APPDATA + "\\SF2"
  324. DEFAULT_SFZ_PATH = APPDATA + "\\SFZ"
  325. if PROGRAMFILESx86:
  326. DEFAULT_LADSPA_PATH += ";" + PROGRAMFILESx86 + "\\LADSPA"
  327. DEFAULT_DSSI_PATH += ";" + PROGRAMFILESx86 + "\\DSSI"
  328. DEFAULT_VST2_PATH += ";" + PROGRAMFILESx86 + "\\VstPlugins"
  329. DEFAULT_VST2_PATH += ";" + PROGRAMFILESx86 + "\\Steinberg\\VstPlugins"
  330. if COMMONPROGRAMFILESx86:
  331. DEFAULT_VST3_PATH += COMMONPROGRAMFILESx86 + "\\VST3"
  332. elif HAIKU:
  333. splitter = ":"
  334. DEFAULT_LADSPA_PATH = HOME + "/.ladspa"
  335. DEFAULT_LADSPA_PATH += ":/system/add-ons/media/ladspaplugins"
  336. DEFAULT_LADSPA_PATH += ":/system/lib/ladspa"
  337. DEFAULT_DSSI_PATH = HOME + "/.dssi"
  338. DEFAULT_DSSI_PATH += ":/system/add-ons/media/dssiplugins"
  339. DEFAULT_DSSI_PATH += ":/system/lib/dssi"
  340. DEFAULT_LV2_PATH = HOME + "/.lv2"
  341. DEFAULT_LV2_PATH += ":/system/add-ons/media/lv2plugins"
  342. DEFAULT_VST2_PATH = HOME + "/.vst"
  343. DEFAULT_VST2_PATH += ":/system/add-ons/media/vstplugins"
  344. DEFAULT_VST3_PATH = HOME + "/.vst3"
  345. DEFAULT_VST3_PATH += ":/system/add-ons/media/vst3plugins"
  346. elif MACOS:
  347. splitter = ":"
  348. DEFAULT_LADSPA_PATH = HOME + "/Library/Audio/Plug-Ins/LADSPA"
  349. DEFAULT_LADSPA_PATH += ":/Library/Audio/Plug-Ins/LADSPA"
  350. DEFAULT_DSSI_PATH = HOME + "/Library/Audio/Plug-Ins/DSSI"
  351. DEFAULT_DSSI_PATH += ":/Library/Audio/Plug-Ins/DSSI"
  352. DEFAULT_LV2_PATH = HOME + "/Library/Audio/Plug-Ins/LV2"
  353. DEFAULT_LV2_PATH += ":/Library/Audio/Plug-Ins/LV2"
  354. DEFAULT_VST2_PATH = HOME + "/Library/Audio/Plug-Ins/VST"
  355. DEFAULT_VST2_PATH += ":/Library/Audio/Plug-Ins/VST"
  356. DEFAULT_VST3_PATH = HOME + "/Library/Audio/Plug-Ins/VST3"
  357. DEFAULT_VST3_PATH += ":/Library/Audio/Plug-Ins/VST3"
  358. else:
  359. splitter = ":"
  360. DEFAULT_LADSPA_PATH = HOME + "/.ladspa"
  361. DEFAULT_LADSPA_PATH += ":/usr/lib/ladspa"
  362. DEFAULT_LADSPA_PATH += ":/usr/local/lib/ladspa"
  363. DEFAULT_DSSI_PATH = HOME + "/.dssi"
  364. DEFAULT_DSSI_PATH += ":/usr/lib/dssi"
  365. DEFAULT_DSSI_PATH += ":/usr/local/lib/dssi"
  366. DEFAULT_LV2_PATH = HOME + "/.lv2"
  367. DEFAULT_LV2_PATH += ":/usr/lib/lv2"
  368. DEFAULT_LV2_PATH += ":/usr/local/lib/lv2"
  369. DEFAULT_VST2_PATH = HOME + "/.vst"
  370. DEFAULT_VST2_PATH += ":/usr/lib/vst"
  371. DEFAULT_VST2_PATH += ":/usr/local/lib/vst"
  372. DEFAULT_VST2_PATH += HOME + "/.lxvst"
  373. DEFAULT_VST2_PATH += ":/usr/lib/lxvst"
  374. DEFAULT_VST2_PATH += ":/usr/local/lib/lxvst"
  375. DEFAULT_VST3_PATH = HOME + "/.vst3"
  376. DEFAULT_VST3_PATH += ":/usr/lib/vst3"
  377. DEFAULT_VST3_PATH += ":/usr/local/lib/vst3"
  378. DEFAULT_SF2_PATH = HOME + "/.sounds/sf2"
  379. DEFAULT_SF2_PATH += HOME + ":/.sounds/sf3"
  380. DEFAULT_SF2_PATH += ":/usr/share/sounds/sf2"
  381. DEFAULT_SF2_PATH += ":/usr/share/sounds/sf3"
  382. DEFAULT_SF2_PATH += ":/usr/share/soundfonts"
  383. DEFAULT_SFZ_PATH = HOME + "/.sounds/sfz"
  384. DEFAULT_SFZ_PATH += ":/usr/share/sounds/sfz"
  385. if not WINDOWS:
  386. winePrefix = os.getenv("WINEPREFIX")
  387. if not winePrefix:
  388. winePrefix = HOME + "/.wine"
  389. if os.path.exists(winePrefix):
  390. DEFAULT_VST2_PATH += ":" + winePrefix + "/drive_c/Program Files/VstPlugins"
  391. DEFAULT_VST3_PATH += ":" + winePrefix + "/drive_c/Program Files/Common Files/VST3"
  392. if kIs64bit and os.path.exists(winePrefix + "/drive_c/Program Files (x86)"):
  393. DEFAULT_VST2_PATH += ":" + winePrefix + "/drive_c/Program Files (x86)/VstPlugins"
  394. DEFAULT_VST3_PATH += ":" + winePrefix + "/drive_c/Program Files (x86)/Common Files/VST3"
  395. del winePrefix
  396. # ------------------------------------------------------------------------------------------------------------
  397. # Default Plugin Folders (set)
  398. readEnvVars = True
  399. if WINDOWS:
  400. # Check if running Wine. If yes, ignore env vars
  401. # pylint: disable=import-error
  402. from winreg import ConnectRegistry, OpenKey, CloseKey, HKEY_CURRENT_USER
  403. # pylint: enable=import-error
  404. _reg = ConnectRegistry(None, HKEY_CURRENT_USER)
  405. try:
  406. _key = OpenKey(_reg, r"SOFTWARE\Wine")
  407. CloseKey(_key)
  408. del _key
  409. readEnvVars = False
  410. except:
  411. pass
  412. CloseKey(_reg)
  413. del _reg
  414. if readEnvVars:
  415. CARLA_DEFAULT_LADSPA_PATH = os.getenv("LADSPA_PATH", DEFAULT_LADSPA_PATH).split(splitter)
  416. CARLA_DEFAULT_DSSI_PATH = os.getenv("DSSI_PATH", DEFAULT_DSSI_PATH).split(splitter)
  417. CARLA_DEFAULT_LV2_PATH = os.getenv("LV2_PATH", DEFAULT_LV2_PATH).split(splitter)
  418. CARLA_DEFAULT_VST2_PATH = os.getenv("VST_PATH", DEFAULT_VST2_PATH).split(splitter)
  419. CARLA_DEFAULT_VST3_PATH = os.getenv("VST3_PATH", DEFAULT_VST3_PATH).split(splitter)
  420. CARLA_DEFAULT_SF2_PATH = os.getenv("SF2_PATH", DEFAULT_SF2_PATH).split(splitter)
  421. CARLA_DEFAULT_SFZ_PATH = os.getenv("SFZ_PATH", DEFAULT_SFZ_PATH).split(splitter)
  422. else:
  423. CARLA_DEFAULT_LADSPA_PATH = DEFAULT_LADSPA_PATH.split(splitter)
  424. CARLA_DEFAULT_DSSI_PATH = DEFAULT_DSSI_PATH.split(splitter)
  425. CARLA_DEFAULT_LV2_PATH = DEFAULT_LV2_PATH.split(splitter)
  426. CARLA_DEFAULT_VST2_PATH = DEFAULT_VST2_PATH.split(splitter)
  427. CARLA_DEFAULT_VST3_PATH = DEFAULT_VST3_PATH.split(splitter)
  428. CARLA_DEFAULT_SF2_PATH = DEFAULT_SF2_PATH.split(splitter)
  429. CARLA_DEFAULT_SFZ_PATH = DEFAULT_SFZ_PATH.split(splitter)
  430. # ------------------------------------------------------------------------------------------------------------
  431. # Default Plugin Folders (cleanup)
  432. del DEFAULT_LADSPA_PATH
  433. del DEFAULT_DSSI_PATH
  434. del DEFAULT_LV2_PATH
  435. del DEFAULT_VST2_PATH
  436. del DEFAULT_VST3_PATH
  437. del DEFAULT_SF2_PATH
  438. del DEFAULT_SFZ_PATH
  439. # ------------------------------------------------------------------------------------------------------------
  440. # Global Carla object
  441. class CarlaObject():
  442. def __init__(self):
  443. self.cnprefix = "" # Client name prefix
  444. self.gui = None # Host Window
  445. self.nogui = False # Skip UI
  446. self.term = False # Terminated by OS signal
  447. self.utils = None # Utils object
  448. gCarla = CarlaObject()
  449. # ------------------------------------------------------------------------------------------------------------
  450. # Set CWD
  451. CWD = sys.path[0]
  452. if not CWD:
  453. CWD = os.path.dirname(sys.argv[0])
  454. # make it work with cxfreeze
  455. if os.path.isfile(CWD):
  456. CWD = os.path.dirname(CWD)
  457. if CWD.endswith("/lib"):
  458. CWD = CWD.rsplit("/lib",1)[0]
  459. CXFREEZE = True
  460. if not WINDOWS:
  461. os.environ['CARLA_MAGIC_FILE'] = os.path.join(CWD, "magic.mgc")
  462. else:
  463. CXFREEZE = False
  464. # ------------------------------------------------------------------------------------------------------------
  465. # Set DLL_EXTENSION
  466. if WINDOWS:
  467. DLL_EXTENSION = "dll"
  468. elif MACOS:
  469. DLL_EXTENSION = "dylib"
  470. else:
  471. DLL_EXTENSION = "so"
  472. # ------------------------------------------------------------------------------------------------------------
  473. # Find decimal points for a parameter, using step and stepSmall
  474. def countDecimalPoints(step, stepSmall):
  475. if stepSmall >= 1.0:
  476. return 0
  477. if step >= 1.0:
  478. return 2
  479. count = 0
  480. value = fmod(abs(step), 1)
  481. while 0.0001 < value < 0.999 and count < 6:
  482. value = fmod(value*10, 1)
  483. count += 1
  484. return count
  485. # ------------------------------------------------------------------------------------------------------------
  486. # Check if a value is a number (float support)
  487. def isNumber(value):
  488. try:
  489. float(value)
  490. return True
  491. except:
  492. return False
  493. # ------------------------------------------------------------------------------------------------------------
  494. # Convert a value to a list
  495. def toList(value):
  496. if value is None:
  497. return []
  498. if not isinstance(value, list):
  499. return [value]
  500. return value
  501. # ------------------------------------------------------------------------------------------------------------
  502. # Get Icon from user theme, using our own as backup (Oxygen)
  503. def getIcon(icon, size, qrcformat):
  504. return QIcon.fromTheme(icon, QIcon(":/%ix%i/%s.%s" % (size, size, icon, qrcformat)))
  505. # ------------------------------------------------------------------------------------------------------------
  506. # Handle some basic command-line arguments shared between all carla variants
  507. def handleInitialCommandLineArguments(file):
  508. initName = os.path.basename(file) if (file is not None and os.path.dirname(file) in PATH) else sys.argv[0]
  509. libPrefix = None
  510. readPrefixNext = False
  511. for arg in sys.argv[1:]:
  512. if arg.startswith("--with-appname="):
  513. initName = os.path.basename(arg.replace("--with-appname=", ""))
  514. elif arg.startswith("--with-libprefix="):
  515. libPrefix = arg.replace("--with-libprefix=", "")
  516. elif arg.startswith("--osc-gui="):
  517. gCarla.nogui = int(arg.replace("--osc-gui=", ""))
  518. elif arg.startswith("--cnprefix="):
  519. gCarla.cnprefix = arg.replace("--cnprefix=", "")
  520. elif arg == "--cnprefix":
  521. readPrefixNext = True
  522. elif arg == "--gdb":
  523. pass
  524. elif arg in ("-n", "--n", "-no-gui", "--no-gui", "-nogui", "--nogui"):
  525. gCarla.nogui = True
  526. elif MACOS and arg.startswith("-psn_"):
  527. pass
  528. elif arg in ("-h", "--h", "-help", "--help"):
  529. print("Usage: %s [OPTION]... [FILE|URL]" % initName)
  530. print("")
  531. print(" where FILE can be a Carla project or preset file to be loaded, or URL if using Carla-Control")
  532. print("")
  533. print(" and OPTION can be one or more of the following:")
  534. print("")
  535. print(" --cnprefix\t Set a prefix for client names in multi-client mode.")
  536. if isinstance(gCarla.nogui, bool):
  537. if X_LIBDIR_X is not None:
  538. print(" --gdb \t Run Carla inside gdb.")
  539. print(" -n,--no-gui \t Run Carla headless, don't show UI.")
  540. print("")
  541. print(" -h,--help \t Print this help text and exit.")
  542. print(" -v,--version \t Print version information and exit.")
  543. print("")
  544. if not isinstance(gCarla.nogui, bool):
  545. print("NOTE: when using %s the FILE is only valid the first time the backend is started" % initName)
  546. sys.exit(1)
  547. sys.exit(0)
  548. elif arg in ("-v", "--v", "-version", "--version"):
  549. pathBinaries, pathResources = getPaths(libPrefix)
  550. print("Using Carla version %s" % VERSION)
  551. print(" Python version: %s" % sys.version.split(" ",1)[0])
  552. print(" Qt version: %s" % QT_VERSION_STR)
  553. print(" PyQt version: %s" % PYQT_VERSION_STR)
  554. print(" Binary dir: %s" % pathBinaries)
  555. print(" Resources dir: %s" % pathResources)
  556. sys.exit(1 if gCarla.nogui else 0)
  557. elif readPrefixNext:
  558. readPrefixNext = False
  559. gCarla.cnprefix = arg
  560. if gCarla.nogui and not isinstance(gCarla.nogui, bool):
  561. if os.fork():
  562. # pylint: disable=protected-access
  563. os._exit(0)
  564. # pylint: enable=protected-access
  565. else:
  566. os.setsid()
  567. return (initName, libPrefix)
  568. # ------------------------------------------------------------------------------------------------------------
  569. # Get initial project file (as passed in the command-line parameters)
  570. def getInitialProjectFile(skipExistCheck = False):
  571. # NOTE: PyQt mishandles unicode characters, we directly use sys.argv instead of qApp->arguments()
  572. # see https://riverbankcomputing.com/pipermail/pyqt/2015-January/035395.html
  573. args = sys.argv[1:]
  574. readPrefixNext = False
  575. for arg in args:
  576. if readPrefixNext:
  577. readPrefixNext = False
  578. continue
  579. if arg.startswith("--cnprefix="):
  580. continue
  581. if arg.startswith("--osc-gui="):
  582. continue
  583. if arg.startswith("--with-appname="):
  584. continue
  585. if arg.startswith("--with-libprefix="):
  586. continue
  587. if arg == "--cnprefix":
  588. readPrefixNext = True
  589. continue
  590. if arg in ("-n", "--n", "-no-gui", "--no-gui", "-nogui", "--nogui", "--gdb"):
  591. continue
  592. if MACOS and arg.startswith("-psn_"):
  593. continue
  594. arg = os.path.expanduser(arg)
  595. if skipExistCheck or os.path.exists(arg):
  596. return arg
  597. return None
  598. # ------------------------------------------------------------------------------------------------------------
  599. # Get paths (binaries, resources)
  600. def getPaths(libPrefix = None):
  601. CWDl = CWD.lower()
  602. # adjust for special distros
  603. libdir = os.path.basename(os.path.normpath(X_LIBDIR_X)) if X_LIBDIR_X else "lib"
  604. datadir = os.path.basename(os.path.normpath(X_DATADIR_X)) if X_DATADIR_X else "share"
  605. # standalone, installed system-wide linux
  606. if libPrefix is not None:
  607. pathBinaries = os.path.join(libPrefix, libdir, "carla")
  608. pathResources = os.path.join(libPrefix, datadir, "carla", "resources")
  609. # standalone, local source
  610. elif CWDl.endswith("frontend"):
  611. pathBinaries = os.path.abspath(os.path.join(CWD, "..", "..", "bin"))
  612. pathResources = os.path.join(pathBinaries, "resources")
  613. # plugin
  614. elif CWDl.endswith("resources"):
  615. # installed system-wide linux
  616. if CWDl.endswith("/share/carla/resources"):
  617. pathBinaries = os.path.abspath(os.path.join(CWD, "..", "..", "..", libdir, "carla"))
  618. pathResources = CWD
  619. # local source
  620. elif CWDl.endswith("native-plugins%sresources" % os.sep):
  621. pathBinaries = os.path.abspath(os.path.join(CWD, "..", "..", "..", "bin"))
  622. pathResources = CWD
  623. # other
  624. else:
  625. pathBinaries = os.path.abspath(os.path.join(CWD, ".."))
  626. pathResources = CWD
  627. # everything else
  628. else:
  629. pathBinaries = CWD
  630. pathResources = os.path.join(pathBinaries, "resources")
  631. return (pathBinaries, pathResources)
  632. # ------------------------------------------------------------------------------------------------------------
  633. # Signal handler
  634. # TODO move to carla_host.py or something
  635. def signalHandler(sig, frame):
  636. if sig in (SIGINT, SIGTERM):
  637. gCarla.term = True
  638. if gCarla.gui is not None:
  639. gCarla.gui.SIGTERM.emit()
  640. elif haveSIGUSR1 and sig == SIGUSR1:
  641. if gCarla.gui is not None:
  642. gCarla.gui.SIGUSR1.emit()
  643. def setUpSignals():
  644. signal(SIGINT, signalHandler)
  645. signal(SIGTERM, signalHandler)
  646. if not haveSIGUSR1:
  647. return
  648. signal(SIGUSR1, signalHandler)
  649. # ------------------------------------------------------------------------------------------------------------
  650. # QLineEdit and QPushButton combo
  651. def getAndSetPath(parent, lineEdit):
  652. newPath = QFileDialog.getExistingDirectory(parent, parent.tr("Set Path"), lineEdit.text(), QFileDialog.ShowDirsOnly)
  653. if newPath:
  654. lineEdit.setText(newPath)
  655. return newPath
  656. # ------------------------------------------------------------------------------------------------------------
  657. # Backwards-compatible horizontalAdvance/width call, depending on Qt version
  658. def fontMetricsHorizontalAdvance(fontMetrics, string):
  659. if QT_VERSION >= 0x50b00:
  660. return fontMetrics.horizontalAdvance(string)
  661. return fontMetrics.width(string)
  662. # ------------------------------------------------------------------------------------------------------------
  663. # Custom QMessageBox which resizes itself to fit text
  664. class QMessageBoxWithBetterWidth(QMessageBox):
  665. def __init__(self, parent):
  666. QMessageBox.__init__(self, parent)
  667. def showEvent(self, event):
  668. fontMetrics = self.fontMetrics()
  669. lines = self.text().strip().split("\n") + self.informativeText().strip().split("\n")
  670. if lines:
  671. width = 0
  672. for line in lines:
  673. width = max(fontMetricsHorizontalAdvance(fontMetrics, line), width)
  674. self.layout().setColumnMinimumWidth(2, width + 12)
  675. QMessageBox.showEvent(self, event)
  676. # ------------------------------------------------------------------------------------------------------------
  677. # Safer QSettings class, which does not throw if type mismatches
  678. class QSafeSettings(QSettings):
  679. def value(self, key, defaultValue, valueType):
  680. if not isinstance(defaultValue, valueType):
  681. print("QSafeSettings.value() - defaultValue type mismatch for key", key)
  682. try:
  683. return QSettings.value(self, key, defaultValue, valueType)
  684. except:
  685. return defaultValue
  686. # ------------------------------------------------------------------------------------------------------------
  687. # Custom MessageBox
  688. # pylint: disable=too-many-arguments
  689. def CustomMessageBox(parent, icon, title, text,
  690. extraText="",
  691. buttons=QMessageBox.Yes|QMessageBox.No,
  692. defButton=QMessageBox.No):
  693. msgBox = QMessageBoxWithBetterWidth(parent)
  694. msgBox.setIcon(icon)
  695. msgBox.setWindowTitle(title)
  696. msgBox.setText(text)
  697. msgBox.setInformativeText(extraText)
  698. msgBox.setStandardButtons(buttons)
  699. msgBox.setDefaultButton(defButton)
  700. return msgBox.exec_()
  701. # pylint: enable=too-many-arguments
  702. # ------------------------------------------------------------------------------------------------------------