Browse Source

Rework C++ plugin list dialog and use it, delete python version

Signed-off-by: falkTX <falktx@falktx.com>
fix-audiofile-buffering
falkTX 1 year ago
parent
commit
f2e0b40f43
Signed by: falkTX <falktx@falktx.com> GPG Key ID: CDBAA37ABC74FBA0
18 changed files with 1756 additions and 5527 deletions
  1. +2
    -10
      source/frontend/CarlaFrontend.h
  2. +1
    -3
      source/frontend/Makefile
  3. +18
    -17
      source/frontend/carla_frontend.py
  4. +14
    -26
      source/frontend/carla_host.py
  5. +0
    -19
      source/frontend/pluginlist/__init__.py
  6. +0
    -411
      source/frontend/pluginlist/discovery.py
  7. +0
    -851
      source/frontend/pluginlist/discoverythread.py
  8. +1363
    -1365
      source/frontend/pluginlist/pluginlistdialog.cpp
  9. +41
    -51
      source/frontend/pluginlist/pluginlistdialog.hpp
  10. +0
    -1000
      source/frontend/pluginlist/pluginlistdialog.py
  11. +27
    -20
      source/frontend/pluginlist/pluginlistdialog.ui
  12. +0
    -590
      source/frontend/pluginlist/pluginlistrefreshdialog.cpp
  13. +0
    -81
      source/frontend/pluginlist/pluginlistrefreshdialog.hpp
  14. +0
    -473
      source/frontend/pluginlist/pluginlistrefreshdialog.py
  15. +0
    -610
      source/frontend/pluginlist/pluginlistrefreshdialog.ui
  16. +65
    -0
      source/frontend/pluginlist/pluginrefreshdialog.hpp
  17. +190
    -0
      source/frontend/pluginlist/pluginrefreshdialog.ui
  18. +35
    -0
      source/frontend/utils/qcarlastring.hpp

+ 2
- 10
source/frontend/CarlaFrontend.h View File

@@ -32,7 +32,6 @@ typedef struct {
} JackAppDialogResults;

