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

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