2 # SPDX-FileCopyrightText: 2011-2024 Filipe Coelho <falktx@falktx.com>
3 # SPDX-License-Identifier: GPL-2.0-or-later
5 # ------------------------------------------------------------------------------------------------------------
13 # ------------------------------------------------------------------------------------------------------------
16 from signal
import signal
, SIGINT
, SIGTERM
19 from signal
import SIGUSR1
24 # ------------------------------------------------------------------------------------------------------------
27 from qt_compat
import qt_config
30 # import changed in PyQt 5.15.8, so try both
32 from PyQt5
.Qt
import PYQT_VERSION_STR
34 from PyQt5
.QtCore
import PYQT_VERSION_STR
36 from PyQt5
.QtCore
import qFatal
, QT_VERSION
, QT_VERSION_STR
, qWarning
, QDir
, QSettings
37 from PyQt5
.QtGui
import QIcon
38 from PyQt5
.QtWidgets
import QFileDialog
, QMessageBox
41 from PyQt6
.QtCore
import qFatal
, PYQT_VERSION_STR
, QT_VERSION
, QT_VERSION_STR
, qWarning
, QDir
, QSettings
42 from PyQt6
.QtGui
import QIcon
43 from PyQt6
.QtWidgets
import QFileDialog
, QMessageBox
45 # ------------------------------------------------------------------------------------------------------------
48 from carla_backend
import (
49 MAX_DEFAULT_PARAMETERS
,
50 ENGINE_PROCESS_MODE_MULTIPLE_CLIENTS
,
51 ENGINE_PROCESS_MODE_PATCHBAY
,
52 ENGINE_TRANSPORT_MODE_INTERNAL
,
53 ENGINE_TRANSPORT_MODE_JACK
56 from common
import kIs64bit
, HAIKU
, LINUX
, MACOS
, WINDOWS
, VERSION
58 # ------------------------------------------------------------------------------------------------------------
61 # These will be modified during install
65 # ------------------------------------------------------------------------------------------------------------
66 # Platform specific stuff
69 WINDIR
= os
.getenv("WINDIR")
71 # ------------------------------------------------------------------------------------------------------------
74 envTMP
= os
.getenv("TMP")
78 qWarning("TMP variable not set")
83 if not os
.path
.exists(TMP
):
84 qWarning("TMP does not exist")
89 # ------------------------------------------------------------------------------------------------------------
92 envHOME
= os
.getenv("HOME")
96 qWarning("HOME variable not set")
97 HOME
= QDir
.toNativeSeparators(QDir
.homePath())
101 if not os
.path
.exists(HOME
):
102 qWarning("HOME does not exist")
107 # ------------------------------------------------------------------------------------------------------------
110 envPATH
= os
.getenv("PATH")
113 qWarning("PATH variable not set")
115 PATH
= ("/opt/local/bin", "/usr/local/bin", "/usr/bin", "/bin")
117 PATH
= (os
.path
.join(WINDIR
, "system32"), WINDIR
)
119 PATH
= ("/usr/local/bin", "/usr/bin", "/bin")
121 PATH
= envPATH
.split(os
.pathsep
)
125 # ------------------------------------------------------------------------------------------------------------
126 # Static MIDI CC list
129 "01 [0x01] Modulation",
132 "05 [0x05] Portamento",
136 "11 [0x0B] Expression",
137 "12 [0x0C] FX Control 1",
138 "13 [0x0D] FX Control 2",
139 "16 [0x10] General Purpose 1",
140 "17 [0x11] General Purpose 2",
141 "18 [0x12] General Purpose 3",
142 "19 [0x13] General Purpose 4",
143 "70 [0x46] Control 1 [Variation]",
144 "71 [0x47] Control 2 [Timbre]",
145 "72 [0x48] Control 3 [Release]",
146 "73 [0x49] Control 4 [Attack]",
147 "74 [0x4A] Control 5 [Brightness]",
148 "75 [0x4B] Control 6 [Decay]",
149 "76 [0x4C] Control 7 [Vib Rate]",
150 "77 [0x4D] Control 8 [Vib Depth]",
151 "78 [0x4E] Control 9 [Vib Delay]",
152 "79 [0x4F] Control 10 [Undefined]",
153 "80 [0x50] General Purpose 5",
154 "81 [0x51] General Purpose 6",
155 "82 [0x52] General Purpose 7",
156 "83 [0x53] General Purpose 8",
157 "84 [0x54] Portamento Control",
158 "91 [0x5B] FX 1 Depth [Reverb]",
159 "92 [0x5C] FX 2 Depth [Tremolo]",
160 "93 [0x5D] FX 3 Depth [Chorus]",
161 "94 [0x5E] FX 4 Depth [Detune]",
162 "95 [0x5F] FX 5 Depth [Phaser]"
165 MAX_MIDI_CC_LIST_ITEM
= 95
167 # ------------------------------------------------------------------------------------------------------------
168 # PatchCanvas defines
170 CANVAS_ANTIALIASING_SMALL
= 1
171 CANVAS_EYECANDY_SMALL
= 1
173 # ------------------------------------------------------------------------------------------------------------
174 # Carla Settings keys
176 CARLA_KEY_MAIN_PROJECT_FOLDER
= "Main/ProjectFolder" # str
177 CARLA_KEY_MAIN_USE_PRO_THEME
= "Main/UseProTheme" # bool
178 CARLA_KEY_MAIN_PRO_THEME_COLOR
= "Main/ProThemeColor" # str
179 CARLA_KEY_MAIN_REFRESH_INTERVAL
= "Main/RefreshInterval" # int
180 CARLA_KEY_MAIN_CONFIRM_EXIT
= "Main/ConfirmExit" # bool
181 CARLA_KEY_MAIN_CLASSIC_SKIN
= "Main/ClassicSkin" # bool
182 CARLA_KEY_MAIN_SHOW_LOGS
= "Main/ShowLogs" # bool
183 CARLA_KEY_MAIN_SYSTEM_ICONS
= "Main/SystemIcons" # bool
184 CARLA_KEY_MAIN_EXPERIMENTAL
= "Main/Experimental" # bool
186 CARLA_KEY_CANVAS_THEME
= "Canvas/Theme" # str
187 CARLA_KEY_CANVAS_SIZE
= "Canvas/Size" # str "NxN"
188 CARLA_KEY_CANVAS_USE_BEZIER_LINES
= "Canvas/UseBezierLines" # bool
189 CARLA_KEY_CANVAS_AUTO_HIDE_GROUPS
= "Canvas/AutoHideGroups" # bool
190 CARLA_KEY_CANVAS_AUTO_SELECT_ITEMS
= "Canvas/AutoSelectItems" # bool
191 CARLA_KEY_CANVAS_EYE_CANDY
= "Canvas/EyeCandy2" # bool
192 CARLA_KEY_CANVAS_FANCY_EYE_CANDY
= "Canvas/FancyEyeCandy" # bool
193 CARLA_KEY_CANVAS_USE_OPENGL
= "Canvas/UseOpenGL" # bool
194 CARLA_KEY_CANVAS_ANTIALIASING
= "Canvas/Antialiasing" # enum
195 CARLA_KEY_CANVAS_HQ_ANTIALIASING
= "Canvas/HQAntialiasing" # bool
196 CARLA_KEY_CANVAS_INLINE_DISPLAYS
= "Canvas/InlineDisplays" # bool
197 CARLA_KEY_CANVAS_FULL_REPAINTS
= "Canvas/FullRepaints" # bool
199 CARLA_KEY_ENGINE_DRIVER_PREFIX
= "Engine/Driver-"
200 CARLA_KEY_ENGINE_AUDIO_DRIVER
= "Engine/AudioDriver" # str
201 CARLA_KEY_ENGINE_AUDIO_DEVICE
= "Engine/AudioDevice" # str
202 CARLA_KEY_ENGINE_BUFFER_SIZE
= "Engine/BufferSize" # int
203 CARLA_KEY_ENGINE_SAMPLE_RATE
= "Engine/SampleRate" # int
204 CARLA_KEY_ENGINE_TRIPLE_BUFFER
= "Engine/TripleBuffer" # bool
205 CARLA_KEY_ENGINE_PROCESS_MODE
= "Engine/ProcessMode" # enum
206 CARLA_KEY_ENGINE_TRANSPORT_MODE
= "Engine/TransportMode" # enum
207 CARLA_KEY_ENGINE_TRANSPORT_EXTRA
= "Engine/TransportExtra" # str
208 CARLA_KEY_ENGINE_FORCE_STEREO
= "Engine/ForceStereo" # bool
209 CARLA_KEY_ENGINE_PREFER_PLUGIN_BRIDGES
= "Engine/PreferPluginBridges" # bool
210 CARLA_KEY_ENGINE_PREFER_UI_BRIDGES
= "Engine/PreferUiBridges" # bool
211 CARLA_KEY_ENGINE_MANAGE_UIS
= "Engine/ManageUIs" # bool
212 CARLA_KEY_ENGINE_UIS_ALWAYS_ON_TOP
= "Engine/UIsAlwaysOnTop" # bool
213 CARLA_KEY_ENGINE_MAX_PARAMETERS
= "Engine/MaxParameters" # int
214 CARLA_KEY_ENGINE_RESET_XRUNS
= "Engine/ResetXruns" # bool
215 CARLA_KEY_ENGINE_UI_BRIDGES_TIMEOUT
= "Engine/UiBridgesTimeout" # int
217 CARLA_KEY_OSC_ENABLED
= "OSC/Enabled"
218 CARLA_KEY_OSC_TCP_PORT_ENABLED
= "OSC/TCPEnabled"
219 CARLA_KEY_OSC_TCP_PORT_NUMBER
= "OSC/TCPNumber"
220 CARLA_KEY_OSC_TCP_PORT_RANDOM
= "OSC/TCPRandom"
221 CARLA_KEY_OSC_UDP_PORT_ENABLED
= "OSC/UDPEnabled"
222 CARLA_KEY_OSC_UDP_PORT_NUMBER
= "OSC/UDPNumber"
223 CARLA_KEY_OSC_UDP_PORT_RANDOM
= "OSC/UDPRandom"
225 CARLA_KEY_PATHS_AUDIO
= "Paths/Audio"
226 CARLA_KEY_PATHS_MIDI
= "Paths/MIDI"
228 CARLA_KEY_PATHS_LADSPA
= "Paths/LADSPA"
229 CARLA_KEY_PATHS_DSSI
= "Paths/DSSI"
230 CARLA_KEY_PATHS_LV2
= "Paths/LV2"
231 CARLA_KEY_PATHS_VST2
= "Paths/VST2"
232 CARLA_KEY_PATHS_VST3
= "Paths/VST3"
233 CARLA_KEY_PATHS_CLAP
= "Paths/CLAP"
234 CARLA_KEY_PATHS_SF2
= "Paths/SF2"
235 CARLA_KEY_PATHS_SFZ
= "Paths/SFZ"
236 CARLA_KEY_PATHS_JSFX
= "Paths/JSFX"
238 CARLA_KEY_WINE_EXECUTABLE
= "Wine/Executable" # str
239 CARLA_KEY_WINE_AUTO_PREFIX
= "Wine/AutoPrefix" # bool
240 CARLA_KEY_WINE_FALLBACK_PREFIX
= "Wine/FallbackPrefix" # str
241 CARLA_KEY_WINE_RT_PRIO_ENABLED
= "Wine/RtPrioEnabled" # bool
242 CARLA_KEY_WINE_BASE_RT_PRIO
= "Wine/BaseRtPrio" # int
243 CARLA_KEY_WINE_SERVER_RT_PRIO
= "Wine/ServerRtPrio" # int
245 CARLA_KEY_EXPERIMENTAL_PLUGIN_BRIDGES
= "Experimental/PluginBridges" # bool
246 CARLA_KEY_EXPERIMENTAL_WINE_BRIDGES
= "Experimental/WineBridges" # bool
247 CARLA_KEY_EXPERIMENTAL_JACK_APPS
= "Experimental/JackApplications" # bool
248 CARLA_KEY_EXPERIMENTAL_EXPORT_LV2
= "Experimental/ExportLV2" # bool
249 CARLA_KEY_EXPERIMENTAL_PREVENT_BAD_BEHAVIOUR
= "Experimental/PreventBadBehaviour" # bool
250 CARLA_KEY_EXPERIMENTAL_LOAD_LIB_GLOBAL
= "Experimental/LoadLibGlobal" # bool
252 # if pro theme is on and color is black
253 CARLA_KEY_CUSTOM_PAINTING
= "UseCustomPainting" # bool
255 # ------------------------------------------------------------------------------------------------------------
256 # Carla Settings defaults
259 CARLA_DEFAULT_MAIN_PROJECT_FOLDER
= HOME
260 CARLA_DEFAULT_MAIN_USE_PRO_THEME
= True
261 CARLA_DEFAULT_MAIN_PRO_THEME_COLOR
= "Black"
262 CARLA_DEFAULT_MAIN_REFRESH_INTERVAL
= 20
263 CARLA_DEFAULT_MAIN_CONFIRM_EXIT
= True
264 CARLA_DEFAULT_MAIN_CLASSIC_SKIN
= False
265 CARLA_DEFAULT_MAIN_SHOW_LOGS
= bool(not WINDOWS
)
266 CARLA_DEFAULT_MAIN_SYSTEM_ICONS
= False
267 CARLA_DEFAULT_MAIN_EXPERIMENTAL
= False
270 CARLA_DEFAULT_CANVAS_THEME
= "Modern Dark"
271 CARLA_DEFAULT_CANVAS_SIZE
= "3100x2400"
272 CARLA_DEFAULT_CANVAS_SIZE_WIDTH
= 3100
273 CARLA_DEFAULT_CANVAS_SIZE_HEIGHT
= 2400
274 CARLA_DEFAULT_CANVAS_USE_BEZIER_LINES
= True
275 CARLA_DEFAULT_CANVAS_AUTO_HIDE_GROUPS
= True
276 CARLA_DEFAULT_CANVAS_AUTO_SELECT_ITEMS
= False
277 CARLA_DEFAULT_CANVAS_EYE_CANDY
= True
278 CARLA_DEFAULT_CANVAS_FANCY_EYE_CANDY
= False
279 CARLA_DEFAULT_CANVAS_USE_OPENGL
= False
280 CARLA_DEFAULT_CANVAS_ANTIALIASING
= CANVAS_ANTIALIASING_SMALL
281 CARLA_DEFAULT_CANVAS_HQ_ANTIALIASING
= False
282 CARLA_DEFAULT_CANVAS_INLINE_DISPLAYS
= False
283 CARLA_DEFAULT_CANVAS_FULL_REPAINTS
= False
286 CARLA_DEFAULT_FORCE_STEREO
= False
287 CARLA_DEFAULT_PREFER_PLUGIN_BRIDGES
= False
288 CARLA_DEFAULT_PREFER_UI_BRIDGES
= True
289 CARLA_DEFAULT_MANAGE_UIS
= True
290 CARLA_DEFAULT_UIS_ALWAYS_ON_TOP
= False
291 CARLA_DEFAULT_MAX_PARAMETERS
= MAX_DEFAULT_PARAMETERS
292 CARLA_DEFAULT_RESET_XRUNS
= False
293 CARLA_DEFAULT_UI_BRIDGES_TIMEOUT
= 4000
295 CARLA_DEFAULT_AUDIO_BUFFER_SIZE
= 512
296 CARLA_DEFAULT_AUDIO_SAMPLE_RATE
= 44100
297 CARLA_DEFAULT_AUDIO_TRIPLE_BUFFER
= False
300 CARLA_DEFAULT_AUDIO_DRIVER
= "SDL"
302 CARLA_DEFAULT_AUDIO_DRIVER
= "CoreAudio"
304 CARLA_DEFAULT_AUDIO_DRIVER
= "Windows Audio"
305 elif os
.path
.exists("/usr/bin/jackd") or os
.path
.exists("/usr/bin/jackdbus") or os
.path
.exists("/usr/bin/pw-jack"):
306 CARLA_DEFAULT_AUDIO_DRIVER
= "JACK"
308 CARLA_DEFAULT_AUDIO_DRIVER
= "PulseAudio"
310 if CARLA_DEFAULT_AUDIO_DRIVER
== "JACK":
311 CARLA_DEFAULT_PROCESS_MODE
= ENGINE_PROCESS_MODE_MULTIPLE_CLIENTS
312 CARLA_DEFAULT_TRANSPORT_MODE
= ENGINE_TRANSPORT_MODE_JACK
314 CARLA_DEFAULT_PROCESS_MODE
= ENGINE_PROCESS_MODE_PATCHBAY
315 CARLA_DEFAULT_TRANSPORT_MODE
= ENGINE_TRANSPORT_MODE_INTERNAL
318 CARLA_DEFAULT_OSC_ENABLED
= not (MACOS
or WINDOWS
)
319 CARLA_DEFAULT_OSC_TCP_PORT_ENABLED
= True
320 CARLA_DEFAULT_OSC_TCP_PORT_NUMBER
= 22752
321 CARLA_DEFAULT_OSC_TCP_PORT_RANDOM
= False
322 CARLA_DEFAULT_OSC_UDP_PORT_ENABLED
= True
323 CARLA_DEFAULT_OSC_UDP_PORT_NUMBER
= 22752
324 CARLA_DEFAULT_OSC_UDP_PORT_RANDOM
= False
327 CARLA_DEFAULT_WINE_EXECUTABLE
= "wine"
328 CARLA_DEFAULT_WINE_AUTO_PREFIX
= True
329 CARLA_DEFAULT_WINE_FALLBACK_PREFIX
= os
.path
.expanduser("~/.wine")
330 CARLA_DEFAULT_WINE_RT_PRIO_ENABLED
= True
331 CARLA_DEFAULT_WINE_BASE_RT_PRIO
= 15
332 CARLA_DEFAULT_WINE_SERVER_RT_PRIO
= 10
335 CARLA_DEFAULT_EXPERIMENTAL_PLUGIN_BRIDGES
= False
336 CARLA_DEFAULT_EXPERIMENTAL_WINE_BRIDGES
= False
337 CARLA_DEFAULT_EXPERIMENTAL_JACK_APPS
= False
338 CARLA_DEFAULT_EXPERIMENTAL_LV2_EXPORT
= False
339 CARLA_DEFAULT_EXPERIMENTAL_PREVENT_BAD_BEHAVIOUR
= False
340 CARLA_DEFAULT_EXPERIMENTAL_LOAD_LIB_GLOBAL
= False
342 # ------------------------------------------------------------------------------------------------------------
343 # Default File Folders
345 CARLA_DEFAULT_FILE_PATH_AUDIO
= []
346 CARLA_DEFAULT_FILE_PATH_MIDI
= []
348 # ------------------------------------------------------------------------------------------------------------
349 # Default Plugin Folders (get)
351 DEFAULT_LADSPA_PATH
= ""
352 DEFAULT_DSSI_PATH
= ""
353 DEFAULT_LV2_PATH
= ""
354 DEFAULT_VST2_PATH
= ""
355 DEFAULT_VST3_PATH
= ""
356 DEFAULT_CLAP_PATH
= ""
357 DEFAULT_SF2_PATH
= ""
358 DEFAULT_SFZ_PATH
= ""
359 DEFAULT_JSFX_PATH
= ""
364 APPDATA
= os
.getenv("APPDATA")
365 LOCALAPPDATA
= os
.getenv("LOCALAPPDATA", APPDATA
)
366 PROGRAMFILES
= os
.getenv("PROGRAMFILES")
367 PROGRAMFILESx86
= os
.getenv("PROGRAMFILES(x86)")
368 COMMONPROGRAMFILES
= os
.getenv("COMMONPROGRAMFILES")
369 COMMONPROGRAMFILESx86
= os
.getenv("COMMONPROGRAMFILES(x86)")
371 # Small integrity tests
373 qFatal("APPDATA variable not set, cannot continue")
377 qFatal("PROGRAMFILES variable not set, cannot continue")
380 if not COMMONPROGRAMFILES
:
381 qFatal("COMMONPROGRAMFILES variable not set, cannot continue")
384 DEFAULT_LADSPA_PATH
= APPDATA
+ "\\LADSPA"
385 DEFAULT_LADSPA_PATH
+= ";" + PROGRAMFILES
+ "\\LADSPA"
387 DEFAULT_DSSI_PATH
= APPDATA
+ "\\DSSI"
388 DEFAULT_DSSI_PATH
+= ";" + PROGRAMFILES
+ "\\DSSI"
390 DEFAULT_LV2_PATH
= APPDATA
+ "\\LV2"
391 DEFAULT_LV2_PATH
+= ";" + COMMONPROGRAMFILES
+ "\\LV2"
393 DEFAULT_VST2_PATH
= PROGRAMFILES
+ "\\VstPlugins"
394 DEFAULT_VST2_PATH
+= ";" + PROGRAMFILES
+ "\\Steinberg\\VstPlugins"
396 DEFAULT_JSFX_PATH
= APPDATA
+ "\\REAPER\\Effects"
397 #DEFAULT_JSFX_PATH += ";" + PROGRAMFILES + "\\REAPER\\InstallData\\Effects"
400 DEFAULT_VST2_PATH
+= ";" + COMMONPROGRAMFILES
+ "\\VST2"
402 DEFAULT_VST3_PATH
= COMMONPROGRAMFILES
+ "\\VST3"
403 DEFAULT_VST3_PATH
+= ";" + LOCALAPPDATA
+ "\\Programs\\Common\\VST3"
405 DEFAULT_CLAP_PATH
= COMMONPROGRAMFILES
+ "\\CLAP"
406 DEFAULT_CLAP_PATH
+= ";" + LOCALAPPDATA
+ "\\Programs\\Common\\CLAP"
408 DEFAULT_SF2_PATH
= APPDATA
+ "\\SF2"
409 DEFAULT_SFZ_PATH
= APPDATA
+ "\\SFZ"
412 DEFAULT_LADSPA_PATH
+= ";" + PROGRAMFILESx86
+ "\\LADSPA"
413 DEFAULT_DSSI_PATH
+= ";" + PROGRAMFILESx86
+ "\\DSSI"
414 DEFAULT_VST2_PATH
+= ";" + PROGRAMFILESx86
+ "\\VstPlugins"
415 DEFAULT_VST2_PATH
+= ";" + PROGRAMFILESx86
+ "\\Steinberg\\VstPlugins"
416 #DEFAULT_JSFX_PATH += ";" + PROGRAMFILESx86 + "\\REAPER\\InstallData\\Effects"
418 if COMMONPROGRAMFILESx86
:
419 DEFAULT_VST3_PATH
+= COMMONPROGRAMFILESx86
+ "\\VST3"
420 DEFAULT_CLAP_PATH
+= COMMONPROGRAMFILESx86
+ "\\CLAP"
425 DEFAULT_LADSPA_PATH
= HOME
+ "/.ladspa"
426 DEFAULT_LADSPA_PATH
+= ":/system/add-ons/media/ladspaplugins"
427 DEFAULT_LADSPA_PATH
+= ":/system/lib/ladspa"
429 DEFAULT_DSSI_PATH
= HOME
+ "/.dssi"
430 DEFAULT_DSSI_PATH
+= ":/system/add-ons/media/dssiplugins"
431 DEFAULT_DSSI_PATH
+= ":/system/lib/dssi"
433 DEFAULT_LV2_PATH
= HOME
+ "/.lv2"
434 DEFAULT_LV2_PATH
+= ":/system/add-ons/media/lv2plugins"
436 DEFAULT_VST2_PATH
= HOME
+ "/.vst"
437 DEFAULT_VST2_PATH
+= ":/system/add-ons/media/vstplugins"
439 DEFAULT_VST3_PATH
= HOME
+ "/.vst3"
440 DEFAULT_VST3_PATH
+= ":/system/add-ons/media/vst3plugins"
442 DEFAULT_CLAP_PATH
= HOME
+ "/.clap"
443 DEFAULT_CLAP_PATH
+= ":/system/add-ons/media/clapplugins"
448 DEFAULT_LADSPA_PATH
= HOME
+ "/Library/Audio/Plug-Ins/LADSPA"
449 DEFAULT_LADSPA_PATH
+= ":/Library/Audio/Plug-Ins/LADSPA"
451 DEFAULT_DSSI_PATH
= HOME
+ "/Library/Audio/Plug-Ins/DSSI"
452 DEFAULT_DSSI_PATH
+= ":/Library/Audio/Plug-Ins/DSSI"
454 DEFAULT_LV2_PATH
= HOME
+ "/Library/Audio/Plug-Ins/LV2"
455 DEFAULT_LV2_PATH
+= ":/Library/Audio/Plug-Ins/LV2"
457 DEFAULT_VST2_PATH
= HOME
+ "/Library/Audio/Plug-Ins/VST"
458 DEFAULT_VST2_PATH
+= ":/Library/Audio/Plug-Ins/VST"
460 DEFAULT_VST3_PATH
= HOME
+ "/Library/Audio/Plug-Ins/VST3"
461 DEFAULT_VST3_PATH
+= ":/Library/Audio/Plug-Ins/VST3"
463 DEFAULT_CLAP_PATH
= HOME
+ "/Library/Audio/Plug-Ins/CLAP"
464 DEFAULT_CLAP_PATH
+= ":/Library/Audio/Plug-Ins/CLAP"
466 DEFAULT_JSFX_PATH
= HOME
+ "/Library/Application Support/REAPER/Effects"
467 #DEFAULT_JSFX_PATH += ":/Applications/REAPER.app/Contents/InstallFiles/Effects"
472 CONFIG_HOME
= os
.getenv("XDG_CONFIG_HOME", HOME
+ "/.config")
474 DEFAULT_LADSPA_PATH
= HOME
+ "/.ladspa"
475 DEFAULT_LADSPA_PATH
+= ":/usr/lib/ladspa"
476 DEFAULT_LADSPA_PATH
+= ":/usr/local/lib/ladspa"
478 DEFAULT_DSSI_PATH
= HOME
+ "/.dssi"
479 DEFAULT_DSSI_PATH
+= ":/usr/lib/dssi"
480 DEFAULT_DSSI_PATH
+= ":/usr/local/lib/dssi"
482 DEFAULT_LV2_PATH
= HOME
+ "/.lv2"
483 DEFAULT_LV2_PATH
+= ":/usr/lib/lv2"
484 DEFAULT_LV2_PATH
+= ":/usr/local/lib/lv2"
486 DEFAULT_VST2_PATH
= HOME
+ "/.vst"
487 DEFAULT_VST2_PATH
+= ":/usr/lib/vst"
488 DEFAULT_VST2_PATH
+= ":/usr/local/lib/vst"
490 DEFAULT_VST2_PATH
+= HOME
+ "/.lxvst"
491 DEFAULT_VST2_PATH
+= ":/usr/lib/lxvst"
492 DEFAULT_VST2_PATH
+= ":/usr/local/lib/lxvst"
494 DEFAULT_VST3_PATH
= HOME
+ "/.vst3"
495 DEFAULT_VST3_PATH
+= ":/usr/lib/vst3"
496 DEFAULT_VST3_PATH
+= ":/usr/local/lib/vst3"
498 DEFAULT_CLAP_PATH
= HOME
+ "/.clap"
499 DEFAULT_CLAP_PATH
+= ":/usr/lib/clap"
500 DEFAULT_CLAP_PATH
+= ":/usr/local/lib/clap"
502 DEFAULT_SF2_PATH
= HOME
+ "/.sounds/sf2"
503 DEFAULT_SF2_PATH
+= ":" + HOME
+ "/.sounds/sf3"
504 DEFAULT_SF2_PATH
+= ":/usr/share/sounds/sf2"
505 DEFAULT_SF2_PATH
+= ":/usr/share/sounds/sf3"
506 DEFAULT_SF2_PATH
+= ":/usr/share/soundfonts"
508 DEFAULT_SFZ_PATH
= HOME
+ "/.sounds/sfz"
509 DEFAULT_SFZ_PATH
+= ":/usr/share/sounds/sfz"
511 DEFAULT_JSFX_PATH
= CONFIG_HOME
+ "/REAPER/Effects"
512 #DEFAULT_JSFX_PATH += ":" + "/opt/REAPER/InstallData/Effects"
515 winePrefix
= os
.getenv("WINEPREFIX")
518 winePrefix
= HOME
+ "/.wine"
520 DEFAULT_VST2_PATH
+= ":" + winePrefix
+ "/drive_c/Program Files/VstPlugins"
521 DEFAULT_VST2_PATH
+= ":" + winePrefix
+ "/drive_c/Program Files/VSTPlugins"
522 DEFAULT_VST2_PATH
+= ":" + winePrefix
+ "/drive_c/Program Files/Steinberg/VstPlugins"
523 DEFAULT_VST2_PATH
+= ":" + winePrefix
+ "/drive_c/Program Files/Steinberg/VSTPlugins"
524 DEFAULT_VST2_PATH
+= ":" + winePrefix
+ "/drive_c/Program Files/Common Files/VST2"
525 DEFAULT_VST3_PATH
+= ":" + winePrefix
+ "/drive_c/Program Files/Common Files/VST3"
526 DEFAULT_CLAP_PATH
+= ":" + winePrefix
+ "/drive_c/Program Files/Common Files/CLAP"
529 DEFAULT_VST2_PATH
+= ":" + winePrefix
+ "/drive_c/Program Files (x86)/VstPlugins"
530 DEFAULT_VST2_PATH
+= ":" + winePrefix
+ "/drive_c/Program Files (x86)/VSTPlugins"
531 DEFAULT_VST2_PATH
+= ":" + winePrefix
+ "/drive_c/Program Files (x86)/Steinberg/VstPlugins"
532 DEFAULT_VST2_PATH
+= ":" + winePrefix
+ "/drive_c/Program Files (x86)/Steinberg/VSTPlugins"
533 DEFAULT_VST3_PATH
+= ":" + winePrefix
+ "/drive_c/Program Files (x86)/Common Files/VST3"
534 DEFAULT_CLAP_PATH
+= ":" + winePrefix
+ "/drive_c/Program Files (x86)/Common Files/CLAP"
538 # ------------------------------------------------------------------------------------------------------------
539 # Default Plugin Folders (set)
544 # Check if running Wine. If yes, ignore env vars
545 # pylint: disable=import-error
546 from winreg
import ConnectRegistry
, OpenKey
, CloseKey
, HKEY_CURRENT_USER
547 # pylint: enable=import-error
548 _reg
= ConnectRegistry(None, HKEY_CURRENT_USER
)
551 _key
= OpenKey(_reg
, r
"SOFTWARE\Wine")
562 CARLA_DEFAULT_LADSPA_PATH
= os
.getenv("LADSPA_PATH", DEFAULT_LADSPA_PATH
).split(splitter
)
563 CARLA_DEFAULT_DSSI_PATH
= os
.getenv("DSSI_PATH", DEFAULT_DSSI_PATH
).split(splitter
)
564 CARLA_DEFAULT_LV2_PATH
= os
.getenv("LV2_PATH", DEFAULT_LV2_PATH
).split(splitter
)
565 CARLA_DEFAULT_VST2_PATH
= os
.getenv("VST_PATH", DEFAULT_VST2_PATH
).split(splitter
)
566 CARLA_DEFAULT_VST3_PATH
= os
.getenv("VST3_PATH", DEFAULT_VST3_PATH
).split(splitter
)
567 CARLA_DEFAULT_CLAP_PATH
= os
.getenv("CLAP_PATH", DEFAULT_CLAP_PATH
).split(splitter
)
568 CARLA_DEFAULT_SF2_PATH
= os
.getenv("SF2_PATH", DEFAULT_SF2_PATH
).split(splitter
)
569 CARLA_DEFAULT_SFZ_PATH
= os
.getenv("SFZ_PATH", DEFAULT_SFZ_PATH
).split(splitter
)
570 CARLA_DEFAULT_JSFX_PATH
= os
.getenv("JSFX_PATH", DEFAULT_JSFX_PATH
).split(splitter
)
573 CARLA_DEFAULT_LADSPA_PATH
= DEFAULT_LADSPA_PATH
.split(splitter
)
574 CARLA_DEFAULT_DSSI_PATH
= DEFAULT_DSSI_PATH
.split(splitter
)
575 CARLA_DEFAULT_LV2_PATH
= DEFAULT_LV2_PATH
.split(splitter
)
576 CARLA_DEFAULT_VST2_PATH
= DEFAULT_VST2_PATH
.split(splitter
)
577 CARLA_DEFAULT_VST3_PATH
= DEFAULT_VST3_PATH
.split(splitter
)
578 CARLA_DEFAULT_CLAP_PATH
= DEFAULT_CLAP_PATH
.split(splitter
)
579 CARLA_DEFAULT_SF2_PATH
= DEFAULT_SF2_PATH
.split(splitter
)
580 CARLA_DEFAULT_SFZ_PATH
= DEFAULT_SFZ_PATH
.split(splitter
)
581 CARLA_DEFAULT_JSFX_PATH
= DEFAULT_JSFX_PATH
.split(splitter
)
583 # ------------------------------------------------------------------------------------------------------------
584 # Default Plugin Folders (cleanup)
586 del DEFAULT_LADSPA_PATH
587 del DEFAULT_DSSI_PATH
589 del DEFAULT_VST2_PATH
590 del DEFAULT_VST3_PATH
591 del DEFAULT_CLAP_PATH
595 # ------------------------------------------------------------------------------------------------------------
596 # Global Carla object
600 self
.cnprefix
= "" # Client name prefix
601 self
.gui
= None # Host Window
602 self
.nogui
= False # Skip UI
603 self
.term
= False # Terminated by OS signal
604 self
.felib
= None # Frontend lib object
605 self
.utils
= None # Utils object
607 gCarla
= CarlaObject()
609 # ------------------------------------------------------------------------------------------------------------
615 CWD
= os
.path
.dirname(sys
.argv
[0])
617 # make it work with cxfreeze
618 if os
.path
.isfile(CWD
):
619 CWD
= os
.path
.dirname(CWD
)
620 if CWD
.endswith("/lib"):
621 CWD
= CWD
.rsplit("/lib",1)[0]
624 os
.environ
['CARLA_MAGIC_FILE'] = os
.path
.join(CWD
, "magic.mgc")
628 # ------------------------------------------------------------------------------------------------------------
632 DLL_EXTENSION
= "dll"
634 DLL_EXTENSION
= "dylib"
638 # ------------------------------------------------------------------------------------------------------------
639 # Find decimal points for a parameter, using step and stepSmall
641 def countDecimalPoints(step
, stepSmall
):
648 value
= fmod(abs(step
), 1)
649 while 0.0001 < value
< 0.999 and count
< 6:
650 value
= fmod(value
*10, 1)
655 # ------------------------------------------------------------------------------------------------------------
656 # Check if a value is a number (float support)
665 # ------------------------------------------------------------------------------------------------------------
666 # Convert a value to a list
671 if not isinstance(value
, list):
675 # ------------------------------------------------------------------------------------------------------------
676 # Get Icon from user theme, using our own as backup (Oxygen)
678 def getIcon(icon
, size
, qrcformat
):
679 return QIcon
.fromTheme(icon
, QIcon(":/%ix%i/%s.%s" % (size
, size
, icon
, qrcformat
)))
681 # ------------------------------------------------------------------------------------------------------------
682 # Handle some basic command-line arguments shared between all carla variants
684 def handleInitialCommandLineArguments(file):
685 initName
= os
.path
.basename(file) if (file is not None and os
.path
.dirname(file) in PATH
) else sys
.argv
[0]
687 readPrefixNext
= False
689 for arg
in sys
.argv
[1:]:
690 if arg
.startswith("--with-appname="):
691 initName
= os
.path
.basename(arg
.replace("--with-appname=", ""))
693 elif arg
.startswith("--with-libprefix="):
694 libPrefix
= arg
.replace("--with-libprefix=", "")
696 elif arg
.startswith("--osc-gui="):
697 gCarla
.nogui
= int(arg
.replace("--osc-gui=", ""))
699 elif arg
.startswith("--cnprefix="):
700 gCarla
.cnprefix
= arg
.replace("--cnprefix=", "")
702 elif arg
== "--cnprefix":
703 readPrefixNext
= True
708 elif arg
in ("-n", "--n", "-no-gui", "--no-gui", "-nogui", "--nogui"):
711 elif MACOS
and arg
.startswith("-psn_"):
714 elif arg
in ("-h", "--h", "-help", "--help"):
715 print("Usage: %s [OPTION]... [FILE|URL]" % initName
)
717 print(" where FILE can be a Carla project or preset file to be loaded, or URL if using Carla-Control")
719 print(" and OPTION can be one or more of the following:")
721 print(" --cnprefix\t Set a prefix for client names in multi-client mode.")
722 if isinstance(gCarla
.nogui
, bool):
723 if X_LIBDIR_X
is not None:
724 print(" --gdb \t Run Carla inside gdb.")
725 print(" -n,--no-gui \t Run Carla headless, don't show UI.")
727 print(" -h,--help \t Print this help text and exit.")
728 print(" -v,--version \t Print version information and exit.")
731 if not isinstance(gCarla
.nogui
, bool):
732 print("NOTE: when using %s the FILE is only valid the first time the backend is started" % initName
)
737 elif arg
in ("-v", "--v", "-version", "--version"):
738 pathBinaries
, pathResources
= getPaths(libPrefix
)
740 print("Using Carla version %s" % VERSION
)
741 print(" Python version: %s" % sys
.version
.split(" ",1)[0])
742 print(" Qt version: %s" % QT_VERSION_STR
)
743 print(" PyQt version: %s" % PYQT_VERSION_STR
)
744 print(" Binary dir: %s" % pathBinaries
)
745 print(" Resources dir: %s" % pathResources
)
747 sys
.exit(1 if gCarla
.nogui
else 0)
750 readPrefixNext
= False
751 gCarla
.cnprefix
= arg
753 if gCarla
.nogui
and not isinstance(gCarla
.nogui
, bool):
755 # pylint: disable=protected-access
757 # pylint: enable=protected-access
761 return (initName
, libPrefix
)
763 # ------------------------------------------------------------------------------------------------------------
764 # Get initial project file (as passed in the command-line parameters)
766 def getInitialProjectFile(skipExistCheck
= False):
767 # NOTE: PyQt mishandles unicode characters, we directly use sys.argv instead of qApp->arguments()
768 # see https://riverbankcomputing.com/pipermail/pyqt/2015-January/035395.html
770 readPrefixNext
= False
773 readPrefixNext
= False
775 if arg
.startswith("--cnprefix="):
777 if arg
.startswith("--osc-gui="):
779 if arg
.startswith("--with-appname="):
781 if arg
.startswith("--with-libprefix="):
783 if arg
== "--cnprefix":
784 readPrefixNext
= True
786 if arg
in ("-n", "--n", "-no-gui", "--no-gui", "-nogui", "--nogui", "--gdb"):
788 if MACOS
and arg
.startswith("-psn_"):
790 arg
= os
.path
.expanduser(arg
)
791 if skipExistCheck
or os
.path
.exists(arg
):
796 # ------------------------------------------------------------------------------------------------------------
797 # Get paths (binaries, resources)
799 def getPaths(libPrefix
= None):
802 # adjust for special distros
803 libdir
= os
.path
.basename(os
.path
.normpath(X_LIBDIR_X
)) if X_LIBDIR_X
else "lib"
804 datadir
= os
.path
.basename(os
.path
.normpath(X_DATADIR_X
)) if X_DATADIR_X
else "share"
806 # standalone, installed system-wide linux
807 if libPrefix
is not None:
808 pathBinaries
= os
.path
.join(libPrefix
, libdir
, "carla")
809 pathResources
= os
.path
.join(libPrefix
, datadir
, "carla", "resources")
811 # standalone, local source
812 elif CWDl
.endswith("frontend"):
813 pathBinaries
= os
.path
.abspath(os
.path
.join(CWD
, "..", "..", "bin"))
814 pathResources
= os
.path
.join(pathBinaries
, "resources")
817 elif CWDl
.endswith("resources"):
818 # installed system-wide linux
819 if CWDl
.endswith("/share/carla/resources"):
820 pathBinaries
= os
.path
.abspath(os
.path
.join(CWD
, "..", "..", "..", libdir
, "carla"))
824 elif CWDl
.endswith("native-plugins%sresources" % os
.sep
):
825 pathBinaries
= os
.path
.abspath(os
.path
.join(CWD
, "..", "..", "..", "bin"))
830 pathBinaries
= os
.path
.abspath(os
.path
.join(CWD
, ".."))
836 pathResources
= os
.path
.join(pathBinaries
, "resources")
838 return (pathBinaries
, pathResources
)
840 # ------------------------------------------------------------------------------------------------------------
842 # TODO move to carla_host.py or something
844 def signalHandler(sig
, frame
):
845 if sig
in (SIGINT
, SIGTERM
):
847 if gCarla
.gui
is not None:
848 gCarla
.gui
.SIGTERM
.emit()
850 elif haveSIGUSR1
and sig
== SIGUSR1
:
851 if gCarla
.gui
is not None:
852 gCarla
.gui
.SIGUSR1
.emit()
855 signal(SIGINT
, signalHandler
)
856 signal(SIGTERM
, signalHandler
)
861 signal(SIGUSR1
, signalHandler
)
863 # ------------------------------------------------------------------------------------------------------------
864 # QLineEdit and QPushButton combo
866 def getAndSetPath(parent
, lineEdit
):
867 newPath
= QFileDialog
.getExistingDirectory(parent
, parent
.tr("Set Path"), lineEdit
.text(), QFileDialog
.ShowDirsOnly
)
869 lineEdit
.setText(newPath
)
872 # ------------------------------------------------------------------------------------------------------------
873 # Backwards-compatible horizontalAdvance/width call, depending on Qt version
875 def fontMetricsHorizontalAdvance(fontMetrics
, string
):
876 if QT_VERSION
>= 0x50b00:
877 return fontMetrics
.horizontalAdvance(string
)
878 return fontMetrics
.width(string
)
880 # ------------------------------------------------------------------------------------------------------------
881 # Custom QMessageBox which resizes itself to fit text
883 class QMessageBoxWithBetterWidth(QMessageBox
):
884 def __init__(self
, parent
):
885 QMessageBox
.__init
__(self
, parent
)
887 def showEvent(self
, event
):
888 fontMetrics
= self
.fontMetrics()
890 lines
= self
.text().strip().split("\n") + self
.informativeText().strip().split("\n")
896 width
= max(fontMetricsHorizontalAdvance(fontMetrics
, line
), width
)
898 self
.layout().setColumnMinimumWidth(2, width
+ 12)
900 QMessageBox
.showEvent(self
, event
)
902 # ------------------------------------------------------------------------------------------------------------
905 # pylint: disable=too-many-arguments
906 def CustomMessageBox(parent
, icon
, title
, text
,
908 buttons
=QMessageBox
.Yes|QMessageBox
.No
,
909 defButton
=QMessageBox
.No
):
910 msgBox
= QMessageBoxWithBetterWidth(parent
)
912 msgBox
.setWindowTitle(title
)
914 msgBox
.setInformativeText(extraText
)
915 msgBox
.setStandardButtons(buttons
)
916 msgBox
.setDefaultButton(defButton
)
917 return msgBox
.exec_()
918 # pylint: enable=too-many-arguments
920 # ------------------------------------------------------------------------------------------------------------