typedef struct {
uint API;
uint build;
uint type;
uint hints;
@@ -48,14 +47,10 @@ typedef struct {
uint cvOuts;
uint midiIns;
uint midiOuts;
uint parametersIns;
uint parametersOuts;
uint parameterIns;
uint parameterOuts;
} PluginListDialogResults;

typedef struct {
char todo;
} PluginListRefreshDialogResults;

// --------------------------------------------------------------------------------------------------------------------

CARLA_API void
@@ -67,9 +62,6 @@ carla_frontend_createAndExecJackAppDialog(void* parent, const char* projectFilen
CARLA_API const PluginListDialogResults*
carla_frontend_createAndExecPluginListDialog(void* parent/*, const HostSettings& hostSettings*/);

CARLA_API const PluginListRefreshDialogResults*
carla_frontend_createAndExecPluginListRefreshDialog(void* parent, bool useSystemIcons);

// --------------------------------------------------------------------------------------------------------------------

#ifdef __cplusplus


+ 1
- 3
source/frontend/Makefile View File

@@ -73,8 +73,7 @@ CPP_FILES = \
carla_frontend.cpp \
dialogs/aboutjucedialog.cpp \
dialogs/jackappdialog.cpp \
pluginlist/pluginlistdialog.cpp \
pluginlist/pluginlistrefreshdialog.cpp
pluginlist/pluginlistdialog.cpp

OBJS = $(CPP_FILES:%=$(OBJDIR)/%.o)

@@ -139,7 +138,6 @@ UIs = $(DIALOG_UI_FILES:dialogs/%.ui=dialogs/ui_%.h)
UIs += $(PLUGINLIST_UI_FILES:pluginlist/%.ui=pluginlist/ui_%.h)

UIs += $(DIALOG_UI_FILES:%.ui=%_ui.py)
UIs += $(PLUGINLIST_UI_FILES:%.ui=%_ui.py)

# old stuff, not yet converted
UIs += \


+ 18
- 17
source/frontend/carla_frontend.py View File

@@ -23,7 +23,7 @@
# Imports (ctypes)

from ctypes import (
c_bool, c_char, c_char_p, c_int, c_void_p, cast,
c_bool, c_char, c_char_p, c_uint, c_uint64, c_void_p, cast,
cdll, Structure,
POINTER
)
@@ -55,15 +55,23 @@ class JackApplicationDialogResults(Structure):

class PluginListDialogResults(Structure):
_fields_ = [
("btype", c_int),
("ptype", c_int),
("binary", c_char_p),
("label", c_char_p)
]

class PluginListRefreshDialogResults(Structure):
_fields_ = [
("todo", c_char)
("build", c_uint),
("type", c_uint),
("hints", c_uint),
("category", c_char_p),
("filename", c_char_p),
("name", c_char_p),
("label", c_char_p),
("maker", c_char_p),
("uniqueId", c_uint64),
("audioIns", c_uint),
("audioOuts", c_uint),
("cvIns", c_uint),
("cvOuts", c_uint),
("midiIns", c_uint),
("midiOuts", c_uint),
("parametersIns", c_uint),
("parametersOuts", c_uint),
]

# ------------------------------------------------------------------------------------------------------------
@@ -82,9 +90,6 @@ class CarlaFrontendLib():
self.lib.carla_frontend_createAndExecPluginListDialog.argtypes = (c_void_p,) # , c_bool)
self.lib.carla_frontend_createAndExecPluginListDialog.restype = POINTER(PluginListDialogResults)

self.lib.carla_frontend_createAndExecPluginListRefreshDialog.argtypes = (c_void_p, c_bool)
self.lib.carla_frontend_createAndExecPluginListRefreshDialog.restype = POINTER(PluginListRefreshDialogResults)

# --------------------------------------------------------------------------------------------------------

def createAndExecAboutJuceDialog(self, parent):
@@ -97,8 +102,4 @@ class CarlaFrontendLib():
def createAndExecPluginListDialog(self, parent, useSystemIcons):
return structToDictOrNull(self.lib.carla_frontend_createAndExecPluginListDialog(unwrapinstance(parent)))

def createAndExecPluginListRefreshDialog(self, parent, useSystemIcons):
return structToDictOrNull(self.lib.carla_frontend_createAndExecPluginListRefreshDialog(unwrapinstance(parent),
useSystemIcons))

# ------------------------------------------------------------------------------------------------------------

+ 14
- 26
source/frontend/carla_host.py View File

@@ -62,7 +62,6 @@ from carla_utils import *
from carla_widgets import *

from patchcanvas import patchcanvas
from pluginlist import PluginListDialog
from widgets.digitalpeakmeter import DigitalPeakMeter
from widgets.pixmapkeyboard import PixmapKeyboardHArea

@@ -1208,25 +1207,14 @@ class HostWindow(QMainWindow):
# Plugins (menu actions)

def showAddPluginDialog(self):
#ret = gCarla.felib.createAndExecPluginListDialog(self.fParentOrSelf,
#self.fSavedSettings[CARLA_KEY_MAIN_SYSTEM_ICONS])
#print(ret)
#return
#ret = gCarla.felib.createAndExecPluginListRefreshDialog(self.fParentOrSelf,
#self.fSavedSettings[CARLA_KEY_MAIN_SYSTEM_ICONS])
#print(ret)
#return

if self.fPluginDatabaseDialog is None:
self.fPluginDatabaseDialog = PluginListDialog(self.fParentOrSelf, self.host,
self.fSavedSettings[CARLA_KEY_MAIN_SYSTEM_ICONS])
dialog = self.fPluginDatabaseDialog
dialog.hasLoadedLv2Plugins = self.fHasLoadedLv2Plugins

ret = dialog.exec_()

if dialog.fFavoritePluginsChanged:
self.fFavoritePlugins = dialog.fFavoritePlugins
# TODO self.fHasLoadedLv2Plugins
ret = gCarla.felib.createAndExecPluginListDialog(self.fParentOrSelf,
self.fSavedSettings[CARLA_KEY_MAIN_SYSTEM_ICONS])
print(ret)

# TODO
#if dialog.fFavoritePluginsChanged:
#self.fFavoritePlugins = dialog.fFavoritePlugins

if not ret:
return
@@ -1235,12 +1223,12 @@ class HostWindow(QMainWindow):
QMessageBox.warning(self, self.tr("Warning"), self.tr("Cannot add new plugins while engine is stopped"))
return

btype = dialog.fRetPlugin['build']
ptype = dialog.fRetPlugin['type']
filename = dialog.fRetPlugin['filename']
label = dialog.fRetPlugin['label']
uniqueId = dialog.fRetPlugin['uniqueId']
extraPtr = self.getExtraPtr(dialog.fRetPlugin)
btype = ret['build']
ptype = ret['type']
filename = ret['filename']
label = ret['label']
uniqueId = ret['uniqueId']
extraPtr = None

return (btype, ptype, filename, label, uniqueId, extraPtr)



+ 0
- 19
source/frontend/pluginlist/__init__.py View File

@@ -1,19 +0,0 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-

# Carla plugin host
# Copyright (C) 2011-2022 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.

from .pluginlistdialog import PluginListDialog

+ 0
- 411
source/frontend/pluginlist/discovery.py View File

@@ -1,411 +0,0 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-

# Carla plugin list code
# Copyright (C) 2011-2022 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

from copy import deepcopy
from subprocess import Popen, PIPE
from PyQt5.QtCore import qWarning

# ---------------------------------------------------------------------------------------------------------------------
# Imports (Carla)

from carla_backend import (
BINARY_NATIVE,
BINARY_NONE,
PLUGIN_AU,
PLUGIN_DSSI,
PLUGIN_LADSPA,
PLUGIN_LV2,
PLUGIN_NONE,
PLUGIN_SF2,
PLUGIN_SFZ,
PLUGIN_VST2,
PLUGIN_VST3,
PLUGIN_CLAP,
)

from carla_shared import (
LINUX,
MACOS,
WINDOWS,
)

from carla_utils import getPluginCategoryAsString

# ---------------------------------------------------------------------------------------------------------------------
# Plugin Query (helper functions)

def findBinaries(binPath, pluginType, OS):
binaries = []

if OS == "HAIKU":
extensions = ("") if pluginType == PLUGIN_VST2 else (".so",)
elif OS == "MACOS":
extensions = (".dylib", ".so")
elif OS == "WINDOWS":
extensions = (".dll",)
else:
extensions = (".so",)

for root, _, files in os.walk(binPath):
for name in tuple(name for name in files if name.lower().endswith(extensions)):
binaries.append(os.path.join(root, name))

return binaries

def findVST3Binaries(binPath):
binaries = []

for root, dirs, files in os.walk(binPath):
for name in tuple(name for name in (files+dirs) if name.lower().endswith(".vst3")):
binaries.append(os.path.join(root, name))

return binaries

def findCLAPBinaries(binPath):
binaries = []

for root, _, files in os.walk(binPath, followlinks=True):
for name in tuple(name for name in files if name.lower().endswith(".clap")):
binaries.append(os.path.join(root, name))

return binaries

def findLV2Bundles(bundlePath):
bundles = []

for root, _, _2 in os.walk(bundlePath, followlinks=True):
if root == bundlePath:
continue
if os.path.exists(os.path.join(root, "manifest.ttl")):
bundles.append(root)

return bundles

def findMacBundles(bundlePath, pluginType):
bundles = []

if pluginType == PLUGIN_VST2:
extension = ".vst"
elif pluginType == PLUGIN_VST3:
extension = ".vst3"
elif pluginType == PLUGIN_CLAP:
extension = ".clap"
else:
return bundles

for root, dirs, _ in os.walk(bundlePath, followlinks=True):
for name in tuple(name for name in dirs if name.lower().endswith(extension)):
bundles.append(os.path.join(root, name))

return bundles

def findFilenames(filePath, stype):
filenames = []

if stype == "sf2":
extensions = (".sf2",".sf3",)
else:
return []

for root, _, files in os.walk(filePath):
for name in tuple(name for name in files if name.lower().endswith(extensions)):
filenames.append(os.path.join(root, name))

return filenames

# ---------------------------------------------------------------------------------------------------------------------
# Plugin Query

# NOTE: this code is ugly, it is meant to be replaced, so let it be as-is for now

PLUGIN_QUERY_API_VERSION = 12

PyPluginInfo = {
'API': PLUGIN_QUERY_API_VERSION,
'valid': False,
'build': BINARY_NONE,
'type': PLUGIN_NONE,
'hints': 0x0,
'category': "",
'filename': "",
'name': "",
'label': "",
'maker': "",
'uniqueId': 0,
'audio.ins': 0,
'audio.outs': 0,
'cv.ins': 0,
'cv.outs': 0,
'midi.ins': 0,
'midi.outs': 0,
'parameters.ins': 0,
'parameters.outs': 0
}

gDiscoveryProcess = None

def findWinePrefix(filename, recursionLimit = 10):
if recursionLimit == 0 or len(filename) < 5 or "/" not in filename:
return ""

path = filename[:filename.rfind("/")]

if os.path.isdir(path + "/dosdevices"):
return path

return findWinePrefix(path, recursionLimit-1)

def runCarlaDiscovery(itype, stype, filename, tool, wineSettings=None):
if not os.path.exists(tool):
qWarning(f"runCarlaDiscovery() - tool '{tool}' does not exist")
return []

command = []

if LINUX or MACOS:
command.append("env")
command.append("LANG=C")
command.append("LD_PRELOAD=")
if wineSettings is not None:
command.append("WINEDEBUG=-all")

if wineSettings['autoPrefix']:
winePrefix = findWinePrefix(filename)
else:
winePrefix = ""

if not winePrefix:
envWinePrefix = os.getenv("WINEPREFIX")

if envWinePrefix:
winePrefix = envWinePrefix
elif wineSettings['fallbackPrefix']:
winePrefix = os.path.expanduser(wineSettings['fallbackPrefix'])
else:
winePrefix = os.path.expanduser("~/.wine")

wineCMD = wineSettings['executable'] if wineSettings['executable'] else "wine"

if tool.endswith("64.exe") and os.path.exists(wineCMD + "64"):
wineCMD += "64"

command.append("WINEPREFIX=" + winePrefix)
command.append(wineCMD)

command.append(tool)
command.append(stype)
command.append(filename)

# pylint: disable=global-statement
global gDiscoveryProcess
# pylint: enable=global-statement

# pylint: disable=consider-using-with
gDiscoveryProcess = Popen(command, stdout=PIPE)
# pylint: enable=consider-using-with

pinfo = None
plugins = []
fakeLabel = os.path.basename(filename).rsplit(".", 1)[0]

while True:
try:
line = gDiscoveryProcess.stdout.readline().decode("utf-8", errors="ignore")
except:
print("ERROR: discovery readline failed")
break

# line is valid, strip it
if line:
line = line.strip()

# line is invalid, try poll() again
elif gDiscoveryProcess.poll() is None:
continue

# line is invalid and poll() failed, stop here
else:
break

if line == "carla-discovery::init::------------":
pinfo = deepcopy(PyPluginInfo)
pinfo['type'] = itype
pinfo['filename'] = filename if filename != ":all" else ""

elif line == "carla-discovery::end::------------":
if pinfo is not None:
plugins.append(pinfo)
del pinfo
pinfo = None

elif line == "Segmentation fault":
print(f"carla-discovery::crash::{filename} crashed during discovery")

elif line.startswith("err:module:import_dll Library"):
print(line)

elif line.startswith("carla-discovery::info::"):
print(f"{line} - {filename}")

elif line.startswith("carla-discovery::warning::"):
print(f"{line} - {filename}")

elif line.startswith("carla-discovery::error::"):
print(f"{line} - {filename}")

elif line.startswith("carla-discovery::"):
if pinfo is None:
continue

try:
prop, value = line.replace("carla-discovery::", "").split("::", 1)
except:
continue

# pylint: disable=unsupported-assignment-operation
if prop == "build":
if value.isdigit():
pinfo['build'] = int(value)
elif prop == "name":
pinfo['name'] = value if value else fakeLabel
elif prop == "label":
pinfo['label'] = value if value else fakeLabel
elif prop == "filename":
pinfo['filename'] = value
elif prop == "maker":
pinfo['maker'] = value
elif prop == "category":
pinfo['category'] = value
elif prop == "uniqueId":
if value.isdigit():
pinfo['uniqueId'] = int(value)
elif prop == "hints":
if value.isdigit():
pinfo['hints'] = int(value)
elif prop == "audio.ins":
if value.isdigit():
pinfo['audio.ins'] = int(value)
elif prop == "audio.outs":
if value.isdigit():
pinfo['audio.outs'] = int(value)
elif prop == "cv.ins":
if value.isdigit():
pinfo['cv.ins'] = int(value)
elif prop == "cv.outs":
if value.isdigit():
pinfo['cv.outs'] = int(value)
elif prop == "midi.ins":
if value.isdigit():
pinfo['midi.ins'] = int(value)
elif prop == "midi.outs":
if value.isdigit():
pinfo['midi.outs'] = int(value)
elif prop == "parameters.ins":
if value.isdigit():
pinfo['parameters.ins'] = int(value)
elif prop == "parameters.outs":
if value.isdigit():
pinfo['parameters.outs'] = int(value)
elif prop == "uri":
if value:
pinfo['label'] = value
else:
# cannot use empty URIs
del pinfo
pinfo = None
continue
else:
print(f"{line} - {filename} (unknown property)")
# pylint: enable=unsupported-assignment-operation

tmp = gDiscoveryProcess
gDiscoveryProcess = None
del tmp

return plugins

def killDiscovery():
# pylint: disable=global-variable-not-assigned
global gDiscoveryProcess
# pylint: enable=global-variable-not-assigned

if gDiscoveryProcess is not None:
gDiscoveryProcess.kill()

def checkPluginCached(desc, ptype):
pinfo = deepcopy(PyPluginInfo)
pinfo['build'] = BINARY_NATIVE
pinfo['type'] = ptype
pinfo['hints'] = desc['hints']
pinfo['name'] = desc['name']
pinfo['label'] = desc['label']
pinfo['maker'] = desc['maker']
pinfo['category'] = getPluginCategoryAsString(desc['category'])

pinfo['audio.ins'] = desc['audioIns']
pinfo['audio.outs'] = desc['audioOuts']

pinfo['cv.ins'] = desc['cvIns']
pinfo['cv.outs'] = desc['cvOuts']

pinfo['midi.ins'] = desc['midiIns']
pinfo['midi.outs'] = desc['midiOuts']

pinfo['parameters.ins'] = desc['parameterIns']
pinfo['parameters.outs'] = desc['parameterOuts']

if ptype == PLUGIN_LV2:
pinfo['filename'], pinfo['label'] = pinfo['label'].split('\\' if WINDOWS else '/',1)

elif ptype == PLUGIN_SFZ:
pinfo['filename'] = pinfo['label']
pinfo['label'] = pinfo['name']

return pinfo

def checkPluginLADSPA(filename, tool, wineSettings=None):
return runCarlaDiscovery(PLUGIN_LADSPA, "LADSPA", filename, tool, wineSettings)

def checkPluginDSSI(filename, tool, wineSettings=None):
return runCarlaDiscovery(PLUGIN_DSSI, "DSSI", filename, tool, wineSettings)

def checkPluginLV2(filename, tool, wineSettings=None):
return runCarlaDiscovery(PLUGIN_LV2, "LV2", filename, tool, wineSettings)

def checkPluginVST2(filename, tool, wineSettings=None):
return runCarlaDiscovery(PLUGIN_VST2, "VST2", filename, tool, wineSettings)

def checkPluginVST3(filename, tool, wineSettings=None):
return runCarlaDiscovery(PLUGIN_VST3, "VST3", filename, tool, wineSettings)

def checkPluginCLAP(filename, tool, wineSettings=None):
return runCarlaDiscovery(PLUGIN_CLAP, "CLAP", filename, tool, wineSettings)

def checkFileSF2(filename, tool):
return runCarlaDiscovery(PLUGIN_SF2, "SF2", filename, tool)

def checkFileSFZ(filename, tool):
return runCarlaDiscovery(PLUGIN_SFZ, "SFZ", filename, tool)

def checkAllPluginsAU(tool):
return runCarlaDiscovery(PLUGIN_AU, "AU", ":all", tool)

+ 0
- 851
source/frontend/pluginlist/discoverythread.py View File

@@ -1,851 +0,0 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-

# Carla plugin host
# Copyright (C) 2011-2022 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

from PyQt5.QtCore import pyqtSignal, QThread
from PyQt5.QtWidgets import QWidget

# ---------------------------------------------------------------------------------------------------------------------
# Imports (Custom)

from carla_backend import (
PLUGIN_AU,
PLUGIN_DSSI,
PLUGIN_JSFX,
PLUGIN_LADSPA,
PLUGIN_LV2,
PLUGIN_SFZ,
PLUGIN_VST2,
PLUGIN_VST3,
PLUGIN_CLAP,
)

from carla_shared import (
CARLA_DEFAULT_DSSI_PATH,
CARLA_DEFAULT_JSFX_PATH,
CARLA_DEFAULT_LADSPA_PATH,
CARLA_DEFAULT_LV2_PATH,
CARLA_DEFAULT_SF2_PATH,
CARLA_DEFAULT_SFZ_PATH,
CARLA_DEFAULT_VST2_PATH,
CARLA_DEFAULT_VST3_PATH,
CARLA_DEFAULT_CLAP_PATH,
CARLA_DEFAULT_WINE_AUTO_PREFIX,
CARLA_DEFAULT_WINE_EXECUTABLE,
CARLA_DEFAULT_WINE_FALLBACK_PREFIX,
CARLA_KEY_PATHS_DSSI,
CARLA_KEY_PATHS_JSFX,
CARLA_KEY_PATHS_LADSPA,
CARLA_KEY_PATHS_LV2,
CARLA_KEY_PATHS_SF2,
CARLA_KEY_PATHS_SFZ,
CARLA_KEY_PATHS_VST2,
CARLA_KEY_PATHS_VST3,
CARLA_KEY_PATHS_CLAP,
CARLA_KEY_WINE_AUTO_PREFIX,
CARLA_KEY_WINE_EXECUTABLE,
CARLA_KEY_WINE_FALLBACK_PREFIX,
HAIKU,
LINUX,
MACOS,
WINDOWS,
gCarla,
splitter,
)

from utils import QSafeSettings

from .discovery import (
checkAllPluginsAU,
checkFileSF2,
checkPluginCached,
checkPluginDSSI,
checkPluginLADSPA,
checkPluginVST2,
checkPluginVST3,
checkPluginCLAP,
findBinaries,
findFilenames,
findMacBundles,
findVST3Binaries,
findCLAPBinaries
)

# ---------------------------------------------------------------------------------------------------------------------
# Separate Thread for Plugin Search

class SearchPluginsThread(QThread):
pluginLook = pyqtSignal(float, str)

def __init__(self, parent: QWidget, pathBinaries: str):
QThread.__init__(self, parent)

self.fContinueChecking = False
self.fPathBinaries = pathBinaries

self.fCheckNative = False
self.fCheckPosix32 = False
self.fCheckPosix64 = False
self.fCheckWin32 = False
self.fCheckWin64 = False

self.fCheckLADSPA = False
self.fCheckDSSI = False
self.fCheckLV2 = False
self.fCheckVST2 = False
self.fCheckVST3 = False
self.fCheckCLAP = False
self.fCheckAU = False
self.fCheckSF2 = False
self.fCheckSFZ = False
self.fCheckJSFX = False

if WINDOWS:
toolNative = "carla-discovery-native.exe"
self.fWineSettings = None

else:
toolNative = "carla-discovery-native"
settings = QSafeSettings("falkTX", "Carla2")
self.fWineSettings = {
'executable' : settings.value(CARLA_KEY_WINE_EXECUTABLE,
CARLA_DEFAULT_WINE_EXECUTABLE, str),
'autoPrefix' : settings.value(CARLA_KEY_WINE_AUTO_PREFIX,
CARLA_DEFAULT_WINE_AUTO_PREFIX, bool),
'fallbackPrefix': settings.value(CARLA_KEY_WINE_FALLBACK_PREFIX,
CARLA_DEFAULT_WINE_FALLBACK_PREFIX, str),
}
del settings

self.fToolNative = os.path.join(pathBinaries, toolNative)

if not os.path.exists(self.fToolNative):
self.fToolNative = ""

self.fCurCount = 0
self.fCurPercentValue = 0
self.fLastCheckValue = 0
self.fSomethingChanged = False

# -----------------------------------------------------------------------------------------------------------------
# public methods

def hasSomethingChanged(self):
return self.fSomethingChanged

def setSearchBinaryTypes(self, native: bool, posix32: bool, posix64: bool, win32: bool, win64: bool):
self.fCheckNative = native
self.fCheckPosix32 = posix32
self.fCheckPosix64 = posix64
self.fCheckWin32 = win32
self.fCheckWin64 = win64

def setSearchPluginTypes(self, ladspa: bool, dssi: bool, lv2: bool, vst2: bool, vst3: bool, clap: bool,
au: bool, sf2: bool, sfz: bool, jsfx: bool):
self.fCheckLADSPA = ladspa
self.fCheckDSSI = dssi
self.fCheckLV2 = lv2
self.fCheckVST2 = vst2
self.fCheckVST3 = vst3
self.fCheckCLAP = clap
self.fCheckAU = au and MACOS
self.fCheckSF2 = sf2
self.fCheckSFZ = sfz
self.fCheckJSFX = jsfx

def stop(self):
self.fContinueChecking = False

# -----------------------------------------------------------------------------------------------------------------
# protected reimplemented methods

def run(self):
settingsDB = QSafeSettings("falkTX", "CarlaPlugins5")

self.fContinueChecking = True
self.fCurCount = 0

if self.fCheckNative and not self.fToolNative:
self.fCheckNative = False

# looking for plugins via external discovery
pluginCount = 0

if self.fCheckLADSPA:
pluginCount += 1
if self.fCheckDSSI:
pluginCount += 1
if self.fCheckVST2:
pluginCount += 1
if self.fCheckVST3:
pluginCount += 1
if self.fCheckCLAP:
pluginCount += 1

# Increase count by the number of externally discoverable plugin types
if self.fCheckNative:
self.fCurCount += pluginCount

if self.fCheckPosix32:
self.fCurCount += pluginCount

if self.fCheckPosix64:
self.fCurCount += pluginCount

if self.fCheckWin32:
self.fCurCount += pluginCount

if self.fCheckWin64:
self.fCurCount += pluginCount

if self.fCheckLV2:
if self.fCheckNative:
self.fCurCount += 1
else:
self.fCheckLV2 = False

if self.fCheckAU:
if self.fCheckNative or self.fCheckPosix32:
self.fCurCount += int(self.fCheckNative) + int(self.fCheckPosix32)
else:
self.fCheckAU = False

if self.fCheckSF2:
if self.fCheckNative:
self.fCurCount += 1
else:
self.fCheckSF2 = False

if self.fCheckSFZ:
if self.fCheckNative:
self.fCurCount += 1
else:
self.fCheckSFZ = False

if self.fCheckJSFX:
if self.fCheckNative:
self.fCurCount += 1
else:
self.fCheckJSFX = False

if self.fCurCount == 0:
return

self.fCurPercentValue = 100.0 / self.fCurCount
self.fLastCheckValue = 0.0

del pluginCount

if HAIKU:
OS = "HAIKU"
elif LINUX:
OS = "LINUX"
elif MACOS:
OS = "MACOS"
elif WINDOWS:
OS = "WINDOWS"
else:
OS = "UNKNOWN"

if not self.fContinueChecking:
return

self.fSomethingChanged = True

if self.fCheckLADSPA:
if self.fCheckNative:
plugins = self._checkLADSPA(OS, self.fToolNative)
settingsDB.setValue("Plugins/LADSPA_native", plugins)
if not self.fContinueChecking:
return

if self.fCheckPosix32:
tool = os.path.join(self.fPathBinaries, "carla-discovery-posix32")
plugins = self._checkLADSPA(OS, tool)
settingsDB.setValue("Plugins/LADSPA_posix32", plugins)
if not self.fContinueChecking:
return

if self.fCheckPosix64:
tool = os.path.join(self.fPathBinaries, "carla-discovery-posix64")
plugins = self._checkLADSPA(OS, tool)
settingsDB.setValue("Plugins/LADSPA_posix64", plugins)
if not self.fContinueChecking:
return

if self.fCheckWin32:
tool = os.path.join(self.fPathBinaries, "carla-discovery-win32.exe")
plugins = self._checkLADSPA("WINDOWS", tool, not WINDOWS)
settingsDB.setValue("Plugins/LADSPA_win32", plugins)
if not self.fContinueChecking:
return

if self.fCheckWin64:
tool = os.path.join(self.fPathBinaries, "carla-discovery-win64.exe")
plugins = self._checkLADSPA("WINDOWS", tool, not WINDOWS)
settingsDB.setValue("Plugins/LADSPA_win64", plugins)

settingsDB.sync()
if not self.fContinueChecking:
return

if self.fCheckDSSI:
if self.fCheckNative:
plugins = self._checkDSSI(OS, self.fToolNative)
settingsDB.setValue("Plugins/DSSI_native", plugins)
if not self.fContinueChecking:
return

if self.fCheckPosix32:
plugins = self._checkDSSI(OS, os.path.join(self.fPathBinaries, "carla-discovery-posix32"))
settingsDB.setValue("Plugins/DSSI_posix32", plugins)
if not self.fContinueChecking:
return

if self.fCheckPosix64:
plugins = self._checkDSSI(OS, os.path.join(self.fPathBinaries, "carla-discovery-posix64"))
settingsDB.setValue("Plugins/DSSI_posix64", plugins)
if not self.fContinueChecking:
return

if self.fCheckWin32:
tool = os.path.join(self.fPathBinaries, "carla-discovery-win32.exe")
plugins = self._checkDSSI("WINDOWS", tool, not WINDOWS)
settingsDB.setValue("Plugins/DSSI_win32", plugins)
if not self.fContinueChecking:
return

if self.fCheckWin64:
tool = os.path.join(self.fPathBinaries, "carla-discovery-win64.exe")
plugins = self._checkDSSI("WINDOWS", tool, not WINDOWS)
settingsDB.setValue("Plugins/DSSI_win64", plugins)

settingsDB.sync()
if not self.fContinueChecking:
return

if self.fCheckLV2:
plugins = self._checkCached(True)
settingsDB.setValue("Plugins/LV2", plugins)
settingsDB.sync()
if not self.fContinueChecking:
return

if self.fCheckVST2:
if self.fCheckNative:
plugins = self._checkVST2(OS, self.fToolNative)
settingsDB.setValue("Plugins/VST2_native", plugins)
if not self.fContinueChecking:
return

if self.fCheckPosix32:
plugins = self._checkVST2(OS, os.path.join(self.fPathBinaries, "carla-discovery-posix32"))
settingsDB.setValue("Plugins/VST2_posix32", plugins)
if not self.fContinueChecking:
return

if self.fCheckPosix64:
plugins = self._checkVST2(OS, os.path.join(self.fPathBinaries, "carla-discovery-posix64"))
settingsDB.setValue("Plugins/VST2_posix64", plugins)
if not self.fContinueChecking:
return

if self.fCheckWin32:
tool = os.path.join(self.fPathBinaries, "carla-discovery-win32.exe")
plugins = self._checkVST2("WINDOWS", tool, not WINDOWS)
settingsDB.setValue("Plugins/VST2_win32", plugins)
if not self.fContinueChecking:
return

if self.fCheckWin64:
tool = os.path.join(self.fPathBinaries, "carla-discovery-win64.exe")
plugins = self._checkVST2("WINDOWS", tool, not WINDOWS)
settingsDB.setValue("Plugins/VST2_win64", plugins)
if not self.fContinueChecking:
return

settingsDB.sync()
if not self.fContinueChecking:
return

if self.fCheckVST3:
if self.fCheckNative and (LINUX or MACOS or WINDOWS):
plugins = self._checkVST3(self.fToolNative)
settingsDB.setValue("Plugins/VST3_native", plugins)
if not self.fContinueChecking:
return

if self.fCheckPosix32:
plugins = self._checkVST3(os.path.join(self.fPathBinaries, "carla-discovery-posix32"))
settingsDB.setValue("Plugins/VST3_posix32", plugins)
if not self.fContinueChecking:
return

if self.fCheckPosix64:
plugins = self._checkVST3(os.path.join(self.fPathBinaries, "carla-discovery-posix64"))
settingsDB.setValue("Plugins/VST3_posix64", plugins)
if not self.fContinueChecking:
return

if self.fCheckWin32:
tool = os.path.join(self.fPathBinaries, "carla-discovery-win32.exe")
plugins = self._checkVST3(tool, not WINDOWS)
settingsDB.setValue("Plugins/VST3_win32", plugins)
if not self.fContinueChecking:
return

if self.fCheckWin64:
tool = os.path.join(self.fPathBinaries, "carla-discovery-win64.exe")
plugins = self._checkVST3(tool, not WINDOWS)
settingsDB.setValue("Plugins/VST3_win64", plugins)
if not self.fContinueChecking:
return

settingsDB.sync()
if not self.fContinueChecking:
return

if self.fCheckCLAP:
if self.fCheckNative:
plugins = self._checkCLAP(self.fToolNative)
settingsDB.setValue("Plugins/CLAP_native", plugins)
if not self.fContinueChecking:
return

if self.fCheckPosix32:
plugins = self._checkCLAP(os.path.join(self.fPathBinaries, "carla-discovery-posix32"))
settingsDB.setValue("Plugins/CLAP_posix32", plugins)
if not self.fContinueChecking:
return

if self.fCheckPosix64:
plugins = self._checkCLAP(os.path.join(self.fPathBinaries, "carla-discovery-posix64"))
settingsDB.setValue("Plugins/CLAP_posix64", plugins)
if not self.fContinueChecking:
return

if self.fCheckWin32:
tool = os.path.join(self.fPathBinaries, "carla-discovery-win32.exe")
plugins = self._checkCLAP(tool, not WINDOWS)
settingsDB.setValue("Plugins/CLAP_win32", plugins)
if not self.fContinueChecking:
return

if self.fCheckWin64:
tool = os.path.join(self.fPathBinaries, "carla-discovery-win64.exe")
plugins = self._checkCLAP(tool, not WINDOWS)
settingsDB.setValue("Plugins/CLAP_win64", plugins)
if not self.fContinueChecking:
return

settingsDB.sync()
if not self.fContinueChecking:
return

if self.fCheckAU:
if self.fCheckNative:
plugins = self._checkCached(False)
settingsDB.setValue("Plugins/AU", plugins)
settingsDB.sync()
if not self.fContinueChecking:
return

if self.fCheckPosix32:
plugins = self._checkAU(os.path.join(self.fPathBinaries, "carla-discovery-posix32"))
settingsDB.setValue("Plugins/AU_posix32", self.fAuPlugins)
if not self.fContinueChecking:
return

settingsDB.sync()
if not self.fContinueChecking:
return

if self.fCheckSF2:
settings = QSafeSettings("falkTX", "Carla2")
SF2_PATH = settings.value(CARLA_KEY_PATHS_SF2, CARLA_DEFAULT_SF2_PATH, list)
del settings

kits = self._checkKIT(SF2_PATH, "sf2")
settingsDB.setValue("Plugins/SF2", kits)
settingsDB.sync()
if not self.fContinueChecking:
return

if self.fCheckSFZ:
kits = self._checkSfzCached()
settingsDB.setValue("Plugins/SFZ", kits)
settingsDB.sync()

if self.fCheckJSFX:
kits = self._checkJsfxCached()
settingsDB.setValue("Plugins/JSFX", kits)
settingsDB.sync()

# -----------------------------------------------------------------------------------------------------------------
# private methods

def _checkLADSPA(self, OS, tool, isWine=False):
ladspaBinaries = []
ladspaPlugins = []

self._pluginLook(self.fLastCheckValue, "LADSPA plugins...")

settings = QSafeSettings("falkTX", "Carla2")
LADSPA_PATH = settings.value(CARLA_KEY_PATHS_LADSPA, CARLA_DEFAULT_LADSPA_PATH, list)
del settings

for iPATH in LADSPA_PATH:
binaries = findBinaries(iPATH, PLUGIN_LADSPA, OS)
for binary in binaries:
if binary not in ladspaBinaries:
ladspaBinaries.append(binary)

ladspaBinaries.sort()

if not self.fContinueChecking:
return ladspaPlugins

for i in range(len(ladspaBinaries)):
ladspa = ladspaBinaries[i]
percent = ( float(i) / len(ladspaBinaries) ) * self.fCurPercentValue
self._pluginLook((self.fLastCheckValue + percent) * 0.9, ladspa)

plugins = checkPluginLADSPA(ladspa, tool, self.fWineSettings if isWine else None)
if plugins:
ladspaPlugins.append(plugins)

if not self.fContinueChecking:
break

self.fLastCheckValue += self.fCurPercentValue
return ladspaPlugins

def _checkDSSI(self, OS, tool, isWine=False):
dssiBinaries = []
dssiPlugins = []

self._pluginLook(self.fLastCheckValue, "DSSI plugins...")

settings = QSafeSettings("falkTX", "Carla2")
DSSI_PATH = settings.value(CARLA_KEY_PATHS_DSSI, CARLA_DEFAULT_DSSI_PATH, list)
del settings

for iPATH in DSSI_PATH:
binaries = findBinaries(iPATH, PLUGIN_DSSI, OS)
for binary in binaries:
if binary not in dssiBinaries:
dssiBinaries.append(binary)

dssiBinaries.sort()

if not self.fContinueChecking:
return dssiPlugins

for i in range(len(dssiBinaries)):
dssi = dssiBinaries[i]
percent = ( float(i) / len(dssiBinaries) ) * self.fCurPercentValue
self._pluginLook(self.fLastCheckValue + percent, dssi)

plugins = checkPluginDSSI(dssi, tool, self.fWineSettings if isWine else None)
if plugins:
dssiPlugins.append(plugins)

if not self.fContinueChecking:
break

self.fLastCheckValue += self.fCurPercentValue
return dssiPlugins

def _checkVST2(self, OS, tool, isWine=False):
vst2Binaries = []
vst2Plugins = []

if MACOS and not isWine:
self._pluginLook(self.fLastCheckValue, "VST2 bundles...")
else:
self._pluginLook(self.fLastCheckValue, "VST2 plugins...")

settings = QSafeSettings("falkTX", "Carla2")
VST2_PATH = settings.value(CARLA_KEY_PATHS_VST2, CARLA_DEFAULT_VST2_PATH, list)
del settings

for iPATH in VST2_PATH:
if MACOS and not isWine:
binaries = findMacBundles(iPATH, PLUGIN_VST2)
else:
binaries = findBinaries(iPATH, PLUGIN_VST2, OS)
for binary in binaries:
if binary not in vst2Binaries:
vst2Binaries.append(binary)

vst2Binaries.sort()

if not self.fContinueChecking:
return vst2Plugins

for i in range(len(vst2Binaries)):
vst2 = vst2Binaries[i]
percent = ( float(i) / len(vst2Binaries) ) * self.fCurPercentValue
self._pluginLook(self.fLastCheckValue + percent, vst2)

plugins = checkPluginVST2(vst2, tool, self.fWineSettings if isWine else None)
if plugins:
vst2Plugins.append(plugins)

if not self.fContinueChecking:
break

self.fLastCheckValue += self.fCurPercentValue
return vst2Plugins

def _checkVST3(self, tool, isWine=False):
vst3Binaries = []
vst3Plugins = []

if MACOS and not isWine:
self._pluginLook(self.fLastCheckValue, "VST3 bundles...")
else:
self._pluginLook(self.fLastCheckValue, "VST3 plugins...")

settings = QSafeSettings("falkTX", "Carla2")
VST3_PATH = settings.value(CARLA_KEY_PATHS_VST3, CARLA_DEFAULT_VST3_PATH, list)
del settings

for iPATH in VST3_PATH:
if MACOS and not isWine:
binaries = findMacBundles(iPATH, PLUGIN_VST3)
else:
binaries = findVST3Binaries(iPATH)
for binary in binaries:
if binary not in vst3Binaries:
vst3Binaries.append(binary)

vst3Binaries.sort()

if not self.fContinueChecking:
return vst3Plugins

for i in range(len(vst3Binaries)):
vst3 = vst3Binaries[i]
percent = ( float(i) / len(vst3Binaries) ) * self.fCurPercentValue
self._pluginLook(self.fLastCheckValue + percent, vst3)

plugins = checkPluginVST3(vst3, tool, self.fWineSettings if isWine else None)
if plugins:
vst3Plugins.append(plugins)

if not self.fContinueChecking:
break

self.fLastCheckValue += self.fCurPercentValue
return vst3Plugins

def _checkCLAP(self, tool, isWine=False):
clapBinaries = []
clapPlugins = []

self._pluginLook(self.fLastCheckValue, "CLAP plugins...")

settings = QSafeSettings("falkTX", "Carla2")
CLAP_PATH = settings.value(CARLA_KEY_PATHS_CLAP, CARLA_DEFAULT_CLAP_PATH, list)
del settings

for iPATH in CLAP_PATH:
if MACOS and not isWine:
binaries = findMacBundles(iPATH, PLUGIN_CLAP)
else:
binaries = findCLAPBinaries(iPATH)
for binary in binaries:
if binary not in clapBinaries:
clapBinaries.append(binary)

clapBinaries.sort()

if not self.fContinueChecking:
return clapPlugins

for i in range(len(clapBinaries)):
clap = clapBinaries[i]
percent = ( float(i) / len(clapBinaries) ) * self.fCurPercentValue
self._pluginLook(self.fLastCheckValue + percent, clap)

plugins = checkPluginCLAP(clap, tool, self.fWineSettings if isWine else None)
if plugins:
clapPlugins.append(plugins)

if not self.fContinueChecking:
break

self.fLastCheckValue += self.fCurPercentValue
return clapPlugins

def _checkAU(self, tool):
auPlugins = []

plugins = checkAllPluginsAU(tool)
if plugins:
auPlugins.append(plugins)

self.fLastCheckValue += self.fCurPercentValue
return auPlugins

def _checkKIT(self, kitPATH, kitExtension):
kitFiles = []
kitPlugins = []

for iPATH in kitPATH:
files = findFilenames(iPATH, kitExtension)
for file_ in files:
if file_ not in kitFiles:
kitFiles.append(file_)

kitFiles.sort()

if not self.fContinueChecking:
return kitPlugins

for i in range(len(kitFiles)):
kit = kitFiles[i]
percent = ( float(i) / len(kitFiles) ) * self.fCurPercentValue
self._pluginLook(self.fLastCheckValue + percent, kit)

if kitExtension == "sf2":
plugins = checkFileSF2(kit, self.fToolNative)
else:
plugins = None

if plugins:
kitPlugins.append(plugins)

if not self.fContinueChecking:
break

self.fLastCheckValue += self.fCurPercentValue
return kitPlugins

def _checkCached(self, isLV2):
if isLV2:
settings = QSafeSettings("falkTX", "Carla2")
PLUG_PATH = splitter.join(settings.value(CARLA_KEY_PATHS_LV2, CARLA_DEFAULT_LV2_PATH, list))
del settings
PLUG_TEXT = "LV2"
PLUG_TYPE = PLUGIN_LV2
else: # AU
PLUG_PATH = ""
PLUG_TEXT = "AU"
PLUG_TYPE = PLUGIN_AU

plugins = []
self._pluginLook(self.fLastCheckValue, f"{PLUG_TEXT} plugins...")

if not isLV2:
gCarla.utils.juce_init()

count = gCarla.utils.get_cached_plugin_count(PLUG_TYPE, PLUG_PATH)

if not self.fContinueChecking:
return plugins

for i in range(count):
descInfo = gCarla.utils.get_cached_plugin_info(PLUG_TYPE, i)

percent = ( float(i) / count ) * self.fCurPercentValue
self._pluginLook(self.fLastCheckValue + percent, descInfo['label'])

if not descInfo['valid']:
continue

plugins.append(checkPluginCached(descInfo, PLUG_TYPE))

if not self.fContinueChecking:
break

if not isLV2:
gCarla.utils.juce_cleanup()

self.fLastCheckValue += self.fCurPercentValue
return plugins

def _checkSfzCached(self):
settings = QSafeSettings("falkTX", "Carla2")
PLUG_PATH = splitter.join(settings.value(CARLA_KEY_PATHS_SFZ, CARLA_DEFAULT_SFZ_PATH, list))
del settings

sfzKits = []
self._pluginLook(self.fLastCheckValue, "SFZ kits...")

count = gCarla.utils.get_cached_plugin_count(PLUGIN_SFZ, PLUG_PATH)

if not self.fContinueChecking:
return sfzKits

for i in range(count):
descInfo = gCarla.utils.get_cached_plugin_info(PLUGIN_SFZ, i)

percent = ( float(i) / count ) * self.fCurPercentValue
self._pluginLook(self.fLastCheckValue + percent, descInfo['label'])

if not descInfo['valid']:
continue

sfzKits.append(checkPluginCached(descInfo, PLUGIN_SFZ))

if not self.fContinueChecking:
break

self.fLastCheckValue += self.fCurPercentValue
return sfzKits

def _checkJsfxCached(self):
settings = QSafeSettings("falkTX", "Carla2")
PLUG_PATH = splitter.join(settings.value(CARLA_KEY_PATHS_JSFX, CARLA_DEFAULT_JSFX_PATH, list))
del settings

jsfxPlugins = []
self._pluginLook(self.fLastCheckValue, "JSFX plugins...")

count = gCarla.utils.get_cached_plugin_count(PLUGIN_JSFX, PLUG_PATH)

if not self.fContinueChecking:
return jsfxPlugins

for i in range(count):
descInfo = gCarla.utils.get_cached_plugin_info(PLUGIN_JSFX, i)

percent = ( float(i) / count ) * self.fCurPercentValue
self._pluginLook(self.fLastCheckValue + percent, descInfo['label'])

if not descInfo['valid']:
continue

jsfxPlugins.append(checkPluginCached(descInfo, PLUGIN_JSFX))

if not self.fContinueChecking:
break

self.fLastCheckValue += self.fCurPercentValue
return jsfxPlugins

def _pluginLook(self, percent, plugin):
self.pluginLook.emit(percent, plugin)

# ---------------------------------------------------------------------------------------------------------------------

+ 1363
- 1365
source/frontend/pluginlist/pluginlistdialog.cpp
File diff suppressed because it is too large
View File


+ 41
- 51
source/frontend/pluginlist/pluginlistdialog.hpp View File

@@ -1,18 +1,7 @@
/*
* Carla plugin host
* 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.
* SPDX-License-Identifier: GPL-2.0-or-later
*/

#pragma once
@@ -35,9 +24,7 @@
# pragma GCC diagnostic pop
#endif

#include "CarlaBackend.h"

static constexpr const uint PLUGIN_QUERY_API_VERSION = 12;
#include "ui_pluginlistdialog.h"

struct HostSettings {
bool showPluginBridges;
@@ -45,73 +32,76 @@ struct HostSettings {
bool useSystemIcons;
};

struct PluginInfo {
uint API;
CARLA_BACKEND_NAMESPACE::BinaryType build;
CARLA_BACKEND_NAMESPACE::PluginType type;
uint hints;
QString category;
QString filename;
QString name;
QString label;
QString maker;
uint64_t uniqueId;
uint audioIns;
uint audioOuts;
uint cvIns;
uint cvOuts;
uint midiIns;
uint midiOuts;
uint parametersIns;
uint parametersOuts;
};
class QSafeSettings;
typedef struct _CarlaPluginDiscoveryInfo CarlaPluginDiscoveryInfo;
struct PluginInfo;

// --------------------------------------------------------------------------------------------------------------------
// Plugin List Dialog

class PluginListDialog : public QDialog
{
struct Self;
Self& self;
enum TableIndex {
TW_FAVORITE,
TW_NAME,
TW_LABEL,
TW_MAKER,
TW_BINARY,
};

enum UserRoles {
UR_PLUGIN_INFO = 1,
UR_SEARCH_TEXT,
};

struct PrivateData;
PrivateData *const p;

Ui_PluginListDialog ui;

// ----------------------------------------------------------------------------------------------------------------
// public methods

public:
explicit PluginListDialog(QWidget* parent, const HostSettings& hostSettings);
~PluginListDialog() override;

// ----------------------------------------------------------------------------------------------------------------
// public methods

const PluginInfo& getSelectedPluginInfo() const;
void addPluginInfo(const CarlaPluginDiscoveryInfo* info, const char* sha1sum);
bool checkPluginCache(const char* filename, const char* sha1sum);

// ----------------------------------------------------------------------------------------------------------------
// protected methods

protected:
void done(int) override;
void showEvent(QShowEvent*) override;
void timerEvent(QTimerEvent*) override;

// ----------------------------------------------------------------------------------------------------------------
// private methods

private:
void addPluginsToTable();
void loadSettings();

// ----------------------------------------------------------------------------------------------------------------
// private slots

private Q_SLOTS:
void slot_cellClicked(int row, int column);
void slot_cellDoubleClicked(int row, int column);
void slot_focusSearchFieldAndSelectAll();
void slot_addPlugin();
void slot_checkPlugin(int row);
void slot_checkFilters();
void slot_checkFiltersCategoryAll(bool clicked);
void slot_checkFiltersCategorySpecific(bool clicked);
void slot_refreshPlugins();
void slot_clearFilters();
void slot_saveSettings();
void cellClicked(int row, int column);
void cellDoubleClicked(int row, int column);
void focusSearchFieldAndSelectAll();
void checkFilters();
void checkFiltersCategoryAll(bool clicked);
void checkFiltersCategorySpecific(bool clicked);
void clearFilters();
void checkPlugin(int row);
void refreshPlugins();
void refreshPluginsStart();
void refreshPluginsStop();
void refreshPluginsSkip();
void saveSettings();
};

// --------------------------------------------------------------------------------------------------------------------

+ 0
- 1000
source/frontend/pluginlist/pluginlistdialog.py
File diff suppressed because it is too large
View File


+ 27
- 20
source/frontend/pluginlist/pluginlistdialog.ui View File

@@ -35,7 +35,7 @@
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="tabBarAutoHide" stdset="0">
<property name="tabBarAutoHide">
<bool>true</bool>
</property>
<widget class="QWidget" name="tw_reqs">
@@ -133,7 +133,7 @@
<string>&amp;Add Plugin</string>
</property>
<property name="icon">
<iconset resource="../resources.qrc">
<iconset resource="../../../resources/resources.qrc">
<normaloff>:/16x16/list-add.svgz</normaloff>:/16x16/list-add.svgz</iconset>
</property>
</widget>
@@ -144,7 +144,7 @@
<string>Cancel</string>
</property>
<property name="icon">
<iconset resource="../resources.qrc">
<iconset resource="../../../resources/resources.qrc">
<normaloff>:/16x16/dialog-cancel.svgz</normaloff>:/16x16/dialog-cancel.svgz</iconset>
</property>
</widget>
@@ -155,7 +155,7 @@
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QLineEdit" name="lineEdit">
<property name="clearButtonEnabled" stdset="0">
<property name="clearButtonEnabled">
<bool>true</bool>
</property>
</widget>
@@ -166,7 +166,7 @@
<string>Refresh</string>
</property>
<property name="icon">
<iconset resource="../resources.qrc">
<iconset resource="../../../resources/resources.qrc">
<normaloff>:/16x16/view-refresh.svgz</normaloff>:/16x16/view-refresh.svgz</iconset>
</property>
</widget>
@@ -177,7 +177,7 @@
<string>Reset filters</string>
</property>
<property name="icon">
<iconset resource="../resources.qrc">
<iconset resource="../../../resources/resources.qrc">
<normaloff>:/16x16/edit-clear.svgz</normaloff>:/16x16/edit-clear.svgz</iconset>
</property>
</widget>
@@ -186,7 +186,7 @@
</item>
<item row="1" column="2" rowspan="3">
<widget class="QTabWidget" name="tab_info">
<property name="tabBarAutoHide" stdset="0">
<property name="tabBarAutoHide">
<bool>true</bool>
</property>
<widget class="QWidget" name="tw_info">
@@ -582,12 +582,12 @@
<attribute name="verticalHeaderVisible">
<bool>false</bool>
</attribute>
<attribute name="verticalHeaderDefaultSectionSize">
<number>22</number>
</attribute>
<attribute name="verticalHeaderMinimumSectionSize">
<number>12</number>
</attribute>
<attribute name="verticalHeaderDefaultSectionSize">
<number>22</number>
</attribute>
<column>
<property name="text">
<string notr="true"/>
@@ -599,7 +599,7 @@
<string notr="true"/>
</property>
<property name="icon">
<iconset resource="../resources.qrc">
<iconset resource="../../../resources/resources.qrc">
<normaloff>:/16x16/bookmarks.svgz</normaloff>:/16x16/bookmarks.svgz</iconset>
</property>
</column>
@@ -635,8 +635,8 @@
<rect>
<x>0</x>
<y>0</y>
<width>158</width>
<height>237</height>
<width>135</width>
<height>282</height>
</rect>
</property>
<attribute name="label">
@@ -733,8 +733,8 @@
<rect>
<x>0</x>
<y>0</y>
<width>158</width>
<height>156</height>
<width>113</width>
<height>120</height>
</rect>
</property>
<attribute name="label">
@@ -785,6 +785,14 @@
</layout>
</widget>
<widget class="QWidget" name="p_category">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>100</width>
<height>282</height>
</rect>
</property>
<attribute name="label">
<string>Category</string>
</attribute>
@@ -879,8 +887,8 @@
<rect>
<x>0</x>
<y>0</y>
<width>158</width>
<height>130</height>
<width>124</width>
<height>93</height>
</rect>
</property>
<attribute name="label">
@@ -967,8 +975,7 @@
<tabstop>tab_info</tabstop>
</tabstops>
<resources>
<include location="../resources.qrc"/>
<include location="../../../resources/resources.qrc"/>
</resources>
<connections>
</connections>
<connections/>
</ui>

+ 0
- 590
source/frontend/pluginlist/pluginlistrefreshdialog.cpp View File

@@ -1,590 +0,0 @@
/*
* Carla plugin host
* Copyright (C) 2011-2022 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.
*/

#include "pluginlistrefreshdialog.hpp"

#ifdef __clang__
# pragma clang diagnostic push
# pragma clang diagnostic ignored "-Wdeprecated-copy-with-user-provided-copy"
# pragma clang diagnostic ignored "-Wdeprecated-register"
#elif defined(__GNUC__) && __GNUC__ >= 8
# pragma GCC diagnostic push
# pragma GCC diagnostic ignored "-Wclass-memaccess"
# pragma GCC diagnostic ignored "-Wdeprecated-copy"
#endif

#include "ui_pluginlistrefreshdialog.h"
#include <QtCore/QFileInfo>
#include <QtWidgets/QPushButton>

#ifdef __clang__
# pragma clang diagnostic pop
#elif defined(__GNUC__) && __GNUC__ >= 8
# pragma GCC diagnostic pop
#endif

#include "qsafesettings.hpp"

#include "CarlaFrontend.h"
#include "CarlaUtils.h"

#include <cstring>

static bool hasFeature(const char* const* const features, const char* const feature)
{
if (features == nullptr)
return false;

for (int i=0; features[i] != nullptr; ++i)
{
if (std::strcmp(features[i], feature) == 0)
return true;
}

return false;
}

// --------------------------------------------------------------------------------------------------------------------
// Jack Application Dialog

struct PluginListRefreshDialog::Self {
Ui_PluginRefreshW ui;
QPixmap fIconYes;
QPixmap fIconNo;

Self() {}

static Self& create()
{
Self* const self = new Self();
return *self;
}
};

PluginListRefreshDialog::PluginListRefreshDialog(QWidget* const parent, const bool useSystemIcons)
: QDialog(parent),
self(Self::create())
{
self.ui.setupUi(this);

// ----------------------------------------------------------------------------------------------------------------
// Internal stuff

#ifdef CARLA_OS_WIN
#define APP_EXT ".exe"
#else
#define APP_EXT ""
#endif

QString hostPathBinaries;
const bool hasNative = QFileInfo::exists(QCarlaString(hostPathBinaries) + CARLA_OS_SEP_STR "carla-discovery-native" APP_EXT);
const bool hasPosix32 = QFileInfo::exists(QCarlaString(hostPathBinaries) + CARLA_OS_SEP_STR "carla-discovery-posix32");
const bool hasPosix64 = QFileInfo::exists(QCarlaString(hostPathBinaries) + CARLA_OS_SEP_STR "carla-discovery-posix64");
const bool hasWin32 = QFileInfo::exists(QCarlaString(hostPathBinaries) + CARLA_OS_SEP_STR "carla-discovery-win32.exe");
const bool hasWin64 = QFileInfo::exists(QCarlaString(hostPathBinaries) + CARLA_OS_SEP_STR "carla-discovery-win64.exe");

// self.fThread = SearchPluginsThread(self, host.pathBinaries)

// ----------------------------------------------------------------------------------------------------------------
// Set-up Icons

if (useSystemIcons)
{
// self.ui.b_start->setIcon(getIcon("arrow-right", 16, "svgz"));
// self.ui.b_close->setIcon(getIcon("window-close", 16, "svgz"));
// if QT_VERSION >= 0x50600:
// size = int(16 * self.devicePixelRatioF())
// else:
// size = 16
// self.fIconYes = QPixmap(getIcon('dialog-ok-apply', 16, 'svgz').pixmap(size))
// self.fIconNo = QPixmap(getIcon('dialog-error', 16, 'svgz').pixmap(size))
}
else
{
self.fIconYes = QPixmap(":/16x16/dialog-ok-apply.svgz");
self.fIconNo = QPixmap(":/16x16/dialog-error.svgz");
}

// ----------------------------------------------------------------------------------------------------------------
// UI setup

// FIXME remove LRDF
self.ui.ico_rdflib->setPixmap(self.fIconNo);

self.ui.b_skip->hide();

#if defined(CARLA_OS_HAIKU)
self.ui.ch_posix32->setText("Haiku 32bit");
self.ui.ch_posix64->setText("Haiku 64bit");
#elif defined(CARLA_OS_LINUX)
self.ui.ch_posix32->setText("Linux 32bit");
self.ui.ch_posix64->setText("Linux 64bit");
#elif defined(CARLA_OS_MAC)
self.ui.ch_posix32->setText("MacOS 32bit");
self.ui.ch_posix64->setText("MacOS 64bit");
#endif

#ifndef CARLA_OS_WIN
if (hasPosix32)
{
self.ui.ico_posix32->setPixmap(self.fIconYes);
}
else
#endif
{
self.ui.ico_posix32->setPixmap(self.fIconNo);
self.ui.ch_posix32->setEnabled(false);
}

#ifndef CARLA_OS_WIN
if (hasPosix64)
{
self.ui.ico_posix64->setPixmap(self.fIconYes);
}
else
#endif
{
self.ui.ico_posix64->setPixmap(self.fIconNo);
self.ui.ch_posix64->setEnabled(false);
}

if (hasWin32)
{
self.ui.ico_win32->setPixmap(self.fIconYes);
}
else
{
self.ui.ico_win32->setPixmap(self.fIconNo);
self.ui.ch_win32->setEnabled(false);
}

if (hasWin64)
{
self.ui.ico_win64->setPixmap(self.fIconYes);
}
else
{
self.ui.ico_win64->setPixmap(self.fIconNo);
self.ui.ch_win64->setEnabled(false);
}

bool hasNonNative;

#if defined(CARLA_OS_WIN)
#ifdef CARLA_OS_64BIT
hasNonNative = hasWin32;
self.ui.ch_win64->setEnabled(false);
self.ui.ch_win64->setVisible(false);
self.ui.ico_win64->setVisible(false);
self.ui.label_win64->setVisible(false);
#else
hasNonNative = hasWin64;
self.ui.ch_win32->setEnabled(false);
self.ui.ch_win32->setVisible(false);
self.ui.ico_win32->setVisible(false);
self.ui.label_win32->setVisible(false);
#endif

self.ui.ch_posix32->setEnabled(false);
self.ui.ch_posix32->setVisible(false);
self.ui.ch_posix64->setEnabled(false);
self.ui.ch_posix64->setVisible(false);
self.ui.ico_posix32->hide();
self.ui.ico_posix64->hide();
self.ui.label_posix32->hide();
self.ui.label_posix64->hide();
self.ui.ico_rdflib->hide();
self.ui.label_rdflib->hide();
#elif defined(CARLA_OS_64BIT)
hasNonNative = hasPosix32 || hasWin32 || hasWin64;
self.ui.ch_posix64->setEnabled(false);
self.ui.ch_posix64->setVisible(false);
self.ui.ico_posix64->setVisible(false);
self.ui.label_posix64->setVisible(false);
#else
hasNonNative = hasPosix64 || hasWin32 || hasWin64;
self.ui.ch_posix32->setEnabled(false);
self.ui.ch_posix32->setVisible(false);
self.ui.ico_posix32->setVisible(false);
self.ui.label_posix32->setVisible(false);
#endif

#ifdef CARLA_OS_MAC
setWindowModality(Qt::WindowModal);
#else
self.ui.ch_au->setEnabled(false);
self.ui.ch_au->setVisible(false);
#endif

if (hasNative)
{
self.ui.ico_native->setPixmap(self.fIconYes);
}
else
{
self.ui.ico_native->setPixmap(self.fIconNo);
self.ui.ch_native->setEnabled(false);
self.ui.ch_sf2->setEnabled(false);
if (! hasNonNative)
{
self.ui.ch_ladspa->setEnabled(false);
self.ui.ch_dssi->setEnabled(false);
self.ui.ch_vst->setEnabled(false);
self.ui.ch_vst3->setEnabled(false);
self.ui.ch_clap->setEnabled(false);
}
}

// TODO
// if (! hasLoadedLv2Plugins)
self.ui.lv2_restart_notice->hide();

setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);

// ----------------------------------------------------------------------------------------------------------------
// Load settings

loadSettings();

// ----------------------------------------------------------------------------------------------------------------
// Hide bridges if disabled

// TODO
bool showPluginBridges = true;
bool showWineBridges = true;

#ifdef CARLA_OS_WIN
#ifndef CARLA_OS_64BIT
// NOTE: We Assume win32 carla build will not run win64 plugins
showPluginBridges = false;
#endif
showWineBridges = false;
#endif

if (! showPluginBridges)
{
self.ui.ch_native->setChecked(true);
self.ui.ch_native->setEnabled(false);
self.ui.ch_native->setVisible(false);
self.ui.ch_posix32->setChecked(false);
self.ui.ch_posix32->setEnabled(false);
self.ui.ch_posix32->setVisible(false);
self.ui.ch_posix64->setChecked(false);
self.ui.ch_posix64->setEnabled(false);
self.ui.ch_posix64->setVisible(false);
self.ui.ch_win32->setChecked(false);
self.ui.ch_win32->setEnabled(false);
self.ui.ch_win32->setVisible(false);
self.ui.ch_win64->setChecked(false);
self.ui.ch_win64->setEnabled(false);
self.ui.ch_win64->setVisible(false);
self.ui.ico_posix32->hide();
self.ui.ico_posix64->hide();
self.ui.ico_win32->hide();
self.ui.ico_win64->hide();
self.ui.label_posix32->hide();
self.ui.label_posix64->hide();
self.ui.label_win32->hide();
self.ui.label_win64->hide();
self.ui.sep_format->hide();
}
else if (! showWineBridges)
{
self.ui.ch_win32->setChecked(false);
self.ui.ch_win32->setEnabled(false);
self.ui.ch_win32->setVisible(false);
self.ui.ch_win64->setChecked(false);
self.ui.ch_win64->setEnabled(false);
self.ui.ch_win64->setVisible(false);
self.ui.ico_win32->hide();
self.ui.ico_win64->hide();
self.ui.label_win32->hide();
self.ui.label_win64->hide();
}

// Disable non-supported features
const char* const* const features = carla_get_supported_features();

if (! hasFeature(features, "sf2"))
{
self.ui.ch_sf2->setChecked(false);
self.ui.ch_sf2->setEnabled(false);
}

#ifdef CARLA_OS_MAC
if (! hasFeature(features, "juce"))
{
self.ui.ch_au->setChecked(false);
self.ui.ch_au->setEnabled(false);
}
#endif

// ----------------------------------------------------------------------------------------------------------------
// Resize to minimum size, as it's very likely UI stuff was hidden

resize(minimumSize());

// ----------------------------------------------------------------------------------------------------------------
// Set-up connections

connect(this, &QDialog::finished,
this, &PluginListRefreshDialog::slot_saveSettings);
// self.ui.b_start.clicked.connect(self.slot_start)
// self.ui.b_skip.clicked.connect(self.slot_skip)
// self.ui.ch_native.clicked.connect(self.slot_checkTools)
// self.ui.ch_posix32.clicked.connect(self.slot_checkTools)
// self.ui.ch_posix64.clicked.connect(self.slot_checkTools)
// self.ui.ch_win32.clicked.connect(self.slot_checkTools)
// self.ui.ch_win64.clicked.connect(self.slot_checkTools)
// self.ui.ch_ladspa.clicked.connect(self.slot_checkTools)
// self.ui.ch_dssi.clicked.connect(self.slot_checkTools)
// self.ui.ch_lv2.clicked.connect(self.slot_checkTools)
// self.ui.ch_vst.clicked.connect(self.slot_checkTools)
// self.ui.ch_vst3.clicked.connect(self.slot_checkTools)
// self.ui.ch_clap.clicked.connect(self.slot_checkTools)
// self.ui.ch_au.clicked.connect(self.slot_checkTools)
// self.ui.ch_sf2.clicked.connect(self.slot_checkTools)
// self.ui.ch_sfz.clicked.connect(self.slot_checkTools)
// self.ui.ch_jsfx.clicked.connect(self.slot_checkTools)
// self.fThread.pluginLook.connect(self.slot_handlePluginLook)
// self.fThread.finished.connect(self.slot_handlePluginThreadFinished)

// connect(this, &QDialog::finished,
// this, &JackAppDialog::slot_saveSettings);
// connect(self.ui.cb_session_mgr, static_cast<void(QComboBox::*)(int)>(&QComboBox::currentIndexChanged),
// this, &JackAppDialog::slot_sessionManagerChanged);
// connect(self.ui.le_command, &QLineEdit::textChanged,
// this, &JackAppDialog::slot_commandChanged);

// ----------------------------------------------------------------------------------------------------------------
// Post-connect setup

slot_checkTools();
}

PluginListRefreshDialog::~PluginListRefreshDialog()
{
delete &self;
}

// -----------------------------------------------------------------------------------------------------------------
// public methods

// -----------------------------------------------------------------------------------------------------------------
// protected methods

void PluginListRefreshDialog::closeEvent(QCloseEvent* const event)
{
/*
if (self.fThread.isRunning())
{
self.fThread.stop();
killDiscovery();
#self.fThread.terminate();
self.fThread.wait();
}

if (self.fThread.hasSomethingChanged())
accept();
else
*/
reject();

QDialog::closeEvent(event);
}

// -----------------------------------------------------------------------------------------------------------------
// private methods

void PluginListRefreshDialog::loadSettings()
{
const QSafeSettings settings("falkTX", "CarlaRefresh2");

bool check;

check = settings.valueBool("PluginDatabase/SearchLADSPA", true) and self.ui.ch_ladspa->isEnabled();
self.ui.ch_ladspa->setChecked(check);

check = settings.valueBool("PluginDatabase/SearchDSSI", true) and self.ui.ch_dssi->isEnabled();
self.ui.ch_dssi->setChecked(check);

check = settings.valueBool("PluginDatabase/SearchLV2", true) and self.ui.ch_lv2->isEnabled();
self.ui.ch_lv2->setChecked(check);

check = settings.valueBool("PluginDatabase/SearchVST2", true) and self.ui.ch_vst->isEnabled();
self.ui.ch_vst->setChecked(check);

check = settings.valueBool("PluginDatabase/SearchVST3", true) and self.ui.ch_vst3->isEnabled();
self.ui.ch_vst3->setChecked(check);

check = settings.valueBool("PluginDatabase/SearchCLAP", true) and self.ui.ch_clap->isEnabled();
self.ui.ch_clap->setChecked(check);

#ifdef CARLA_OS_MAC
check = settings.valueBool("PluginDatabase/SearchAU", true) and self.ui.ch_au->isEnabled();
#else
check = false;
#endif
self.ui.ch_au->setChecked(check);

check = settings.valueBool("PluginDatabase/SearchSF2", false) and self.ui.ch_sf2->isEnabled();
self.ui.ch_sf2->setChecked(check);

check = settings.valueBool("PluginDatabase/SearchSFZ", false) and self.ui.ch_sfz->isEnabled();
self.ui.ch_sfz->setChecked(check);

check = settings.valueBool("PluginDatabase/SearchJSFX", true) and self.ui.ch_jsfx->isEnabled();
self.ui.ch_jsfx->setChecked(check);

check = settings.valueBool("PluginDatabase/SearchNative", true) and self.ui.ch_native->isEnabled();
self.ui.ch_native->setChecked(check);

check = settings.valueBool("PluginDatabase/SearchPOSIX32", false) and self.ui.ch_posix32->isEnabled();
self.ui.ch_posix32->setChecked(check);

check = settings.valueBool("PluginDatabase/SearchPOSIX64", false) and self.ui.ch_posix64->isEnabled();
self.ui.ch_posix64->setChecked(check);

check = settings.valueBool("PluginDatabase/SearchWin32", false) and self.ui.ch_win32->isEnabled();
self.ui.ch_win32->setChecked(check);

check = settings.valueBool("PluginDatabase/SearchWin64", false) and self.ui.ch_win64->isEnabled();
self.ui.ch_win64->setChecked(check);

self.ui.ch_do_checks->setChecked(settings.valueBool("PluginDatabase/DoChecks", false));
}

// -----------------------------------------------------------------------------------------------------------------
// private slots

void PluginListRefreshDialog::slot_saveSettings()
{
QSafeSettings settings("falkTX", "CarlaRefresh2");
settings.setValue("PluginDatabase/SearchLADSPA", self.ui.ch_ladspa->isChecked());
settings.setValue("PluginDatabase/SearchDSSI", self.ui.ch_dssi->isChecked());
settings.setValue("PluginDatabase/SearchLV2", self.ui.ch_lv2->isChecked());
settings.setValue("PluginDatabase/SearchVST2", self.ui.ch_vst->isChecked());
settings.setValue("PluginDatabase/SearchVST3", self.ui.ch_vst3->isChecked());
settings.setValue("PluginDatabase/SearchCLAP", self.ui.ch_clap->isChecked());
settings.setValue("PluginDatabase/SearchAU", self.ui.ch_au->isChecked());
settings.setValue("PluginDatabase/SearchSF2", self.ui.ch_sf2->isChecked());
settings.setValue("PluginDatabase/SearchSFZ", self.ui.ch_sfz->isChecked());
settings.setValue("PluginDatabase/SearchJSFX", self.ui.ch_jsfx->isChecked());
settings.setValue("PluginDatabase/SearchNative", self.ui.ch_native->isChecked());
settings.setValue("PluginDatabase/SearchPOSIX32", self.ui.ch_posix32->isChecked());
settings.setValue("PluginDatabase/SearchPOSIX64", self.ui.ch_posix64->isChecked());
settings.setValue("PluginDatabase/SearchWin32", self.ui.ch_win32->isChecked());
settings.setValue("PluginDatabase/SearchWin64", self.ui.ch_win64->isChecked());
settings.setValue("PluginDatabase/DoChecks", self.ui.ch_do_checks->isChecked());
}

void PluginListRefreshDialog::slot_start()
{
self.ui.progressBar->setMinimum(0);
self.ui.progressBar->setMaximum(100);
self.ui.progressBar->setValue(0);
self.ui.b_start->setEnabled(false);
self.ui.b_skip->setVisible(true);
self.ui.b_close->setVisible(false);
self.ui.group_types->setEnabled(false);
self.ui.group_options->setEnabled(false);

// if gCarla.utils:
// if self.ui.ch_do_checks.isChecked():
// gCarla.utils.unsetenv("CARLA_DISCOVERY_NO_PROCESSING_CHECKS")
// else:
// gCarla.utils.setenv("CARLA_DISCOVERY_NO_PROCESSING_CHECKS", "true")
//
// native, posix32, posix64, win32, win64 = (self.ui.ch_native.isChecked(),
// self.ui.ch_posix32.isChecked(), self.ui.ch_posix64.isChecked(),
// self.ui.ch_win32.isChecked(), self.ui.ch_win64.isChecked())
//
// ladspa, dssi, lv2, vst, vst3, clap, au, sf2, sfz, jsfx = (self.ui.ch_ladspa.isChecked(), self.ui.ch_dssi.isChecked(),
// self.ui.ch_lv2.isChecked(), self.ui.ch_vst.isChecked(),
// self.ui.ch_vst3.isChecked(), self.ui.ch_clap.isChecked(),
// self.ui.ch_au.isChecked(), self.ui.ch_sf2.isChecked(),
// self.ui.ch_sfz.isChecked(), self.ui.ch_jsfx.isChecked())
//
// self.fThread.setSearchBinaryTypes(native, posix32, posix64, win32, win64)
// self.fThread.setSearchPluginTypes(ladspa, dssi, lv2, vst, vst3, clap, au, sf2, sfz, jsfx)
// self.fThread.start()
}

void PluginListRefreshDialog::slot_skip()
{
// killDiscovery();
}

void PluginListRefreshDialog::slot_checkTools()
{
const bool enabled1 = self.ui.ch_native->isChecked()
|| self.ui.ch_posix32->isChecked()
|| self.ui.ch_posix64->isChecked()
|| self.ui.ch_win32->isChecked()
|| self.ui.ch_win64->isChecked();

const bool enabled2 = self.ui.ch_ladspa->isChecked()
|| self.ui.ch_dssi->isChecked()
|| self.ui.ch_lv2->isChecked()
|| self.ui.ch_vst->isChecked()
|| self.ui.ch_vst3->isChecked()
|| self.ui.ch_clap->isChecked()
|| self.ui.ch_au->isChecked()
|| self.ui.ch_sf2->isChecked()
|| self.ui.ch_sfz->isChecked()
|| self.ui.ch_jsfx->isChecked();

self.ui.b_start->setEnabled(enabled1 and enabled2);
}

void PluginListRefreshDialog::slot_handlePluginLook(const int percent, const QString plugin)
{
self.ui.progressBar->setFormat(plugin);
self.ui.progressBar->setValue(percent);
}

void PluginListRefreshDialog::slot_handlePluginThreadFinished()
{
self.ui.progressBar->setMinimum(0);
self.ui.progressBar->setMaximum(1);
self.ui.progressBar->setValue(1);
self.ui.progressBar->setFormat(tr("Done"));
self.ui.b_start->setEnabled(true);
self.ui.b_skip->setVisible(false);
self.ui.b_close->setVisible(true);
self.ui.group_types->setEnabled(true);
self.ui.group_options->setEnabled(true);
}

// --------------------------------------------------------------------------------------------------------------------

const PluginListRefreshDialogResults*
carla_frontend_createAndExecPluginListRefreshDialog(void* const parent, const bool useSystemIcons)
{
PluginListRefreshDialog gui(reinterpret_cast<QWidget*>(parent), useSystemIcons);

if (gui.exec())
{
static PluginListRefreshDialogResults ret = {};

return &ret;
}

return nullptr;
}

// --------------------------------------------------------------------------------------------------------------------

+ 0
- 81
source/frontend/pluginlist/pluginlistrefreshdialog.hpp View File

@@ -1,81 +0,0 @@
/*
* Carla plugin host
* Copyright (C) 2011-2022 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.
*/

#pragma once

#ifdef __clang__
# pragma clang diagnostic push
# pragma clang diagnostic ignored "-Wdeprecated-copy-with-user-provided-copy"
# pragma clang diagnostic ignored "-Wdeprecated-register"
#elif defined(__GNUC__) && __GNUC__ >= 8
# pragma GCC diagnostic push
# pragma GCC diagnostic ignored "-Wclass-memaccess"
# pragma GCC diagnostic ignored "-Wdeprecated-copy"
#endif

#include <QtWidgets/QDialog>

#ifdef __clang__
# pragma clang diagnostic pop
#elif defined(__GNUC__) && __GNUC__ >= 8
# pragma GCC diagnostic pop
#endif

#include "qcarlastring.hpp"

// --------------------------------------------------------------------------------------------------------------------
// Jack Application Dialog

class PluginListRefreshDialog : public QDialog
{
struct Self;
Self& self;

// ----------------------------------------------------------------------------------------------------------------

public:
explicit PluginListRefreshDialog(QWidget* parent, bool useSystemIcons);
~PluginListRefreshDialog() override;

// ----------------------------------------------------------------------------------------------------------------
// public methods

// ----------------------------------------------------------------------------------------------------------------
// protected methods

protected:
void closeEvent(QCloseEvent*) override;

// ----------------------------------------------------------------------------------------------------------------
// private methods

private:
void loadSettings();

// ----------------------------------------------------------------------------------------------------------------
// private slots

private slots:
void slot_saveSettings();
void slot_start();
void slot_skip();
void slot_checkTools();
void slot_handlePluginLook(int percent, QString plugin);
void slot_handlePluginThreadFinished();
};

// --------------------------------------------------------------------------------------------------------------------

+ 0
- 473
source/frontend/pluginlist/pluginlistrefreshdialog.py View File

@@ -1,473 +0,0 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-

# Carla plugin host
# Copyright (C) 2011-2022 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

from PyQt5.QtCore import pyqtSlot, Qt, QT_VERSION
from PyQt5.QtGui import QPixmap
from PyQt5.QtWidgets import QDialog, QWidget

# ---------------------------------------------------------------------------------------------------------------------
# Imports (Carla)

from carla_shared import (
HAIKU,
LINUX,
MACOS,
WINDOWS,
gCarla,
getIcon,
kIs64bit,
)

from utils import QSafeSettings

# ---------------------------------------------------------------------------------------------------------------------
# Imports (Local)

from .discovery import killDiscovery
from .discoverythread import SearchPluginsThread
from .pluginlistrefreshdialog_ui import Ui_PluginRefreshW

# ---------------------------------------------------------------------------------------------------------------------
# Plugin Refresh Dialog

class PluginRefreshW(QDialog):
def __init__(self, parent: QWidget, host, useSystemIcons: bool, hasLoadedLv2Plugins: bool):
QDialog.__init__(self, parent)
self.host = host
self.ui = Ui_PluginRefreshW()
self.ui.setupUi(self)

# -------------------------------------------------------------------------------------------------------------
# Internal stuff

toolNative = "carla-discovery-native.exe" if WINDOWS else "carla-discovery-native"
hasNative = os.path.exists(os.path.join(host.pathBinaries, toolNative))
hasPosix32 = os.path.exists(os.path.join(host.pathBinaries, "carla-discovery-posix32"))
hasPosix64 = os.path.exists(os.path.join(host.pathBinaries, "carla-discovery-posix64"))
hasWin32 = os.path.exists(os.path.join(host.pathBinaries, "carla-discovery-win32.exe"))
hasWin64 = os.path.exists(os.path.join(host.pathBinaries, "carla-discovery-win64.exe"))

self.fThread = SearchPluginsThread(self, host.pathBinaries)

# -------------------------------------------------------------------------------------------------------------
# Set-up Icons

if useSystemIcons:
self.ui.b_start.setIcon(getIcon('arrow-right', 16, 'svgz'))
self.ui.b_close.setIcon(getIcon('window-close', 16, 'svgz'))
if QT_VERSION >= 0x50600:
size = int(16 * self.devicePixelRatioF())
else:
size = 16
self.fIconYes = QPixmap(getIcon('dialog-ok-apply', 16, 'svgz').pixmap(size))
self.fIconNo = QPixmap(getIcon('dialog-error', 16, 'svgz').pixmap(size))
else:
self.fIconYes = QPixmap(":/16x16/dialog-ok-apply.svgz")
self.fIconNo = QPixmap(":/16x16/dialog-error.svgz")

# -------------------------------------------------------------------------------------------------------------
# Set-up GUI

# FIXME remove LRDF
self.ui.ico_rdflib.setPixmap(self.fIconNo)

self.ui.b_skip.setVisible(False)

if HAIKU:
self.ui.ch_posix32.setText("Haiku 32bit")
self.ui.ch_posix64.setText("Haiku 64bit")
elif LINUX:
self.ui.ch_posix32.setText("Linux 32bit")
self.ui.ch_posix64.setText("Linux 64bit")
elif MACOS:
self.ui.ch_posix32.setText("MacOS 32bit")
self.ui.ch_posix64.setText("MacOS 64bit")

if hasPosix32 and not WINDOWS:
self.ui.ico_posix32.setPixmap(self.fIconYes)
else:
self.ui.ico_posix32.setPixmap(self.fIconNo)
self.ui.ch_posix32.setEnabled(False)

if hasPosix64 and not WINDOWS:
self.ui.ico_posix64.setPixmap(self.fIconYes)
else:
self.ui.ico_posix64.setPixmap(self.fIconNo)
self.ui.ch_posix64.setEnabled(False)

if hasWin32:
self.ui.ico_win32.setPixmap(self.fIconYes)
else:
self.ui.ico_win32.setPixmap(self.fIconNo)
self.ui.ch_win32.setEnabled(False)

if hasWin64:
self.ui.ico_win64.setPixmap(self.fIconYes)
else:
self.ui.ico_win64.setPixmap(self.fIconNo)
self.ui.ch_win64.setEnabled(False)

if WINDOWS:
if kIs64bit:
hasNonNative = hasWin32
self.ui.ch_win64.setEnabled(False)
self.ui.ch_win64.setVisible(False)
self.ui.ico_win64.setVisible(False)
self.ui.label_win64.setVisible(False)
else:
hasNonNative = hasWin64
self.ui.ch_win32.setEnabled(False)
self.ui.ch_win32.setVisible(False)
self.ui.ico_win32.setVisible(False)
self.ui.label_win32.setVisible(False)

self.ui.ch_posix32.setEnabled(False)
self.ui.ch_posix32.setVisible(False)
self.ui.ch_posix64.setEnabled(False)
self.ui.ch_posix64.setVisible(False)
self.ui.ico_posix32.hide()
self.ui.ico_posix64.hide()
self.ui.label_posix32.hide()
self.ui.label_posix64.hide()
self.ui.ico_rdflib.hide()
self.ui.label_rdflib.hide()

else:
if kIs64bit:
hasNonNative = bool(hasPosix32 or hasWin32 or hasWin64)
self.ui.ch_posix64.setEnabled(False)
self.ui.ch_posix64.setVisible(False)
self.ui.ico_posix64.setVisible(False)
self.ui.label_posix64.setVisible(False)
else:
hasNonNative = bool(hasPosix64 or hasWin32 or hasWin64)
self.ui.ch_posix32.setEnabled(False)
self.ui.ch_posix32.setVisible(False)
self.ui.ico_posix32.setVisible(False)
self.ui.label_posix32.setVisible(False)

if MACOS:
self.setWindowModality(Qt.WindowModal)
else:
self.ui.ch_au.setEnabled(False)
self.ui.ch_au.setVisible(False)

if hasNative:
self.ui.ico_native.setPixmap(self.fIconYes)
else:
self.ui.ico_native.setPixmap(self.fIconNo)
self.ui.ch_native.setEnabled(False)
self.ui.ch_sf2.setEnabled(False)
if not hasNonNative:
self.ui.ch_ladspa.setEnabled(False)
self.ui.ch_dssi.setEnabled(False)
self.ui.ch_vst.setEnabled(False)
self.ui.ch_vst3.setEnabled(False)
self.ui.ch_clap.setEnabled(False)

if not hasLoadedLv2Plugins:
self.ui.lv2_restart_notice.hide()

self.setWindowFlags(self.windowFlags() & ~Qt.WindowContextHelpButtonHint)

# -------------------------------------------------------------------------------------------------------------
# Load settings

self.loadSettings()

# -------------------------------------------------------------------------------------------------------------
# Hide bridges if disabled

# NOTE: We Assume win32 carla build will not run win64 plugins
if (WINDOWS and not kIs64bit) or not host.showPluginBridges:
self.ui.ch_native.setChecked(True)
self.ui.ch_native.setEnabled(False)
self.ui.ch_native.setVisible(False)
self.ui.ch_posix32.setChecked(False)
self.ui.ch_posix32.setEnabled(False)
self.ui.ch_posix32.setVisible(False)
self.ui.ch_posix64.setChecked(False)
self.ui.ch_posix64.setEnabled(False)
self.ui.ch_posix64.setVisible(False)
self.ui.ch_win32.setChecked(False)
self.ui.ch_win32.setEnabled(False)
self.ui.ch_win32.setVisible(False)
self.ui.ch_win64.setChecked(False)
self.ui.ch_win64.setEnabled(False)
self.ui.ch_win64.setVisible(False)
self.ui.ico_posix32.hide()
self.ui.ico_posix64.hide()
self.ui.ico_win32.hide()
self.ui.ico_win64.hide()
self.ui.label_posix32.hide()
self.ui.label_posix64.hide()
self.ui.label_win32.hide()
self.ui.label_win64.hide()
self.ui.sep_format.hide()

elif not (WINDOWS or host.showWineBridges):
self.ui.ch_win32.setChecked(False)
self.ui.ch_win32.setEnabled(False)
self.ui.ch_win32.setVisible(False)
self.ui.ch_win64.setChecked(False)
self.ui.ch_win64.setEnabled(False)
self.ui.ch_win64.setVisible(False)
self.ui.ico_win32.hide()
self.ui.ico_win64.hide()
self.ui.label_win32.hide()
self.ui.label_win64.hide()

# Disable non-supported features
features = gCarla.utils.get_supported_features() if gCarla.utils else ()

if "sf2" not in features:
self.ui.ch_sf2.setChecked(False)
self.ui.ch_sf2.setEnabled(False)

if MACOS and "juce" not in features:
self.ui.ch_au.setChecked(False)
self.ui.ch_au.setEnabled(False)

# -------------------------------------------------------------------------------------------------------------
# Resize to minimum size, as it's very likely UI stuff was hidden

self.resize(self.minimumSize())

# -------------------------------------------------------------------------------------------------------------
# Set-up connections

self.finished.connect(self.slot_saveSettings)
self.ui.b_start.clicked.connect(self.slot_start)
self.ui.b_skip.clicked.connect(self.slot_skip)
self.ui.ch_native.clicked.connect(self.slot_checkTools)
self.ui.ch_posix32.clicked.connect(self.slot_checkTools)
self.ui.ch_posix64.clicked.connect(self.slot_checkTools)
self.ui.ch_win32.clicked.connect(self.slot_checkTools)
self.ui.ch_win64.clicked.connect(self.slot_checkTools)
self.ui.ch_ladspa.clicked.connect(self.slot_checkTools)
self.ui.ch_dssi.clicked.connect(self.slot_checkTools)
self.ui.ch_lv2.clicked.connect(self.slot_checkTools)
self.ui.ch_vst.clicked.connect(self.slot_checkTools)
self.ui.ch_vst3.clicked.connect(self.slot_checkTools)
self.ui.ch_clap.clicked.connect(self.slot_checkTools)
self.ui.ch_au.clicked.connect(self.slot_checkTools)
self.ui.ch_sf2.clicked.connect(self.slot_checkTools)
self.ui.ch_sfz.clicked.connect(self.slot_checkTools)
self.ui.ch_jsfx.clicked.connect(self.slot_checkTools)
self.fThread.pluginLook.connect(self.slot_handlePluginLook)
self.fThread.finished.connect(self.slot_handlePluginThreadFinished)

# -------------------------------------------------------------------------------------------------------------
# Post-connect setup

self.slot_checkTools()

# -----------------------------------------------------------------------------------------------------------------

def loadSettings(self):
settings = QSafeSettings("falkTX", "CarlaRefresh2")

check = settings.value("PluginDatabase/SearchLADSPA", True, bool) and self.ui.ch_ladspa.isEnabled()
self.ui.ch_ladspa.setChecked(check)

check = settings.value("PluginDatabase/SearchDSSI", True, bool) and self.ui.ch_dssi.isEnabled()
self.ui.ch_dssi.setChecked(check)

check = settings.value("PluginDatabase/SearchLV2", True, bool) and self.ui.ch_lv2.isEnabled()
self.ui.ch_lv2.setChecked(check)

check = settings.value("PluginDatabase/SearchVST2", True, bool) and self.ui.ch_vst.isEnabled()
self.ui.ch_vst.setChecked(check)

check = settings.value("PluginDatabase/SearchVST3", True, bool) and self.ui.ch_vst3.isEnabled()
self.ui.ch_vst3.setChecked(check)

check = settings.value("PluginDatabase/SearchCLAP", True, bool) and self.ui.ch_clap.isEnabled()
self.ui.ch_clap.setChecked(check)

if MACOS:
check = settings.value("PluginDatabase/SearchAU", True, bool) and self.ui.ch_au.isEnabled()
else:
check = False
self.ui.ch_au.setChecked(check)

check = settings.value("PluginDatabase/SearchSF2", False, bool) and self.ui.ch_sf2.isEnabled()
self.ui.ch_sf2.setChecked(check)

check = settings.value("PluginDatabase/SearchSFZ", False, bool) and self.ui.ch_sfz.isEnabled()
self.ui.ch_sfz.setChecked(check)

check = settings.value("PluginDatabase/SearchJSFX", True, bool) and self.ui.ch_jsfx.isEnabled()
self.ui.ch_jsfx.setChecked(check)

check = settings.value("PluginDatabase/SearchNative", True, bool) and self.ui.ch_native.isEnabled()
self.ui.ch_native.setChecked(check)

check = settings.value("PluginDatabase/SearchPOSIX32", False, bool) and self.ui.ch_posix32.isEnabled()
self.ui.ch_posix32.setChecked(check)

check = settings.value("PluginDatabase/SearchPOSIX64", False, bool) and self.ui.ch_posix64.isEnabled()
self.ui.ch_posix64.setChecked(check)

check = settings.value("PluginDatabase/SearchWin32", False, bool) and self.ui.ch_win32.isEnabled()
self.ui.ch_win32.setChecked(check)

check = settings.value("PluginDatabase/SearchWin64", False, bool) and self.ui.ch_win64.isEnabled()
self.ui.ch_win64.setChecked(check)

self.ui.ch_do_checks.setChecked(settings.value("PluginDatabase/DoChecks", False, bool))

# -----------------------------------------------------------------------------------------------------------------

@pyqtSlot()
def slot_saveSettings(self):
settings = QSafeSettings("falkTX", "CarlaRefresh2")
settings.setValue("PluginDatabase/SearchLADSPA", self.ui.ch_ladspa.isChecked())
settings.setValue("PluginDatabase/SearchDSSI", self.ui.ch_dssi.isChecked())
settings.setValue("PluginDatabase/SearchLV2", self.ui.ch_lv2.isChecked())
settings.setValue("PluginDatabase/SearchVST2", self.ui.ch_vst.isChecked())
settings.setValue("PluginDatabase/SearchVST3", self.ui.ch_vst3.isChecked())
settings.setValue("PluginDatabase/SearchCLAP", self.ui.ch_clap.isChecked())
settings.setValue("PluginDatabase/SearchAU", self.ui.ch_au.isChecked())
settings.setValue("PluginDatabase/SearchSF2", self.ui.ch_sf2.isChecked())
settings.setValue("PluginDatabase/SearchSFZ", self.ui.ch_sfz.isChecked())
settings.setValue("PluginDatabase/SearchJSFX", self.ui.ch_jsfx.isChecked())
settings.setValue("PluginDatabase/SearchNative", self.ui.ch_native.isChecked())
settings.setValue("PluginDatabase/SearchPOSIX32", self.ui.ch_posix32.isChecked())
settings.setValue("PluginDatabase/SearchPOSIX64", self.ui.ch_posix64.isChecked())
settings.setValue("PluginDatabase/SearchWin32", self.ui.ch_win32.isChecked())
settings.setValue("PluginDatabase/SearchWin64", self.ui.ch_win64.isChecked())
settings.setValue("PluginDatabase/DoChecks", self.ui.ch_do_checks.isChecked())

# -----------------------------------------------------------------------------------------------------------------

@pyqtSlot()
def slot_start(self):
self.ui.progressBar.setMinimum(0)
self.ui.progressBar.setMaximum(100)
self.ui.progressBar.setValue(0)
self.ui.b_start.setEnabled(False)
self.ui.b_skip.setVisible(True)
self.ui.b_close.setVisible(False)
self.ui.group_types.setEnabled(False)
self.ui.group_options.setEnabled(False)

if gCarla.utils:
if self.ui.ch_do_checks.isChecked():
gCarla.utils.unsetenv("CARLA_DISCOVERY_NO_PROCESSING_CHECKS")
else:
gCarla.utils.setenv("CARLA_DISCOVERY_NO_PROCESSING_CHECKS", "true")

native, posix32, posix64, win32, win64 = (self.ui.ch_native.isChecked(),
self.ui.ch_posix32.isChecked(), self.ui.ch_posix64.isChecked(),
self.ui.ch_win32.isChecked(), self.ui.ch_win64.isChecked())

ladspa, dssi, lv2, vst, vst3, clap, au, sf2, sfz, jsfx = (self.ui.ch_ladspa.isChecked(), self.ui.ch_dssi.isChecked(),
self.ui.ch_lv2.isChecked(), self.ui.ch_vst.isChecked(),
self.ui.ch_vst3.isChecked(), self.ui.ch_clap.isChecked(),
self.ui.ch_au.isChecked(), self.ui.ch_sf2.isChecked(),
self.ui.ch_sfz.isChecked(), self.ui.ch_jsfx.isChecked())

self.fThread.setSearchBinaryTypes(native, posix32, posix64, win32, win64)
self.fThread.setSearchPluginTypes(ladspa, dssi, lv2, vst, vst3, clap, au, sf2, sfz, jsfx)
self.fThread.start()

# -----------------------------------------------------------------------------------------------------------------

@pyqtSlot()
def slot_skip(self):
killDiscovery()

# -----------------------------------------------------------------------------------------------------------------

@pyqtSlot()
def slot_checkTools(self):
enabled1 = bool(self.ui.ch_native.isChecked() or
self.ui.ch_posix32.isChecked() or self.ui.ch_posix64.isChecked() or
self.ui.ch_win32.isChecked() or self.ui.ch_win64.isChecked())

enabled2 = bool(self.ui.ch_ladspa.isChecked() or self.ui.ch_dssi.isChecked() or
self.ui.ch_lv2.isChecked() or self.ui.ch_vst.isChecked() or
self.ui.ch_vst3.isChecked() or self.ui.ch_clap.isChecked() or
self.ui.ch_au.isChecked() or self.ui.ch_sf2.isChecked() or
self.ui.ch_sfz.isChecked() or self.ui.ch_jsfx.isChecked())

self.ui.b_start.setEnabled(enabled1 and enabled2)

# -----------------------------------------------------------------------------------------------------------------

@pyqtSlot(float, str)
def slot_handlePluginLook(self, percent, plugin):
self.ui.progressBar.setFormat(plugin)
self.ui.progressBar.setValue(int(percent))

# -----------------------------------------------------------------------------------------------------------------

@pyqtSlot()
def slot_handlePluginThreadFinished(self):
self.ui.progressBar.setMinimum(0)
self.ui.progressBar.setMaximum(1)
self.ui.progressBar.setValue(1)
self.ui.progressBar.setFormat(self.tr("Done"))
self.ui.b_start.setEnabled(True)
self.ui.b_skip.setVisible(False)
self.ui.b_close.setVisible(True)
self.ui.group_types.setEnabled(True)
self.ui.group_options.setEnabled(True)

# -----------------------------------------------------------------------------------------------------------------

def closeEvent(self, event):
if self.fThread.isRunning():
self.fThread.stop()
killDiscovery()
#self.fThread.terminate()
self.fThread.wait()

if self.fThread.hasSomethingChanged():
self.accept()
else:
self.reject()

QDialog.closeEvent(self, event)

# ---------------------------------------------------------------------------------------------------------------------
# Testing

if __name__ == '__main__':
import sys
# pylint: disable=ungrouped-imports
from PyQt5.QtWidgets import QApplication
# pylint: enable=ungrouped-imports

class _host:
pathBinaries = ""
showPluginBridges = False
showWineBridges = False
_host = _host()

_app = QApplication(sys.argv)
_gui = PluginRefreshW(None, _host, True, False)
_app.exec_()

# ---------------------------------------------------------------------------------------------------------------------

+ 0
- 610
source/frontend/pluginlist/pluginlistrefreshdialog.ui View File

@@ -1,610 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>PluginRefreshW</class>
<widget class="QDialog" name="PluginRefreshW">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>613</width>
<height>369</height>
</rect>
</property>
<property name="windowTitle">
<string>Carla - Refresh</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_5">
<item>
<layout class="QHBoxLayout" name="horizontalLayout_3">
<item>
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Preferred</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>30</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QGroupBox" name="group_types">
<property name="title">
<string>Search for new...</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QCheckBox" name="ch_ladspa">
<property name="text">
<string>LADSPA</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="ch_dssi">
<property name="text">
<string>DSSI</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="ch_lv2">
<property name="text">
<string>LV2</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="ch_vst">
<property name="text">
<string>VST2</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="ch_vst3">
<property name="text">
<string>VST3</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="ch_clap">
<property name="text">
<string>CLAP</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="ch_au">
<property name="text">
<string>AU</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="ch_jsfx">
<property name="text">
<string>JSFX</string>
</property>
</widget>
</item>
<item>
<widget class="Line" name="line_3">
<property name="lineWidth">
<number>0</number>
</property>
<property name="midLineWidth">
<number>1</number>
</property>
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="ch_sf2">
<property name="text">
<string>SF2/3</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="ch_sfz">
<property name="text">
<string>SFZ</string>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_4">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>5</height>
</size>
</property>
</spacer>
</item>
<item>
<spacer name="verticalSpacer_3">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
<item>
<widget class="Line" name="sep_format">
<property name="lineWidth">
<number>0</number>
</property>
<property name="midLineWidth">
<number>1</number>
</property>
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
</widget>
</item>
<item>
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<widget class="QCheckBox" name="ch_native">
<property name="text">
<string>Native</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="ch_posix32">
<property name="text">
<string>POSIX 32bit</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="ch_posix64">
<property name="text">
<string>POSIX 64bit</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="ch_win32">
<property name="text">
<string>Windows 32bit</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="ch_win64">
<property name="text">
<string>Windows 64bit</string>
</property>
</widget>
</item>
<item>
<spacer name="verticalSpacer_2">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
</layout>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_3">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Fixed</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<layout class="QVBoxLayout" name="verticalLayout_3">
<item>
<widget class="QGroupBox" name="group_tools">
<property name="title">
<string>Available tools:</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
<property name="flat">
<bool>true</bool>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="0">
<widget class="QLabel" name="ico_native">
<property name="maximumSize">
<size>
<width>16</width>
<height>16</height>
</size>
</property>
<property name="text">
<string/>
</property>
<property name="pixmap">
<pixmap resource="../resources.qrc">:/16x16/dialog-ok-apply.svgz</pixmap>
</property>
<property name="scaledContents">
<bool>true</bool>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="ico_posix32">
<property name="maximumSize">
<size>
<width>16</width>
<height>16</height>
</size>
</property>
<property name="text">
<string/>
</property>
<property name="pixmap">
<pixmap resource="../resources.qrc">:/16x16/dialog-ok-apply.svgz</pixmap>
</property>
<property name="scaledContents">
<bool>true</bool>
</property>
</widget>
</item>
<item row="5" column="1">
<widget class="QLabel" name="label_rdflib">
<property name="text">
<string>python3-rdflib (LADSPA-RDF support)</string>
</property>
</widget>
</item>
<item row="4" column="1">
<widget class="QLabel" name="label_win64">
<property name="text">
<string>carla-discovery-win64</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QLabel" name="label_native">
<property name="text">
<string>carla-discovery-native</string>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="ico_posix64">
<property name="maximumSize">
<size>
<width>16</width>
<height>16</height>
</size>
</property>
<property name="text">
<string/>
</property>
<property name="pixmap">
<pixmap resource="../resources.qrc">:/16x16/dialog-ok-apply.svgz</pixmap>
</property>
<property name="scaledContents">
<bool>true</bool>
</property>
</widget>
</item>
<item row="5" column="0">
<widget class="QLabel" name="ico_rdflib">
<property name="maximumSize">
<size>
<width>16</width>
<height>16</height>
</size>
</property>
<property name="text">
<string/>
</property>
<property name="pixmap">
<pixmap resource="../resources.qrc">:/16x16/dialog-ok-apply.svgz</pixmap>
</property>
<property name="scaledContents">
<bool>true</bool>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QLabel" name="label_posix32">
<property name="text">
<string>carla-discovery-posix32</string>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QLabel" name="ico_win32">
<property name="maximumSize">
<size>
<width>16</width>
<height>16</height>
</size>
</property>
<property name="text">
<string/>
</property>
<property name="pixmap">
<pixmap resource="../resources.qrc">:/16x16/dialog-ok-apply.svgz</pixmap>
</property>
<property name="scaledContents">
<bool>true</bool>
</property>
</widget>
</item>
<item row="4" column="0">
<widget class="QLabel" name="ico_win64">
<property name="maximumSize">
<size>
<width>16</width>
<height>16</height>
</size>
</property>
<property name="text">
<string/>
</property>
<property name="pixmap">
<pixmap resource="../resources.qrc">:/16x16/dialog-ok-apply.svgz</pixmap>
</property>
<property name="scaledContents">
<bool>true</bool>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QLabel" name="label_posix64">
<property name="text">
<string>carla-discovery-posix64</string>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QLabel" name="label_win32">
<property name="text">
<string>carla-discovery-win32</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<spacer name="verticalSpacer_5">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QGroupBox" name="group_options">
<property name="title">
<string>Options:</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
<property name="flat">
<bool>true</bool>
</property>
<layout class="QVBoxLayout" name="verticalLayout_4">
<item>
<widget class="QCheckBox" name="ch_do_checks">
<property name="toolTip">
<string>Carla will run small processing checks when scanning the plugins (to make sure they won't crash).
You can disable these checks to get a faster scanning time (at your own risk).</string>
</property>
<property name="text">
<string>Run processing checks while scanning</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<spacer name="verticalSpacer_4">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
<item>
<spacer name="horizontalSpacer_2">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Preferred</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>30</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
<item>
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>6</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QWidget" name="lv2_restart_notice" native="true">
<layout class="QHBoxLayout" name="horizontalLayout_4">
<item>
<widget class="QLabel" name="label_4">
<property name="maximumSize">
<size>
<width>22</width>
<height>22</height>
</size>
</property>
<property name="text">
<string/>
</property>
<property name="pixmap">
<pixmap resource="../resources.qrc">:/16x16/dialog-information.svgz</pixmap>
</property>
<property name="scaledContents">
<bool>true</bool>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="label_5">
<property name="text">
<string>Restart Carla to list the new LV2 plugins</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QProgressBar" name="progressBar">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="maximum">
<number>100</number>
</property>
<property name="value">
<number>0</number>
</property>
<property name="format">
<string>Press 'Scan' to begin the search</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="b_start">
<property name="text">
<string>Scan</string>
</property>
<property name="icon">
<iconset resource="../resources.qrc">
<normaloff>:/16x16/arrow-right.svgz</normaloff>:/16x16/arrow-right.svgz</iconset>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="b_skip">
<property name="text">
<string>&gt;&gt; Skip</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="b_close">
<property name="text">
<string>Close</string>
</property>
<property name="icon">
<iconset resource="../resources.qrc">
<normaloff>:/16x16/window-close.svgz</normaloff>:/16x16/window-close.svgz</iconset>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
<resources>
<include location="../resources.qrc"/>
<include location="../resources.qrc"/>
</resources>
<connections>
<connection>
<sender>b_close</sender>
<signal>clicked()</signal>
<receiver>PluginRefreshW</receiver>
<slot>close()</slot>
<hints>
<hint type="sourcelabel">
<x>426</x>
<y>231</y>
</hint>
<hint type="destinationlabel">
<x>236</x>
<y>125</y>
</hint>
</hints>
</connection>
</connections>
</ui>

+ 65
- 0
source/frontend/pluginlist/pluginrefreshdialog.hpp View File

@@ -0,0 +1,65 @@
/*
* Carla plugin host
* Copyright (C) 2011-2023 Filipe Coelho <falktx@falktx.com>
* SPDX-License-Identifier: GPL-2.0-or-later
*/

#pragma once

#include "ui_pluginrefreshdialog.h"

#include "qsafesettings.hpp"

// --------------------------------------------------------------------------------------------------------------------
// Plugin Refresh Dialog

struct PluginRefreshDialog : QDialog, Ui_PluginRefreshDialog {
explicit PluginRefreshDialog(QWidget* const parent)
: QDialog(parent)
{
setupUi(this);

setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
#ifdef CARLA_OS_MAC
setWindowModality(Qt::WindowModal);
#endif

b_skip->setEnabled(false);
ch_invalid->setEnabled(false);

// ------------------------------------------------------------------------------------------------------------
// Load settings

{
const QSafeSettings settings;

restoreGeometry(settings.valueByteArray("PluginRefreshDialog/Geometry"));

if (settings.valueBool("PluginRefreshDialog/RefreshAll", false))
ch_all->setChecked(true);
else
ch_updated->setChecked(true);

ch_invalid->setChecked(settings.valueBool("PluginRefreshDialog/CheckInvalid", false));
}

// ------------------------------------------------------------------------------------------------------------
// Set-up connections

QObject::connect(this, &QDialog::finished, this, &PluginRefreshDialog::saveSettings);
}

// ----------------------------------------------------------------------------------------------------------------
// private slots

private Q_SLOTS:
void saveSettings()
{
QSafeSettings settings;
settings.setValue("PluginRefreshDialog/Geometry", saveGeometry());
settings.setValue("PluginRefreshDialog/RefreshAll", ch_all->isChecked());
settings.setValue("PluginRefreshDialog/CheckInvalid", ch_invalid->isChecked());
}
};

// --------------------------------------------------------------------------------------------------------------------

+ 190
- 0
source/frontend/pluginlist/pluginrefreshdialog.ui View File

@@ -0,0 +1,190 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>PluginRefreshDialog</class>
<widget class="QDialog" name="PluginRefreshDialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>873</width>
<height>179</height>
</rect>
</property>
<property name="windowTitle">
<string>Plugin Refresh</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_5">
<item>
<layout class="QHBoxLayout" name="horizontalLayout_3">
<item>
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Preferred</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>30</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QGroupBox" name="group">
<property name="title">
<string>Search for:</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QRadioButton" name="ch_all">
<property name="text">
<string>All plugins, ignoring cache</string>
</property>
</widget>
</item>
<item>
<widget class="QRadioButton" name="ch_updated">
<property name="text">
<string>Updated plugins only</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="ch_invalid">
<property name="text">
<string>Check previously invalid plugins</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_3">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Preferred</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
<item>
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>6</height>
</size>
</property>
</spacer>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QProgressBar" name="progressBar">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="maximum">
<number>100</number>
</property>
<property name="value">
<number>0</number>
</property>
<property name="format">
<string>Press 'Scan' to begin the search</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="b_start">
<property name="text">
<string>Scan</string>
</property>
<property name="icon">
<iconset resource="../../../resources/resources.qrc">
<normaloff>:/16x16/arrow-right.svgz</normaloff>:/16x16/arrow-right.svgz</iconset>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="b_skip">
<property name="text">
<string>&gt;&gt; Skip</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="b_close">
<property name="text">
<string>Close</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
<resources>
<include location="../../../resources/resources.qrc"/>
</resources>
<connections>
<connection>
<sender>b_close</sender>
<signal>clicked()</signal>
<receiver>PluginRefreshDialog</receiver>
<slot>close()</slot>
<hints>
<hint type="sourcelabel">
<x>426</x>
<y>231</y>
</hint>
<hint type="destinationlabel">
<x>236</x>
<y>125</y>
</hint>
</hints>
</connection>
<connection>
<sender>ch_updated</sender>
<signal>toggled(bool)</signal>
<receiver>ch_invalid</receiver>
<slot>setEnabled(bool)</slot>
<hints>
<hint type="sourcelabel">
<x>436</x>
<y>78</y>
</hint>
<hint type="destinationlabel">
<x>436</x>
<y>105</y>
</hint>
</hints>
</connection>
</connections>
</ui>

+ 35
- 0
source/frontend/utils/qcarlastring.hpp View File

@@ -49,6 +49,11 @@ public:
explicit inline QCarlaString(const char* const str)
: QString(fromUtf8(str)) {}

#if QT_VERSION < 0x60000
explicit inline QCarlaString(const QChar* const str, const qsizetype size)
: QString(str, size) {}
#endif

inline QCarlaString(const QString& s)
: QString(s) {}

@@ -66,6 +71,36 @@ public:
{
return simplified().remove(' ');
}

#if QT_VERSION < 0x60000
inline QCarlaString sliced(const qsizetype pos) const
{
return QCarlaString(data() + pos, size() - pos);
}
#endif
};

//---------------------------------------------------------------------------------------------------------------------
// Custom QByteArray class with a few extra methods

class QCarlaByteArray : public QByteArray
{
public:
explicit inline QCarlaByteArray()
: QByteArray() {}

explicit inline QCarlaByteArray(const char* const data, const qsizetype size)
: QByteArray(data, size) {}

inline QCarlaByteArray(const QByteArray& b)
: QByteArray(b) {}

#if QT_VERSION < 0x60000
inline QCarlaByteArray sliced(const qsizetype pos) const
{
return QCarlaByteArray(data() + pos, size() - pos);
}
#endif
};

//---------------------------------------------------------------------------------------------------------------------

Loading…
Cancel
Save