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 32KB

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