|
- #!/usr/bin/env python3
- # -*- coding: utf-8 -*-
-
- # Common Carla code
- # Copyright (C) 2011-2023 Filipe Coelho <falktx@falktx.com>
- #
- # This program is free software; you can redistribute it and/or
- # modify it under the terms of the GNU General Public License as
- # published by the Free Software Foundation; either version 2 of
- # the License, or any later version.
- #
- # This program is distributed in the hope that it will be useful,
- # but WITHOUT ANY WARRANTY; without even the implied warranty of
- # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- # GNU General Public License for more details.
- #
- # For a full copy of the GNU General Public License see the doc/GPL.txt file.
-
- # ------------------------------------------------------------------------------------------------------------
- # Imports (Global)
-
- import os
- import sys
-
- from math import fmod
-
- # ------------------------------------------------------------------------------------------------------------
- # Imports (Signal)
-
- from signal import signal, SIGINT, SIGTERM
-
- try:
- from signal import SIGUSR1
- haveSIGUSR1 = True
- except:
- haveSIGUSR1 = False
-
- # ------------------------------------------------------------------------------------------------------------
- # Imports (PyQt5)
-
- # import changed in PyQt 5.15.8, so try both
- try:
- from PyQt5.Qt import PYQT_VERSION_STR
- except ImportError:
- from PyQt5.QtCore import PYQT_VERSION_STR
-
- from PyQt5.QtCore import qFatal, QT_VERSION, QT_VERSION_STR, qWarning, QDir, QSettings
- from PyQt5.QtGui import QIcon
- from PyQt5.QtWidgets import QFileDialog, QMessageBox
-
- # ------------------------------------------------------------------------------------------------------------
- # Imports (Custom)
-
- from carla_backend import (
- kIs64bit, HAIKU, LINUX, MACOS, WINDOWS,
- MAX_DEFAULT_PARAMETERS,
- ENGINE_PROCESS_MODE_MULTIPLE_CLIENTS,
- ENGINE_PROCESS_MODE_PATCHBAY,
- ENGINE_TRANSPORT_MODE_INTERNAL,
- ENGINE_TRANSPORT_MODE_JACK
- )
-
- # ------------------------------------------------------------------------------------------------------------
- # Config
-
- # These will be modified during install
- X_LIBDIR_X = None
- X_DATADIR_X = None
-
- # ------------------------------------------------------------------------------------------------------------
- # Platform specific stuff
-
- if WINDOWS:
- WINDIR = os.getenv("WINDIR")
-
- # ------------------------------------------------------------------------------------------------------------
- # Set Version
-
- VERSION = "2.5.4"
-
- # ------------------------------------------------------------------------------------------------------------
- # Set TMP
-
- envTMP = os.getenv("TMP")
-
- if envTMP is None:
- if WINDOWS:
- qWarning("TMP variable not set")
- TMP = QDir.tempPath()
- else:
- TMP = envTMP
-
- if not os.path.exists(TMP):
- qWarning("TMP does not exist")
- TMP = "/"
-
- del envTMP
-
- # ------------------------------------------------------------------------------------------------------------
- # Set HOME
-
- envHOME = os.getenv("HOME")
-
- if envHOME is None:
- if LINUX or MACOS:
- qWarning("HOME variable not set")
- HOME = QDir.toNativeSeparators(QDir.homePath())
- else:
- HOME = envHOME
-
- if not os.path.exists(HOME):
- qWarning("HOME does not exist")
- HOME = TMP
-
- del envHOME
-
- # ------------------------------------------------------------------------------------------------------------
- # Set PATH
-
- envPATH = os.getenv("PATH")
-
- if envPATH is None:
- qWarning("PATH variable not set")
- if MACOS:
- PATH = ("/opt/local/bin", "/usr/local/bin", "/usr/bin", "/bin")
- elif WINDOWS:
- PATH = (os.path.join(WINDIR, "system32"), WINDIR)
- else:
- PATH = ("/usr/local/bin", "/usr/bin", "/bin")
- else:
- PATH = envPATH.split(os.pathsep)
-
- del envPATH
-
- # ------------------------------------------------------------------------------------------------------------
- # Static MIDI CC list
-
- MIDI_CC_LIST = (
- "01 [0x01] Modulation",
- "02 [0x02] Breath",
- "04 [0x04] Foot",
- "05 [0x05] Portamento",
- "07 [0x07] Volume",
- "08 [0x08] Balance",
- "10 [0x0A] Pan",
- "11 [0x0B] Expression",
- "12 [0x0C] FX Control 1",
- "13 [0x0D] FX Control 2",
- "16 [0x10] General Purpose 1",
- "17 [0x11] General Purpose 2",
- "18 [0x12] General Purpose 3",
- "19 [0x13] General Purpose 4",
- "70 [0x46] Control 1 [Variation]",
- "71 [0x47] Control 2 [Timbre]",
- "72 [0x48] Control 3 [Release]",
- "73 [0x49] Control 4 [Attack]",
- "74 [0x4A] Control 5 [Brightness]",
- "75 [0x4B] Control 6 [Decay]",
- "76 [0x4C] Control 7 [Vib Rate]",
- "77 [0x4D] Control 8 [Vib Depth]",
- "78 [0x4E] Control 9 [Vib Delay]",
- "79 [0x4F] Control 10 [Undefined]",
- "80 [0x50] General Purpose 5",
- "81 [0x51] General Purpose 6",
- "82 [0x52] General Purpose 7",
- "83 [0x53] General Purpose 8",
- "84 [0x54] Portamento Control",
- "91 [0x5B] FX 1 Depth [Reverb]",
- "92 [0x5C] FX 2 Depth [Tremolo]",
- "93 [0x5D] FX 3 Depth [Chorus]",
- "94 [0x5E] FX 4 Depth [Detune]",
- "95 [0x5F] FX 5 Depth [Phaser]"
- )
-
- MAX_MIDI_CC_LIST_ITEM = 95
-
- # ------------------------------------------------------------------------------------------------------------
- # PatchCanvas defines
-
- CANVAS_ANTIALIASING_SMALL = 1
- CANVAS_EYECANDY_SMALL = 1
-
- # ------------------------------------------------------------------------------------------------------------
- # Carla Settings keys
-
- CARLA_KEY_MAIN_PROJECT_FOLDER = "Main/ProjectFolder" # str
- CARLA_KEY_MAIN_USE_PRO_THEME = "Main/UseProTheme" # bool
- CARLA_KEY_MAIN_PRO_THEME_COLOR = "Main/ProThemeColor" # str
- CARLA_KEY_MAIN_REFRESH_INTERVAL = "Main/RefreshInterval" # int
- CARLA_KEY_MAIN_CONFIRM_EXIT = "Main/ConfirmExit" # bool
- CARLA_KEY_MAIN_CLASSIC_SKIN = "Main/ClassicSkin" # bool
- CARLA_KEY_MAIN_SHOW_LOGS = "Main/ShowLogs" # bool
- CARLA_KEY_MAIN_SYSTEM_ICONS = "Main/SystemIcons" # bool
- CARLA_KEY_MAIN_EXPERIMENTAL = "Main/Experimental" # bool
-
- CARLA_KEY_CANVAS_THEME = "Canvas/Theme" # str
- CARLA_KEY_CANVAS_SIZE = "Canvas/Size" # str "NxN"
- CARLA_KEY_CANVAS_USE_BEZIER_LINES = "Canvas/UseBezierLines" # bool
- CARLA_KEY_CANVAS_AUTO_HIDE_GROUPS = "Canvas/AutoHideGroups" # bool
- CARLA_KEY_CANVAS_AUTO_SELECT_ITEMS = "Canvas/AutoSelectItems" # bool
- CARLA_KEY_CANVAS_EYE_CANDY = "Canvas/EyeCandy2" # bool
- CARLA_KEY_CANVAS_FANCY_EYE_CANDY = "Canvas/FancyEyeCandy" # bool
- CARLA_KEY_CANVAS_USE_OPENGL = "Canvas/UseOpenGL" # bool
- CARLA_KEY_CANVAS_ANTIALIASING = "Canvas/Antialiasing" # enum
- CARLA_KEY_CANVAS_HQ_ANTIALIASING = "Canvas/HQAntialiasing" # bool
- CARLA_KEY_CANVAS_INLINE_DISPLAYS = "Canvas/InlineDisplays" # bool
- CARLA_KEY_CANVAS_FULL_REPAINTS = "Canvas/FullRepaints" # bool
-
- CARLA_KEY_ENGINE_DRIVER_PREFIX = "Engine/Driver-"
- CARLA_KEY_ENGINE_AUDIO_DRIVER = "Engine/AudioDriver" # str
- CARLA_KEY_ENGINE_PROCESS_MODE = "Engine/ProcessMode" # enum
- CARLA_KEY_ENGINE_TRANSPORT_MODE = "Engine/TransportMode" # enum
- CARLA_KEY_ENGINE_TRANSPORT_EXTRA = "Engine/TransportExtra" # str
- CARLA_KEY_ENGINE_FORCE_STEREO = "Engine/ForceStereo" # bool
- CARLA_KEY_ENGINE_PREFER_PLUGIN_BRIDGES = "Engine/PreferPluginBridges" # bool
- CARLA_KEY_ENGINE_PREFER_UI_BRIDGES = "Engine/PreferUiBridges" # bool
- CARLA_KEY_ENGINE_MANAGE_UIS = "Engine/ManageUIs" # bool
- CARLA_KEY_ENGINE_UIS_ALWAYS_ON_TOP = "Engine/UIsAlwaysOnTop" # bool
- CARLA_KEY_ENGINE_MAX_PARAMETERS = "Engine/MaxParameters" # int
- CARLA_KEY_ENGINE_RESET_XRUNS = "Engine/ResetXruns" # bool
- CARLA_KEY_ENGINE_UI_BRIDGES_TIMEOUT = "Engine/UiBridgesTimeout" # int
-
- CARLA_KEY_OSC_ENABLED = "OSC/Enabled"
- CARLA_KEY_OSC_TCP_PORT_ENABLED = "OSC/TCPEnabled"
- CARLA_KEY_OSC_TCP_PORT_NUMBER = "OSC/TCPNumber"
- CARLA_KEY_OSC_TCP_PORT_RANDOM = "OSC/TCPRandom"
- CARLA_KEY_OSC_UDP_PORT_ENABLED = "OSC/UDPEnabled"
- CARLA_KEY_OSC_UDP_PORT_NUMBER = "OSC/UDPNumber"
- CARLA_KEY_OSC_UDP_PORT_RANDOM = "OSC/UDPRandom"
-
- CARLA_KEY_PATHS_AUDIO = "Paths/Audio"
- CARLA_KEY_PATHS_MIDI = "Paths/MIDI"
-
- CARLA_KEY_PATHS_LADSPA = "Paths/LADSPA"
- CARLA_KEY_PATHS_DSSI = "Paths/DSSI"
- CARLA_KEY_PATHS_LV2 = "Paths/LV2"
- CARLA_KEY_PATHS_VST2 = "Paths/VST2"
- CARLA_KEY_PATHS_VST3 = "Paths/VST3"
- CARLA_KEY_PATHS_SF2 = "Paths/SF2"
- CARLA_KEY_PATHS_SFZ = "Paths/SFZ"
- CARLA_KEY_PATHS_JSFX = "Paths/JSFX"
-
- CARLA_KEY_WINE_EXECUTABLE = "Wine/Executable" # str
- CARLA_KEY_WINE_AUTO_PREFIX = "Wine/AutoPrefix" # bool
- CARLA_KEY_WINE_FALLBACK_PREFIX = "Wine/FallbackPrefix" # str
- CARLA_KEY_WINE_RT_PRIO_ENABLED = "Wine/RtPrioEnabled" # bool
- CARLA_KEY_WINE_BASE_RT_PRIO = "Wine/BaseRtPrio" # int
- CARLA_KEY_WINE_SERVER_RT_PRIO = "Wine/ServerRtPrio" # int
-
- CARLA_KEY_EXPERIMENTAL_PLUGIN_BRIDGES = "Experimental/PluginBridges" # bool
- CARLA_KEY_EXPERIMENTAL_WINE_BRIDGES = "Experimental/WineBridges" # bool
- CARLA_KEY_EXPERIMENTAL_JACK_APPS = "Experimental/JackApplications" # bool
- CARLA_KEY_EXPERIMENTAL_EXPORT_LV2 = "Experimental/ExportLV2" # bool
- CARLA_KEY_EXPERIMENTAL_PREVENT_BAD_BEHAVIOUR = "Experimental/PreventBadBehaviour" # bool
- CARLA_KEY_EXPERIMENTAL_LOAD_LIB_GLOBAL = "Experimental/LoadLibGlobal" # bool
-
- # if pro theme is on and color is black
- CARLA_KEY_CUSTOM_PAINTING = "UseCustomPainting" # bool
-
- # ------------------------------------------------------------------------------------------------------------
- # Carla Settings defaults
-
- # Main
- CARLA_DEFAULT_MAIN_PROJECT_FOLDER = HOME
- CARLA_DEFAULT_MAIN_USE_PRO_THEME = True
- CARLA_DEFAULT_MAIN_PRO_THEME_COLOR = "Black"
- CARLA_DEFAULT_MAIN_REFRESH_INTERVAL = 20
- CARLA_DEFAULT_MAIN_CONFIRM_EXIT = True
- CARLA_DEFAULT_MAIN_CLASSIC_SKIN = False
- CARLA_DEFAULT_MAIN_SHOW_LOGS = bool(not WINDOWS)
- CARLA_DEFAULT_MAIN_SYSTEM_ICONS = False
- CARLA_DEFAULT_MAIN_EXPERIMENTAL = False
-
- # Canvas
- CARLA_DEFAULT_CANVAS_THEME = "Modern Dark"
- CARLA_DEFAULT_CANVAS_SIZE = "3100x2400"
- CARLA_DEFAULT_CANVAS_SIZE_WIDTH = 3100
- CARLA_DEFAULT_CANVAS_SIZE_HEIGHT = 2400
- CARLA_DEFAULT_CANVAS_USE_BEZIER_LINES = True
- CARLA_DEFAULT_CANVAS_AUTO_HIDE_GROUPS = True
- CARLA_DEFAULT_CANVAS_AUTO_SELECT_ITEMS = False
- CARLA_DEFAULT_CANVAS_EYE_CANDY = True
- CARLA_DEFAULT_CANVAS_FANCY_EYE_CANDY = False
- CARLA_DEFAULT_CANVAS_USE_OPENGL = False
- CARLA_DEFAULT_CANVAS_ANTIALIASING = CANVAS_ANTIALIASING_SMALL
- CARLA_DEFAULT_CANVAS_HQ_ANTIALIASING = False
- CARLA_DEFAULT_CANVAS_INLINE_DISPLAYS = False
- CARLA_DEFAULT_CANVAS_FULL_REPAINTS = False
-
- # Engine
- CARLA_DEFAULT_FORCE_STEREO = False
- CARLA_DEFAULT_PREFER_PLUGIN_BRIDGES = False
- CARLA_DEFAULT_PREFER_UI_BRIDGES = True
- CARLA_DEFAULT_MANAGE_UIS = True
- CARLA_DEFAULT_UIS_ALWAYS_ON_TOP = False
- CARLA_DEFAULT_MAX_PARAMETERS = MAX_DEFAULT_PARAMETERS
- CARLA_DEFAULT_RESET_XRUNS = False
- CARLA_DEFAULT_UI_BRIDGES_TIMEOUT = 4000
-
- CARLA_DEFAULT_AUDIO_BUFFER_SIZE = 512
- CARLA_DEFAULT_AUDIO_SAMPLE_RATE = 44100
- CARLA_DEFAULT_AUDIO_TRIPLE_BUFFER = False
-
- if HAIKU:
- CARLA_DEFAULT_AUDIO_DRIVER = "SDL"
- elif MACOS:
- CARLA_DEFAULT_AUDIO_DRIVER = "CoreAudio"
- elif WINDOWS:
- CARLA_DEFAULT_AUDIO_DRIVER = "Windows Audio"
- elif os.path.exists("/usr/bin/jackd") or os.path.exists("/usr/bin/jackdbus") or os.path.exists("/usr/bin/pw-jack"):
- CARLA_DEFAULT_AUDIO_DRIVER = "JACK"
- else:
- CARLA_DEFAULT_AUDIO_DRIVER = "PulseAudio"
-
- if CARLA_DEFAULT_AUDIO_DRIVER == "JACK":
- CARLA_DEFAULT_PROCESS_MODE = ENGINE_PROCESS_MODE_MULTIPLE_CLIENTS
- CARLA_DEFAULT_TRANSPORT_MODE = ENGINE_TRANSPORT_MODE_JACK
- else:
- CARLA_DEFAULT_PROCESS_MODE = ENGINE_PROCESS_MODE_PATCHBAY
- CARLA_DEFAULT_TRANSPORT_MODE = ENGINE_TRANSPORT_MODE_INTERNAL
-
- # OSC
- CARLA_DEFAULT_OSC_ENABLED = not (MACOS or WINDOWS)
- CARLA_DEFAULT_OSC_TCP_PORT_ENABLED = True
- CARLA_DEFAULT_OSC_TCP_PORT_NUMBER = 22752
- CARLA_DEFAULT_OSC_TCP_PORT_RANDOM = False
- CARLA_DEFAULT_OSC_UDP_PORT_ENABLED = True
- CARLA_DEFAULT_OSC_UDP_PORT_NUMBER = 22752
- CARLA_DEFAULT_OSC_UDP_PORT_RANDOM = False
-
- # Wine
- CARLA_DEFAULT_WINE_EXECUTABLE = "wine"
- CARLA_DEFAULT_WINE_AUTO_PREFIX = True
- CARLA_DEFAULT_WINE_FALLBACK_PREFIX = os.path.expanduser("~/.wine")
- CARLA_DEFAULT_WINE_RT_PRIO_ENABLED = True
- CARLA_DEFAULT_WINE_BASE_RT_PRIO = 15
- CARLA_DEFAULT_WINE_SERVER_RT_PRIO = 10
-
- # Experimental
- CARLA_DEFAULT_EXPERIMENTAL_PLUGIN_BRIDGES = False
- CARLA_DEFAULT_EXPERIMENTAL_WINE_BRIDGES = False
- CARLA_DEFAULT_EXPERIMENTAL_JACK_APPS = False
- CARLA_DEFAULT_EXPERIMENTAL_LV2_EXPORT = False
- CARLA_DEFAULT_EXPERIMENTAL_PREVENT_BAD_BEHAVIOUR = False
- CARLA_DEFAULT_EXPERIMENTAL_LOAD_LIB_GLOBAL = False
-
- # ------------------------------------------------------------------------------------------------------------
- # Default File Folders
-
- CARLA_DEFAULT_FILE_PATH_AUDIO = []
- CARLA_DEFAULT_FILE_PATH_MIDI = []
-
- # ------------------------------------------------------------------------------------------------------------
- # Default Plugin Folders (get)
-
- DEFAULT_LADSPA_PATH = ""
- DEFAULT_DSSI_PATH = ""
- DEFAULT_LV2_PATH = ""
- DEFAULT_VST2_PATH = ""
- DEFAULT_VST3_PATH = ""
- DEFAULT_SF2_PATH = ""
- DEFAULT_SFZ_PATH = ""
- DEFAULT_JSFX_PATH = ""
-
- if WINDOWS:
- splitter = ";"
-
- APPDATA = os.getenv("APPDATA")
- LOCALAPPDATA = os.getenv("LOCALAPPDATA", APPDATA)
- PROGRAMFILES = os.getenv("PROGRAMFILES")
- PROGRAMFILESx86 = os.getenv("PROGRAMFILES(x86)")
- COMMONPROGRAMFILES = os.getenv("COMMONPROGRAMFILES")
- COMMONPROGRAMFILESx86 = os.getenv("COMMONPROGRAMFILES(x86)")
-
- # Small integrity tests
- if not APPDATA:
- qFatal("APPDATA variable not set, cannot continue")
- sys.exit(1)
-
- if not PROGRAMFILES:
- qFatal("PROGRAMFILES variable not set, cannot continue")
- sys.exit(1)
-
- if not COMMONPROGRAMFILES:
- qFatal("COMMONPROGRAMFILES variable not set, cannot continue")
- sys.exit(1)
-
- DEFAULT_LADSPA_PATH = APPDATA + "\\LADSPA"
- DEFAULT_LADSPA_PATH += ";" + PROGRAMFILES + "\\LADSPA"
-
- DEFAULT_DSSI_PATH = APPDATA + "\\DSSI"
- DEFAULT_DSSI_PATH += ";" + PROGRAMFILES + "\\DSSI"
-
- DEFAULT_LV2_PATH = APPDATA + "\\LV2"
- DEFAULT_LV2_PATH += ";" + COMMONPROGRAMFILES + "\\LV2"
-
- DEFAULT_VST2_PATH = PROGRAMFILES + "\\VstPlugins"
- DEFAULT_VST2_PATH += ";" + PROGRAMFILES + "\\Steinberg\\VstPlugins"
-
- DEFAULT_JSFX_PATH = APPDATA + "\\REAPER\\Effects"
- #DEFAULT_JSFX_PATH += ";" + PROGRAMFILES + "\\REAPER\\InstallData\\Effects"
-
- if kIs64bit:
- DEFAULT_VST2_PATH += ";" + COMMONPROGRAMFILES + "\\VST2"
-
- DEFAULT_VST3_PATH = COMMONPROGRAMFILES + "\\VST3"
- DEFAULT_VST3_PATH += ";" + LOCALAPPDATA + "\\Programs\\Common\\VST3"
-
- DEFAULT_SF2_PATH = APPDATA + "\\SF2"
- DEFAULT_SFZ_PATH = APPDATA + "\\SFZ"
-
- if PROGRAMFILESx86:
- DEFAULT_LADSPA_PATH += ";" + PROGRAMFILESx86 + "\\LADSPA"
- DEFAULT_DSSI_PATH += ";" + PROGRAMFILESx86 + "\\DSSI"
- DEFAULT_VST2_PATH += ";" + PROGRAMFILESx86 + "\\VstPlugins"
- DEFAULT_VST2_PATH += ";" + PROGRAMFILESx86 + "\\Steinberg\\VstPlugins"
- #DEFAULT_JSFX_PATH += ";" + PROGRAMFILESx86 + "\\REAPER\\InstallData\\Effects"
-
- if COMMONPROGRAMFILESx86:
- DEFAULT_VST3_PATH += COMMONPROGRAMFILESx86 + "\\VST3"
-
- elif HAIKU:
- splitter = ":"
-
- DEFAULT_LADSPA_PATH = HOME + "/.ladspa"
- DEFAULT_LADSPA_PATH += ":/system/add-ons/media/ladspaplugins"
- DEFAULT_LADSPA_PATH += ":/system/lib/ladspa"
-
- DEFAULT_DSSI_PATH = HOME + "/.dssi"
- DEFAULT_DSSI_PATH += ":/system/add-ons/media/dssiplugins"
- DEFAULT_DSSI_PATH += ":/system/lib/dssi"
-
- DEFAULT_LV2_PATH = HOME + "/.lv2"
- DEFAULT_LV2_PATH += ":/system/add-ons/media/lv2plugins"
-
- DEFAULT_VST2_PATH = HOME + "/.vst"
- DEFAULT_VST2_PATH += ":/system/add-ons/media/vstplugins"
-
- DEFAULT_VST3_PATH = HOME + "/.vst3"
- DEFAULT_VST3_PATH += ":/system/add-ons/media/vst3plugins"
-
- elif MACOS:
- splitter = ":"
-
- DEFAULT_LADSPA_PATH = HOME + "/Library/Audio/Plug-Ins/LADSPA"
- DEFAULT_LADSPA_PATH += ":/Library/Audio/Plug-Ins/LADSPA"
-
- DEFAULT_DSSI_PATH = HOME + "/Library/Audio/Plug-Ins/DSSI"
- DEFAULT_DSSI_PATH += ":/Library/Audio/Plug-Ins/DSSI"
-
- DEFAULT_LV2_PATH = HOME + "/Library/Audio/Plug-Ins/LV2"
- DEFAULT_LV2_PATH += ":/Library/Audio/Plug-Ins/LV2"
-
- DEFAULT_VST2_PATH = HOME + "/Library/Audio/Plug-Ins/VST"
- DEFAULT_VST2_PATH += ":/Library/Audio/Plug-Ins/VST"
-
- DEFAULT_VST3_PATH = HOME + "/Library/Audio/Plug-Ins/VST3"
- DEFAULT_VST3_PATH += ":/Library/Audio/Plug-Ins/VST3"
-
- DEFAULT_JSFX_PATH = HOME + "/Library/Application Support/REAPER/Effects"
- #DEFAULT_JSFX_PATH += ":/Applications/REAPER.app/Contents/InstallFiles/Effects"
-
- else:
- CONFIG_HOME = os.getenv("XDG_CONFIG_HOME", HOME + "/.config")
-
- splitter = ":"
-
- DEFAULT_LADSPA_PATH = HOME + "/.ladspa"
- DEFAULT_LADSPA_PATH += ":/usr/lib/ladspa"
- DEFAULT_LADSPA_PATH += ":/usr/local/lib/ladspa"
-
- DEFAULT_DSSI_PATH = HOME + "/.dssi"
- DEFAULT_DSSI_PATH += ":/usr/lib/dssi"
- DEFAULT_DSSI_PATH += ":/usr/local/lib/dssi"
-
- DEFAULT_LV2_PATH = HOME + "/.lv2"
- DEFAULT_LV2_PATH += ":/usr/lib/lv2"
- DEFAULT_LV2_PATH += ":/usr/local/lib/lv2"
-
- DEFAULT_VST2_PATH = HOME + "/.vst"
- DEFAULT_VST2_PATH += ":/usr/lib/vst"
- DEFAULT_VST2_PATH += ":/usr/local/lib/vst"
-
- DEFAULT_VST2_PATH += HOME + "/.lxvst"
- DEFAULT_VST2_PATH += ":/usr/lib/lxvst"
- DEFAULT_VST2_PATH += ":/usr/local/lib/lxvst"
-
- DEFAULT_VST3_PATH = HOME + "/.vst3"
- DEFAULT_VST3_PATH += ":/usr/lib/vst3"
- DEFAULT_VST3_PATH += ":/usr/local/lib/vst3"
-
- DEFAULT_SF2_PATH = HOME + "/.sounds/sf2"
- DEFAULT_SF2_PATH += ":" + HOME + "/.sounds/sf3"
- DEFAULT_SF2_PATH += ":/usr/share/sounds/sf2"
- DEFAULT_SF2_PATH += ":/usr/share/sounds/sf3"
- DEFAULT_SF2_PATH += ":/usr/share/soundfonts"
-
- DEFAULT_SFZ_PATH = HOME + "/.sounds/sfz"
- DEFAULT_SFZ_PATH += ":/usr/share/sounds/sfz"
-
- DEFAULT_JSFX_PATH = CONFIG_HOME + "/REAPER/Effects"
- #DEFAULT_JSFX_PATH += ":" + "/opt/REAPER/InstallData/Effects"
-
- if not WINDOWS:
- winePrefix = os.getenv("WINEPREFIX")
-
- if not winePrefix:
- winePrefix = HOME + "/.wine"
-
- if os.path.exists(winePrefix):
- DEFAULT_VST2_PATH += ":" + winePrefix + "/drive_c/Program Files/VstPlugins"
- DEFAULT_VST3_PATH += ":" + winePrefix + "/drive_c/Program Files/Common Files/VST3"
-
- if kIs64bit and os.path.exists(winePrefix + "/drive_c/Program Files (x86)"):
- DEFAULT_VST2_PATH += ":" + winePrefix + "/drive_c/Program Files (x86)/VstPlugins"
- DEFAULT_VST3_PATH += ":" + winePrefix + "/drive_c/Program Files (x86)/Common Files/VST3"
-
- del winePrefix
-
- # ------------------------------------------------------------------------------------------------------------
- # Default Plugin Folders (set)
-
- readEnvVars = True
-
- if WINDOWS:
- # Check if running Wine. If yes, ignore env vars
- # pylint: disable=import-error
- from winreg import ConnectRegistry, OpenKey, CloseKey, HKEY_CURRENT_USER
- # pylint: enable=import-error
- _reg = ConnectRegistry(None, HKEY_CURRENT_USER)
-
- try:
- _key = OpenKey(_reg, r"SOFTWARE\Wine")
- CloseKey(_key)
- del _key
- readEnvVars = False
- except:
- pass
-
- CloseKey(_reg)
- del _reg
-
- if readEnvVars:
- CARLA_DEFAULT_LADSPA_PATH = os.getenv("LADSPA_PATH", DEFAULT_LADSPA_PATH).split(splitter)
- CARLA_DEFAULT_DSSI_PATH = os.getenv("DSSI_PATH", DEFAULT_DSSI_PATH).split(splitter)
- CARLA_DEFAULT_LV2_PATH = os.getenv("LV2_PATH", DEFAULT_LV2_PATH).split(splitter)
- CARLA_DEFAULT_VST2_PATH = os.getenv("VST_PATH", DEFAULT_VST2_PATH).split(splitter)
- CARLA_DEFAULT_VST3_PATH = os.getenv("VST3_PATH", DEFAULT_VST3_PATH).split(splitter)
- CARLA_DEFAULT_SF2_PATH = os.getenv("SF2_PATH", DEFAULT_SF2_PATH).split(splitter)
- CARLA_DEFAULT_SFZ_PATH = os.getenv("SFZ_PATH", DEFAULT_SFZ_PATH).split(splitter)
- CARLA_DEFAULT_JSFX_PATH = os.getenv("JSFX_PATH", DEFAULT_JSFX_PATH).split(splitter)
-
- else:
- CARLA_DEFAULT_LADSPA_PATH = DEFAULT_LADSPA_PATH.split(splitter)
- CARLA_DEFAULT_DSSI_PATH = DEFAULT_DSSI_PATH.split(splitter)
- CARLA_DEFAULT_LV2_PATH = DEFAULT_LV2_PATH.split(splitter)
- CARLA_DEFAULT_VST2_PATH = DEFAULT_VST2_PATH.split(splitter)
- CARLA_DEFAULT_VST3_PATH = DEFAULT_VST3_PATH.split(splitter)
- CARLA_DEFAULT_SF2_PATH = DEFAULT_SF2_PATH.split(splitter)
- CARLA_DEFAULT_SFZ_PATH = DEFAULT_SFZ_PATH.split(splitter)
- CARLA_DEFAULT_JSFX_PATH = DEFAULT_JSFX_PATH.split(splitter)
-
- # ------------------------------------------------------------------------------------------------------------
- # Default Plugin Folders (cleanup)
-
- del DEFAULT_LADSPA_PATH
- del DEFAULT_DSSI_PATH
- del DEFAULT_LV2_PATH
- del DEFAULT_VST2_PATH
- del DEFAULT_VST3_PATH
- del DEFAULT_SF2_PATH
- del DEFAULT_SFZ_PATH
-
- # ------------------------------------------------------------------------------------------------------------
- # Global Carla object
-
- class CarlaObject():
- def __init__(self):
- self.cnprefix = "" # Client name prefix
- self.gui = None # Host Window
- self.nogui = False # Skip UI
- self.term = False # Terminated by OS signal
- self.utils = None # Utils object
-
- gCarla = CarlaObject()
-
- # ------------------------------------------------------------------------------------------------------------
- # Set CWD
-
- CWD = sys.path[0]
-
- if not CWD:
- CWD = os.path.dirname(sys.argv[0])
-
- # make it work with cxfreeze
- if os.path.isfile(CWD):
- CWD = os.path.dirname(CWD)
- if CWD.endswith("/lib"):
- CWD = CWD.rsplit("/lib",1)[0]
- CXFREEZE = True
- if not WINDOWS:
- os.environ['CARLA_MAGIC_FILE'] = os.path.join(CWD, "magic.mgc")
- else:
- CXFREEZE = False
-
- # ------------------------------------------------------------------------------------------------------------
- # Set DLL_EXTENSION
-
- if WINDOWS:
- DLL_EXTENSION = "dll"
- elif MACOS:
- DLL_EXTENSION = "dylib"
- else:
- DLL_EXTENSION = "so"
-
- # ------------------------------------------------------------------------------------------------------------
- # Find decimal points for a parameter, using step and stepSmall
-
- def countDecimalPoints(step, stepSmall):
- if stepSmall >= 1.0:
- return 0
- if step >= 1.0:
- return 2
-
- count = 0
- value = fmod(abs(step), 1)
- while 0.0001 < value < 0.999 and count < 6:
- value = fmod(value*10, 1)
- count += 1
-
- return count
-
- # ------------------------------------------------------------------------------------------------------------
- # Check if a value is a number (float support)
-
- def isNumber(value):
- try:
- float(value)
- return True
- except:
- return False
-
- # ------------------------------------------------------------------------------------------------------------
- # Convert a value to a list
-
- def toList(value):
- if value is None:
- return []
- if not isinstance(value, list):
- return [value]
- return value
-
- # ------------------------------------------------------------------------------------------------------------
- # Get Icon from user theme, using our own as backup (Oxygen)
-
- def getIcon(icon, size, qrcformat):
- return QIcon.fromTheme(icon, QIcon(":/%ix%i/%s.%s" % (size, size, icon, qrcformat)))
-
- # ------------------------------------------------------------------------------------------------------------
- # Handle some basic command-line arguments shared between all carla variants
-
- def handleInitialCommandLineArguments(file):
- initName = os.path.basename(file) if (file is not None and os.path.dirname(file) in PATH) else sys.argv[0]
- libPrefix = None
- readPrefixNext = False
-
- for arg in sys.argv[1:]:
- if arg.startswith("--with-appname="):
- initName = os.path.basename(arg.replace("--with-appname=", ""))
-
- elif arg.startswith("--with-libprefix="):
- libPrefix = arg.replace("--with-libprefix=", "")
-
- elif arg.startswith("--osc-gui="):
- gCarla.nogui = int(arg.replace("--osc-gui=", ""))
-
- elif arg.startswith("--cnprefix="):
- gCarla.cnprefix = arg.replace("--cnprefix=", "")
-
- elif arg == "--cnprefix":
- readPrefixNext = True
-
- elif arg == "--gdb":
- pass
-
- elif arg in ("-n", "--n", "-no-gui", "--no-gui", "-nogui", "--nogui"):
- gCarla.nogui = True
-
- elif MACOS and arg.startswith("-psn_"):
- pass
-
- elif arg in ("-h", "--h", "-help", "--help"):
- print("Usage: %s [OPTION]... [FILE|URL]" % initName)
- print("")
- print(" where FILE can be a Carla project or preset file to be loaded, or URL if using Carla-Control")
- print("")
- print(" and OPTION can be one or more of the following:")
- print("")
- print(" --cnprefix\t Set a prefix for client names in multi-client mode.")
- if isinstance(gCarla.nogui, bool):
- if X_LIBDIR_X is not None:
- print(" --gdb \t Run Carla inside gdb.")
- print(" -n,--no-gui \t Run Carla headless, don't show UI.")
- print("")
- print(" -h,--help \t Print this help text and exit.")
- print(" -v,--version \t Print version information and exit.")
- print("")
-
- if not isinstance(gCarla.nogui, bool):
- print("NOTE: when using %s the FILE is only valid the first time the backend is started" % initName)
- sys.exit(1)
-
- sys.exit(0)
-
- elif arg in ("-v", "--v", "-version", "--version"):
- pathBinaries, pathResources = getPaths(libPrefix)
-
- print("Using Carla version %s" % VERSION)
- print(" Python version: %s" % sys.version.split(" ",1)[0])
- print(" Qt version: %s" % QT_VERSION_STR)
- print(" PyQt version: %s" % PYQT_VERSION_STR)
- print(" Binary dir: %s" % pathBinaries)
- print(" Resources dir: %s" % pathResources)
-
- sys.exit(1 if gCarla.nogui else 0)
-
- elif readPrefixNext:
- readPrefixNext = False
- gCarla.cnprefix = arg
-
- if gCarla.nogui and not isinstance(gCarla.nogui, bool):
- if os.fork():
- # pylint: disable=protected-access
- os._exit(0)
- # pylint: enable=protected-access
- else:
- os.setsid()
-
- return (initName, libPrefix)
-
- # ------------------------------------------------------------------------------------------------------------
- # Get initial project file (as passed in the command-line parameters)
-
- def getInitialProjectFile(skipExistCheck = False):
- # NOTE: PyQt mishandles unicode characters, we directly use sys.argv instead of qApp->arguments()
- # see https://riverbankcomputing.com/pipermail/pyqt/2015-January/035395.html
- args = sys.argv[1:]
- readPrefixNext = False
- for arg in args:
- if readPrefixNext:
- readPrefixNext = False
- continue
- if arg.startswith("--cnprefix="):
- continue
- if arg.startswith("--osc-gui="):
- continue
- if arg.startswith("--with-appname="):
- continue
- if arg.startswith("--with-libprefix="):
- continue
- if arg == "--cnprefix":
- readPrefixNext = True
- continue
- if arg in ("-n", "--n", "-no-gui", "--no-gui", "-nogui", "--nogui", "--gdb"):
- continue
- if MACOS and arg.startswith("-psn_"):
- continue
- arg = os.path.expanduser(arg)
- if skipExistCheck or os.path.exists(arg):
- return arg
-
- return None
-
- # ------------------------------------------------------------------------------------------------------------
- # Get paths (binaries, resources)
-
- def getPaths(libPrefix = None):
- CWDl = CWD.lower()
-
- # adjust for special distros
- libdir = os.path.basename(os.path.normpath(X_LIBDIR_X)) if X_LIBDIR_X else "lib"
- datadir = os.path.basename(os.path.normpath(X_DATADIR_X)) if X_DATADIR_X else "share"
-
- # standalone, installed system-wide linux
- if libPrefix is not None:
- pathBinaries = os.path.join(libPrefix, libdir, "carla")
- pathResources = os.path.join(libPrefix, datadir, "carla", "resources")
-
- # standalone, local source
- elif CWDl.endswith("frontend"):
- pathBinaries = os.path.abspath(os.path.join(CWD, "..", "..", "bin"))
- pathResources = os.path.join(pathBinaries, "resources")
-
- # plugin
- elif CWDl.endswith("resources"):
- # installed system-wide linux
- if CWDl.endswith("/share/carla/resources"):
- pathBinaries = os.path.abspath(os.path.join(CWD, "..", "..", "..", libdir, "carla"))
- pathResources = CWD
-
- # local source
- elif CWDl.endswith("native-plugins%sresources" % os.sep):
- pathBinaries = os.path.abspath(os.path.join(CWD, "..", "..", "..", "bin"))
- pathResources = CWD
-
- # other
- else:
- pathBinaries = os.path.abspath(os.path.join(CWD, ".."))
- pathResources = CWD
-
- # everything else
- else:
- pathBinaries = CWD
- pathResources = os.path.join(pathBinaries, "resources")
-
- return (pathBinaries, pathResources)
-
- # ------------------------------------------------------------------------------------------------------------
- # Signal handler
- # TODO move to carla_host.py or something
-
- def signalHandler(sig, frame):
- if sig in (SIGINT, SIGTERM):
- gCarla.term = True
- if gCarla.gui is not None:
- gCarla.gui.SIGTERM.emit()
-
- elif haveSIGUSR1 and sig == SIGUSR1:
- if gCarla.gui is not None:
- gCarla.gui.SIGUSR1.emit()
-
- def setUpSignals():
- signal(SIGINT, signalHandler)
- signal(SIGTERM, signalHandler)
-
- if not haveSIGUSR1:
- return
-
- signal(SIGUSR1, signalHandler)
-
- # ------------------------------------------------------------------------------------------------------------
- # QLineEdit and QPushButton combo
-
- def getAndSetPath(parent, lineEdit):
- newPath = QFileDialog.getExistingDirectory(parent, parent.tr("Set Path"), lineEdit.text(), QFileDialog.ShowDirsOnly)
- if newPath:
- lineEdit.setText(newPath)
- return newPath
-
- # ------------------------------------------------------------------------------------------------------------
- # Backwards-compatible horizontalAdvance/width call, depending on Qt version
-
- def fontMetricsHorizontalAdvance(fontMetrics, string):
- if QT_VERSION >= 0x50b00:
- return fontMetrics.horizontalAdvance(string)
- return fontMetrics.width(string)
-
- # ------------------------------------------------------------------------------------------------------------
- # Custom QMessageBox which resizes itself to fit text
-
- class QMessageBoxWithBetterWidth(QMessageBox):
- def __init__(self, parent):
- QMessageBox.__init__(self, parent)
-
- def showEvent(self, event):
- fontMetrics = self.fontMetrics()
-
- lines = self.text().strip().split("\n") + self.informativeText().strip().split("\n")
-
- if lines:
- width = 0
-
- for line in lines:
- width = max(fontMetricsHorizontalAdvance(fontMetrics, line), width)
-
- self.layout().setColumnMinimumWidth(2, width + 12)
-
- QMessageBox.showEvent(self, event)
-
- # ------------------------------------------------------------------------------------------------------------
- # Safer QSettings class, which does not throw if type mismatches
-
- class QSafeSettings(QSettings):
- def value(self, key, defaultValue, valueType):
- if not isinstance(defaultValue, valueType):
- print("QSafeSettings.value() - defaultValue type mismatch for key", key)
-
- try:
- return QSettings.value(self, key, defaultValue, valueType)
- except:
- return defaultValue
-
- # ------------------------------------------------------------------------------------------------------------
- # Custom MessageBox
-
- # pylint: disable=too-many-arguments
- def CustomMessageBox(parent, icon, title, text,
- extraText="",
- buttons=QMessageBox.Yes|QMessageBox.No,
- defButton=QMessageBox.No):
- msgBox = QMessageBoxWithBetterWidth(parent)
- msgBox.setIcon(icon)
- msgBox.setWindowTitle(title)
- msgBox.setText(text)
- msgBox.setInformativeText(extraText)
- msgBox.setStandardButtons(buttons)
- msgBox.setDefaultButton(defButton)
- return msgBox.exec_()
- # pylint: enable=too-many-arguments
-
- # ------------------------------------------------------------------------------------------------------------
|