@@ -4,6 +4,7 @@ | |||
.*.kate-swp | |||
.libmagic-tmp | |||
.libmagic-tmp.bc | |||
.cache/ | |||
.kdev4/ | |||
.DS_Store | |||
@@ -17,6 +18,7 @@ | |||
*.7z | |||
*.bz2 | |||
*.a | |||
*.d | |||
*.o | |||
*.dll | |||
*.dll.def | |||
@@ -58,6 +60,8 @@ qrc_resources.cpp | |||
*.pyc | |||
# Qt files | |||
*_ui.hpp | |||
*_ui.py | |||
*_rc.cpp | |||
*_rc.py | |||
ui_*.hpp | |||
@@ -104,6 +108,7 @@ carla-native-plugin | |||
carla-rest-server | |||
zynaddsubfx-ui | |||
compile_commands.json | |||
stoat-output.png | |||
source/tests/ansi-pedantic-test_* | |||
@@ -143,7 +148,7 @@ bin/resources/widgets | |||
source/native-plugins/resources/*.py | |||
# Other | |||
source/frontend/carla_config.py | |||
source/frontend/pluginlist/jackappdialog | |||
source/includes/asio/ | |||
source/includes/rewire/ | |||
source/includes/vst2 | |||
@@ -294,6 +294,7 @@ ifeq ($(HAVE_QT5),true) | |||
QT5_HOSTBINS = $(shell $(PKG_CONFIG) --variable=host_bins Qt5Core) | |||
MOC_QT5 ?= $(QT5_HOSTBINS)/moc | |||
RCC_QT5 ?= $(QT5_HOSTBINS)/rcc | |||
UIC_QT5 ?= $(QT5_HOSTBINS)/uic | |||
ifeq (,$(wildcard $(MOC_QT5))) | |||
HAVE_QT5 = false | |||
endif | |||
@@ -315,191 +315,3 @@ void PluginDatabaseW::slot_saveSettings() | |||
} | |||
// -------------------------------------------------------------------------------------------------------------------- | |||
// Jack Application Dialog | |||
// NOTE: index matches the one in the UI | |||
enum UiSessionManager { | |||
UI_SESSION_NONE, | |||
UI_SESSION_LADISH, | |||
UI_SESSION_NSM | |||
}; | |||
struct JackApplicationW::PrivateData { | |||
Ui::Dialog ui; | |||
const QString fProjectFilename; | |||
PrivateData(JackApplicationW* const dialog, const QString& projectFilename) | |||
: ui(), | |||
fProjectFilename(projectFilename) | |||
{ | |||
ui.setupUi(dialog); | |||
ui.group_error->setVisible(false); | |||
// ------------------------------------------------------------------------------------------------------------ | |||
// Load settings | |||
loadSettings(); | |||
} | |||
void checkIfButtonBoxShouldBeEnabled(int index, const QString text) | |||
{ | |||
static QList<QChar> badFirstChars = { '.', '/' }; | |||
bool enabled = text.length() > 0; | |||
QCarlaString showErr; | |||
// NSM applications must not be abstract or absolute paths, and must not contain arguments | |||
if (enabled && index == UI_SESSION_NSM) | |||
{ | |||
if (badFirstChars.contains(text[0])) | |||
showErr = tr("NSM applications cannot use abstract or absolute paths"); | |||
else if (text.contains(' ') || text.contains(';') || text.contains('&')) | |||
showErr = tr("NSM applications cannot use CLI arguments"); | |||
else if (fProjectFilename.isEmpty()) | |||
showErr = tr("You need to save the current Carla project before NSM can be used"); | |||
} | |||
if (showErr.isNotEmpty()) | |||
{ | |||
enabled = false; | |||
ui.l_error->setText(showErr); | |||
ui.group_error->setVisible(true); | |||
} | |||
else | |||
{ | |||
ui.group_error->setVisible(false); | |||
} | |||
if (QPushButton* const button = ui.buttonBox->button(QDialogButtonBox::Ok)) | |||
button->setEnabled(enabled); | |||
} | |||
void loadSettings() | |||
{ | |||
const QSafeSettings settings("falkTX", "CarlaAddJackApp"); | |||
const QString smName = settings.valueString("SessionManager", ""); | |||
if (smName == "LADISH (SIGUSR1)") | |||
ui.cb_session_mgr->setCurrentIndex(UI_SESSION_LADISH); | |||
else if (smName == "NSM") | |||
ui.cb_session_mgr->setCurrentIndex(UI_SESSION_NSM); | |||
else | |||
ui.cb_session_mgr->setCurrentIndex(UI_SESSION_NONE); | |||
ui.le_command->setText(settings.valueString("Command", "")); | |||
ui.le_name->setText(settings.valueString("Name", "")); | |||
ui.sb_audio_ins->setValue(settings.valueIntPositive("NumAudioIns", 2)); | |||
ui.sb_audio_ins->setValue(settings.valueIntPositive("NumAudioIns", 2)); | |||
ui.sb_audio_outs->setValue(settings.valueIntPositive("NumAudioOuts", 2)); | |||
ui.sb_midi_ins->setValue(settings.valueIntPositive("NumMidiIns", 0)); | |||
ui.sb_midi_outs->setValue(settings.valueIntPositive("NumMidiOuts", 0)); | |||
ui.cb_manage_window->setChecked(settings.valueBool("ManageWindow", true)); | |||
ui.cb_capture_first_window->setChecked(settings.valueBool("CaptureFirstWindow", false)); | |||
ui.cb_out_midi_mixdown->setChecked(settings.valueBool("MidiOutMixdown", false)); | |||
checkIfButtonBoxShouldBeEnabled(ui.cb_session_mgr->currentIndex(), ui.le_command->text()); | |||
} | |||
void saveSettings() | |||
{ | |||
QSafeSettings settings("falkTX", "CarlaAddJackApp"); | |||
settings.setValue("Command", ui.le_command->text()); | |||
settings.setValue("Name", ui.le_name->text()); | |||
settings.setValue("SessionManager", ui.cb_session_mgr->currentText()); | |||
settings.setValue("NumAudioIns", ui.sb_audio_ins->value()); | |||
settings.setValue("NumAudioOuts", ui.sb_audio_outs->value()); | |||
settings.setValue("NumMidiIns", ui.sb_midi_ins->value()); | |||
settings.setValue("NumMidiOuts", ui.sb_midi_outs->value()); | |||
settings.setValue("ManageWindow", ui.cb_manage_window->isChecked()); | |||
settings.setValue("CaptureFirstWindow", ui.cb_capture_first_window->isChecked()); | |||
settings.setValue("MidiOutMixdown", ui.cb_out_midi_mixdown->isChecked()); | |||
} | |||
CARLA_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(PrivateData) | |||
}; | |||
JackApplicationW::JackApplicationW(QWidget* parent, const QString& projectFilename) | |||
: QDialog(parent), | |||
self(new PrivateData(this, projectFilename)) | |||
{ | |||
adjustSize(); | |||
setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint); | |||
// ---------------------------------------------------------------------------------------------------------------- | |||
// Set-up connections | |||
connect(this, SIGNAL(finished(int)), SLOT(slot_saveSettings())); | |||
connect(self->ui.cb_session_mgr, SIGNAL(currentIndexChanged(int)), SLOT(slot_sessionManagerChanged(int))); | |||
connect(self->ui.le_command, SIGNAL(textChanged(QString)), SLOT(slot_commandChanged(QString))); | |||
} | |||
JackApplicationW::~JackApplicationW() | |||
{ | |||
delete self; | |||
} | |||
void JackApplicationW::getCommandAndFlags(QString& command, QString& name, QString& labelSetup) | |||
{ | |||
name = self->ui.le_name->text(); | |||
command = self->ui.le_command->text(); | |||
if (name.isEmpty()) | |||
{ | |||
name = QFileInfo(command.split(' ').first()).baseName(); | |||
// FIXME | |||
name[0] = name[0].toTitleCase(); | |||
} | |||
SessionManager smgr; | |||
switch (self->ui.cb_session_mgr->currentIndex()) | |||
{ | |||
case UI_SESSION_LADISH: | |||
smgr = LIBJACK_SESSION_MANAGER_LADISH; | |||
break; | |||
case UI_SESSION_NSM: | |||
smgr = LIBJACK_SESSION_MANAGER_NSM; | |||
break; | |||
default: | |||
smgr = LIBJACK_SESSION_MANAGER_NONE; | |||
break; | |||
} | |||
uint flags = 0x0; | |||
if (self->ui.cb_manage_window->isChecked()) | |||
flags |= LIBJACK_FLAG_CONTROL_WINDOW; | |||
if (self->ui.cb_capture_first_window->isChecked()) | |||
flags |= LIBJACK_FLAG_CAPTURE_FIRST_WINDOW; | |||
if (self->ui.cb_buffers_addition_mode->isChecked()) | |||
flags |= LIBJACK_FLAG_AUDIO_BUFFERS_ADDITION; | |||
if (self->ui.cb_out_midi_mixdown->isChecked()) | |||
flags |= LIBJACK_FLAG_MIDI_OUTPUT_CHANNEL_MIXDOWN; | |||
if (self->ui.cb_external_start->isChecked()) | |||
flags |= LIBJACK_FLAG_EXTERNAL_START; | |||
labelSetup = QString("%1%2%3%4%5%6").arg(QChar('0' + self->ui.sb_audio_ins->value())) | |||
.arg(QChar('0' + self->ui.sb_audio_outs->value())) | |||
.arg(QChar('0' + self->ui.sb_midi_ins->value())) | |||
.arg(QChar('0' + self->ui.sb_midi_outs->value())) | |||
.arg(QChar('0' + smgr)) | |||
.arg(QChar('0' + flags)); | |||
} | |||
void JackApplicationW::slot_commandChanged(const QString text) | |||
{ | |||
self->checkIfButtonBoxShouldBeEnabled(self->ui.cb_session_mgr->currentIndex(), text); | |||
} | |||
void JackApplicationW::slot_sessionManagerChanged(const int index) | |||
{ | |||
self->checkIfButtonBoxShouldBeEnabled(index, self->ui.le_command->text()); | |||
} | |||
void JackApplicationW::slot_saveSettings() | |||
{ | |||
self->saveSettings(); | |||
} | |||
// -------------------------------------------------------------------------------------------------------------------- |
@@ -370,124 +370,6 @@ void QMessageBoxWithBetterWidth::showEvent(QShowEvent* const event) | |||
QMessageBox::showEvent(event); | |||
} | |||
//--------------------------------------------------------------------------------------------------------------------- | |||
// Safer QSettings class, which does not throw if type mismatches | |||
bool QSafeSettings::valueBool(const QString key, const bool defaultValue) const | |||
{ | |||
QVariant var(value(key, defaultValue)); | |||
if (var.isNull()) | |||
return defaultValue; | |||
CARLA_SAFE_ASSERT_RETURN(var.convert(QVariant::Bool), defaultValue); | |||
return var.isValid() ? var.toBool() : defaultValue; | |||
} | |||
Qt::CheckState QSafeSettings::valueCheckState(const QString key, const Qt::CheckState defaultValue) const | |||
{ | |||
QVariant var(value(key, defaultValue)); | |||
if (var.isNull()) | |||
return defaultValue; | |||
CARLA_SAFE_ASSERT_RETURN(var.convert(QVariant::UInt), defaultValue); | |||
if (! var.isValid()) | |||
return defaultValue; | |||
const uint value = var.toUInt(); | |||
switch (value) | |||
{ | |||
case Qt::Unchecked: | |||
case Qt::PartiallyChecked: | |||
case Qt::Checked: | |||
return static_cast<Qt::CheckState>(value); | |||
default: | |||
return defaultValue; | |||
} | |||
} | |||
int QSafeSettings::valueIntPositive(const QString key, const int defaultValue) const | |||
{ | |||
CARLA_SAFE_ASSERT_INT(defaultValue >= 0, defaultValue); | |||
QVariant var(value(key, defaultValue)); | |||
if (var.isNull()) | |||
return defaultValue; | |||
CARLA_SAFE_ASSERT_RETURN(var.convert(QVariant::Int), defaultValue); | |||
CARLA_SAFE_ASSERT_RETURN(var.isValid(), defaultValue); | |||
const int value = var.toInt(); | |||
CARLA_SAFE_ASSERT_RETURN(value >= 0, defaultValue); | |||
return value; | |||
} | |||
uint QSafeSettings::valueUInt(const QString key, const uint defaultValue) const | |||
{ | |||
QVariant var(value(key, defaultValue)); | |||
if (var.isNull()) | |||
return defaultValue; | |||
CARLA_SAFE_ASSERT_RETURN(var.convert(QVariant::UInt), defaultValue); | |||
return var.isValid() ? var.toUInt() : defaultValue; | |||
} | |||
double QSafeSettings::valueDouble(const QString key, const double defaultValue) const | |||
{ | |||
QVariant var(value(key, defaultValue)); | |||
if (var.isNull()) | |||
return defaultValue; | |||
CARLA_SAFE_ASSERT_RETURN(var.convert(QVariant::Double), defaultValue); | |||
return var.isValid() ? var.toDouble() : defaultValue; | |||
} | |||
QString QSafeSettings::valueString(const QString key, const QString defaultValue) const | |||
{ | |||
QVariant var(value(key, defaultValue)); | |||
if (var.isNull()) | |||
return defaultValue; | |||
CARLA_SAFE_ASSERT_RETURN(var.convert(QVariant::String), defaultValue); | |||
return var.isValid() ? var.toString() : defaultValue; | |||
} | |||
QByteArray QSafeSettings::valueByteArray(const QString key, const QByteArray defaultValue) const | |||
{ | |||
QVariant var(value(key, defaultValue)); | |||
if (var.isNull()) | |||
return defaultValue; | |||
CARLA_SAFE_ASSERT_RETURN(var.convert(QVariant::ByteArray), defaultValue); | |||
return var.isValid() ? var.toByteArray() : defaultValue; | |||
} | |||
QStringList QSafeSettings::valueStringList(const QString key, const QStringList defaultValue) const | |||
{ | |||
QVariant var(value(key, defaultValue)); | |||
if (var.isNull()) | |||
return defaultValue; | |||
CARLA_SAFE_ASSERT_RETURN(var.convert(QVariant::StringList), defaultValue); | |||
return var.isValid() ? var.toStringList() : defaultValue; | |||
} | |||
//--------------------------------------------------------------------------------------------------------------------- | |||
// Custom MessageBox | |||
@@ -437,32 +437,6 @@ int getIndexOfQDoubleListValue(const QList<double>& list, const double value); | |||
bool isQDoubleListEqual(const QList<double>& list1, const QList<double>& list2); | |||
//--------------------------------------------------------------------------------------------------------------------- | |||
// Custom QString class with a few extra methods | |||
class QCarlaString : public QString | |||
{ | |||
public: | |||
inline QCarlaString() | |||
: QString() {} | |||
inline QCarlaString(const char* const ch) | |||
: QString(ch) {} | |||
inline QCarlaString(const QString& s) | |||
: QString(s) {} | |||
inline bool isNotEmpty() const | |||
{ | |||
return !isEmpty(); | |||
} | |||
inline QCarlaString& operator=(const char* const ch) | |||
{ | |||
return (*this = fromUtf8(ch)); | |||
} | |||
}; | |||
//--------------------------------------------------------------------------------------------------------------------- | |||
// Custom QMessageBox which resizes itself to fit text | |||
@@ -476,28 +450,6 @@ protected: | |||
void showEvent(QShowEvent* event); | |||
}; | |||
//--------------------------------------------------------------------------------------------------------------------- | |||
// Safer QSettings class, which does not throw if type mismatches | |||
class QSafeSettings : public QSettings | |||
{ | |||
public: | |||
inline QSafeSettings() | |||
: QSettings() {} | |||
inline QSafeSettings(const QString organizationName, const QString applicationName) | |||
: QSettings(organizationName, applicationName) {} | |||
bool valueBool(const QString key, const bool defaultValue) const; | |||
Qt::CheckState valueCheckState(const QString key, const Qt::CheckState defaultValue) const; | |||
int valueIntPositive(const QString key, const int defaultValue) const; | |||
uint valueUInt(const QString key, const uint defaultValue) const; | |||
double valueDouble(const QString key, const double defaultValue) const; | |||
QString valueString(const QString key, const QString defaultValue) const; | |||
QByteArray valueByteArray(const QString key, const QByteArray defaultValue = QByteArray()) const; | |||
QStringList valueStringList(const QString key, const QStringList defaultValue = QStringList()) const; | |||
}; | |||
//--------------------------------------------------------------------------------------------------------------------- | |||
// Custom MessageBox | |||
@@ -12,6 +12,24 @@ include $(CWD)/Makefile.mk | |||
BINDIR := $(CWD)/../bin | |||
RESDIR := $(CWD)/../resources | |||
# --------------------------------------------------------------------------------------------------------------------- | |||
ifeq ($(WINDOWS),true) | |||
QT5_LINK_FLAGS = $(shell echo $(LINK_FLAGS) | awk 'sub(" -static","")') -static-libgcc | |||
else | |||
QT5_LINK_FLAGS = $(LINK_FLAGS) | |||
endif | |||
ifeq ($(HAVE_QT5),true) | |||
QT5_PREFIX = $(shell pkg-config --variable=prefix Qt5Core) | |||
BUILD_CXX_FLAGS += $(shell pkg-config --cflags Qt5Core Qt5Gui Qt5Widgets) | |||
QT5_LINK_FLAGS += -Wl,-rpath,$(QT5_PREFIX)/lib $(shell pkg-config --libs Qt5Core Qt5Gui Qt5Widgets) | |||
else ifeq ($(HAVE_QT5PKG),true) | |||
QT5_PREFIX = $(shell pkg-config --variable=prefix Qt5OpenGLExtensions) | |||
BUILD_CXX_FLAGS += -DQT_CORE_LIB -DQT_GUI_LIB -DQT_WIDGETS_LIB -I $(QT5_PREFIX)/include/qt5 | |||
QT5_LINK_FLAGS += -Wl,-rpath,$(QT5_PREFIX)/lib -F $(QT5_PREFIX)/lib -framework QtCore -framework QtGui -framework QtWidgets | |||
endif | |||
# --------------------------------------------------------------------------------------------------------------------- | |||
# Translations | |||
@@ -77,26 +95,29 @@ endif | |||
# --------------------------------------------------------------------------------------------------------------------- | |||
# UI code | |||
UIs = \ | |||
ui_carla_about.py \ | |||
ui_carla_about_juce.py \ | |||
ui_carla_add_jack.py \ | |||
ui_carla_database.py \ | |||
ui_carla_edit.py \ | |||
ui_carla_host.py \ | |||
ui_carla_osc_connect.py \ | |||
ui_carla_parameter.py \ | |||
ui_carla_plugin_calf.py \ | |||
ui_carla_plugin_classic.py \ | |||
ui_carla_plugin_compact.py \ | |||
ui_carla_plugin_default.py \ | |||
ui_carla_plugin_presets.py \ | |||
ui_carla_refresh.py \ | |||
ui_carla_settings.py \ | |||
ui_carla_settings_driver.py \ | |||
ui_inputdialog_value.py \ | |||
ui_midipattern.py \ | |||
ui_xycontroller.py | |||
UI_FILES = $(wildcard pluginlist/*.ui) | |||
UIs = $(UI_FILES:%.ui=%_ui.hpp) | |||
UIs += $(UI_FILES:%.ui=%_ui.py) | |||
# ui_carla_about.py \ | |||
# ui_carla_about_juce.py \ | |||
# ui_carla_database.py \ | |||
# ui_carla_edit.py \ | |||
# ui_carla_host.py \ | |||
# ui_carla_osc_connect.py \ | |||
# ui_carla_parameter.py \ | |||
# ui_carla_plugin_calf.py \ | |||
# ui_carla_plugin_classic.py \ | |||
# ui_carla_plugin_compact.py \ | |||
# ui_carla_plugin_default.py \ | |||
# ui_carla_plugin_presets.py \ | |||
# ui_carla_refresh.py \ | |||
# ui_carla_settings.py \ | |||
# ui_carla_settings_driver.py \ | |||
# ui_inputdialog_value.py \ | |||
# ui_midipattern.py \ | |||
# ui_xycontroller.py | |||
# --------------------------------------------------------------------------------------------------------------------- | |||
@@ -104,7 +125,10 @@ all: $(QMs) $(RES) $(UIs) | |||
# --------------------------------------------------------------------------------------------------------------------- | |||
ui_%.py: $(RESDIR)/ui/%.ui | |||
%_ui.hpp: %.ui | |||
$(UIC_QT5) $< -o $@ | |||
%_ui.py: %.ui | |||
$(PYUIC) $< -o $@ | |||
resources_rc.py: $(RESDIR)/resources.qrc $(RESDIR)/*/*.png $(RESDIR)/*/*.svg $(RESDIR)/*/*.svgz | |||
@@ -132,6 +156,16 @@ debug: | |||
# --------------------------------------------------------------------------------------------------------------------- | |||
tests: $(UI_FILES:%.ui=%$(APP_EXT)) | |||
pluginlist/jackappdialog$(APP_EXT): pluginlist/jackappdialog.cpp pluginlist/jackappdialog.ui pluginlist/jackappdialog_ui.hpp | |||
$(CXX) $< $(BUILD_CXX_FLAGS) $(QT5_LINK_FLAGS) -o $@ | |||
pluginlist/pluginlistdialog$(APP_EXT): pluginlist/pluginlistdialog.cpp pluginlist/pluginlistdialog.ui pluginlist/pluginlistdialog_ui.hpp | |||
$(CXX) $< $(BUILD_CXX_FLAGS) $(QT5_LINK_FLAGS) -o $@ | |||
# --------------------------------------------------------------------------------------------------------------------- | |||
lint: | |||
pylint \ | |||
--extension-pkg-whitelist=PyQt5 \ | |||
@@ -2,7 +2,7 @@ | |||
# -*- coding: utf-8 -*- | |||
# Carla plugin host | |||
# Copyright (C) 2011-2017 Filipe Coelho <falktx@falktx.com> | |||
# 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 | |||
@@ -19,7 +19,20 @@ | |||
# ---------------------------------------------------------------------------------------------------------------------- | |||
# Imports (Custom Stuff) | |||
from carla_host import * | |||
from carla_app import ( | |||
CarlaApplication, | |||
) | |||
from carla_host import ( | |||
HostWindow, | |||
initHost, | |||
loadHostSettings, | |||
) | |||
from carla_shared import ( | |||
handleInitialCommandLineArguments, | |||
setUpSignals, | |||
) | |||
# ---------------------------------------------------------------------------------------------------------------------- | |||
# Main | |||
@@ -46,10 +46,11 @@ from carla_shared import ( | |||
CARLA_DEFAULT_MAIN_PRO_THEME_COLOR, | |||
CWD, VERSION, | |||
getPaths, | |||
QSafeSettings, | |||
gCarla | |||
) | |||
from utils import QSafeSettings | |||
# ------------------------------------------------------------------------------------------------------------ | |||
class CarlaApplication(): | |||
@@ -53,13 +53,15 @@ from PyQt5.QtWidgets import ( | |||
import ui_carla_host | |||
from carla_app import * | |||
from carla_backend import * | |||
from carla_backend_qt import CarlaHostQtDLL, CarlaHostQtNull | |||
from carla_database import * | |||
from carla_shared import * | |||
from carla_settings import * | |||
from carla_utils import * | |||
from carla_widgets import * | |||
from patchcanvas import patchcanvas | |||
from pluginlist import PluginDatabaseW | |||
from widgets.digitalpeakmeter import DigitalPeakMeter | |||
from widgets.pixmapkeyboard import PixmapKeyboardHArea | |||
@@ -178,11 +178,12 @@ from carla_shared import ( | |||
getIcon, | |||
fontMetricsHorizontalAdvance, | |||
splitter, | |||
QSafeSettings | |||
) | |||
from patchcanvas.theme import Theme, getThemeName | |||
from utils import QSafeSettings | |||
# --------------------------------------------------------------------------------------------------------------------- | |||
# ... | |||
@@ -870,19 +870,6 @@ class QMessageBoxWithBetterWidth(QMessageBox): | |||
QMessageBox.showEvent(self, event) | |||
# ------------------------------------------------------------------------------------------------------------ | |||
# Safer QSettings class, which does not throw if type mismatches | |||
class QSafeSettings(QSettings): | |||
def value(self, key, defaultValue, valueType): | |||
if not isinstance(defaultValue, valueType): | |||
print("QSafeSettings.value() - defaultValue type mismatch for key", key) | |||
try: | |||
return QSettings.value(self, key, defaultValue, valueType) | |||
except: | |||
return defaultValue | |||
# ------------------------------------------------------------------------------------------------------------ | |||
# Custom MessageBox | |||
@@ -63,7 +63,7 @@ from .utils import CanvasCallback, CanvasGetNewGroupPos, CanvasItemFX, CanvasRem | |||
from . import * | |||
from .scene import PatchScene | |||
from carla_shared import QSafeSettings | |||
from utils import QSafeSettings | |||
# ------------------------------------------------------------------------------------------------------------ | |||
@@ -0,0 +1,20 @@ | |||
#!/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 .jackappdialog import JackApplicationW | |||
from .pluginlistdialog import PluginDatabaseW |
@@ -0,0 +1,390 @@ | |||
#!/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, | |||
) | |||
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 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 findMacVSTBundles(bundlePath, isVST3): | |||
bundles = [] | |||
extension = ".vst3" if isVST3 else ".vst" | |||
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 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,0 +1,772 @@ | |||
#!/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, | |||
) | |||
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_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_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, | |||
findBinaries, | |||
findFilenames, | |||
findMacVSTBundles, | |||
findVST3Binaries | |||
) | |||
# --------------------------------------------------------------------------------------------------------------------- | |||
# 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.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, au: bool, | |||
sf2: bool, sfz: bool, jsfx: bool): | |||
self.fCheckLADSPA = ladspa | |||
self.fCheckDSSI = dssi | |||
self.fCheckLV2 = lv2 | |||
self.fCheckVST2 = vst2 | |||
self.fCheckVST3 = vst3 and (LINUX or MACOS or WINDOWS) | |||
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 | |||
# Increase count by the number of externally discoverable plugin types | |||
if self.fCheckNative: | |||
self.fCurCount += pluginCount | |||
# Linux, MacOS and Windows are the only VST3 supported OSes | |||
if self.fCheckVST3 and not (LINUX or MACOS or WINDOWS): | |||
self.fCurCount -= 1 | |||
if self.fCheckPosix32: | |||
self.fCurCount += pluginCount | |||
if self.fCheckVST3 and not (LINUX or MACOS): | |||
self.fCurCount -= 1 | |||
if self.fCheckPosix64: | |||
self.fCurCount += pluginCount | |||
if self.fCheckVST3 and not (LINUX or MACOS): | |||
self.fCurCount -= 1 | |||
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.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 = findMacVSTBundles(iPATH, False) | |||
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 = findMacVSTBundles(iPATH, True) | |||
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 _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) | |||
# --------------------------------------------------------------------------------------------------------------------- |
@@ -0,0 +1,264 @@ | |||
/* | |||
* 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 "jackappdialog.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 "jackappdialog_ui.hpp" | |||
#include <QtCore/QFileInfo> | |||
#include <QtCore/QVector> | |||
#include <QtWidgets/QPushButton> | |||
#ifdef __clang__ | |||
# pragma clang diagnostic pop | |||
#elif defined(__GNUC__) && __GNUC__ >= 8 | |||
# pragma GCC diagnostic pop | |||
#endif | |||
#include "../utils/qsafesettings.hpp" | |||
#include "../../includes/CarlaLibJackHints.h" | |||
// -------------------------------------------------------------------------------------------------------------------- | |||
// Jack Application Dialog | |||
enum { | |||
UI_SESSION_NONE = 0, | |||
UI_SESSION_LADISH = 1, | |||
UI_SESSION_NSM = 2, | |||
}; | |||
struct JackApplicationW::Self { | |||
Ui_Dialog ui; | |||
const QString fProjectFilename; | |||
Self(const char* const projectFilename) | |||
: fProjectFilename(projectFilename) {} | |||
static Self& create(const char* const projectFilename) | |||
{ | |||
Self* const self = new Self(projectFilename); | |||
return *self; | |||
} | |||
}; | |||
JackApplicationW::JackApplicationW(QWidget* const parent, const char* const projectFilename) | |||
: QDialog(parent), | |||
self(Self::create(projectFilename)) | |||
{ | |||
self.ui.setupUi(this); | |||
// ------------------------------------------------------------------------------------------------------------- | |||
// UI setup | |||
self.ui.group_error->setVisible(false); | |||
adjustSize(); | |||
setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint); | |||
// ------------------------------------------------------------------------------------------------------------- | |||
// Load settings | |||
loadSettings(); | |||
// ------------------------------------------------------------------------------------------------------------- | |||
// Set-up connections | |||
connect(this, &QDialog::finished, | |||
this, &JackApplicationW::slot_saveSettings); | |||
connect(self.ui.cb_session_mgr, static_cast<void(QComboBox::*)(int)>(&QComboBox::currentIndexChanged), | |||
this, &JackApplicationW::slot_sessionManagerChanged); | |||
connect(self.ui.le_command, &QLineEdit::textChanged, | |||
this, &JackApplicationW::slot_commandChanged); | |||
} | |||
JackApplicationW::~JackApplicationW() | |||
{ | |||
delete &self; | |||
} | |||
// ----------------------------------------------------------------------------------------------------------------- | |||
// public methods | |||
JackApplicationW::CommandAndFlags JackApplicationW::getCommandAndFlags() const | |||
{ | |||
const QString command = self.ui.le_command->text(); | |||
QString name = self.ui.le_name->text(); | |||
if (name.isEmpty()) | |||
{ | |||
name = QFileInfo(command.split(' ').first()).baseName(); | |||
name[0] = name[0].toTitleCase(); | |||
} | |||
SessionManager smgr; | |||
switch(self.ui.cb_session_mgr->currentIndex()) | |||
{ | |||
case UI_SESSION_LADISH: | |||
smgr = LIBJACK_SESSION_MANAGER_LADISH; | |||
break; | |||
case UI_SESSION_NSM: | |||
smgr = LIBJACK_SESSION_MANAGER_NSM; | |||
break; | |||
default: | |||
smgr = LIBJACK_SESSION_MANAGER_NONE; | |||
break; | |||
} | |||
uint flags = 0x0; | |||
if (self.ui.cb_manage_window->isChecked()) | |||
flags |= LIBJACK_FLAG_CONTROL_WINDOW; | |||
if (self.ui.cb_capture_first_window->isChecked()) | |||
flags |= LIBJACK_FLAG_CAPTURE_FIRST_WINDOW; | |||
if (self.ui.cb_buffers_addition_mode->isChecked()) | |||
flags |= LIBJACK_FLAG_AUDIO_BUFFERS_ADDITION; | |||
if (self.ui.cb_out_midi_mixdown->isChecked()) | |||
flags |= LIBJACK_FLAG_MIDI_OUTPUT_CHANNEL_MIXDOWN; | |||
if (self.ui.cb_external_start->isChecked()) | |||
flags |= LIBJACK_FLAG_EXTERNAL_START; | |||
const QString labelSetup(QString("%1%2%3%4%5%6").arg(QChar('0' + self.ui.sb_audio_ins->value())) | |||
.arg(QChar('0' + self.ui.sb_audio_outs->value())) | |||
.arg(QChar('0' + self.ui.sb_midi_ins->value())) | |||
.arg(QChar('0' + self.ui.sb_midi_outs->value())) | |||
.arg(QChar('0' + smgr)) | |||
.arg(QChar('0' + flags))); | |||
return {command, name, labelSetup}; | |||
} | |||
// ----------------------------------------------------------------------------------------------------------------- | |||
// private methods | |||
void JackApplicationW::checkIfButtonBoxShouldBeEnabled(const int index, const QCarlaString& command) | |||
{ | |||
bool enabled = command.isNotEmpty(); | |||
QCarlaString showErr; | |||
// NSM applications must not be abstract or absolute paths, and must not contain arguments | |||
if (enabled and index == UI_SESSION_NSM) | |||
{ | |||
if (QVector<QChar>{'.', '/'}.contains(command[0])) | |||
showErr = tr("NSM applications cannot use abstract or absolute paths"); | |||
else if (command.contains(' ') or command.contains(';') or command.contains('&')) | |||
showErr = tr("NSM applications cannot use CLI arguments"); | |||
else if (self.fProjectFilename.isEmpty()) | |||
showErr = tr("You need to save the current Carla project before NSM can be used"); | |||
} | |||
if (showErr.isNotEmpty()) | |||
{ | |||
enabled = false; | |||
self.ui.l_error->setText(showErr); | |||
self.ui.group_error->setVisible(true); | |||
} | |||
else | |||
{ | |||
self.ui.group_error->setVisible(false); | |||
} | |||
if (QPushButton* const button = self.ui.buttonBox->button(QDialogButtonBox::Ok)) | |||
button->setEnabled(enabled); | |||
} | |||
void JackApplicationW::loadSettings() | |||
{ | |||
const QSafeSettings settings("falkTX", "CarlaAddJackApp"); | |||
const QString smName = settings.valueString("SessionManager", ""); | |||
if (smName == "LADISH (SIGUSR1)") | |||
self.ui.cb_session_mgr->setCurrentIndex(UI_SESSION_LADISH); | |||
else if (smName == "NSM") | |||
self.ui.cb_session_mgr->setCurrentIndex(UI_SESSION_NSM); | |||
else | |||
self.ui.cb_session_mgr->setCurrentIndex(UI_SESSION_NONE); | |||
self.ui.le_command->setText(settings.valueString("Command", "")); | |||
self.ui.le_name->setText(settings.valueString("Name", "")); | |||
self.ui.sb_audio_ins->setValue(settings.valueIntPositive("NumAudioIns", 2)); | |||
self.ui.sb_audio_ins->setValue(settings.valueIntPositive("NumAudioIns", 2)); | |||
self.ui.sb_audio_outs->setValue(settings.valueIntPositive("NumAudioOuts", 2)); | |||
self.ui.sb_midi_ins->setValue(settings.valueIntPositive("NumMidiIns", 0)); | |||
self.ui.sb_midi_outs->setValue(settings.valueIntPositive("NumMidiOuts", 0)); | |||
self.ui.cb_manage_window->setChecked(settings.valueBool("ManageWindow", true)); | |||
self.ui.cb_capture_first_window->setChecked(settings.valueBool("CaptureFirstWindow", false)); | |||
self.ui.cb_out_midi_mixdown->setChecked(settings.valueBool("MidiOutMixdown", false)); | |||
checkIfButtonBoxShouldBeEnabled(self.ui.cb_session_mgr->currentIndex(), | |||
self.ui.le_command->text()); | |||
} | |||
// ----------------------------------------------------------------------------------------------------------------- | |||
// private slots | |||
void JackApplicationW::slot_commandChanged(const QString& command) | |||
{ | |||
checkIfButtonBoxShouldBeEnabled(self.ui.cb_session_mgr->currentIndex(), command); | |||
} | |||
void JackApplicationW::slot_sessionManagerChanged(const int index) | |||
{ | |||
checkIfButtonBoxShouldBeEnabled(index, self.ui.le_command->text()); | |||
} | |||
void JackApplicationW::slot_saveSettings() | |||
{ | |||
QSafeSettings settings("falkTX", "CarlaAddJackApp"); | |||
settings.setValue("Command", self.ui.le_command->text()); | |||
settings.setValue("Name", self.ui.le_name->text()); | |||
settings.setValue("SessionManager", self.ui.cb_session_mgr->currentText()); | |||
settings.setValue("NumAudioIns", self.ui.sb_audio_ins->value()); | |||
settings.setValue("NumAudioOuts", self.ui.sb_audio_outs->value()); | |||
settings.setValue("NumMidiIns", self.ui.sb_midi_ins->value()); | |||
settings.setValue("NumMidiOuts", self.ui.sb_midi_outs->value()); | |||
settings.setValue("ManageWindow", self.ui.cb_manage_window->isChecked()); | |||
settings.setValue("CaptureFirstWindow", self.ui.cb_capture_first_window->isChecked()); | |||
settings.setValue("MidiOutMixdown", self.ui.cb_out_midi_mixdown->isChecked()); | |||
} | |||
// -------------------------------------------------------------------------------------------------------------------- | |||
// Testing | |||
#include "../utils/qsafesettings.cpp" | |||
int main(int argc, char* argv[]) | |||
{ | |||
QApplication app(argc, argv); | |||
JackApplicationW gui(nullptr, ""); | |||
gui.show(); | |||
if (gui.exec()) | |||
{ | |||
auto cf = gui.getCommandAndFlags(); | |||
printf("Results:\n"); | |||
printf("\tCommand: %s\n", cf.command.toUtf8().constData()); | |||
printf("\tName: %s\n", cf.name.toUtf8().constData()); | |||
printf("\tLabelSetup: %s\n", cf.labelSetup.toUtf8().constData()); | |||
} | |||
return 0; | |||
} | |||
// -------------------------------------------------------------------------------------------------------------------- |
@@ -0,0 +1,76 @@ | |||
/* | |||
* 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. | |||
*/ | |||
#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 "../utils/qcarlastring.hpp" | |||
// -------------------------------------------------------------------------------------------------------------------- | |||
// Jack Application Dialog | |||
class JackApplicationW : public QDialog | |||
{ | |||
struct Self; | |||
Self& self; | |||
public: | |||
explicit JackApplicationW(QWidget* parent, const char* projectFilename); | |||
~JackApplicationW() override; | |||
// ---------------------------------------------------------------------------------------------------------------- | |||
// public methods | |||
struct CommandAndFlags { | |||
QString command; | |||
QString name; | |||
QString labelSetup; | |||
}; | |||
CommandAndFlags getCommandAndFlags() const; | |||
// ---------------------------------------------------------------------------------------------------------------- | |||
// private methods | |||
private: | |||
void checkIfButtonBoxShouldBeEnabled(int index, const QCarlaString& text); | |||
void loadSettings(); | |||
// ---------------------------------------------------------------------------------------------------------------- | |||
// private slots | |||
private slots: | |||
void slot_commandChanged(const QString& command); | |||
void slot_sessionManagerChanged(int); | |||
void slot_saveSettings(); | |||
}; | |||
// -------------------------------------------------------------------------------------------------------------------- |
@@ -0,0 +1,221 @@ | |||
#!/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 | |||
from PyQt5.QtWidgets import QDialog, QDialogButtonBox, QWidget | |||
# --------------------------------------------------------------------------------------------------------------------- | |||
# Imports (Carla) | |||
from utils import QSafeSettings | |||
# --------------------------------------------------------------------------------------------------------------------- | |||
# Imports (Local) | |||
from .jackappdialog_ui import Ui_Dialog | |||
# --------------------------------------------------------------------------------------------------------------------- | |||
# Imports (API) | |||
SESSION_MGR_NONE = 0 | |||
SESSION_MGR_AUTO = 1 | |||
SESSION_MGR_JACK = 2 | |||
SESSION_MGR_LADISH = 3 | |||
SESSION_MGR_NSM = 4 | |||
FLAG_CONTROL_WINDOW = 0x01 | |||
FLAG_CAPTURE_FIRST_WINDOW = 0x02 | |||
FLAG_BUFFERS_ADDITION_MODE = 0x10 | |||
FLAG_MIDI_OUTPUT_CHANNEL_MIXDOWN = 0x20 | |||
FLAG_EXTERNAL_START = 0x40 | |||
# --------------------------------------------------------------------------------------------------------------------- | |||
# Jack Application Dialog | |||
UI_SESSION_NONE = 0 | |||
UI_SESSION_LADISH = 1 | |||
UI_SESSION_NSM = 2 | |||
class JackApplicationW(QDialog): | |||
def __init__(self, parent: QWidget, projectFilename: str): | |||
QDialog.__init__(self, parent) | |||
self.ui = Ui_Dialog() | |||
self.ui.setupUi(self) | |||
self.fProjectFilename = projectFilename | |||
# -------------------------------------------------------------------------------------------------------------- | |||
# UI setup | |||
self.ui.group_error.setVisible(False) | |||
self.adjustSize() | |||
self.setWindowFlags(self.windowFlags() & ~Qt.WindowContextHelpButtonHint) | |||
# -------------------------------------------------------------------------------------------------------------- | |||
# Load settings | |||
self._loadSettings() | |||
# -------------------------------------------------------------------------------------------------------------- | |||
# Set-up connections | |||
self.finished.connect(self._slot_saveSettings) | |||
self.ui.cb_session_mgr.currentIndexChanged.connect(self._slot_sessionManagerChanged) | |||
self.ui.le_command.textChanged.connect(self._slot_commandChanged) | |||
# ----------------------------------------------------------------------------------------------------------------- | |||
# public methods | |||
def getCommandAndFlags(self): | |||
name = self.ui.le_name.text() | |||
command = self.ui.le_command.text() | |||
smgr = SESSION_MGR_NONE | |||
flags = 0x0 | |||
if not name: | |||
name = os.path.basename(command.split(" ",1)[0]).title() | |||
uiSessionMgrIndex = self.ui.cb_session_mgr.currentIndex() | |||
if uiSessionMgrIndex == UI_SESSION_LADISH: | |||
smgr = SESSION_MGR_LADISH | |||
elif uiSessionMgrIndex == UI_SESSION_NSM: | |||
smgr = SESSION_MGR_NSM | |||
if self.ui.cb_manage_window.isChecked(): | |||
flags |= FLAG_CONTROL_WINDOW | |||
if self.ui.cb_capture_first_window.isChecked(): | |||
flags |= FLAG_CAPTURE_FIRST_WINDOW | |||
if self.ui.cb_buffers_addition_mode.isChecked(): | |||
flags |= FLAG_BUFFERS_ADDITION_MODE | |||
if self.ui.cb_out_midi_mixdown.isChecked(): | |||
flags |= FLAG_MIDI_OUTPUT_CHANNEL_MIXDOWN | |||
if self.ui.cb_external_start.isChecked(): | |||
flags |= FLAG_EXTERNAL_START | |||
bv = ord('0') | |||
v1 = chr(bv + self.ui.sb_audio_ins.value()) | |||
v2 = chr(bv + self.ui.sb_audio_outs.value()) | |||
v3 = chr(bv + self.ui.sb_midi_ins.value()) | |||
v4 = chr(bv + self.ui.sb_midi_outs.value()) | |||
v5 = chr(bv + smgr) | |||
v6 = chr(bv + flags) | |||
labelSetup = f"{v1}{v2}{v3}{v4}{v5}{v6}" | |||
return (command, name, labelSetup) | |||
# ----------------------------------------------------------------------------------------------------------------- | |||
# private methods | |||
def _checkIfButtonBoxShouldBeEnabled(self, index: int, command: str): | |||
enabled = len(command) > 0 | |||
showErr = "" | |||
# NSM applications must not be abstract or absolute paths, and must not contain arguments | |||
if enabled and index == UI_SESSION_NSM: | |||
if command[0] in (".", "/"): | |||
showErr = self.tr("NSM applications cannot use abstract or absolute paths") | |||
elif " " in command or ";" in command or "&" in command: | |||
showErr = self.tr("NSM applications cannot use CLI arguments") | |||
elif not self.fProjectFilename: | |||
showErr = self.tr("You need to save the current Carla project before NSM can be used") | |||
if showErr: | |||
enabled = False | |||
self.ui.l_error.setText(showErr) | |||
self.ui.group_error.setVisible(True) | |||
else: | |||
self.ui.group_error.setVisible(False) | |||
self.ui.buttonBox.button(QDialogButtonBox.Ok).setEnabled(enabled) | |||
def _loadSettings(self): | |||
settings = QSafeSettings("falkTX", "CarlaAddJackApp") | |||
smName = settings.value("SessionManager", "", str) | |||
if smName == "LADISH (SIGUSR1)": | |||
self.ui.cb_session_mgr.setCurrentIndex(UI_SESSION_LADISH) | |||
elif smName == "NSM": | |||
self.ui.cb_session_mgr.setCurrentIndex(UI_SESSION_NSM) | |||
else: | |||
self.ui.cb_session_mgr.setCurrentIndex(UI_SESSION_NONE) | |||
self.ui.le_command.setText(settings.value("Command", "", str)) | |||
self.ui.le_name.setText(settings.value("Name", "", str)) | |||
self.ui.sb_audio_ins.setValue(settings.value("NumAudioIns", 2, int)) | |||
self.ui.sb_audio_ins.setValue(settings.value("NumAudioIns", 2, int)) | |||
self.ui.sb_audio_outs.setValue(settings.value("NumAudioOuts", 2, int)) | |||
self.ui.sb_midi_ins.setValue(settings.value("NumMidiIns", 0, int)) | |||
self.ui.sb_midi_outs.setValue(settings.value("NumMidiOuts", 0, int)) | |||
self.ui.cb_manage_window.setChecked(settings.value("ManageWindow", True, bool)) | |||
self.ui.cb_capture_first_window.setChecked(settings.value("CaptureFirstWindow", False, bool)) | |||
self.ui.cb_out_midi_mixdown.setChecked(settings.value("MidiOutMixdown", False, bool)) | |||
self._checkIfButtonBoxShouldBeEnabled(self.ui.cb_session_mgr.currentIndex(), | |||
self.ui.le_command.text()) | |||
# ----------------------------------------------------------------------------------------------------------------- | |||
# private slots | |||
@pyqtSlot(str) | |||
def _slot_commandChanged(self, command: str): | |||
self._checkIfButtonBoxShouldBeEnabled(self.ui.cb_session_mgr.currentIndex(), command) | |||
@pyqtSlot(int) | |||
def _slot_sessionManagerChanged(self, index: int): | |||
self._checkIfButtonBoxShouldBeEnabled(index, self.ui.le_command.text()) | |||
@pyqtSlot() | |||
def _slot_saveSettings(self): | |||
settings = QSafeSettings("falkTX", "CarlaAddJackApp") | |||
settings.setValue("Command", self.ui.le_command.text()) | |||
settings.setValue("Name", self.ui.le_name.text()) | |||
settings.setValue("SessionManager", self.ui.cb_session_mgr.currentText()) | |||
settings.setValue("NumAudioIns", self.ui.sb_audio_ins.value()) | |||
settings.setValue("NumAudioOuts", self.ui.sb_audio_outs.value()) | |||
settings.setValue("NumMidiIns", self.ui.sb_midi_ins.value()) | |||
settings.setValue("NumMidiOuts", self.ui.sb_midi_outs.value()) | |||
settings.setValue("ManageWindow", self.ui.cb_manage_window.isChecked()) | |||
settings.setValue("CaptureFirstWindow", self.ui.cb_capture_first_window.isChecked()) | |||
settings.setValue("MidiOutMixdown", self.ui.cb_out_midi_mixdown.isChecked()) | |||
# --------------------------------------------------------------------------------------------------------------------- | |||
# Testing | |||
if __name__ == '__main__': | |||
import sys | |||
# pylint: disable=ungrouped-imports | |||
from PyQt5.QtWidgets import QApplication | |||
# pylint: enable=ungrouped-imports | |||
_app = QApplication(sys.argv) | |||
_gui = JackApplicationW(None, "") | |||
if _gui.exec_(): | |||
_command, _name, _labelSetup = _gui.getCommandAndFlags() | |||
print("Results:") | |||
print(f"\tCommand: {_command}") | |||
print(f"\tName: {_name}") | |||
print(f"\tLabelSetup: {_labelSetup}") | |||
# --------------------------------------------------------------------------------------------------------------------- |
@@ -0,0 +1,971 @@ | |||
#!/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, QByteArray, QEventLoop | |||
from PyQt5.QtWidgets import QApplication, QDialog, QHeaderView, QTableWidgetItem, QWidget | |||
# --------------------------------------------------------------------------------------------------------------------- | |||
# Imports (Carla) | |||
from carla_backend import ( | |||
BINARY_NATIVE, | |||
BINARY_OTHER, | |||
BINARY_POSIX32, | |||
BINARY_POSIX64, | |||
BINARY_WIN32, | |||
BINARY_WIN64, | |||
PLUGIN_AU, | |||
PLUGIN_DSSI, | |||
PLUGIN_HAS_CUSTOM_UI, | |||
PLUGIN_HAS_INLINE_DISPLAY, | |||
PLUGIN_INTERNAL, | |||
PLUGIN_IS_BRIDGE, | |||
PLUGIN_IS_RTSAFE, | |||
PLUGIN_IS_SYNTH, | |||
PLUGIN_JSFX, | |||
PLUGIN_LADSPA, | |||
PLUGIN_LV2, | |||
PLUGIN_SF2, | |||
PLUGIN_SFZ, | |||
PLUGIN_VST2, | |||
PLUGIN_VST3, | |||
) | |||
from carla_shared import ( | |||
CARLA_DEFAULT_LV2_PATH, | |||
CARLA_KEY_PATHS_LV2, | |||
HAIKU, | |||
LINUX, | |||
MACOS, | |||
WINDOWS, | |||
fontMetricsHorizontalAdvance, | |||
gCarla, | |||
getIcon, | |||
kIs64bit, | |||
splitter, | |||
) | |||
from carla_utils import getPluginTypeAsString | |||
from utils import QSafeSettings | |||
# --------------------------------------------------------------------------------------------------------------------- | |||
# Imports (Local) | |||
from .discovery import PLUGIN_QUERY_API_VERSION, checkPluginCached | |||
from .pluginlistdialog_ui import Ui_PluginDatabaseW | |||
from .pluginlistrefreshdialog import PluginRefreshW | |||
# --------------------------------------------------------------------------------------------------------------------- | |||
# Plugin Database Dialog | |||
class PluginDatabaseW(QDialog): | |||
TABLEWIDGET_ITEM_FAVORITE = 0 | |||
TABLEWIDGET_ITEM_NAME = 1 | |||
TABLEWIDGET_ITEM_LABEL = 2 | |||
TABLEWIDGET_ITEM_MAKER = 3 | |||
TABLEWIDGET_ITEM_BINARY = 4 | |||
def __init__(self, parent: QWidget, host, useSystemIcons: bool): | |||
QDialog.__init__(self, parent) | |||
self.host = host | |||
self.ui = Ui_PluginDatabaseW() | |||
self.ui.setupUi(self) | |||
# To be changed by parent | |||
self.hasLoadedLv2Plugins = False | |||
# ---------------------------------------------------------------------------------------------------- | |||
# Internal stuff | |||
self.fLastTableIndex = 0 | |||
self.fRetPlugin = None | |||
self.fRealParent = parent | |||
self.fFavoritePlugins = [] | |||
self.fFavoritePluginsChanged = False | |||
self.fUseSystemIcons = useSystemIcons | |||
self.fTrYes = self.tr("Yes") | |||
self.fTrNo = self.tr("No") | |||
self.fTrNative = self.tr("Native") | |||
# ---------------------------------------------------------------------------------------------------- | |||
# Set-up GUI | |||
self.ui.b_add.setEnabled(False) | |||
self.addAction(self.ui.act_focus_search) | |||
self.ui.act_focus_search.triggered.connect(self.slot_focusSearchFieldAndSelectAll) | |||
if BINARY_NATIVE in (BINARY_POSIX32, BINARY_WIN32): | |||
self.ui.ch_bridged.setText(self.tr("Bridged (64bit)")) | |||
else: | |||
self.ui.ch_bridged.setText(self.tr("Bridged (32bit)")) | |||
if not (LINUX or MACOS): | |||
self.ui.ch_bridged_wine.setChecked(False) | |||
self.ui.ch_bridged_wine.setEnabled(False) | |||
if MACOS: | |||
self.setWindowModality(Qt.WindowModal) | |||
else: | |||
self.ui.ch_au.setChecked(False) | |||
self.ui.ch_au.setEnabled(False) | |||
self.ui.ch_au.setVisible(False) | |||
self.ui.tab_info.tabBar().hide() | |||
self.ui.tab_reqs.tabBar().hide() | |||
# FIXME, why /2 needed? | |||
self.ui.tab_info.setMinimumWidth(int(self.ui.la_id.width()/2) + | |||
fontMetricsHorizontalAdvance(self.ui.l_id.fontMetrics(), "9999999999") + 6*3) | |||
self.setWindowFlags(self.windowFlags() & ~Qt.WindowContextHelpButtonHint) | |||
# ---------------------------------------------------------------------------------------------------- | |||
# Load settings | |||
self.loadSettings() | |||
# ---------------------------------------------------------------------------------------------------- | |||
# Disable bridges if not enabled in settings | |||
# 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(True) | |||
self.ui.ch_bridged.setChecked(False) | |||
self.ui.ch_bridged.setEnabled(False) | |||
self.ui.ch_bridged.setVisible(False) | |||
self.ui.ch_bridged_wine.setChecked(False) | |||
self.ui.ch_bridged_wine.setEnabled(False) | |||
self.ui.ch_bridged_wine.setVisible(False) | |||
self.ui.l_arch.setVisible(False) | |||
elif not host.showWineBridges: | |||
self.ui.ch_bridged_wine.setChecked(False) | |||
self.ui.ch_bridged_wine.setEnabled(False) | |||
self.ui.ch_bridged_wine.setVisible(False) | |||
# ---------------------------------------------------------------------------------------------------- | |||
# Set-up Icons | |||
if useSystemIcons: | |||
self.ui.b_add.setIcon(getIcon('list-add', 16, 'svgz')) | |||
self.ui.b_cancel.setIcon(getIcon('dialog-cancel', 16, 'svgz')) | |||
self.ui.b_clear_filters.setIcon(getIcon('edit-clear', 16, 'svgz')) | |||
self.ui.b_refresh.setIcon(getIcon('view-refresh', 16, 'svgz')) | |||
hhi = self.ui.tableWidget.horizontalHeaderItem(self.TABLEWIDGET_ITEM_FAVORITE) | |||
hhi.setIcon(getIcon('bookmarks', 16, 'svgz')) | |||
# ---------------------------------------------------------------------------------------------------- | |||
# Set-up connections | |||
self.finished.connect(self.slot_saveSettings) | |||
self.ui.b_add.clicked.connect(self.slot_addPlugin) | |||
self.ui.b_cancel.clicked.connect(self.reject) | |||
self.ui.b_refresh.clicked.connect(self.slot_refreshPlugins) | |||
self.ui.b_clear_filters.clicked.connect(self.slot_clearFilters) | |||
self.ui.lineEdit.textChanged.connect(self.slot_checkFilters) | |||
self.ui.tableWidget.currentCellChanged.connect(self.slot_checkPlugin) | |||
self.ui.tableWidget.cellClicked.connect(self.slot_cellClicked) | |||
self.ui.tableWidget.cellDoubleClicked.connect(self.slot_cellDoubleClicked) | |||
self.ui.ch_internal.clicked.connect(self.slot_checkFilters) | |||
self.ui.ch_ladspa.clicked.connect(self.slot_checkFilters) | |||
self.ui.ch_dssi.clicked.connect(self.slot_checkFilters) | |||
self.ui.ch_lv2.clicked.connect(self.slot_checkFilters) | |||
self.ui.ch_vst.clicked.connect(self.slot_checkFilters) | |||
self.ui.ch_vst3.clicked.connect(self.slot_checkFilters) | |||
self.ui.ch_au.clicked.connect(self.slot_checkFilters) | |||
self.ui.ch_jsfx.clicked.connect(self.slot_checkFilters) | |||
self.ui.ch_kits.clicked.connect(self.slot_checkFilters) | |||
self.ui.ch_effects.clicked.connect(self.slot_checkFilters) | |||
self.ui.ch_instruments.clicked.connect(self.slot_checkFilters) | |||
self.ui.ch_midi.clicked.connect(self.slot_checkFilters) | |||
self.ui.ch_other.clicked.connect(self.slot_checkFilters) | |||
self.ui.ch_native.clicked.connect(self.slot_checkFilters) | |||
self.ui.ch_bridged.clicked.connect(self.slot_checkFilters) | |||
self.ui.ch_bridged_wine.clicked.connect(self.slot_checkFilters) | |||
self.ui.ch_favorites.clicked.connect(self.slot_checkFilters) | |||
self.ui.ch_rtsafe.clicked.connect(self.slot_checkFilters) | |||
self.ui.ch_cv.clicked.connect(self.slot_checkFilters) | |||
self.ui.ch_gui.clicked.connect(self.slot_checkFilters) | |||
self.ui.ch_inline_display.clicked.connect(self.slot_checkFilters) | |||
self.ui.ch_stereo.clicked.connect(self.slot_checkFilters) | |||
self.ui.ch_cat_all.clicked.connect(self.slot_checkFiltersCategoryAll) | |||
self.ui.ch_cat_delay.clicked.connect(self.slot_checkFiltersCategorySpecific) | |||
self.ui.ch_cat_distortion.clicked.connect(self.slot_checkFiltersCategorySpecific) | |||
self.ui.ch_cat_dynamics.clicked.connect(self.slot_checkFiltersCategorySpecific) | |||
self.ui.ch_cat_eq.clicked.connect(self.slot_checkFiltersCategorySpecific) | |||
self.ui.ch_cat_filter.clicked.connect(self.slot_checkFiltersCategorySpecific) | |||
self.ui.ch_cat_modulator.clicked.connect(self.slot_checkFiltersCategorySpecific) | |||
self.ui.ch_cat_synth.clicked.connect(self.slot_checkFiltersCategorySpecific) | |||
self.ui.ch_cat_utility.clicked.connect(self.slot_checkFiltersCategorySpecific) | |||
self.ui.ch_cat_other.clicked.connect(self.slot_checkFiltersCategorySpecific) | |||
# ---------------------------------------------------------------------------------------------------- | |||
# Post-connect setup | |||
self._reAddPlugins() | |||
self.slot_focusSearchFieldAndSelectAll() | |||
# -------------------------------------------------------------------------------------------------------- | |||
@pyqtSlot(int, int) | |||
def slot_cellClicked(self, row, column): | |||
if column == self.TABLEWIDGET_ITEM_FAVORITE: | |||
widget = self.ui.tableWidget.item(row, self.TABLEWIDGET_ITEM_FAVORITE) | |||
plugin = self.ui.tableWidget.item(row, self.TABLEWIDGET_ITEM_NAME).data(Qt.UserRole+1) | |||
plugin = self._createFavoritePluginDict(plugin) | |||
if widget.checkState() == Qt.Checked: | |||
if not plugin in self.fFavoritePlugins: | |||
self.fFavoritePlugins.append(plugin) | |||
self.fFavoritePluginsChanged = True | |||
else: | |||
try: | |||
self.fFavoritePlugins.remove(plugin) | |||
self.fFavoritePluginsChanged = True | |||
except ValueError: | |||
pass | |||
@pyqtSlot(int, int) | |||
def slot_cellDoubleClicked(self, _, column): | |||
if column != self.TABLEWIDGET_ITEM_FAVORITE: | |||
self.slot_addPlugin() | |||
@pyqtSlot() | |||
def slot_focusSearchFieldAndSelectAll(self): | |||
self.ui.lineEdit.setFocus() | |||
self.ui.lineEdit.selectAll() | |||
@pyqtSlot() | |||
def slot_addPlugin(self): | |||
if self.ui.tableWidget.currentRow() >= 0: | |||
self.fRetPlugin = self.ui.tableWidget.item(self.ui.tableWidget.currentRow(), | |||
self.TABLEWIDGET_ITEM_NAME).data(Qt.UserRole+1) | |||
self.accept() | |||
else: | |||
self.reject() | |||
@pyqtSlot(int) | |||
def slot_checkPlugin(self, row): | |||
if row >= 0: | |||
self.ui.b_add.setEnabled(True) | |||
plugin = self.ui.tableWidget.item(self.ui.tableWidget.currentRow(), | |||
self.TABLEWIDGET_ITEM_NAME).data(Qt.UserRole+1) | |||
isSynth = bool(plugin['hints'] & PLUGIN_IS_SYNTH) | |||
isEffect = bool(plugin['audio.ins'] > 0 < plugin['audio.outs'] and not isSynth) | |||
isMidi = bool(plugin['audio.ins'] == 0 and | |||
plugin['audio.outs'] == 0 and | |||
plugin['midi.ins'] > 0 < plugin['midi.outs']) | |||
# isKit = bool(plugin['type'] in (PLUGIN_SF2, PLUGIN_SFZ)) | |||
# isOther = bool(not (isEffect or isSynth or isMidi or isKit)) | |||
if isSynth: | |||
ptype = "Instrument" | |||
elif isEffect: | |||
ptype = "Effect" | |||
elif isMidi: | |||
ptype = "MIDI Plugin" | |||
else: | |||
ptype = "Other" | |||
if plugin['build'] == BINARY_NATIVE: | |||
parch = self.fTrNative | |||
elif plugin['build'] == BINARY_POSIX32: | |||
parch = "posix32" | |||
elif plugin['build'] == BINARY_POSIX64: | |||
parch = "posix64" | |||
elif plugin['build'] == BINARY_WIN32: | |||
parch = "win32" | |||
elif plugin['build'] == BINARY_WIN64: | |||
parch = "win64" | |||
elif plugin['build'] == BINARY_OTHER: | |||
parch = self.tr("Other") | |||
elif plugin['build'] == BINARY_WIN32: | |||
parch = self.tr("Unknown") | |||
self.ui.l_format.setText(getPluginTypeAsString(plugin['type'])) | |||
self.ui.l_type.setText(ptype) | |||
self.ui.l_arch.setText(parch) | |||
self.ui.l_id.setText(str(plugin['uniqueId'])) | |||
self.ui.l_ains.setText(str(plugin['audio.ins'])) | |||
self.ui.l_aouts.setText(str(plugin['audio.outs'])) | |||
self.ui.l_cvins.setText(str(plugin['cv.ins'])) | |||
self.ui.l_cvouts.setText(str(plugin['cv.outs'])) | |||
self.ui.l_mins.setText(str(plugin['midi.ins'])) | |||
self.ui.l_mouts.setText(str(plugin['midi.outs'])) | |||
self.ui.l_pins.setText(str(plugin['parameters.ins'])) | |||
self.ui.l_pouts.setText(str(plugin['parameters.outs'])) | |||
self.ui.l_gui.setText(self.fTrYes if plugin['hints'] & PLUGIN_HAS_CUSTOM_UI else self.fTrNo) | |||
self.ui.l_idisp.setText(self.fTrYes if plugin['hints'] & PLUGIN_HAS_INLINE_DISPLAY else self.fTrNo) | |||
self.ui.l_bridged.setText(self.fTrYes if plugin['hints'] & PLUGIN_IS_BRIDGE else self.fTrNo) | |||
self.ui.l_synth.setText(self.fTrYes if isSynth else self.fTrNo) | |||
else: | |||
self.ui.b_add.setEnabled(False) | |||
self.ui.l_format.setText("---") | |||
self.ui.l_type.setText("---") | |||
self.ui.l_arch.setText("---") | |||
self.ui.l_id.setText("---") | |||
self.ui.l_ains.setText("---") | |||
self.ui.l_aouts.setText("---") | |||
self.ui.l_cvins.setText("---") | |||
self.ui.l_cvouts.setText("---") | |||
self.ui.l_mins.setText("---") | |||
self.ui.l_mouts.setText("---") | |||
self.ui.l_pins.setText("---") | |||
self.ui.l_pouts.setText("---") | |||
self.ui.l_gui.setText("---") | |||
self.ui.l_idisp.setText("---") | |||
self.ui.l_bridged.setText("---") | |||
self.ui.l_synth.setText("---") | |||
@pyqtSlot() | |||
def slot_checkFilters(self): | |||
self._checkFilters() | |||
@pyqtSlot(bool) | |||
def slot_checkFiltersCategoryAll(self, clicked): | |||
self.ui.ch_cat_delay.setChecked(not clicked) | |||
self.ui.ch_cat_distortion.setChecked(not clicked) | |||
self.ui.ch_cat_dynamics.setChecked(not clicked) | |||
self.ui.ch_cat_eq.setChecked(not clicked) | |||
self.ui.ch_cat_filter.setChecked(not clicked) | |||
self.ui.ch_cat_modulator.setChecked(not clicked) | |||
self.ui.ch_cat_synth.setChecked(not clicked) | |||
self.ui.ch_cat_utility.setChecked(not clicked) | |||
self.ui.ch_cat_other.setChecked(not clicked) | |||
self._checkFilters() | |||
@pyqtSlot(bool) | |||
def slot_checkFiltersCategorySpecific(self, clicked): | |||
if clicked: | |||
self.ui.ch_cat_all.setChecked(False) | |||
elif not (self.ui.ch_cat_delay.isChecked() or | |||
self.ui.ch_cat_distortion.isChecked() or | |||
self.ui.ch_cat_dynamics.isChecked() or | |||
self.ui.ch_cat_eq.isChecked() or | |||
self.ui.ch_cat_filter.isChecked() or | |||
self.ui.ch_cat_modulator.isChecked() or | |||
self.ui.ch_cat_synth.isChecked() or | |||
self.ui.ch_cat_utility.isChecked() or | |||
self.ui.ch_cat_other.isChecked()): | |||
self.ui.ch_cat_all.setChecked(True) | |||
self._checkFilters() | |||
@pyqtSlot() | |||
def slot_refreshPlugins(self): | |||
if PluginRefreshW(self, self.host, self.fUseSystemIcons, self.hasLoadedLv2Plugins).exec_(): | |||
self._reAddPlugins() | |||
if self.fRealParent: | |||
self.fRealParent.setLoadRDFsNeeded() | |||
@pyqtSlot() | |||
def slot_clearFilters(self): | |||
self.blockSignals(True) | |||
self.ui.ch_internal.setChecked(True) | |||
self.ui.ch_ladspa.setChecked(True) | |||
self.ui.ch_dssi.setChecked(True) | |||
self.ui.ch_lv2.setChecked(True) | |||
self.ui.ch_vst.setChecked(True) | |||
self.ui.ch_jsfx.setChecked(True) | |||
self.ui.ch_kits.setChecked(True) | |||
self.ui.ch_instruments.setChecked(True) | |||
self.ui.ch_effects.setChecked(True) | |||
self.ui.ch_midi.setChecked(True) | |||
self.ui.ch_other.setChecked(True) | |||
self.ui.ch_native.setChecked(True) | |||
self.ui.ch_bridged.setChecked(False) | |||
self.ui.ch_bridged_wine.setChecked(False) | |||
self.ui.ch_favorites.setChecked(False) | |||
self.ui.ch_rtsafe.setChecked(False) | |||
self.ui.ch_stereo.setChecked(False) | |||
self.ui.ch_cv.setChecked(False) | |||
self.ui.ch_gui.setChecked(False) | |||
self.ui.ch_inline_display.setChecked(False) | |||
if self.ui.ch_vst3.isEnabled(): | |||
self.ui.ch_vst3.setChecked(True) | |||
if self.ui.ch_au.isEnabled(): | |||
self.ui.ch_au.setChecked(True) | |||
self.ui.ch_cat_all.setChecked(True) | |||
self.ui.ch_cat_delay.setChecked(False) | |||
self.ui.ch_cat_distortion.setChecked(False) | |||
self.ui.ch_cat_dynamics.setChecked(False) | |||
self.ui.ch_cat_eq.setChecked(False) | |||
self.ui.ch_cat_filter.setChecked(False) | |||
self.ui.ch_cat_modulator.setChecked(False) | |||
self.ui.ch_cat_synth.setChecked(False) | |||
self.ui.ch_cat_utility.setChecked(False) | |||
self.ui.ch_cat_other.setChecked(False) | |||
self.ui.lineEdit.clear() | |||
self.blockSignals(False) | |||
self._checkFilters() | |||
# -------------------------------------------------------------------------------------------------------- | |||
@pyqtSlot() | |||
def slot_saveSettings(self): | |||
settings = QSafeSettings("falkTX", "CarlaDatabase2") | |||
settings.setValue("PluginDatabase/Geometry", self.saveGeometry()) | |||
settings.setValue("PluginDatabase/TableGeometry_6", self.ui.tableWidget.horizontalHeader().saveState()) | |||
settings.setValue("PluginDatabase/ShowEffects", self.ui.ch_effects.isChecked()) | |||
settings.setValue("PluginDatabase/ShowInstruments", self.ui.ch_instruments.isChecked()) | |||
settings.setValue("PluginDatabase/ShowMIDI", self.ui.ch_midi.isChecked()) | |||
settings.setValue("PluginDatabase/ShowOther", self.ui.ch_other.isChecked()) | |||
settings.setValue("PluginDatabase/ShowInternal", self.ui.ch_internal.isChecked()) | |||
settings.setValue("PluginDatabase/ShowLADSPA", self.ui.ch_ladspa.isChecked()) | |||
settings.setValue("PluginDatabase/ShowDSSI", self.ui.ch_dssi.isChecked()) | |||
settings.setValue("PluginDatabase/ShowLV2", self.ui.ch_lv2.isChecked()) | |||
settings.setValue("PluginDatabase/ShowVST2", self.ui.ch_vst.isChecked()) | |||
settings.setValue("PluginDatabase/ShowVST3", self.ui.ch_vst3.isChecked()) | |||
settings.setValue("PluginDatabase/ShowAU", self.ui.ch_au.isChecked()) | |||
settings.setValue("PluginDatabase/ShowJSFX", self.ui.ch_jsfx.isChecked()) | |||
settings.setValue("PluginDatabase/ShowKits", self.ui.ch_kits.isChecked()) | |||
settings.setValue("PluginDatabase/ShowNative", self.ui.ch_native.isChecked()) | |||
settings.setValue("PluginDatabase/ShowBridged", self.ui.ch_bridged.isChecked()) | |||
settings.setValue("PluginDatabase/ShowBridgedWine", self.ui.ch_bridged_wine.isChecked()) | |||
settings.setValue("PluginDatabase/ShowFavorites", self.ui.ch_favorites.isChecked()) | |||
settings.setValue("PluginDatabase/ShowRtSafe", self.ui.ch_rtsafe.isChecked()) | |||
settings.setValue("PluginDatabase/ShowHasCV", self.ui.ch_cv.isChecked()) | |||
settings.setValue("PluginDatabase/ShowHasGUI", self.ui.ch_gui.isChecked()) | |||
settings.setValue("PluginDatabase/ShowHasInlineDisplay", self.ui.ch_inline_display.isChecked()) | |||
settings.setValue("PluginDatabase/ShowStereoOnly", self.ui.ch_stereo.isChecked()) | |||
settings.setValue("PluginDatabase/SearchText", self.ui.lineEdit.text()) | |||
if self.ui.ch_cat_all.isChecked(): | |||
settings.setValue("PluginDatabase/ShowCategory", "all") | |||
else: | |||
categoryhash = "" | |||
if self.ui.ch_cat_delay.isChecked(): | |||
categoryhash += ":delay" | |||
if self.ui.ch_cat_distortion.isChecked(): | |||
categoryhash += ":distortion" | |||
if self.ui.ch_cat_dynamics.isChecked(): | |||
categoryhash += ":dynamics" | |||
if self.ui.ch_cat_eq.isChecked(): | |||
categoryhash += ":eq" | |||
if self.ui.ch_cat_filter.isChecked(): | |||
categoryhash += ":filter" | |||
if self.ui.ch_cat_modulator.isChecked(): | |||
categoryhash += ":modulator" | |||
if self.ui.ch_cat_synth.isChecked(): | |||
categoryhash += ":synth" | |||
if self.ui.ch_cat_utility.isChecked(): | |||
categoryhash += ":utility" | |||
if self.ui.ch_cat_other.isChecked(): | |||
categoryhash += ":other" | |||
if categoryhash: | |||
categoryhash += ":" | |||
settings.setValue("PluginDatabase/ShowCategory", categoryhash) | |||
if self.fFavoritePluginsChanged: | |||
settings.setValue("PluginDatabase/Favorites", self.fFavoritePlugins) | |||
# -------------------------------------------------------------------------------------------------------- | |||
def loadSettings(self): | |||
settings = QSafeSettings("falkTX", "CarlaDatabase2") | |||
self.fFavoritePlugins = settings.value("PluginDatabase/Favorites", [], list) | |||
self.fFavoritePluginsChanged = False | |||
self.restoreGeometry(settings.value("PluginDatabase/Geometry", QByteArray(), QByteArray)) | |||
self.ui.ch_effects.setChecked(settings.value("PluginDatabase/ShowEffects", True, bool)) | |||
self.ui.ch_instruments.setChecked(settings.value("PluginDatabase/ShowInstruments", True, bool)) | |||
self.ui.ch_midi.setChecked(settings.value("PluginDatabase/ShowMIDI", True, bool)) | |||
self.ui.ch_other.setChecked(settings.value("PluginDatabase/ShowOther", True, bool)) | |||
self.ui.ch_internal.setChecked(settings.value("PluginDatabase/ShowInternal", True, bool)) | |||
self.ui.ch_ladspa.setChecked(settings.value("PluginDatabase/ShowLADSPA", True, bool)) | |||
self.ui.ch_dssi.setChecked(settings.value("PluginDatabase/ShowDSSI", True, bool)) | |||
self.ui.ch_lv2.setChecked(settings.value("PluginDatabase/ShowLV2", True, bool)) | |||
self.ui.ch_vst.setChecked(settings.value("PluginDatabase/ShowVST2", True, bool)) | |||
self.ui.ch_vst3.setChecked(settings.value("PluginDatabase/ShowVST3", (MACOS or WINDOWS), bool)) | |||
self.ui.ch_au.setChecked(settings.value("PluginDatabase/ShowAU", MACOS, bool)) | |||
self.ui.ch_jsfx.setChecked(settings.value("PluginDatabase/ShowJSFX", True, bool)) | |||
self.ui.ch_kits.setChecked(settings.value("PluginDatabase/ShowKits", True, bool)) | |||
self.ui.ch_native.setChecked(settings.value("PluginDatabase/ShowNative", True, bool)) | |||
self.ui.ch_bridged.setChecked(settings.value("PluginDatabase/ShowBridged", True, bool)) | |||
self.ui.ch_bridged_wine.setChecked(settings.value("PluginDatabase/ShowBridgedWine", True, bool)) | |||
self.ui.ch_favorites.setChecked(settings.value("PluginDatabase/ShowFavorites", False, bool)) | |||
self.ui.ch_rtsafe.setChecked(settings.value("PluginDatabase/ShowRtSafe", False, bool)) | |||
self.ui.ch_cv.setChecked(settings.value("PluginDatabase/ShowHasCV", False, bool)) | |||
self.ui.ch_gui.setChecked(settings.value("PluginDatabase/ShowHasGUI", False, bool)) | |||
self.ui.ch_inline_display.setChecked(settings.value("PluginDatabase/ShowHasInlineDisplay", False, bool)) | |||
self.ui.ch_stereo.setChecked(settings.value("PluginDatabase/ShowStereoOnly", False, bool)) | |||
self.ui.lineEdit.setText(settings.value("PluginDatabase/SearchText", "", str)) | |||
categoryhash = settings.value("PluginDatabase/ShowCategory", "all", str) | |||
if categoryhash == "all" or len(categoryhash) < 2: | |||
self.ui.ch_cat_all.setChecked(True) | |||
self.ui.ch_cat_delay.setChecked(False) | |||
self.ui.ch_cat_distortion.setChecked(False) | |||
self.ui.ch_cat_dynamics.setChecked(False) | |||
self.ui.ch_cat_eq.setChecked(False) | |||
self.ui.ch_cat_filter.setChecked(False) | |||
self.ui.ch_cat_modulator.setChecked(False) | |||
self.ui.ch_cat_synth.setChecked(False) | |||
self.ui.ch_cat_utility.setChecked(False) | |||
self.ui.ch_cat_other.setChecked(False) | |||
else: | |||
self.ui.ch_cat_all.setChecked(False) | |||
self.ui.ch_cat_delay.setChecked(":delay:" in categoryhash) | |||
self.ui.ch_cat_distortion.setChecked(":distortion:" in categoryhash) | |||
self.ui.ch_cat_dynamics.setChecked(":dynamics:" in categoryhash) | |||
self.ui.ch_cat_eq.setChecked(":eq:" in categoryhash) | |||
self.ui.ch_cat_filter.setChecked(":filter:" in categoryhash) | |||
self.ui.ch_cat_modulator.setChecked(":modulator:" in categoryhash) | |||
self.ui.ch_cat_synth.setChecked(":synth:" in categoryhash) | |||
self.ui.ch_cat_utility.setChecked(":utility:" in categoryhash) | |||
self.ui.ch_cat_other.setChecked(":other:" in categoryhash) | |||
tableGeometry = settings.value("PluginDatabase/TableGeometry_6", QByteArray(), QByteArray) | |||
horizontalHeader = self.ui.tableWidget.horizontalHeader() | |||
if not tableGeometry.isNull(): | |||
horizontalHeader.restoreState(tableGeometry) | |||
else: | |||
horizontalHeader.setSectionResizeMode(self.TABLEWIDGET_ITEM_FAVORITE, QHeaderView.Fixed) | |||
self.ui.tableWidget.setColumnWidth(self.TABLEWIDGET_ITEM_FAVORITE, 24) | |||
self.ui.tableWidget.setColumnWidth(self.TABLEWIDGET_ITEM_NAME, 250) | |||
self.ui.tableWidget.setColumnWidth(self.TABLEWIDGET_ITEM_LABEL, 200) | |||
self.ui.tableWidget.setColumnWidth(self.TABLEWIDGET_ITEM_MAKER, 150) | |||
self.ui.tableWidget.sortByColumn(self.TABLEWIDGET_ITEM_NAME, Qt.AscendingOrder) | |||
# -------------------------------------------------------------------------------------------------------- | |||
def _createFavoritePluginDict(self, plugin): | |||
return { | |||
'name' : plugin['name'], | |||
'build' : plugin['build'], | |||
'type' : plugin['type'], | |||
'filename': plugin['filename'], | |||
'label' : plugin['label'], | |||
'uniqueId': plugin['uniqueId'], | |||
} | |||
def _checkFilters(self): | |||
text = self.ui.lineEdit.text().lower() | |||
hideEffects = not self.ui.ch_effects.isChecked() | |||
hideInstruments = not self.ui.ch_instruments.isChecked() | |||
hideMidi = not self.ui.ch_midi.isChecked() | |||
hideOther = not self.ui.ch_other.isChecked() | |||
hideInternal = not self.ui.ch_internal.isChecked() | |||
hideLadspa = not self.ui.ch_ladspa.isChecked() | |||
hideDssi = not self.ui.ch_dssi.isChecked() | |||
hideLV2 = not self.ui.ch_lv2.isChecked() | |||
hideVST2 = not self.ui.ch_vst.isChecked() | |||
hideVST3 = not self.ui.ch_vst3.isChecked() | |||
hideAU = not self.ui.ch_au.isChecked() | |||
hideJSFX = not self.ui.ch_jsfx.isChecked() | |||
hideKits = not self.ui.ch_kits.isChecked() | |||
hideNative = not self.ui.ch_native.isChecked() | |||
hideBridged = not self.ui.ch_bridged.isChecked() | |||
hideBridgedWine = not self.ui.ch_bridged_wine.isChecked() | |||
hideNonFavs = self.ui.ch_favorites.isChecked() | |||
hideNonRtSafe = self.ui.ch_rtsafe.isChecked() | |||
hideNonCV = self.ui.ch_cv.isChecked() | |||
hideNonGui = self.ui.ch_gui.isChecked() | |||
hideNonIDisp = self.ui.ch_inline_display.isChecked() | |||
hideNonStereo = self.ui.ch_stereo.isChecked() | |||
if HAIKU or LINUX or MACOS: | |||
nativeBins = [BINARY_POSIX32, BINARY_POSIX64] | |||
wineBins = [BINARY_WIN32, BINARY_WIN64] | |||
elif WINDOWS: | |||
nativeBins = [BINARY_WIN32, BINARY_WIN64] | |||
wineBins = [] | |||
else: | |||
nativeBins = [] | |||
wineBins = [] | |||
self.ui.tableWidget.setRowCount(self.fLastTableIndex) | |||
for i in range(self.fLastTableIndex): | |||
plugin = self.ui.tableWidget.item(i, self.TABLEWIDGET_ITEM_NAME).data(Qt.UserRole+1) | |||
ptext = self.ui.tableWidget.item(i, self.TABLEWIDGET_ITEM_NAME).data(Qt.UserRole+2) | |||
aIns = plugin['audio.ins'] | |||
aOuts = plugin['audio.outs'] | |||
cvIns = plugin['cv.ins'] | |||
cvOuts = plugin['cv.outs'] | |||
mIns = plugin['midi.ins'] | |||
mOuts = plugin['midi.outs'] | |||
phints = plugin['hints'] | |||
ptype = plugin['type'] | |||
categ = plugin['category'] | |||
isSynth = bool(phints & PLUGIN_IS_SYNTH) | |||
isEffect = bool(aIns > 0 < aOuts and not isSynth) | |||
isMidi = bool(aIns == 0 and aOuts == 0 and mIns > 0 < mOuts) | |||
isKit = bool(ptype in (PLUGIN_SF2, PLUGIN_SFZ)) | |||
isOther = bool(not (isEffect or isSynth or isMidi or isKit)) | |||
isNative = bool(plugin['build'] == BINARY_NATIVE) | |||
isRtSafe = bool(phints & PLUGIN_IS_RTSAFE) | |||
isStereo = bool(aIns == 2 and aOuts == 2) or (isSynth and aOuts == 2) | |||
hasCV = bool(cvIns + cvOuts > 0) | |||
hasGui = bool(phints & PLUGIN_HAS_CUSTOM_UI) | |||
hasIDisp = bool(phints & PLUGIN_HAS_INLINE_DISPLAY) | |||
isBridged = bool(not isNative and plugin['build'] in nativeBins) | |||
isBridgedWine = bool(not isNative and plugin['build'] in wineBins) | |||
if hideEffects and isEffect: | |||
self.ui.tableWidget.hideRow(i) | |||
elif hideInstruments and isSynth: | |||
self.ui.tableWidget.hideRow(i) | |||
elif hideMidi and isMidi: | |||
self.ui.tableWidget.hideRow(i) | |||
elif hideOther and isOther: | |||
self.ui.tableWidget.hideRow(i) | |||
elif hideKits and isKit: | |||
self.ui.tableWidget.hideRow(i) | |||
elif hideInternal and ptype == PLUGIN_INTERNAL: | |||
self.ui.tableWidget.hideRow(i) | |||
elif hideLadspa and ptype == PLUGIN_LADSPA: | |||
self.ui.tableWidget.hideRow(i) | |||
elif hideDssi and ptype == PLUGIN_DSSI: | |||
self.ui.tableWidget.hideRow(i) | |||
elif hideLV2 and ptype == PLUGIN_LV2: | |||
self.ui.tableWidget.hideRow(i) | |||
elif hideVST2 and ptype == PLUGIN_VST2: | |||
self.ui.tableWidget.hideRow(i) | |||
elif hideVST3 and ptype == PLUGIN_VST3: | |||
self.ui.tableWidget.hideRow(i) | |||
elif hideAU and ptype == PLUGIN_AU: | |||
self.ui.tableWidget.hideRow(i) | |||
elif hideJSFX and ptype == PLUGIN_JSFX: | |||
self.ui.tableWidget.hideRow(i) | |||
elif hideNative and isNative: | |||
self.ui.tableWidget.hideRow(i) | |||
elif hideBridged and isBridged: | |||
self.ui.tableWidget.hideRow(i) | |||
elif hideBridgedWine and isBridgedWine: | |||
self.ui.tableWidget.hideRow(i) | |||
elif hideNonRtSafe and not isRtSafe: | |||
self.ui.tableWidget.hideRow(i) | |||
elif hideNonCV and not hasCV: | |||
self.ui.tableWidget.hideRow(i) | |||
elif hideNonGui and not hasGui: | |||
self.ui.tableWidget.hideRow(i) | |||
elif hideNonIDisp and not hasIDisp: | |||
self.ui.tableWidget.hideRow(i) | |||
elif hideNonStereo and not isStereo: | |||
self.ui.tableWidget.hideRow(i) | |||
elif text and not all(t in ptext for t in text.strip().split(' ')): | |||
self.ui.tableWidget.hideRow(i) | |||
elif hideNonFavs and self._createFavoritePluginDict(plugin) not in self.fFavoritePlugins: | |||
self.ui.tableWidget.hideRow(i) | |||
elif (self.ui.ch_cat_all.isChecked() or | |||
(self.ui.ch_cat_delay.isChecked() and categ == "delay") or | |||
(self.ui.ch_cat_distortion.isChecked() and categ == "distortion") or | |||
(self.ui.ch_cat_dynamics.isChecked() and categ == "dynamics") or | |||
(self.ui.ch_cat_eq.isChecked() and categ == "eq") or | |||
(self.ui.ch_cat_filter.isChecked() and categ == "filter") or | |||
(self.ui.ch_cat_modulator.isChecked() and categ == "modulator") or | |||
(self.ui.ch_cat_synth.isChecked() and categ == "synth") or | |||
(self.ui.ch_cat_utility.isChecked() and categ == "utility") or | |||
(self.ui.ch_cat_other.isChecked() and categ == "other")): | |||
self.ui.tableWidget.showRow(i) | |||
else: | |||
self.ui.tableWidget.hideRow(i) | |||
# -------------------------------------------------------------------------------------------------------- | |||
def _addPluginToTable(self, plugin, ptype): | |||
if plugin['API'] != PLUGIN_QUERY_API_VERSION: | |||
return | |||
if ptype in (self.tr("Internal"), "LV2", "SF2", "SFZ", "JSFX"): | |||
plugin['build'] = BINARY_NATIVE | |||
index = self.fLastTableIndex | |||
isFav = bool(self._createFavoritePluginDict(plugin) in self.fFavoritePlugins) | |||
favItem = QTableWidgetItem() | |||
favItem.setCheckState(Qt.Checked if isFav else Qt.Unchecked) | |||
favItem.setText(" " if isFav else " ") | |||
pluginText = (plugin['name']+plugin['label']+plugin['maker']+plugin['filename']).lower() | |||
self.ui.tableWidget.setItem(index, self.TABLEWIDGET_ITEM_FAVORITE, favItem) | |||
self.ui.tableWidget.setItem(index, self.TABLEWIDGET_ITEM_NAME, QTableWidgetItem(plugin['name'])) | |||
self.ui.tableWidget.setItem(index, self.TABLEWIDGET_ITEM_LABEL, QTableWidgetItem(plugin['label'])) | |||
self.ui.tableWidget.setItem(index, self.TABLEWIDGET_ITEM_MAKER, QTableWidgetItem(plugin['maker'])) | |||
self.ui.tableWidget.setItem(index, self.TABLEWIDGET_ITEM_BINARY, QTableWidgetItem(os.path.basename(plugin['filename']))) | |||
self.ui.tableWidget.item(index, self.TABLEWIDGET_ITEM_NAME).setData(Qt.UserRole+1, plugin) | |||
self.ui.tableWidget.item(index, self.TABLEWIDGET_ITEM_NAME).setData(Qt.UserRole+2, pluginText) | |||
self.fLastTableIndex += 1 | |||
# -------------------------------------------------------------------------------------------------------- | |||
def _reAddInternalHelper(self, settingsDB, ptype, path): | |||
if ptype == PLUGIN_INTERNAL: | |||
ptypeStr = "Internal" | |||
ptypeStrTr = self.tr("Internal") | |||
elif ptype == PLUGIN_LV2: | |||
ptypeStr = "LV2" | |||
ptypeStrTr = ptypeStr | |||
elif ptype == PLUGIN_AU: | |||
ptypeStr = "AU" | |||
ptypeStrTr = ptypeStr | |||
#elif ptype == PLUGIN_SFZ: | |||
#ptypeStr = "SFZ" | |||
#ptypeStrTr = ptypeStr | |||
# TODO(jsfx) what to do here? | |||
else: | |||
return 0 | |||
plugins = settingsDB.value("Plugins/" + ptypeStr, [], list) | |||
pluginCount = settingsDB.value("PluginCount/" + ptypeStr, 0, int) | |||
if ptype == PLUGIN_AU: | |||
gCarla.utils.juce_init() | |||
pluginCountNew = gCarla.utils.get_cached_plugin_count(ptype, path) | |||
if pluginCountNew != pluginCount or len(plugins) != pluginCount or (len(plugins) > 0 and plugins[0]['API'] != PLUGIN_QUERY_API_VERSION): | |||
plugins = [] | |||
pluginCount = pluginCountNew | |||
QApplication.processEvents(QEventLoop.ExcludeUserInputEvents, 50) | |||
if ptype == PLUGIN_AU: | |||
gCarla.utils.juce_idle() | |||
for i in range(pluginCountNew): | |||
descInfo = gCarla.utils.get_cached_plugin_info(ptype, i) | |||
if not descInfo['valid']: | |||
continue | |||
info = checkPluginCached(descInfo, ptype) | |||
plugins.append(info) | |||
if i % 50 == 0: | |||
QApplication.processEvents(QEventLoop.ExcludeUserInputEvents, 50) | |||
if ptype == PLUGIN_AU: | |||
gCarla.utils.juce_idle() | |||
settingsDB.setValue("Plugins/" + ptypeStr, plugins) | |||
settingsDB.setValue("PluginCount/" + ptypeStr, pluginCount) | |||
if ptype == PLUGIN_AU: | |||
gCarla.utils.juce_cleanup() | |||
# prepare rows in advance | |||
self.ui.tableWidget.setRowCount(self.fLastTableIndex + len(plugins)) | |||
for plugin in plugins: | |||
self._addPluginToTable(plugin, ptypeStrTr) | |||
return pluginCount | |||
def _reAddPlugins(self): | |||
settingsDB = QSafeSettings("falkTX", "CarlaPlugins5") | |||
self.fLastTableIndex = 0 | |||
self.ui.tableWidget.setSortingEnabled(False) | |||
self.ui.tableWidget.clearContents() | |||
settings = QSafeSettings("falkTX", "Carla2") | |||
LV2_PATH = splitter.join(settings.value(CARLA_KEY_PATHS_LV2, CARLA_DEFAULT_LV2_PATH, list)) | |||
del settings | |||
# ---------------------------------------------------------------------------------------------------- | |||
# plugins handled through backend | |||
internalCount = self._reAddInternalHelper(settingsDB, PLUGIN_INTERNAL, "") | |||
lv2Count = self._reAddInternalHelper(settingsDB, PLUGIN_LV2, LV2_PATH) | |||
auCount = self._reAddInternalHelper(settingsDB, PLUGIN_AU, "") if MACOS else 0 | |||
# ---------------------------------------------------------------------------------------------------- | |||
# LADSPA | |||
ladspaPlugins = [] | |||
ladspaPlugins += settingsDB.value("Plugins/LADSPA_native", [], list) | |||
ladspaPlugins += settingsDB.value("Plugins/LADSPA_posix32", [], list) | |||
ladspaPlugins += settingsDB.value("Plugins/LADSPA_posix64", [], list) | |||
ladspaPlugins += settingsDB.value("Plugins/LADSPA_win32", [], list) | |||
ladspaPlugins += settingsDB.value("Plugins/LADSPA_win64", [], list) | |||
# ---------------------------------------------------------------------------------------------------- | |||
# DSSI | |||
dssiPlugins = [] | |||
dssiPlugins += settingsDB.value("Plugins/DSSI_native", [], list) | |||
dssiPlugins += settingsDB.value("Plugins/DSSI_posix32", [], list) | |||
dssiPlugins += settingsDB.value("Plugins/DSSI_posix64", [], list) | |||
dssiPlugins += settingsDB.value("Plugins/DSSI_win32", [], list) | |||
dssiPlugins += settingsDB.value("Plugins/DSSI_win64", [], list) | |||
# ---------------------------------------------------------------------------------------------------- | |||
# VST2 | |||
vst2Plugins = [] | |||
vst2Plugins += settingsDB.value("Plugins/VST2_native", [], list) | |||
vst2Plugins += settingsDB.value("Plugins/VST2_posix32", [], list) | |||
vst2Plugins += settingsDB.value("Plugins/VST2_posix64", [], list) | |||
vst2Plugins += settingsDB.value("Plugins/VST2_win32", [], list) | |||
vst2Plugins += settingsDB.value("Plugins/VST2_win64", [], list) | |||
# ---------------------------------------------------------------------------------------------------- | |||
# VST3 | |||
vst3Plugins = [] | |||
vst3Plugins += settingsDB.value("Plugins/VST3_native", [], list) | |||
vst3Plugins += settingsDB.value("Plugins/VST3_posix32", [], list) | |||
vst3Plugins += settingsDB.value("Plugins/VST3_posix64", [], list) | |||
vst3Plugins += settingsDB.value("Plugins/VST3_win32", [], list) | |||
vst3Plugins += settingsDB.value("Plugins/VST3_win64", [], list) | |||
# ---------------------------------------------------------------------------------------------------- | |||
# AU (extra non-cached) | |||
auPlugins32 = settingsDB.value("Plugins/AU_posix32", [], list) if MACOS else [] | |||
# ---------------------------------------------------------------------------------------------------- | |||
# JSFX | |||
jsfxPlugins = settingsDB.value("Plugins/JSFX", [], list) | |||
# ---------------------------------------------------------------------------------------------------- | |||
# Kits | |||
sf2s = settingsDB.value("Plugins/SF2", [], list) | |||
sfzs = settingsDB.value("Plugins/SFZ", [], list) | |||
# ---------------------------------------------------------------------------------------------------- | |||
# count plugins first, so we can create rows in advance | |||
ladspaCount = 0 | |||
dssiCount = 0 | |||
vstCount = 0 | |||
vst3Count = 0 | |||
au32Count = 0 | |||
jsfxCount = len(jsfxPlugins) | |||
sf2Count = 0 | |||
sfzCount = len(sfzs) | |||
for plugins in ladspaPlugins: | |||
ladspaCount += len(plugins) | |||
for plugins in dssiPlugins: | |||
dssiCount += len(plugins) | |||
for plugins in vst2Plugins: | |||
vstCount += len(plugins) | |||
for plugins in vst3Plugins: | |||
vst3Count += len(plugins) | |||
for plugins in auPlugins32: | |||
au32Count += len(plugins) | |||
for plugins in sf2s: | |||
sf2Count += len(plugins) | |||
self.ui.tableWidget.setRowCount(self.fLastTableIndex + | |||
ladspaCount + dssiCount + vstCount + vst3Count + au32Count + jsfxCount + | |||
sf2Count + sfzCount) | |||
if MACOS: | |||
self.ui.label.setText(self.tr("Have %i Internal, %i LADSPA, %i DSSI, %i LV2, %i VST2, %i VST3, %i AudioUnit plugins and %i JSFX plugins, plus %i Sound Kits" % ( | |||
internalCount, ladspaCount, dssiCount, lv2Count, vstCount, vst3Count, auCount+au32Count, jsfxCount, sf2Count+sfzCount))) | |||
else: | |||
self.ui.label.setText(self.tr("Have %i Internal, %i LADSPA, %i DSSI, %i LV2, %i VST2, %i VST3 plugins and %i JSFX plugins, plus %i Sound Kits" % ( | |||
internalCount, ladspaCount, dssiCount, lv2Count, vstCount, vst3Count, jsfxCount, sf2Count+sfzCount))) | |||
# ---------------------------------------------------------------------------------------------------- | |||
# now add all plugins to the table | |||
for plugins in ladspaPlugins: | |||
for plugin in plugins: | |||
self._addPluginToTable(plugin, "LADSPA") | |||
for plugins in dssiPlugins: | |||
for plugin in plugins: | |||
self._addPluginToTable(plugin, "DSSI") | |||
for plugins in vst2Plugins: | |||
for plugin in plugins: | |||
self._addPluginToTable(plugin, "VST2") | |||
for plugins in vst3Plugins: | |||
for plugin in plugins: | |||
self._addPluginToTable(plugin, "VST3") | |||
for plugins in auPlugins32: | |||
for plugin in plugins: | |||
self._addPluginToTable(plugin, "AU") | |||
for plugin in jsfxPlugins: | |||
self._addPluginToTable(plugin, "JSFX") | |||
for sf2 in sf2s: | |||
for sf2_i in sf2: | |||
self._addPluginToTable(sf2_i, "SF2") | |||
for sfz in sfzs: | |||
self._addPluginToTable(sfz, "SFZ") | |||
# ---------------------------------------------------------------------------------------------------- | |||
self.ui.tableWidget.setSortingEnabled(True) | |||
self._checkFilters() | |||
self.slot_checkPlugin(self.ui.tableWidget.currentRow()) | |||
# -------------------------------------------------------------------------------------------------------- | |||
def showEvent(self, event): | |||
self.slot_focusSearchFieldAndSelectAll() | |||
QDialog.showEvent(self, event) | |||
# --------------------------------------------------------------------------------------------------------------------- | |||
# Testing | |||
if __name__ == '__main__': | |||
import sys | |||
class _host: | |||
pathBinaries = "" | |||
showPluginBridges = False | |||
showWineBridges = False | |||
_host = _host() | |||
_app = QApplication(sys.argv) | |||
_gui = PluginDatabaseW(None, _host, True) | |||
if _gui.exec_(): | |||
print(f"Result: {_gui.fRetPlugin}") | |||
# --------------------------------------------------------------------------------------------------------------------- |
@@ -0,0 +1,471 @@ | |||
#!/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 not (LINUX or hasWin32 or hasWin64): | |||
self.ui.ch_vst3.setEnabled(False) | |||
self.ui.ch_vst3.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) | |||
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_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) | |||
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/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, 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_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, 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_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,0 +1,19 @@ | |||
#!/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. | |||
from .qsafesettings import QSafeSettings |
@@ -0,0 +1,64 @@ | |||
/* | |||
* 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 <QtCore/QString> | |||
#ifdef __clang__ | |||
# pragma clang diagnostic pop | |||
#elif defined(__GNUC__) && __GNUC__ >= 8 | |||
# pragma GCC diagnostic pop | |||
#endif | |||
//--------------------------------------------------------------------------------------------------------------------- | |||
// Custom QString class with a few extra methods | |||
class QCarlaString : public QString | |||
{ | |||
public: | |||
explicit inline QCarlaString() | |||
: QString() {} | |||
explicit inline QCarlaString(const char* const str) | |||
: QString(fromUtf8(str)) {} | |||
inline QCarlaString(const QString& s) | |||
: QString(s) {} | |||
inline bool isNotEmpty() const | |||
{ | |||
return !isEmpty(); | |||
} | |||
inline QCarlaString& operator=(const char* const str) | |||
{ | |||
return (*this = fromUtf8(str)); | |||
} | |||
}; | |||
//--------------------------------------------------------------------------------------------------------------------- |
@@ -0,0 +1,113 @@ | |||
/* | |||
* 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 "qsafesettings.hpp" | |||
//--------------------------------------------------------------------------------------------------------------------- | |||
bool QSafeSettings::valueBool(const QString& key, const bool defaultValue) const | |||
{ | |||
QVariant var(value(key, defaultValue)); | |||
if (!var.isNull() && var.convert(QVariant::Bool) && var.isValid()) | |||
return var.toBool(); | |||
return defaultValue; | |||
} | |||
Qt::CheckState QSafeSettings::valueCheckState(const QString& key, const Qt::CheckState defaultValue) const | |||
{ | |||
QVariant var(value(key, defaultValue)); | |||
if (!var.isNull() && var.convert(QVariant::UInt) && var.isValid()) | |||
{ | |||
const uint value = var.toUInt(); | |||
switch (value) | |||
{ | |||
case Qt::Unchecked: | |||
case Qt::PartiallyChecked: | |||
case Qt::Checked: | |||
return static_cast<Qt::CheckState>(value); | |||
} | |||
} | |||
return defaultValue; | |||
} | |||
int QSafeSettings::valueIntPositive(const QString& key, const int defaultValue) const | |||
{ | |||
QVariant var(value(key, defaultValue)); | |||
if (!var.isNull() && var.convert(QVariant::Int) && var.isValid()) | |||
return defaultValue; | |||
const int value = var.toInt(); | |||
return value >= 0 ? value : defaultValue; | |||
} | |||
uint QSafeSettings::valueUInt(const QString& key, const uint defaultValue) const | |||
{ | |||
QVariant var(value(key, defaultValue)); | |||
if (!var.isNull() && var.convert(QVariant::UInt) && var.isValid()) | |||
return var.toUInt(); | |||
return defaultValue; | |||
} | |||
double QSafeSettings::valueDouble(const QString& key, const double defaultValue) const | |||
{ | |||
QVariant var(value(key, defaultValue)); | |||
if (!var.isNull() && var.convert(QVariant::Double) && var.isValid()) | |||
return var.toDouble(); | |||
return defaultValue; | |||
} | |||
QString QSafeSettings::valueString(const QString& key, const QString& defaultValue) const | |||
{ | |||
QVariant var(value(key, defaultValue)); | |||
if (!var.isNull() && var.convert(QVariant::String) && var.isValid()) | |||
return var.toString(); | |||
return defaultValue; | |||
} | |||
QByteArray QSafeSettings::valueByteArray(const QString& key, const QByteArray defaultValue) const | |||
{ | |||
QVariant var(value(key, defaultValue)); | |||
if (!var.isNull() && var.convert(QVariant::ByteArray) && var.isValid()) | |||
return var.toByteArray(); | |||
return defaultValue; | |||
} | |||
QStringList QSafeSettings::valueStringList(const QString& key, const QStringList defaultValue) const | |||
{ | |||
QVariant var(value(key, defaultValue)); | |||
if (!var.isNull() && var.convert(QVariant::StringList) && var.isValid()) | |||
return var.toStringList(); | |||
return defaultValue; | |||
} | |||
//--------------------------------------------------------------------------------------------------------------------- |
@@ -0,0 +1,60 @@ | |||
/* | |||
* 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 <QtCore/QSettings> | |||
#ifdef __clang__ | |||
# pragma clang diagnostic pop | |||
#elif defined(__GNUC__) && __GNUC__ >= 8 | |||
# pragma GCC diagnostic pop | |||
#endif | |||
//--------------------------------------------------------------------------------------------------------------------- | |||
// Safer QSettings class, which does not throw if type mismatches | |||
class QSafeSettings : public QSettings | |||
{ | |||
public: | |||
inline QSafeSettings() | |||
: QSettings() {} | |||
inline QSafeSettings(const QString& organization, const QString& application) | |||
: QSettings(organization, application) {} | |||
bool valueBool(const QString& key, bool defaultValue) const; | |||
Qt::CheckState valueCheckState(const QString& key, Qt::CheckState defaultValue) const; | |||
int valueIntPositive(const QString& key, int defaultValue) const; | |||
uint valueUInt(const QString& key, uint defaultValue) const; | |||
double valueDouble(const QString& key, double defaultValue) const; | |||
QString valueString(const QString& key, const QString& defaultValue) const; | |||
QByteArray valueByteArray(const QString& key, QByteArray defaultValue = {}) const; | |||
QStringList valueStringList(const QString& key, QStringList defaultValue = {}) const; | |||
}; | |||
//--------------------------------------------------------------------------------------------------------------------- |
@@ -0,0 +1,37 @@ | |||
#!/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) | |||
from PyQt5.QtCore import QSettings | |||
# --------------------------------------------------------------------------------------------------------------------- | |||
# Safer QSettings class, which does not throw if type mismatches | |||
class QSafeSettings(QSettings): | |||
def value(self, key, defaultValue, valueType): | |||
if not isinstance(defaultValue, valueType): | |||
print("QSafeSettings.value() - defaultValue type mismatch for key", key) | |||
try: | |||
return QSettings.value(self, key, defaultValue, valueType) | |||
except: | |||
return defaultValue | |||
# --------------------------------------------------------------------------------------------------------------------- |
@@ -24,9 +24,9 @@ from PyQt5.QtGui import QColor, QPainter, QPixmap | |||
from PyQt5.QtWidgets import QActionGroup, QMenu, QScrollArea, QWidget | |||
# --------------------------------------------------------------------------------------------------------------------- | |||
# Imports (Custom) | |||
# Imports (Carla) | |||
from carla_shared import QSafeSettings | |||
from utils import QSafeSettings | |||
# --------------------------------------------------------------------------------------------------------------------- | |||
@@ -27,7 +27,6 @@ | |||
#include "water/memory/SharedResourcePointer.h" | |||
#include "water/text/StringArray.h" | |||
using water::Array; | |||
using water::File; | |||
using water::SharedResourcePointer; | |||
using water::String; | |||