From 5fed7a05d7597f444af4c2dfd53ebe7b18d3549f Mon Sep 17 00:00:00 2001 From: falkTX Date: Sat, 21 Dec 2019 23:52:21 +0000 Subject: [PATCH] Implement add-jack in c++, start plugin refresh Signed-off-by: falkTX --- source/frontend/Makefile | 2 + source/frontend/carla_database.cpp | 289 ++++++++++++++++++++++++- source/frontend/carla_database.hpp | 11 +- source/frontend/carla_database_app.cpp | 2 +- source/frontend/carla_shared.cpp | 36 ++- source/frontend/carla_shared.hpp | 2 +- 6 files changed, 326 insertions(+), 16 deletions(-) diff --git a/source/frontend/Makefile b/source/frontend/Makefile index e24eee7c0..2a0f96504 100644 --- a/source/frontend/Makefile +++ b/source/frontend/Makefile @@ -198,6 +198,7 @@ OBJS = \ $(OBJDIR)/carla_shared.cpp.o \ $(OBJDIR)/carla_widgets.cpp.o \ $(OBJDIR)/patchcanvas/theme.cpp.o \ + $(OBJDIR)/moc_carla_database.cpp.o \ $(OBJDIR)/moc_carla_host.cpp.o \ $(OBJDIR)/moc_carla_settings.cpp.o \ $(OBJDIR)/moc_carla_widgets.cpp.o \ @@ -282,5 +283,6 @@ debug: # --------------------------------------------------------------------------------------------------------------------- -include $(OBJS:%.o=%.d) +-include $(OBJDIR)/carla_database_app.cpp.d # --------------------------------------------------------------------------------------------------------------------- diff --git a/source/frontend/carla_database.cpp b/source/frontend/carla_database.cpp index fdbf32ae9..5f58e71db 100644 --- a/source/frontend/carla_database.cpp +++ b/source/frontend/carla_database.cpp @@ -17,18 +17,104 @@ #include "carla_database.hpp" +//--------------------------------------------------------------------------------------------------------------------- +// Imports (Global) + +#include +#include + +#include + +//--------------------------------------------------------------------------------------------------------------------- +// Imports (Custom) + +#include "ui_carla_add_jack.hpp" +#include "ui_carla_database.hpp" +#include "ui_carla_refresh.hpp" + +#include "carla_host.hpp" + +#include "CarlaHost.h" +#include "CarlaLibJackHints.h" + // -------------------------------------------------------------------------------------------------------------------- // Separate Thread for Plugin Search +struct WineSettings { + QString executable; + bool autoPrefix; + QString fallbackPrefix; + + WineSettings() + : executable(), + autoPrefix(false), + fallbackPrefix() + { + const QSafeSettings settings("falkTX", "Carla2"); + + executable = settings.valueString(CARLA_KEY_WINE_EXECUTABLE, CARLA_DEFAULT_WINE_EXECUTABLE); + autoPrefix = settings.valueBool(CARLA_KEY_WINE_AUTO_PREFIX, CARLA_DEFAULT_WINE_AUTO_PREFIX); + fallbackPrefix = settings.valueString(CARLA_KEY_WINE_FALLBACK_PREFIX, CARLA_DEFAULT_WINE_FALLBACK_PREFIX); + } +}; + struct SearchPluginsThread::PrivateData { - PrivateData(void*) + bool fContinueChecking; + QString fPathBinaries; + + bool fCheckNative; + bool fCheckPosix32; + bool fCheckPosix64; + bool fCheckWin32; + bool fCheckWin64; + + bool fCheckLADSPA; + bool fCheckDSSI; + bool fCheckLV2; + bool fCheckVST2; + bool fCheckVST3; + bool fCheckAU; + bool fCheckSF2; + bool fCheckSFZ; + + WineSettings fWineSettings; + + QString fToolNative; + + uint fCurCount; + uint fCurPercentValue; + uint fLastCheckValue; + bool fSomethingChanged; + + PrivateData(void*, const QString pathBinaries) + : fContinueChecking(false), + fPathBinaries(pathBinaries), + fCheckNative(false), + fCheckPosix32(false), + fCheckPosix64(false), + fCheckWin32(false), + fCheckWin64(false), + fCheckLADSPA(false), + fCheckDSSI(false), + fCheckLV2(false), + fCheckVST2(false), + fCheckVST3(false), + fCheckAU(false), + fCheckSF2(false), + fCheckSFZ(false), + fWineSettings(), + fToolNative(), + fCurCount(0), + fCurPercentValue(0), + fLastCheckValue(0), + fSomethingChanged(false) { } }; -SearchPluginsThread::SearchPluginsThread(QObject* parent, QString pathBinaries) +SearchPluginsThread::SearchPluginsThread(QObject* parent, const QString pathBinaries) : QThread(parent), - self(new PrivateData(this)) + self(new PrivateData(this, pathBinaries)) { } @@ -37,24 +123,82 @@ SearchPluginsThread::~SearchPluginsThread() delete self; } +void SearchPluginsThread::run() +{ +} + // -------------------------------------------------------------------------------------------------------------------- // Plugin Refresh Dialog struct PluginRefreshW::PrivateData { - PrivateData(void*) + Ui::PluginRefreshW ui; + + SearchPluginsThread fThread; + QPixmap fIconYes; + QPixmap fIconNo; + + PrivateData(PluginRefreshW* const refreshDialog, const CarlaHost& host) + : fThread(refreshDialog, host.pathBinaries), + fIconYes(":/16x16/dialog-ok-apply.svgz"), + fIconNo(":/16x16/dialog-error.svgz") + { + ui.setupUi(refreshDialog); + + // ------------------------------------------------------------------------------------------------------------ + // Internal stuff + + const bool hasNative = QFileInfo::exists(host.pathBinaries + CARLA_OS_SEP_STR "carla-discovery-native"); + const bool hasPosix32 = QFileInfo::exists(host.pathBinaries + CARLA_OS_SEP_STR "carla-discovery-posix32"); + const bool hasPosix64 = QFileInfo::exists(host.pathBinaries + CARLA_OS_SEP_STR "carla-discovery-posix64"); + const bool hasWin32 = QFileInfo::exists(host.pathBinaries + CARLA_OS_SEP_STR "carla-discovery-win32.exe"); + const bool hasWin64 = QFileInfo::exists(host.pathBinaries + CARLA_OS_SEP_STR "carla-discovery-win64.exe"); + } + + void loadSettings() { } }; -PluginRefreshW::PluginRefreshW(QWidget* parent) +PluginRefreshW::PluginRefreshW(QWidget* const parent, const CarlaHost& host) : QDialog(parent), - self(new PrivateData(this)) + self(new PrivateData(this, host)) { - delete self; + // ---------------------------------------------------------------------------------------------------------------- + // Resize to minimum size, as it's very likely UI stuff was hidden + + resize(minimumSize()); + + // ---------------------------------------------------------------------------------------------------------------- + // Set-up connections + + connect(this, SIGNAL(finished(int)), SLOT(slot_saveSettings())); + connect(self->ui.b_start, SIGNAL(clicked()), SLOT(slot_start())); + connect(self->ui.b_skip, SIGNAL(clicked()), SLOT(slot_skip())); + connect(self->ui.ch_native, SIGNAL(clicked()), SLOT(slot_checkTools())); + connect(self->ui.ch_posix32, SIGNAL(clicked()), SLOT(slot_checkTools())); + connect(self->ui.ch_posix64, SIGNAL(clicked()), SLOT(slot_checkTools())); + connect(self->ui.ch_win32, SIGNAL(clicked()), SLOT(slot_checkTools())); + connect(self->ui.ch_win64, SIGNAL(clicked()), SLOT(slot_checkTools())); + connect(self->ui.ch_ladspa, SIGNAL(clicked()), SLOT(slot_checkTools())); + connect(self->ui.ch_dssi, SIGNAL(clicked()), SLOT(slot_checkTools())); + connect(self->ui.ch_lv2, SIGNAL(clicked()), SLOT(slot_checkTools())); + connect(self->ui.ch_vst, SIGNAL(clicked()), SLOT(slot_checkTools())); + connect(self->ui.ch_vst3, SIGNAL(clicked()), SLOT(slot_checkTools())); + connect(self->ui.ch_au, SIGNAL(clicked()), SLOT(slot_checkTools())); + connect(self->ui.ch_sf2, SIGNAL(clicked()), SLOT(slot_checkTools())); + connect(self->ui.ch_sfz, SIGNAL(clicked()), SLOT(slot_checkTools())); + connect(&self->fThread, SIGNAL(pluginLook(float, QString)), SLOT(slot_handlePluginLook(float, QString))); + connect(&self->fThread, SIGNAL(finished(int)), SLOT(slot_handlePluginThreadFinished())); + + // ---------------------------------------------------------------------------------------------------------------- + // Post-connect setup + + slot_checkTools(); } PluginRefreshW::~PluginRefreshW() { + delete self; } void PluginRefreshW::getValues(QString& audioDevice, uint& bufferSize, double& sampleRate) @@ -148,9 +292,81 @@ 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 { - PrivateData(void*) + Ui::Dialog ui; + + PrivateData(JackApplicationW* const dialog) + : ui() + { + ui.setupUi(dialog); + + // ------------------------------------------------------------------------------------------------------------ + // Load settings + + loadSettings(); + } + + void checkIfButtonBoxShouldBeEnabled(int index, const QString text) + { + static QList badFirstChars = { '.', '/' }; + + bool enabled = text.length() > 0; + + // NSM applications must not be abstract or absolute paths, and must not contain arguments + if (enabled && index == UI_SESSION_NSM) + enabled = ! (badFirstChars.contains(text[0]) || text.contains(' ')); + + 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.valueUInt("NumAudioIns", 2)); + ui.sb_audio_ins->setValue(settings.valueUInt("NumAudioIns", 2)); + ui.sb_audio_outs->setValue(settings.valueUInt("NumAudioOuts", 2)); + ui.sb_midi_ins->setValue(settings.valueUInt("NumMidiIns", 0)); + ui.sb_midi_outs->setValue(settings.valueUInt("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()); } }; @@ -158,6 +374,14 @@ JackApplicationW::JackApplicationW(QWidget* parent) : QDialog(parent), self(new PrivateData(this)) { + 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() @@ -167,18 +391,63 @@ JackApplicationW::~JackApplicationW() 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(QString text) +void JackApplicationW::slot_commandChanged(const QString text) { + self->checkIfButtonBoxShouldBeEnabled(self->ui.cb_session_mgr->currentIndex(), text); } -void JackApplicationW::slot_sessionManagerChanged(int index) +void JackApplicationW::slot_sessionManagerChanged(const int index) { + self->checkIfButtonBoxShouldBeEnabled(index, self->ui.le_command->text()); } void JackApplicationW::slot_saveSettings() { + self->saveSettings(); } // -------------------------------------------------------------------------------------------------------------------- diff --git a/source/frontend/carla_database.hpp b/source/frontend/carla_database.hpp index edb074533..a09fdc8c5 100644 --- a/source/frontend/carla_database.hpp +++ b/source/frontend/carla_database.hpp @@ -22,6 +22,7 @@ // Imports (Global) #include + #include //--------------------------------------------------------------------------------------------------------------------- @@ -39,7 +40,7 @@ class SearchPluginsThread : public QThread Q_OBJECT signals: - void pluginLook(); + void pluginLook(float percent, QString plugin); public: SearchPluginsThread(QObject* parent, QString pathBinaries); @@ -49,6 +50,9 @@ private: struct PrivateData; PrivateData* const self; +protected: + void run() override; + CARLA_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(SearchPluginsThread) }; @@ -60,7 +64,7 @@ class PluginRefreshW : public QDialog Q_OBJECT public: - PluginRefreshW(QWidget* parent); + PluginRefreshW(QWidget* parent, const CarlaHost& host); ~PluginRefreshW() override; void getValues(QString& audioDevice, uint& bufferSize, double& sampleRate); @@ -80,6 +84,7 @@ private slots: void slot_handlePluginLook(float percent, QString plugin); void slot_handlePluginThreadFinished(); +private: CARLA_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(PluginRefreshW) }; @@ -111,6 +116,7 @@ private slots: void slot_clearFilters(); void slot_saveSettings(); +private: CARLA_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(PluginDatabaseW) }; @@ -136,6 +142,7 @@ private slots: void slot_sessionManagerChanged(int index); void slot_saveSettings(); +private: CARLA_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(JackApplicationW) }; diff --git a/source/frontend/carla_database_app.cpp b/source/frontend/carla_database_app.cpp index 1231a0ffb..5881b3ffe 100644 --- a/source/frontend/carla_database_app.cpp +++ b/source/frontend/carla_database_app.cpp @@ -46,7 +46,7 @@ int main(int argc, char* argv[]) // ---------------------------------------------------------------------------------------------------------------- // Create GUI - JackApplicationW gui(nullptr); + PluginRefreshW gui(nullptr, host); // ---------------------------------------------------------------------------------------------------------------- // Show GUI diff --git a/source/frontend/carla_shared.cpp b/source/frontend/carla_shared.cpp index 43834db4f..6dee671d5 100644 --- a/source/frontend/carla_shared.cpp +++ b/source/frontend/carla_shared.cpp @@ -35,6 +35,7 @@ #include "carla_host.hpp" +#include "CarlaUtils.h" #include "CarlaMathUtils.hpp" //--------------------------------------------------------------------------------------------------------------------- @@ -133,9 +134,40 @@ QString getInitialProjectFile(bool) //--------------------------------------------------------------------------------------------------------------------- // Get paths (binaries, resources) -void getPaths(QString& pathBinaries, QString& pathResources) +bool getPaths(QString& pathBinaries, QString& pathResources) { - // TODO + const QString libFolder(carla_get_library_folder()); + + QDir dir(libFolder); + + // FIXME need to completely rework this in C++ mode, so check if all cases are valid + + if (libFolder.endsWith("bin")) + { + CARLA_SAFE_ASSERT_RETURN(dir.cd("resources"), false); + pathBinaries = libFolder; + pathResources = dir.absolutePath(); + return true; + } + else if (libFolder.endsWith("carla")) + { + for (int i=2; --i>=0;) + { + CARLA_SAFE_ASSERT_INT_RETURN(dir.cdUp(), i, false); + CARLA_SAFE_ASSERT_INT_RETURN(dir.cd("share"), i, false); + + if (dir.exists()) + { + CARLA_SAFE_ASSERT_INT_RETURN(dir.cd("carla"), i, false); + CARLA_SAFE_ASSERT_INT_RETURN(dir.cd("resources"), i, false); + pathBinaries = libFolder; + pathResources = dir.absolutePath(); + return true; + } + } + } + + return false; } //--------------------------------------------------------------------------------------------------------------------- diff --git a/source/frontend/carla_shared.hpp b/source/frontend/carla_shared.hpp index 431ec6694..d812a4e5b 100644 --- a/source/frontend/carla_shared.hpp +++ b/source/frontend/carla_shared.hpp @@ -379,7 +379,7 @@ QString getInitialProjectFile(bool skipExistCheck = false); //--------------------------------------------------------------------------------------------------------------------- // Get paths (binaries, resources) -void getPaths(QString& pathBinaries, QString& pathResources); +bool getPaths(QString& pathBinaries, QString& pathResources); //--------------------------------------------------------------------------------------------------------------------- // Signal handler