|
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058 |
- /*
- * Carla plugin host
- * Copyright (C) 2011-2023 Filipe Coelho <falktx@falktx.com>
- * SPDX-License-Identifier: GPL-2.0-or-later
- */
-
- #include "pluginlistdialog.hpp"
- #include "pluginrefreshdialog.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 <QtCore/QDir>
- #include <QtCore/QFileInfo>
- #include <QtCore/QList>
- #include <QtCore/QTimer>
-
- #ifdef __clang__
- # pragma clang diagnostic pop
- #elif defined(__GNUC__) && __GNUC__ >= 8
- # pragma GCC diagnostic pop
- #endif
-
- #include "qcarlastring.hpp"
- #include "qsafesettings.hpp"
-
- #include "CarlaBackendUtils.hpp"
- #include "CarlaJuceUtils.hpp"
- #include "CarlaFrontend.h"
- #include "CarlaUtils.h"
-
- #include "CarlaString.hpp"
-
- #include <cstdlib>
-
- CARLA_BACKEND_USE_NAMESPACE
-
- // --------------------------------------------------------------------------------------------------------------------
- // Carla Settings keys
-
- #define CARLA_KEY_PATHS_LADSPA "Paths/LADSPA"
- #define CARLA_KEY_PATHS_DSSI "Paths/DSSI"
- #define CARLA_KEY_PATHS_LV2 "Paths/LV2"
- #define CARLA_KEY_PATHS_VST2 "Paths/VST2"
- #define CARLA_KEY_PATHS_VST3 "Paths/VST3"
- #define CARLA_KEY_PATHS_CLAP "Paths/CLAP"
- #define CARLA_KEY_PATHS_SF2 "Paths/SF2"
- #define CARLA_KEY_PATHS_SFZ "Paths/SFZ"
- #define CARLA_KEY_PATHS_JSFX "Paths/JSFX"
-
- // --------------------------------------------------------------------------------------------------------------------
- // Carla Settings defaults
-
- // --------------------------------------------------------------------------------------------------------------------
- // getenv with a fallback value if unset
-
- static inline
- const char* getEnvWithFallback(const char* const env, const char* const fallback)
- {
- if (const char* const value = std::getenv(env))
- return value;
-
- return fallback;
- }
-
- // --------------------------------------------------------------------------------------------------------------------
- // Plugin paths (from env vars first, then default locations)
-
- struct PluginPaths {
- #ifndef CARLA_FRONTEND_ONLY_EMBEDDABLE_PLUGINS
- QCarlaString ladspa;
- QCarlaString dssi;
- #endif
- QCarlaString lv2;
- QCarlaString vst2;
- QCarlaString vst3;
- QCarlaString clap;
- #ifndef CARLA_FRONTEND_ONLY_EMBEDDABLE_PLUGINS
- QCarlaString jsfx;
- QCarlaString sf2;
- QCarlaString sfz;
- #endif
-
- PluginPaths()
- {
- // get common env vars
- const QString HOME = QDir::toNativeSeparators(QDir::homePath());
-
- #if defined(CARLA_OS_WIN)
- const char *const envAPPDATA = std::getenv("APPDATA");
- const char *const envLOCALAPPDATA = getEnvWithFallback("LOCALAPPDATA", envAPPDATA);
- const char *const envPROGRAMFILES = std::getenv("PROGRAMFILES");
- const char* const envPROGRAMFILESx86 = std::getenv("PROGRAMFILES(x86)");
- const char *const envCOMMONPROGRAMFILES = std::getenv("COMMONPROGRAMFILES");
- const char* const envCOMMONPROGRAMFILESx86 = std::getenv("COMMONPROGRAMFILES(x86)");
-
- // Small integrity tests
- if (envAPPDATA == nullptr)
- {
- qFatal("APPDATA variable not set, cannot continue");
- abort();
- }
-
- if (envPROGRAMFILES == nullptr)
- {
- qFatal("PROGRAMFILES variable not set, cannot continue");
- abort();
- }
-
- if (envCOMMONPROGRAMFILES == nullptr)
- {
- qFatal("COMMONPROGRAMFILES variable not set, cannot continue");
- abort();
- }
-
- const QCarlaString APPDATA(envAPPDATA);
- const QCarlaString LOCALAPPDATA(envLOCALAPPDATA);
- const QCarlaString PROGRAMFILES(envPROGRAMFILES);
- const QCarlaString COMMONPROGRAMFILES(envCOMMONPROGRAMFILES);
- #elif !defined(CARLA_OS_MAC)
- const QCarlaString CONFIG_HOME(getEnvWithFallback("XDG_CONFIG_HOME", (HOME + "/.config").toUtf8()));
- #endif
-
- #ifndef CARLA_FRONTEND_ONLY_EMBEDDABLE_PLUGINS
- // now set paths, listing format path spec if available
- if (const char *const envLADSPA = std::getenv("LADSPA_PATH"))
- {
- ladspa = envLADSPA;
- }
- else
- {
- // no official spec, use common paths
- #if defined(CARLA_OS_WIN)
- ladspa = APPDATA + "\\LADSPA";
- ladspa += ";" + PROGRAMFILES + "\\LADSPA";
- #elif defined(CARLA_OS_HAIKU)
- ladspa = HOME + "/.ladspa";
- ladspa += ":/system/add-ons/media/ladspaplugins";
- ladspa += ":/system/lib/ladspa";
- #elif defined(CARLA_OS_MAC)
- ladspa = HOME + "/Library/Audio/Plug-Ins/LADSPA";
- ladspa += ":/Library/Audio/Plug-Ins/LADSPA";
- #else
- ladspa = HOME + "/.ladspa";
- ladspa += ":/usr/local/lib/ladspa";
- ladspa += ":/usr/lib/ladspa";
- #endif
- }
-
- if (const char *const envDSSI = std::getenv("DSSI_PATH"))
- {
- dssi = envDSSI;
- }
- else
- {
- // no official spec, use common paths
- #if defined(CARLA_OS_WIN)
- dssi = APPDATA + "\\DSSI";
- dssi += ";" + PROGRAMFILES + "\\DSSI";
- #elif defined(CARLA_OS_HAIKU)
- dssi = HOME + "/.dssi";
- dssi += ":/system/add-ons/media/dssiplugins";
- dssi += ":/system/lib/dssi";
- #elif defined(CARLA_OS_MAC)
- dssi = HOME + "/Library/Audio/Plug-Ins/DSSI";
- dssi += ":/Library/Audio/Plug-Ins/DSSI";
- #else
- dssi = HOME + "/.dssi";
- dssi += ":/usr/local/lib/dssi";
- dssi += ":/usr/lib/dssi";
- #endif
- }
- #endif // !CARLA_FRONTEND_ONLY_EMBEDDABLE_PLUGINS
-
- if (const char *const envLV2 = std::getenv("LV2_PATH"))
- {
- lv2 = envLV2;
- }
- else
- {
- // https://lv2plug.in/pages/filesystem-hierarchy-standard.html
- #if defined(CARLA_OS_WIN)
- lv2 = APPDATA + "\\LV2";
- lv2 += ";" + COMMONPROGRAMFILES + "\\LV2";
- #elif defined(CARLA_OS_HAIKU)
- lv2 = HOME + "/.lv2";
- lv2 += ":/system/add-ons/media/lv2plugins";
- #elif defined(CARLA_OS_MAC)
- lv2 = HOME + "/Library/Audio/Plug-Ins/LV2";
- lv2 += ":/Library/Audio/Plug-Ins/LV2";
- #else
- lv2 = HOME + "/.lv2";
- lv2 += ":/usr/local/lib/lv2";
- lv2 += ":/usr/lib/lv2";
- #endif
- }
-
- if (const char *const envVST2 = std::getenv("VST_PATH"))
- {
- vst2 = envVST2;
- }
- else
- {
- #if defined(CARLA_OS_WIN)
- // https://helpcenter.steinberg.de/hc/en-us/articles/115000177084
- vst2 = PROGRAMFILES + "\\VSTPlugins";
- vst2 += ";" + PROGRAMFILES + "\\Steinberg\\VSTPlugins";
- vst2 += ";" + COMMONPROGRAMFILES + "\\VST2";
- vst2 += ";" + COMMONPROGRAMFILES + "\\Steinberg\\VST2";
- #elif defined(CARLA_OS_HAIKU)
- vst2 = HOME + "/.vst";
- vst2 += ":/system/add-ons/media/vstplugins";
- #elif defined(CARLA_OS_MAC)
- // https://helpcenter.steinberg.de/hc/en-us/articles/115000171310
- vst2 = HOME + "/Library/Audio/Plug-Ins/VST";
- vst2 += ":/Library/Audio/Plug-Ins/VST";
- #else
- // no official spec, use common paths
- vst2 = HOME + "/.vst";
- vst2 += ":" + HOME + "/.lxvst";
- vst2 += ":/usr/local/lib/vst";
- vst2 += ":/usr/local/lib/lxvst";
- vst2 += ":/usr/lib/vst";
- vst2 += ":/usr/lib/lxvst";
- #endif
- }
-
- if (const char *const envVST3 = std::getenv("VST3_PATH"))
- {
- vst3 = envVST3;
- }
- else
- {
- // https://steinbergmedia.github.io/vst3_dev_portal/pages/Technical+Documentation/Locations+Format/Plugin+Locations.html
- #if defined(CARLA_OS_WIN)
- vst3 = LOCALAPPDATA + "\\Programs\\Common\\VST3";
- vst3 += ";" + COMMONPROGRAMFILES + "\\VST3";
- #elif defined(CARLA_OS_HAIKU)
- vst3 = HOME + "/.vst3";
- vst3 += ":/system/add-ons/media/vst3plugins";
- #elif defined(CARLA_OS_MAC)
- vst3 = HOME + "/Library/Audio/Plug-Ins/VST3";
- vst3 += ":/Library/Audio/Plug-Ins/VST3";
- #else
- vst3 = HOME + "/.vst3";
- vst3 += ":/usr/local/lib/vst3";
- vst3 += ":/usr/lib/vst3";
- #endif
- }
-
- if (const char *const envCLAP = std::getenv("CLAP_PATH"))
- {
- clap = envCLAP;
- }
- else
- {
- // https://github.com/free-audio/clap/blob/main/include/clap/entry.h
- #if defined(CARLA_OS_WIN)
- clap = LOCALAPPDATA + "\\Programs\\Common\\CLAP";
- clap += ";" + COMMONPROGRAMFILES + "\\CLAP";
- #elif defined(CARLA_OS_HAIKU)
- clap = HOME + "/.clap";
- clap += ":/system/add-ons/media/clapplugins";
- #elif defined(CARLA_OS_MAC)
- clap = HOME + "/Library/Audio/Plug-Ins/CLAP";
- clap += ":/Library/Audio/Plug-Ins/CLAP";
- #else
- clap = HOME + "/.clap";
- clap += ":/usr/local/lib/clap";
- clap += ":/usr/lib/clap";
- #endif
- }
-
- #ifndef CARLA_FRONTEND_ONLY_EMBEDDABLE_PLUGINS
- if (const char *const envJSFX = std::getenv("JSFX_PATH"))
- {
- jsfx = envJSFX;
- }
- else
- {
- // REAPER user data directory
- #if defined(CARLA_OS_WIN)
- jsfx = APPDATA + "\\REAPER\\Effects";
- #elif defined(CARLA_OS_MAC)
- jsfx = HOME + "/Library/Application Support/REAPER/Effects";
- #else
- jsfx = CONFIG_HOME + "/REAPER/Effects";
- #endif
- }
-
- if (const char *const envSF2 = std::getenv("SF2_PATH"))
- {
- sf2 = envSF2;
- }
- else
- {
- #if defined(CARLA_OS_WIN)
- sf2 = APPDATA + "\\SF2";
- #else
- sf2 = HOME + "/.sounds/sf2";
- sf2 += ":" + HOME + "/.sounds/sf3";
- sf2 += ":/usr/share/sounds/sf2";
- sf2 += ":/usr/share/sounds/sf3";
- sf2 += ":/usr/share/soundfonts";
- #endif
- }
-
- if (const char *const envSFZ = std::getenv("SFZ_PATH"))
- {
- sfz = envSFZ;
- }
- else
- {
- #if defined(CARLA_OS_WIN)
- sfz = APPDATA + "\\SFZ";
- #else
- sfz = HOME + "/.sounds/sfz";
- sfz += ":/usr/share/sounds/sfz";
- #endif
- }
- #endif // !CARLA_FRONTEND_ONLY_EMBEDDABLE_PLUGINS
-
- #ifdef CARLA_OS_WIN
- if (envPROGRAMFILESx86 != nullptr)
- {
- const QCarlaString PROGRAMFILESx86(envPROGRAMFILESx86);
- #ifndef CARLA_FRONTEND_ONLY_EMBEDDABLE_PLUGINS
- ladspa += ";" + PROGRAMFILESx86 + "\\LADSPA";
- dssi += ";" + PROGRAMFILESx86 + "\\DSSI";
- #endif
- vst2 += ";" + PROGRAMFILESx86 + "\\VSTPlugins";
- vst2 += ";" + PROGRAMFILESx86 + "\\Steinberg\\VSTPlugins";
- }
-
- if (envCOMMONPROGRAMFILESx86 != nullptr)
- {
- const QCarlaString COMMONPROGRAMFILESx86(envCOMMONPROGRAMFILESx86);
- vst3 += COMMONPROGRAMFILESx86 + "\\VST3";
- clap += COMMONPROGRAMFILESx86 + "\\CLAP";
- }
- #elif !defined(CARLA_FRONTEND_ONLY_EMBEDDABLE_PLUGINS)
- QCarlaString winePrefix;
-
- if (const char* const envWINEPREFIX = std::getenv("WINEPREFIX"))
- winePrefix = envWINEPREFIX;
-
- if (winePrefix.isEmpty())
- winePrefix = HOME + "/.wine";
-
- if (QDir(winePrefix).exists())
- {
- vst2 += ":" + winePrefix + "/drive_c/Program Files/VstPlugins";
- vst2 += ":" + winePrefix + "/drive_c/Program Files/Steinberg/VstPlugins";
- vst3 += ":" + winePrefix + "/drive_c/Program Files/Common Files/VST3";
- clap += ":" + winePrefix + "/drive_c/Program Files/Common Files/CLAP";
-
- #ifdef CARLA_OS_64BIT
- if (QDir(winePrefix + "/drive_c/Program Files (x86)").exists())
- {
- vst2 += ":" + winePrefix + "/drive_c/Program Files (x86)/VstPlugins";
- vst2 += ":" + winePrefix + "/drive_c/Program Files (x86)/Steinberg/VstPlugins";
- vst3 += ":" + winePrefix + "/drive_c/Program Files (x86)/Common Files/VST3";
- clap += ":" + winePrefix + "/drive_c/Program Files (x86)/Common Files/CLAP";
- }
- #endif
- }
- #endif
- }
- };
-
- // --------------------------------------------------------------------------------------------------------------------
- // Backwards-compatible horizontalAdvance/width call, depending on Qt version
-
- static inline
- int fontMetricsHorizontalAdvance(const QFontMetrics& fontMetrics, const QString& string)
- {
- #if QT_VERSION >= 0x50b00
- return fontMetrics.horizontalAdvance(string);
- #else
- return fontMetrics.width(string);
- #endif
- }
-
- // --------------------------------------------------------------------------------------------------------------------
- // Qt-compatible plugin info
-
- // base details, nicely packed and POD-only so we can directly use as binary
- struct PluginInfoHeader {
- uint16_t build;
- uint16_t type;
- uint32_t hints;
- uint64_t uniqueId;
- uint16_t audioIns;
- uint16_t audioOuts;
- uint16_t cvIns;
- uint16_t cvOuts;
- uint16_t midiIns;
- uint16_t midiOuts;
- uint16_t parameterIns;
- uint16_t parameterOuts;
- };
-
- // full details, now with non-POD types
- struct PluginInfo : PluginInfoHeader {
- QString category;
- QString filename;
- QString name;
- QString label;
- QString maker;
- };
-
- // convert PluginInfo to Qt types
- static QVariant asByteArray(const PluginInfo& info)
- {
- QByteArray qdata;
-
- // start with the POD data, stored as-is
- qdata.append(static_cast<const char*>(static_cast<const void*>(&info)), sizeof(PluginInfoHeader));
-
- // then all the strings, with a null terminating byte
- {
- const QByteArray qcategory(info.category.toUtf8());
- qdata += qcategory.constData();
- qdata += '\0';
- }
-
- {
- const QByteArray qfilename(info.filename.toUtf8());
- qdata += qfilename.constData();
- qdata += '\0';
- }
-
- {
- const QByteArray qname(info.name.toUtf8());
- qdata += qname.constData();
- qdata += '\0';
- }
-
- {
- const QByteArray qlabel(info.label.toUtf8());
- qdata += qlabel.constData();
- qdata += '\0';
- }
-
- {
- const QByteArray qmaker(info.maker.toUtf8());
- qdata += qmaker.constData();
- qdata += '\0';
- }
-
- return qdata;
- }
-
- static QVariant asVariant(const PluginInfo& info)
- {
- return QVariant(asByteArray(info));
- }
-
- // convert Qt types to PluginInfo
- static PluginInfo asPluginInfo(const QByteArray &qdata)
- {
- // make sure data is big enough to fit POD data + 5 strings
- CARLA_SAFE_ASSERT_RETURN(static_cast<size_t>(qdata.size()) >= sizeof(PluginInfoHeader) + sizeof(char) * 5, {});
-
- // read POD data first
- const PluginInfoHeader* const data
- = static_cast<const PluginInfoHeader*>(static_cast<const void*>(qdata.constData()));
- PluginInfo info = {};
- info.build = data->build;
- info.type = data->type;
- info.hints = data->hints;
- info.uniqueId = data->uniqueId;
- info.audioIns = data->audioIns;
- info.audioOuts = data->audioOuts;
- info.cvIns = data->cvIns;
- info.cvOuts = data->cvOuts;
- info.midiIns = data->midiIns;
- info.midiOuts = data->midiOuts;
- info.parameterIns = data->parameterIns;
- info.parameterOuts = data->parameterOuts;
-
- // then all the strings, keeping the same order as in `asVariant`
- const char* sdata = static_cast<const char*>(static_cast<const void*>(data + 1));
-
- info.category = QString::fromUtf8(sdata);
- sdata += info.category.size() + 1;
-
- info.filename = QString::fromUtf8(sdata);
- sdata += info.filename.size() + 1;
-
- info.name = QString::fromUtf8(sdata);
- sdata += info.name.size() + 1;
-
- info.label = QString::fromUtf8(sdata);
- sdata += info.label.size() + 1;
-
- info.maker = QString::fromUtf8(sdata);
- sdata += info.maker.size() + 1;
-
- return info;
- }
-
- static PluginInfo asPluginInfo(const QVariant& var)
- {
- return asPluginInfo(var.toByteArray());
- }
-
- static QList<PluginInfo> asPluginInfoList(const QVariant& var)
- {
- QCarlaByteArray qdata(var.toByteArray());
-
- QList<PluginInfo> plist;
-
- while (!qdata.isEmpty())
- {
- const PluginInfo info = asPluginInfo(qdata);
- CARLA_SAFE_ASSERT_RETURN(info.build != BINARY_NONE, {});
-
- plist.append(info);
- qdata = qdata.sliced(sizeof(PluginInfoHeader)
- + info.category.size() + info.filename.size() + info.name.size()
- + info.label.size() + info.maker.size() + 5);
- }
-
- return plist;
- }
-
- // --------------------------------------------------------------------------------------------------------------------
- // Qt-compatible plugin favorite
-
- // base details, nicely packed and POD-only so we can directly use as binary
- struct PluginFavoriteHeader {
- uint16_t type;
- uint64_t uniqueId;
- };
-
- // full details, now with non-POD types
- struct PluginFavorite : PluginFavoriteHeader {
- QString filename;
- QString label;
-
- PluginFavorite()
- {
- type = PLUGIN_NONE;
- uniqueId = 0;
- }
-
- PluginFavorite(uint16_t t, uint64_t u, const QString& f, const QString& l)
- : filename(f), label(l)
- {
- type = t;
- uniqueId = u;
- }
-
- bool operator==(const PluginFavorite& other) const
- {
- return type == other.type && uniqueId == other.uniqueId && filename == other.filename && label == other.label;
- }
- };
-
- // convert PluginFavorite to Qt types
- static QByteArray asByteArray(const PluginFavorite& fav)
- {
- QByteArray qdata;
-
- // start with the POD data, stored as-is
- qdata.append(static_cast<const char*>(static_cast<const void*>(&fav)), sizeof(PluginFavoriteHeader));
-
- // then all the strings, with a null terminating byte
- {
- const QByteArray qfilename(fav.filename.toUtf8());
- qdata += qfilename.constData();
- qdata += '\0';
- }
-
- {
- const QByteArray qlabel(fav.label.toUtf8());
- qdata += qlabel.constData();
- qdata += '\0';
- }
-
- return qdata;
- }
-
- static QVariant asVariant(const QList<PluginFavorite>& favlist)
- {
- QByteArray qdata;
-
- for (const PluginFavorite &fav : favlist)
- qdata += asByteArray(fav);
-
- return QVariant(qdata);
- }
-
- // convert Qt types to PluginInfo
- static PluginFavorite asPluginFavorite(const QByteArray& qdata)
- {
- // make sure data is big enough to fit POD data + 3 strings
- CARLA_SAFE_ASSERT_RETURN(static_cast<size_t>(qdata.size()) >= sizeof(PluginFavoriteHeader) + sizeof(char) * 3, {});
-
- // read POD data first
- const PluginFavoriteHeader* const data
- = static_cast<const PluginFavoriteHeader*>(static_cast<const void*>(qdata.constData()));
- PluginFavorite fav = { data->type, data->uniqueId, {}, {} };
-
- // then all the strings, keeping the same order as in `asVariant`
- const char* sdata = static_cast<const char*>(static_cast<const void*>(data + 1));
-
- fav.filename = QString::fromUtf8(sdata);
- sdata += fav.filename.size() + 1;
-
- fav.label = QString::fromUtf8(sdata);
- sdata += fav.label.size() + 1;
-
- return fav;
- }
-
- static QList<PluginFavorite> asPluginFavoriteList(const QVariant& var)
- {
- QCarlaByteArray qdata(var.toByteArray());
-
- QList<PluginFavorite> favlist;
-
- while (!qdata.isEmpty())
- {
- const PluginFavorite fav = asPluginFavorite(qdata);
- CARLA_SAFE_ASSERT_RETURN(fav.type != PLUGIN_NONE, {});
-
- favlist.append(fav);
- qdata = qdata.sliced(sizeof(PluginFavoriteHeader) + fav.filename.size() + fav.label.size() + 2);
- }
-
- return favlist;
- }
-
- // create PluginFavorite from PluginInfo data
- static PluginFavorite asPluginFavorite(const PluginInfo& info)
- {
- return PluginFavorite(info.type, info.uniqueId, info.filename, info.label);
- }
-
- // --------------------------------------------------------------------------------------------------------------------
- // discovery callbacks
-
- static void discoveryCallback(void* const ptr, const CarlaPluginDiscoveryInfo* const info, const char* const sha1sum)
- {
- static_cast<PluginListDialog*>(ptr)->addPluginInfo(info, sha1sum);
- }
-
- static bool checkCacheCallback(void* const ptr, const char* const filename, const char* const sha1sum)
- {
- if (sha1sum == nullptr)
- return false;
-
- return static_cast<PluginListDialog*>(ptr)->checkPluginCache(filename, sha1sum);
- }
-
- // --------------------------------------------------------------------------------------------------------------------
-
- struct PluginListDialog::PrivateData {
- int lastTableWidgetIndex = 0;
- int timerId = 0;
- PluginInfo retPlugin;
-
- // To be changed by parent
- bool hasLoadedLv2Plugins = false;
-
- struct Discovery {
- BinaryType btype = BINARY_NATIVE;
- PluginType ptype = PLUGIN_NONE;
- bool firstInit = true;
- bool ignoreCache = false;
- bool checkInvalid = false;
- CarlaPluginDiscoveryHandle handle = nullptr;
- QCarlaString tool;
- CarlaScopedPointer<PluginRefreshDialog> dialog;
- Discovery()
- {
- restart();
- }
-
- ~Discovery()
- {
- if (handle != nullptr)
- carla_plugin_discovery_stop(handle);
- }
-
- bool nextTool()
- {
- if (handle != nullptr)
- {
- carla_plugin_discovery_stop(handle);
- handle = nullptr;
- }
-
- #ifdef CARLA_OS_WIN
- #ifdef CARLA_OS_WIN64
- // look for win32 plugins on win64
- if (btype == BINARY_NATIVE)
- {
- btype = BINARY_WIN32;
- ptype = PLUGIN_INTERNAL;
- tool = carla_get_library_folder();
- tool += CARLA_OS_SEP_STR "carla-discovery-win32.exe";
-
- if (QFile(tool).exists())
- return true;
- }
- #endif
-
- // no other types to try
- return false;
- #else // CARLA_OS_WIN
-
- #ifndef CARLA_OS_MAC
- // try 32bit plugins on 64bit systems, skipping macOS where 32bit is no longer supported
- if (btype == BINARY_NATIVE)
- {
- btype = BINARY_POSIX32;
- ptype = PLUGIN_INTERNAL;
- tool = carla_get_library_folder();
- tool += CARLA_OS_SEP_STR "carla-discovery-posix32";
-
- if (QFile(tool).exists())
- return true;
- }
- #endif
-
- // try wine bridges
- #ifdef CARLA_OS_64BIT
- if (btype == BINARY_NATIVE || btype == BINARY_POSIX32)
- {
- btype = BINARY_WIN64;
- ptype = PLUGIN_INTERNAL;
- tool = carla_get_library_folder();
- tool += CARLA_OS_SEP_STR "carla-discovery-win64.exe";
-
- if (QFile(tool).exists())
- return true;
- }
- #endif
-
- {
- btype = BINARY_WIN32;
- ptype = PLUGIN_INTERNAL;
- tool = carla_get_library_folder();
- tool += CARLA_OS_SEP_STR "carla-discovery-win32.exe";
-
- if (QFile(tool).exists())
- return true;
- }
-
- return false;
- #endif // CARLA_OS_WIN
- }
-
- void restart()
- {
- btype = BINARY_NATIVE;
- ptype = PLUGIN_NONE;
- tool = carla_get_library_folder();
- tool += CARLA_OS_SEP_STR "carla-discovery-native";
- #ifdef CARLA_OS_WIN
- tool += ".exe";
- #endif
- }
- } discovery;
-
- PluginPaths paths;
-
- struct {
- #ifndef CARLA_FRONTEND_ONLY_EMBEDDABLE_PLUGINS
- std::vector<PluginInfo> internal;
- std::vector<PluginInfo> ladspa;
- std::vector<PluginInfo> dssi;
- #endif
- std::vector<PluginInfo> lv2;
- std::vector<PluginInfo> vst2;
- std::vector<PluginInfo> vst3;
- std::vector<PluginInfo> clap;
- #ifndef CARLA_FRONTEND_ONLY_EMBEDDABLE_PLUGINS
- #ifdef CARLA_OS_MAC
- std::vector<PluginInfo> au;
- #endif
- std::vector<PluginInfo> jsfx;
- std::vector<PluginInfo> kits;
- #endif
- QMap<QString, QList<PluginInfo>> cache;
- QList<PluginFavorite> favorites;
-
- bool add(const PluginInfo& pinfo)
- {
- switch (pinfo.type)
- {
- #ifndef CARLA_FRONTEND_ONLY_EMBEDDABLE_PLUGINS
- case PLUGIN_INTERNAL: internal.push_back(pinfo); return true;
- case PLUGIN_LADSPA: ladspa.push_back(pinfo); return true;
- case PLUGIN_DSSI: dssi.push_back(pinfo); return true;
- #endif
- case PLUGIN_LV2: lv2.push_back(pinfo); return true;
- case PLUGIN_VST2: vst2.push_back(pinfo); return true;
- case PLUGIN_VST3: vst3.push_back(pinfo); return true;
- case PLUGIN_CLAP: clap.push_back(pinfo); return true;
- #ifndef CARLA_FRONTEND_ONLY_EMBEDDABLE_PLUGINS
- #ifdef CARLA_OS_MAC
- case PLUGIN_AU: au.push_back(pinfo); return true;
- #endif
- case PLUGIN_JSFX: jsfx.push_back(pinfo); return true;
- case PLUGIN_SF2:
- case PLUGIN_SFZ: kits.push_back(pinfo); return true;
- #endif
- default: return false;
- }
- }
- } plugins;
- };
-
- // --------------------------------------------------------------------------------------------------------------------
- // Plugin List Dialog
-
- PluginListDialog::PluginListDialog(QWidget* const parent, const HostSettings& hostSettings)
- : QDialog(parent),
- p(new PrivateData)
- {
- ui.setupUi(this);
-
- // p->hostSettings = hostSettings;
-
- // ----------------------------------------------------------------------------------------------------------------
- // Set-up GUI
-
- ui.b_add->setEnabled(false);
-
- ui.tab_info->tabBar()->hide();
- ui.tab_reqs->tabBar()->hide();
-
- #ifdef CARLA_FRONTEND_ONLY_EMBEDDABLE_PLUGINS
- ui.ch_internal->hide();
- ui.ch_ladspa->hide();
- ui.ch_dssi->hide();
- ui.ch_au->hide();
- ui.ch_jsfx->hide();
- ui.ch_kits->hide();
- ui.ch_gui->hide();
- ui.ch_inline_display->hide();
- ui.toolBox->setItemEnabled(3, false);
- #endif
-
- // do not resize info frame so much
- const QLayout *const infoLayout = ui.tw_info->layout();
- const QMargins infoMargins = infoLayout->contentsMargins();
- ui.tab_info->setMinimumWidth(infoMargins.left() + infoMargins.right() + infoLayout->spacing() * 3
- + fontMetricsHorizontalAdvance(ui.la_id->fontMetrics(), "Has Custom GUI: 9999999999"));
-
- // start with no plugin selected
- checkPlugin(-1);
-
- // custom action that listens for Ctrl+F shortcut
- addAction(ui.act_focus_search);
-
- #ifdef CARLA_OS_64BIT
- ui.ch_bridged->setText(tr("Bridged (32bit)"));
- #else
- ui.ch_bridged->setChecked(false);
- ui.ch_bridged->setEnabled(false);
- #endif
-
- #if !(defined(CARLA_OS_LINUX) || defined(CARLA_OS_MAC))
- ui.ch_bridged_wine->setChecked(false);
- ui.ch_bridged_wine->setEnabled(false);
- #endif
-
- #ifdef CARLA_OS_MAC
- setWindowModality(Qt::WindowModal);
- #else
- ui.ch_au->setChecked(false);
- ui.ch_au->setEnabled(false);
- ui.ch_au->setVisible(false);
- #endif
-
- setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
-
- // ----------------------------------------------------------------------------------------------------------------
- // Load settings
-
- loadSettings();
-
- // ----------------------------------------------------------------------------------------------------------------
- // Disable bridges if not enabled in settings
-
- #if 0
- // NOTE: We Assume win32 carla build will not run win64 plugins
- if (WINDOWS and not kIs64bit) or not host.showPluginBridges:
- ui.ch_native.setChecked(True)
- ui.ch_native.setEnabled(False)
- ui.ch_native.setVisible(True)
- ui.ch_bridged.setChecked(False)
- ui.ch_bridged.setEnabled(False)
- ui.ch_bridged.setVisible(False)
- ui.ch_bridged_wine.setChecked(False)
- ui.ch_bridged_wine.setEnabled(False)
- ui.ch_bridged_wine.setVisible(False)
-
- elif not host.showWineBridges:
- ui.ch_bridged_wine.setChecked(False)
- ui.ch_bridged_wine.setEnabled(False)
- ui.ch_bridged_wine.setVisible(False)
- #endif
-
- // ----------------------------------------------------------------------------------------------------------------
- // Set-up Icons
-
- if (hostSettings.useSystemIcons)
- {
- #if 0
- ui.b_add.setIcon(getIcon('list-add', 16, 'svgz'))
- ui.b_cancel.setIcon(getIcon('dialog-cancel', 16, 'svgz'))
- ui.b_clear_filters.setIcon(getIcon('edit-clear', 16, 'svgz'))
- ui.b_refresh.setIcon(getIcon('view-refresh', 16, 'svgz'))
- QTableWidgetItem* const hhi = ui.tableWidget->horizontalHeaderItem(TW_FAVORITE);
- hhi.setIcon(getIcon('bookmarks', 16, 'svgz'))
- #endif
- }
-
- // ----------------------------------------------------------------------------------------------------------------
- // Set-up connections
-
- QObject::connect(this, &QDialog::finished, this, &PluginListDialog::saveSettings);
- QObject::connect(ui.b_add, &QPushButton::clicked, this, &QDialog::accept);
- QObject::connect(ui.b_cancel, &QPushButton::clicked, this, &QDialog::reject);
-
- QObject::connect(ui.b_refresh, &QPushButton::clicked, this, &PluginListDialog::refreshPlugins);
- QObject::connect(ui.b_clear_filters, &QPushButton::clicked, this, &PluginListDialog::clearFilters);
- QObject::connect(ui.lineEdit, &QLineEdit::textChanged, this, &PluginListDialog::checkFilters);
- QObject::connect(ui.tableWidget, &QTableWidget::currentCellChanged, this, &PluginListDialog::checkPlugin);
- QObject::connect(ui.tableWidget, &QTableWidget::cellClicked, this, &PluginListDialog::cellClicked);
- QObject::connect(ui.tableWidget, &QTableWidget::cellDoubleClicked, this, &PluginListDialog::cellDoubleClicked);
-
- QObject::connect(ui.ch_internal, &QCheckBox::clicked, this, &PluginListDialog::checkFilters);
- QObject::connect(ui.ch_ladspa, &QCheckBox::clicked, this, &PluginListDialog::checkFilters);
- QObject::connect(ui.ch_dssi, &QCheckBox::clicked, this, &PluginListDialog::checkFilters);
- QObject::connect(ui.ch_lv2, &QCheckBox::clicked, this, &PluginListDialog::checkFilters);
- QObject::connect(ui.ch_vst, &QCheckBox::clicked, this, &PluginListDialog::checkFilters);
- QObject::connect(ui.ch_vst3, &QCheckBox::clicked, this, &PluginListDialog::checkFilters);
- QObject::connect(ui.ch_clap, &QCheckBox::clicked, this, &PluginListDialog::checkFilters);
- QObject::connect(ui.ch_au, &QCheckBox::clicked, this, &PluginListDialog::checkFilters);
- QObject::connect(ui.ch_jsfx, &QCheckBox::clicked, this, &PluginListDialog::checkFilters);
- QObject::connect(ui.ch_kits, &QCheckBox::clicked, this, &PluginListDialog::checkFilters);
- QObject::connect(ui.ch_effects, &QCheckBox::clicked, this, &PluginListDialog::checkFilters);
- QObject::connect(ui.ch_instruments, &QCheckBox::clicked, this, &PluginListDialog::checkFilters);
- QObject::connect(ui.ch_midi, &QCheckBox::clicked, this, &PluginListDialog::checkFilters);
- QObject::connect(ui.ch_other, &QCheckBox::clicked, this, &PluginListDialog::checkFilters);
- QObject::connect(ui.ch_native, &QCheckBox::clicked, this, &PluginListDialog::checkFilters);
- QObject::connect(ui.ch_bridged, &QCheckBox::clicked, this, &PluginListDialog::checkFilters);
- QObject::connect(ui.ch_bridged_wine, &QCheckBox::clicked, this, &PluginListDialog::checkFilters);
- QObject::connect(ui.ch_favorites, &QCheckBox::clicked, this, &PluginListDialog::checkFilters);
- QObject::connect(ui.ch_rtsafe, &QCheckBox::clicked, this, &PluginListDialog::checkFilters);
- QObject::connect(ui.ch_cv, &QCheckBox::clicked, this, &PluginListDialog::checkFilters);
- QObject::connect(ui.ch_gui, &QCheckBox::clicked, this, &PluginListDialog::checkFilters);
- QObject::connect(ui.ch_inline_display, &QCheckBox::clicked, this, &PluginListDialog::checkFilters);
- QObject::connect(ui.ch_stereo, &QCheckBox::clicked, this, &PluginListDialog::checkFilters);
- QObject::connect(ui.ch_cat_all, &QCheckBox::clicked, this, &PluginListDialog::checkFiltersCategoryAll);
- QObject::connect(ui.ch_cat_delay, &QCheckBox::clicked, this, &PluginListDialog::checkFiltersCategorySpecific);
- QObject::connect(ui.ch_cat_distortion, &QCheckBox::clicked, this, &PluginListDialog::checkFiltersCategorySpecific);
- QObject::connect(ui.ch_cat_dynamics, &QCheckBox::clicked, this, &PluginListDialog::checkFiltersCategorySpecific);
- QObject::connect(ui.ch_cat_eq, &QCheckBox::clicked, this, &PluginListDialog::checkFiltersCategorySpecific);
- QObject::connect(ui.ch_cat_filter, &QCheckBox::clicked, this, &PluginListDialog::checkFiltersCategorySpecific);
- QObject::connect(ui.ch_cat_modulator, &QCheckBox::clicked, this, &PluginListDialog::checkFiltersCategorySpecific);
- QObject::connect(ui.ch_cat_synth, &QCheckBox::clicked, this, &PluginListDialog::checkFiltersCategorySpecific);
- QObject::connect(ui.ch_cat_utility, &QCheckBox::clicked, this, &PluginListDialog::checkFiltersCategorySpecific);
- QObject::connect(ui.ch_cat_other, &QCheckBox::clicked, this, &PluginListDialog::checkFiltersCategorySpecific);
-
- QObject::connect(ui.act_focus_search, &QAction::triggered, this, &PluginListDialog::focusSearchFieldAndSelectAll);
- }
-
- PluginListDialog::~PluginListDialog()
- {
- if (p->timerId != 0)
- killTimer(p->timerId);
-
- delete p;
- }
-
- // --------------------------------------------------------------------------------------------------------------------
- // public methods
-
- const PluginInfo& PluginListDialog::getSelectedPluginInfo() const
- {
- return p->retPlugin;
- }
-
- void PluginListDialog::addPluginInfo(const CarlaPluginDiscoveryInfo* const info, const char* const sha1sum)
- {
- if (info == nullptr)
- {
- if (sha1sum != nullptr)
- {
- QSafeSettings settings("falkTX", "CarlaDatabase3");
- settings.setValue(QString("PluginCache/%1").arg(sha1sum), QByteArray());
-
- const QString qsha1sum(sha1sum);
- p->plugins.cache[qsha1sum] = {};
- }
- return;
- }
-
- PluginInfo pinfo = {};
- pinfo.build = static_cast<uint16_t>(info->btype);
- pinfo.type = static_cast<uint16_t>(info->ptype);
- pinfo.hints = info->metadata.hints;
- pinfo.uniqueId = info->uniqueId;
- pinfo.audioIns = static_cast<uint16_t>(info->io.audioIns);
- pinfo.audioOuts = static_cast<uint16_t>(info->io.audioOuts);
- pinfo.cvIns = static_cast<uint16_t>(info->io.cvIns);
- pinfo.cvOuts = static_cast<uint16_t>(info->io.cvOuts);
- pinfo.midiIns = static_cast<uint16_t>(info->io.midiIns);
- pinfo.midiOuts = static_cast<uint16_t>(info->io.midiOuts);
- pinfo.parameterIns = static_cast<uint16_t>(info->io.parameterIns);
- pinfo.parameterOuts = static_cast<uint16_t>(info->io.parameterOuts);
- pinfo.category = getPluginCategoryAsString(info->metadata.category);
- pinfo.filename = QString::fromUtf8(info->filename);
- pinfo.name = QString::fromUtf8(info->metadata.name);
- pinfo.label = QString::fromUtf8(info->label);
- pinfo.maker = QString::fromUtf8(info->metadata.maker);
-
- if (sha1sum != nullptr)
- {
- QSafeSettings settings("falkTX", "CarlaDatabase3");
- const QString qsha1sum(sha1sum);
- const QString key = QString("PluginCache/%1").arg(sha1sum);
-
- // single sha1sum can contain >1 plugin
- QByteArray qdata;
- if (p->plugins.cache.contains(qsha1sum))
- qdata = settings.valueByteArray(key);
- qdata += asVariant(pinfo).toByteArray();
-
- settings.setValue(key, qdata);
-
- p->plugins.cache[qsha1sum].append(pinfo);
- }
-
- #ifdef CARLA_FRONTEND_ONLY_EMBEDDABLE_PLUGINS
- if ((pinfo.hints & PLUGIN_HAS_CUSTOM_EMBED_UI) == 0x0)
- return;
- #endif
-
- p->plugins.add(pinfo);
- }
-
- bool PluginListDialog::checkPluginCache(const char* const filename, const char* const sha1sum)
- {
- // sha1sum is always valid for this call
- const QString qsha1sum(sha1sum);
-
- if (filename != nullptr)
- p->discovery.dialog->progressBar->setFormat(filename);
-
- if (!p->plugins.cache.contains(qsha1sum))
- return false;
-
- const QList<PluginInfo>& plist(p->plugins.cache[qsha1sum]);
-
- if (plist.isEmpty())
- return p->discovery.ignoreCache || !p->discovery.checkInvalid;
-
- // if filename does not match, abort (hash collision?)
- if (filename == nullptr || plist.first().filename != filename)
- {
- p->plugins.cache.remove(qsha1sum);
- return false;
- }
-
- for (const PluginInfo& info : plist)
- {
- #ifdef CARLA_FRONTEND_ONLY_EMBEDDABLE_PLUGINS
- if ((info.hints & PLUGIN_HAS_CUSTOM_EMBED_UI) == 0x0)
- continue;
- #endif
- p->plugins.add(info);
- }
-
- return true;
- }
-
- // --------------------------------------------------------------------------------------------------------------------
- // protected methods
-
- void PluginListDialog::done(const int r)
- {
- if (r == QDialog::Accepted && ui.tableWidget->currentRow() >= 0)
- {
- QTableWidgetItem* const widget = ui.tableWidget->item(ui.tableWidget->currentRow(), TW_NAME);
- p->retPlugin = asPluginInfo(widget->data(Qt::UserRole + UR_PLUGIN_INFO));
- }
- else
- {
- p->retPlugin = {};
- }
-
- QDialog::done(r);
- }
-
- void PluginListDialog::showEvent(QShowEvent* const event)
- {
- focusSearchFieldAndSelectAll();
- QDialog::showEvent(event);
-
- // Set up initial discovery
- if (p->discovery.firstInit)
- {
- p->discovery.firstInit = false;
-
- p->discovery.dialog = new PluginRefreshDialog(this);
- p->discovery.dialog->b_start->setEnabled(false);
- p->discovery.dialog->b_skip->setEnabled(true);
- p->discovery.dialog->ch_updated->setChecked(true);
- p->discovery.dialog->ch_invalid->setChecked(false);
- p->discovery.dialog->group->setEnabled(false);
- p->discovery.dialog->progressBar->setFormat("Starting initial discovery...");
-
- QObject::connect(p->discovery.dialog->b_skip, &QPushButton::clicked,
- this, &PluginListDialog::refreshPluginsSkip);
- QObject::connect(p->discovery.dialog, &QDialog::finished,
- this, &PluginListDialog::refreshPluginsStop);
-
- p->timerId = startTimer(0);
-
- QTimer::singleShot(0, p->discovery.dialog, &QDialog::exec);
- }
- }
-
- void PluginListDialog::timerEvent(QTimerEvent* const event)
- {
- if (event->timerId() == p->timerId)
- {
- do {
- // discovery in progress, keep it going
- if (p->discovery.handle != nullptr)
- {
- if (!carla_plugin_discovery_idle(p->discovery.handle))
- {
- carla_plugin_discovery_stop(p->discovery.handle);
- p->discovery.handle = nullptr;
- }
- break;
- }
-
- // start next discovery
- QCarlaString path;
- switch (p->discovery.ptype)
- {
- case PLUGIN_NONE:
- #ifndef CARLA_FRONTEND_ONLY_EMBEDDABLE_PLUGINS
- if (p->discovery.btype == BINARY_NATIVE)
- {
- ui.label->setText(tr("Discovering internal plugins..."));
- p->discovery.ptype = PLUGIN_INTERNAL;
- break;
- }
- [[fallthrough]];
- case PLUGIN_INTERNAL:
- ui.label->setText(tr("Discovering LADSPA plugins..."));
- path = p->paths.ladspa;
- p->discovery.ptype = PLUGIN_LADSPA;
- break;
- case PLUGIN_LADSPA:
- ui.label->setText(tr("Discovering DSSI plugins..."));
- path = p->paths.dssi;
- p->discovery.ptype = PLUGIN_DSSI;
- break;
- case PLUGIN_DSSI:
- #endif
- ui.label->setText(tr("Discovering LV2 plugins..."));
- path = p->paths.lv2;
- p->discovery.ptype = PLUGIN_LV2;
- break;
- case PLUGIN_LV2:
- ui.label->setText(tr("Discovering VST2 plugins..."));
- path = p->paths.vst2;
- p->discovery.ptype = PLUGIN_VST2;
- break;
- case PLUGIN_VST2:
- ui.label->setText(tr("Discovering VST3 plugins..."));
- path = p->paths.vst3;
- p->discovery.ptype = PLUGIN_VST3;
- break;
- case PLUGIN_VST3:
- ui.label->setText(tr("Discovering CLAP plugins..."));
- path = p->paths.clap;
- p->discovery.ptype = PLUGIN_CLAP;
- break;
- case PLUGIN_CLAP:
- #ifndef CARLA_FRONTEND_ONLY_EMBEDDABLE_PLUGINS
- #ifdef CARLA_OS_MAC
- if (p->discovery.btype == BINARY_POSIX32 || p->discovery.btype == BINARY_POSIX64)
- {
- ui.label->setText(tr("Discovering AU plugins..."));
- p->discovery.ptype = PLUGIN_AU;
- break;
- }
- [[fallthrough]];
- case PLUGIN_AU:
- #endif
- if (p->discovery.btype == BINARY_NATIVE && p->paths.jsfx.isNotEmpty())
- {
- ui.label->setText(tr("Discovering JSFX plugins..."));
- path = p->paths.jsfx;
- p->discovery.ptype = PLUGIN_JSFX;
- break;
- }
- [[fallthrough]];
- case PLUGIN_JSFX:
- if (p->discovery.btype == BINARY_NATIVE && p->paths.sf2.isNotEmpty())
- {
- ui.label->setText(tr("Discovering SF2 kits..."));
- path = p->paths.sf2;
- p->discovery.ptype = PLUGIN_SF2;
- break;
- }
- [[fallthrough]];
- case PLUGIN_SF2:
- if (p->discovery.btype == BINARY_NATIVE && p->paths.sfz.isNotEmpty())
- {
- ui.label->setText(tr("Discovering SFZ kits..."));
- path = p->paths.sfz;
- p->discovery.ptype = PLUGIN_SFZ;
- break;
- }
- [[fallthrough]];
- case PLUGIN_SFZ:
- #endif
- default:
- // discovery complete
- if (! p->discovery.nextTool())
- refreshPluginsStop();
- }
-
- if (p->timerId == 0)
- break;
-
- if (p->discovery.dialog)
- p->discovery.dialog->progressBar->setFormat(ui.label->text());
-
- p->discovery.handle = carla_plugin_discovery_start(p->discovery.tool.toUtf8().constData(),
- p->discovery.btype,
- p->discovery.ptype,
- path.toUtf8().constData(),
- discoveryCallback, checkCacheCallback, this);
- } while (false);
- }
-
- QDialog::timerEvent(event);
- }
-
- // --------------------------------------------------------------------------------------------------------------------
- // private methods
-
- void PluginListDialog::addPluginsToTable()
- {
- // ----------------------------------------------------------------------------------------------------------------
- // sum plugins first, creating all needed rows in advance
-
- ui.tableWidget->setSortingEnabled(false);
- ui.tableWidget->clearContents();
-
- #ifdef CARLA_FRONTEND_ONLY_EMBEDDABLE_PLUGINS
- ui.tableWidget->setRowCount(
- int(p->plugins.lv2.size() + p->plugins.vst2.size() + p->plugins.vst3.size() + p->plugins.clap.size()));
-
- constexpr const char* const txt = "Have %1 LV2, %2 VST2, %3 VST3 and %4 CLAP plugins";
-
- ui.label->setText(tr(txt)
- .arg(QString::number(p->plugins.lv2.size()))
- .arg(QString::number(p->plugins.vst2.size()))
- .arg(QString::number(p->plugins.vst3.size()))
- .arg(QString::number(p->plugins.clap.size())));
- #else
- ui.tableWidget->setRowCount(
- int(p->plugins.internal.size() + p->plugins.ladspa.size() + p->plugins.dssi.size() +
- p->plugins.lv2.size() + p->plugins.vst2.size() + p->plugins.vst3.size() + p->plugins.clap.size() +
- #ifdef CARLA_OS_MAC
- p->plugins.au.size() +
- #endif
- p->plugins.jsfx.size() + p->plugins.kits.size()));
-
- constexpr const char* const txt = "Have %1 Internal, %2 LADSPA, %3 DSSI, %4 LV2, %5 VST2, %6 VST3, %7 CLAP"
- #ifdef CARLA_OS_MAC
- ", %8 AudioUnit and %9 JSFX plugins, plus %10 Sound Kits"
- #endif
- " and %8 JSFX plugins, plus %9 Sound Kits";
-
- ui.label->setText(tr(txt)
- .arg(QString::number(p->plugins.internal.size()))
- .arg(QString::number(p->plugins.ladspa.size()))
- .arg(QString::number(p->plugins.dssi.size()))
- .arg(QString::number(p->plugins.lv2.size()))
- .arg(QString::number(p->plugins.vst2.size()))
- .arg(QString::number(p->plugins.vst3.size()))
- .arg(QString::number(p->plugins.clap.size()))
- #ifdef CARLA_OS_MAC
- .arg(QString::number(p->plugins.au.size()))
- #endif
- .arg(QString::number(p->plugins.jsfx.size()))
- .arg(QString::number(p->plugins.kits.size())));
- #endif
-
- // ----------------------------------------------------------------------------------------------------------------
- // now add all plugins to the table
-
- auto addPluginToTable = [=](const PluginInfo& info) {
- const int index = p->lastTableWidgetIndex++;
- const bool isFav = p->plugins.favorites.contains(asPluginFavorite(info));
-
- QTableWidgetItem* const itemFav = new QTableWidgetItem;
- itemFav->setCheckState(isFav ? Qt::Checked : Qt::Unchecked);
- itemFav->setText(isFav ? " " : " ");
-
- const QString pluginText = (info.name + info.label + info.maker + info.filename).toLower();
- ui.tableWidget->setItem(index, TW_FAVORITE, itemFav);
- ui.tableWidget->setItem(index, TW_NAME, new QTableWidgetItem(info.name));
- ui.tableWidget->setItem(index, TW_LABEL, new QTableWidgetItem(info.label));
- ui.tableWidget->setItem(index, TW_MAKER, new QTableWidgetItem(info.maker));
- ui.tableWidget->setItem(index, TW_BINARY, new QTableWidgetItem(QFileInfo(info.filename).fileName()));
-
- QTableWidgetItem *const itemName = ui.tableWidget->item(index, TW_NAME);
- itemName->setData(Qt::UserRole + UR_PLUGIN_INFO, asVariant(info));
- itemName->setData(Qt::UserRole + UR_SEARCH_TEXT, pluginText);
- };
-
- p->lastTableWidgetIndex = 0;
-
- #ifndef CARLA_FRONTEND_ONLY_EMBEDDABLE_PLUGINS
- for (const PluginInfo &plugin : p->plugins.internal)
- addPluginToTable(plugin);
-
- for (const PluginInfo &plugin : p->plugins.ladspa)
- addPluginToTable(plugin);
-
- for (const PluginInfo &plugin : p->plugins.dssi)
- addPluginToTable(plugin);
- #endif
-
- for (const PluginInfo &plugin : p->plugins.lv2)
- addPluginToTable(plugin);
-
- for (const PluginInfo &plugin : p->plugins.vst2)
- addPluginToTable(plugin);
-
- for (const PluginInfo &plugin : p->plugins.vst3)
- addPluginToTable(plugin);
-
- for (const PluginInfo& plugin : p->plugins.clap)
- addPluginToTable(plugin);
-
- #ifndef CARLA_FRONTEND_ONLY_EMBEDDABLE_PLUGINS
- #ifdef CARLA_OS_MAC
- for (const PluginInfo& plugin : p->plugins.au)
- addPluginToTable(plugin);
- #endif
-
- for (const PluginInfo& plugin : p->plugins.jsfx)
- addPluginToTable(plugin);
-
- for (const PluginInfo& plugin : p->plugins.kits)
- addPluginToTable(plugin);
- #endif
-
- CARLA_SAFE_ASSERT_INT2(p->lastTableWidgetIndex == ui.tableWidget->rowCount(),
- p->lastTableWidgetIndex, ui.tableWidget->rowCount());
-
- // ----------------------------------------------------------------------------------------------------------------
- // and reenable sorting + filtering
-
- ui.tableWidget->setSortingEnabled(true);
-
- checkFilters();
- checkPlugin(ui.tableWidget->currentRow());
- }
-
- void PluginListDialog::loadSettings()
- {
- const QSafeSettings settings("falkTX", "CarlaDatabase3");
-
- restoreGeometry(settings.valueByteArray("PluginDatabase/Geometry"));
- ui.ch_effects->setChecked(settings.valueBool("PluginDatabase/ShowEffects", true));
- ui.ch_instruments->setChecked(settings.valueBool("PluginDatabase/ShowInstruments", true));
- ui.ch_midi->setChecked(settings.valueBool("PluginDatabase/ShowMIDI", true));
- ui.ch_other->setChecked(settings.valueBool("PluginDatabase/ShowOther", true));
- ui.ch_internal->setChecked(settings.valueBool("PluginDatabase/ShowInternal", true));
- ui.ch_ladspa->setChecked(settings.valueBool("PluginDatabase/ShowLADSPA", true));
- ui.ch_dssi->setChecked(settings.valueBool("PluginDatabase/ShowDSSI", true));
- ui.ch_lv2->setChecked(settings.valueBool("PluginDatabase/ShowLV2", true));
- ui.ch_vst->setChecked(settings.valueBool("PluginDatabase/ShowVST2", true));
- ui.ch_vst3->setChecked(settings.valueBool("PluginDatabase/ShowVST3", true));
- ui.ch_clap->setChecked(settings.valueBool("PluginDatabase/ShowCLAP", true));
- #ifdef CARLA_OS_MAC
- ui.ch_au->setChecked(settings.valueBool("PluginDatabase/ShowAU", true));
- #endif
- ui.ch_jsfx->setChecked(settings.valueBool("PluginDatabase/ShowJSFX", true));
- ui.ch_kits->setChecked(settings.valueBool("PluginDatabase/ShowKits", true));
- ui.ch_native->setChecked(settings.valueBool("PluginDatabase/ShowNative", true));
- ui.ch_bridged->setChecked(settings.valueBool("PluginDatabase/ShowBridged", true));
- ui.ch_bridged_wine->setChecked(settings.valueBool("PluginDatabase/ShowBridgedWine", true));
- ui.ch_favorites->setChecked(settings.valueBool("PluginDatabase/ShowFavorites", false));
- ui.ch_rtsafe->setChecked(settings.valueBool("PluginDatabase/ShowRtSafe", false));
- ui.ch_cv->setChecked(settings.valueBool("PluginDatabase/ShowHasCV", false));
- ui.ch_gui->setChecked(settings.valueBool("PluginDatabase/ShowHasGUI", false));
- ui.ch_inline_display->setChecked(settings.valueBool("PluginDatabase/ShowHasInlineDisplay", false));
- ui.ch_stereo->setChecked(settings.valueBool("PluginDatabase/ShowStereoOnly", false));
- ui.lineEdit->setText(settings.valueString("PluginDatabase/SearchText", ""));
-
- const QString categories = settings.valueString("PluginDatabase/ShowCategory", "all");
- if (categories == "all" or categories.length() < 2)
- {
- ui.ch_cat_all->setChecked(true);
- ui.ch_cat_delay->setChecked(false);
- ui.ch_cat_distortion->setChecked(false);
- ui.ch_cat_dynamics->setChecked(false);
- ui.ch_cat_eq->setChecked(false);
- ui.ch_cat_filter->setChecked(false);
- ui.ch_cat_modulator->setChecked(false);
- ui.ch_cat_synth->setChecked(false);
- ui.ch_cat_utility->setChecked(false);
- ui.ch_cat_other->setChecked(false);
- }
- else
- {
- ui.ch_cat_all->setChecked(false);
- ui.ch_cat_delay->setChecked(categories.contains(":delay:"));
- ui.ch_cat_distortion->setChecked(categories.contains(":distortion:"));
- ui.ch_cat_dynamics->setChecked(categories.contains(":dynamics:"));
- ui.ch_cat_eq->setChecked(categories.contains(":eq:"));
- ui.ch_cat_filter->setChecked(categories.contains(":filter:"));
- ui.ch_cat_modulator->setChecked(categories.contains(":modulator:"));
- ui.ch_cat_synth->setChecked(categories.contains(":synth:"));
- ui.ch_cat_utility->setChecked(categories.contains(":utility:"));
- ui.ch_cat_other->setChecked(categories.contains(":other:"));
- }
-
- const QByteArray tableGeometry = settings.valueByteArray("PluginDatabase/TableGeometry");
- QHeaderView* const horizontalHeader = ui.tableWidget->horizontalHeader();
- if (! tableGeometry.isNull())
- {
- horizontalHeader->restoreState(tableGeometry);
- }
- else
- {
- ui.tableWidget->setColumnWidth(TW_NAME, 250);
- ui.tableWidget->setColumnWidth(TW_LABEL, 200);
- ui.tableWidget->setColumnWidth(TW_MAKER, 150);
- ui.tableWidget->sortByColumn(TW_NAME, Qt::AscendingOrder);
- }
-
- horizontalHeader->setSectionResizeMode(TW_FAVORITE, QHeaderView::Fixed);
- ui.tableWidget->setColumnWidth(TW_FAVORITE, 24);
- ui.tableWidget->setSortingEnabled(true);
-
- p->plugins.favorites = asPluginFavoriteList(settings.valueByteArray("PluginListDialog/Favorites"));
-
- // load entire plugin cache
- const QStringList keys = settings.allKeys();
- for (const QCarlaString key : keys)
- {
- if (!key.startsWith("PluginCache/"))
- continue;
-
- const QByteArray data(settings.valueByteArray(key));
-
- if (data.isEmpty())
- p->plugins.cache.insert(key.sliced(12), {});
- else
- p->plugins.cache.insert(key.sliced(12), asPluginInfoList(data));
- }
-
- #ifdef CARLA_FRONTEND_ONLY_EMBEDDABLE_PLUGINS
- // these are not visible, force their value
- ui.ch_native->setChecked(true);
- ui.ch_bridged->setChecked(false);
- ui.ch_bridged_wine->setChecked(false);
- ui.ch_inline_display->setChecked(false);
- #endif
- }
-
- // -----------------------------------------------------------------------------------------------------------------
- // private slots
-
- void PluginListDialog::cellClicked(const int row, const int column)
- {
- if (column != TW_FAVORITE)
- return;
-
- const PluginInfo info = asPluginInfo(ui.tableWidget->item(row, TW_NAME)->data(Qt::UserRole + UR_PLUGIN_INFO));
- const PluginFavorite fav = asPluginFavorite(info);
- const bool isFavorite = p->plugins.favorites.contains(fav);
-
- if (ui.tableWidget->item(row, TW_FAVORITE)->checkState() == Qt::Checked)
- {
- if (!isFavorite)
- p->plugins.favorites.append(fav);
- }
- else if (isFavorite)
- {
- p->plugins.favorites.removeAll(fav);
- }
-
- QSafeSettings settings("falkTX", "CarlaDatabase3");
- settings.setValue("PluginListDialog/Favorites", asVariant(p->plugins.favorites));
- }
-
- void PluginListDialog::cellDoubleClicked(int, const int column)
- {
- if (column != TW_FAVORITE)
- done(QDialog::Accepted);
- }
-
- void PluginListDialog::focusSearchFieldAndSelectAll()
- {
- ui.lineEdit->setFocus();
- ui.lineEdit->selectAll();
- }
-
- void PluginListDialog::checkFilters()
- {
- const QCarlaString text = ui.lineEdit->text().toLower();
-
- const bool hideEffects = !ui.ch_effects->isChecked();
- const bool hideInstruments = !ui.ch_instruments->isChecked();
- const bool hideMidi = !ui.ch_midi->isChecked();
- const bool hideOther = !ui.ch_other->isChecked();
-
- const bool hideInternal = !ui.ch_internal->isChecked();
- const bool hideLadspa = !ui.ch_ladspa->isChecked();
- const bool hideDSSI = !ui.ch_dssi->isChecked();
- const bool hideLV2 = !ui.ch_lv2->isChecked();
- const bool hideVST2 = !ui.ch_vst->isChecked();
- const bool hideVST3 = !ui.ch_vst3->isChecked();
- const bool hideCLAP = !ui.ch_clap->isChecked();
- const bool hideAU = !ui.ch_au->isChecked();
- const bool hideJSFX = !ui.ch_jsfx->isChecked();
- const bool hideKits = !ui.ch_kits->isChecked();
-
- const bool hideNative = !ui.ch_native->isChecked();
- const bool hideBridged = !ui.ch_bridged->isChecked();
- const bool hideBridgedWine = !ui.ch_bridged_wine->isChecked();
-
- const bool hideNonFavs = ui.ch_favorites->isChecked();
- const bool hideNonRtSafe = ui.ch_rtsafe->isChecked();
- const bool hideNonCV = ui.ch_cv->isChecked();
- const bool hideNonGui = ui.ch_gui->isChecked();
- const bool hideNonIDisp = ui.ch_inline_display->isChecked();
- const bool hideNonStereo = ui.ch_stereo->isChecked();
-
- #if defined(CARLA_OS_WIN64)
- static constexpr const BinaryType nativeBins[2] = { BINARY_WIN32, BINARY_WIN64 };
- static constexpr const BinaryType wineBins[2] = { BINARY_NONE, BINARY_NONE };
- #elif defined(CARLA_OS_WIN32)
- static constexpr const BinaryType nativeBins[2] = { BINARY_WIN32, BINARY_NONE };
- static constexpr const BinaryType wineBins[2] = { BINARY_NONE, BINARY_NONE };
- #elif defined(CARLA_OS_MAC)
- static constexpr const BinaryType nativeBins[2] = { BINARY_POSIX64, BINARY_NONE };
- static constexpr const BinaryType wineBins[2] = { BINARY_WIN32, BINARY_WIN64 };
- #else
- static constexpr const BinaryType nativeBins[2] = { BINARY_POSIX32, BINARY_POSIX64 };
- static constexpr const BinaryType wineBins[2] = { BINARY_WIN32, BINARY_WIN64 };
- #endif
-
- for (int i=0, c=ui.tableWidget->rowCount(); i<c; ++i)
- {
- const PluginInfo info = asPluginInfo(ui.tableWidget->item(i, TW_NAME)->data(Qt::UserRole + UR_PLUGIN_INFO));
- const QString ptext = ui.tableWidget->item(i, TW_NAME)->data(Qt::UserRole + UR_SEARCH_TEXT).toString();
-
- const uint16_t aIns = info.audioIns;
- const uint16_t aOuts = info.audioOuts;
- const uint16_t cvIns = info.cvIns;
- const uint16_t cvOuts = info.cvOuts;
- const uint16_t mIns = info.midiIns;
- const uint16_t mOuts = info.midiOuts;
- const uint32_t phints = info.hints;
- const uint16_t ptype = info.type;
- const QString categ = info.category;
- const bool isSynth = phints & PLUGIN_IS_SYNTH;
- const bool isEffect = aIns > 0 && aOuts > 0 && !isSynth;
- const bool isMidi = aIns == 0 && aOuts == 0 && mIns > 0 && mOuts > 0;
- const bool isKit = ptype == PLUGIN_SF2 || ptype == PLUGIN_SFZ;
- const bool isOther = !(isEffect || isSynth || isMidi || isKit);
- const bool isNative = info.build == BINARY_NATIVE;
- const bool isRtSafe = phints & PLUGIN_IS_RTSAFE;
- const bool isStereo = (aIns == 2 && aOuts == 2) || (isSynth && aOuts == 2);
- const bool hasCV = cvIns + cvOuts > 0;
- const bool hasGui = phints & PLUGIN_HAS_CUSTOM_UI;
- const bool hasIDisp = phints & PLUGIN_HAS_INLINE_DISPLAY;
- const bool isBridged = !isNative && (nativeBins[0] == info.build || nativeBins[1] == info.build);
- const bool isBridgedWine = !isNative && (wineBins[0] == info.build || wineBins[1] == info.build);
-
- const auto hasText = [text, ptext]() {
- const QStringList textSplit = text.strip().split(' ');
- for (const QString& t : textSplit)
- if (ptext.contains(t))
- return true;
- return false;
- };
-
- /**/ if (hideEffects && isEffect)
- ui.tableWidget->hideRow(i);
- else if (hideInstruments && isSynth)
- ui.tableWidget->hideRow(i);
- else if (hideMidi && isMidi)
- ui.tableWidget->hideRow(i);
- else if (hideOther && isOther)
- ui.tableWidget->hideRow(i);
- else if (hideKits && isKit)
- ui.tableWidget->hideRow(i);
- else if (hideInternal && ptype == PLUGIN_INTERNAL)
- ui.tableWidget->hideRow(i);
- else if (hideLadspa && ptype == PLUGIN_LADSPA)
- ui.tableWidget->hideRow(i);
- else if (hideDSSI && ptype == PLUGIN_DSSI)
- ui.tableWidget->hideRow(i);
- else if (hideLV2 && ptype == PLUGIN_LV2)
- ui.tableWidget->hideRow(i);
- else if (hideVST2 && ptype == PLUGIN_VST2)
- ui.tableWidget->hideRow(i);
- else if (hideVST3 && ptype == PLUGIN_VST3)
- ui.tableWidget->hideRow(i);
- else if (hideCLAP && ptype == PLUGIN_CLAP)
- ui.tableWidget->hideRow(i);
- else if (hideAU && ptype == PLUGIN_AU)
- ui.tableWidget->hideRow(i);
- else if (hideJSFX && ptype == PLUGIN_JSFX)
- ui.tableWidget->hideRow(i);
- else if (hideNative && isNative)
- ui.tableWidget->hideRow(i);
- else if (hideBridged && isBridged)
- ui.tableWidget->hideRow(i);
- else if (hideBridgedWine && isBridgedWine)
- ui.tableWidget->hideRow(i);
- else if (hideNonRtSafe && not isRtSafe)
- ui.tableWidget->hideRow(i);
- else if (hideNonCV && not hasCV)
- ui.tableWidget->hideRow(i);
- else if (hideNonGui && not hasGui)
- ui.tableWidget->hideRow(i);
- else if (hideNonIDisp && not hasIDisp)
- ui.tableWidget->hideRow(i);
- else if (hideNonStereo && not isStereo)
- ui.tableWidget->hideRow(i);
- else if (text.isNotEmpty() && ! hasText())
- ui.tableWidget->hideRow(i);
- else if (hideNonFavs && !p->plugins.favorites.contains(asPluginFavorite(info)))
- ui.tableWidget->hideRow(i);
- else if (ui.ch_cat_all->isChecked() or
- (ui.ch_cat_delay->isChecked() && categ == "delay") or
- (ui.ch_cat_distortion->isChecked() && categ == "distortion") or
- (ui.ch_cat_dynamics->isChecked() && categ == "dynamics") or
- (ui.ch_cat_eq->isChecked() && categ == "eq") or
- (ui.ch_cat_filter->isChecked() && categ == "filter") or
- (ui.ch_cat_modulator->isChecked() && categ == "modulator") or
- (ui.ch_cat_synth->isChecked() && categ == "synth") or
- (ui.ch_cat_utility->isChecked() && categ == "utility") or
- (ui.ch_cat_other->isChecked() && categ == "other"))
- ui.tableWidget->showRow(i);
- else
- ui.tableWidget->hideRow(i);
- }
- }
-
- void PluginListDialog::checkFiltersCategoryAll(const bool clicked)
- {
- const bool notClicked = !clicked;
- ui.ch_cat_delay->setChecked(notClicked);
- ui.ch_cat_distortion->setChecked(notClicked);
- ui.ch_cat_dynamics->setChecked(notClicked);
- ui.ch_cat_eq->setChecked(notClicked);
- ui.ch_cat_filter->setChecked(notClicked);
- ui.ch_cat_modulator->setChecked(notClicked);
- ui.ch_cat_synth->setChecked(notClicked);
- ui.ch_cat_utility->setChecked(notClicked);
- ui.ch_cat_other->setChecked(notClicked);
- checkFilters();
- }
-
- void PluginListDialog::checkFiltersCategorySpecific(bool clicked)
- {
- if (clicked)
- {
- ui.ch_cat_all->setChecked(false);
- }
- else if (! (ui.ch_cat_delay->isChecked() ||
- ui.ch_cat_distortion->isChecked() ||
- ui.ch_cat_dynamics->isChecked() ||
- ui.ch_cat_eq->isChecked() ||
- ui.ch_cat_filter->isChecked() ||
- ui.ch_cat_modulator->isChecked() ||
- ui.ch_cat_synth->isChecked() ||
- ui.ch_cat_utility->isChecked() ||
- ui.ch_cat_other->isChecked()))
- {
- ui.ch_cat_all->setChecked(true);
- }
- checkFilters();
- }
-
- void PluginListDialog::clearFilters()
- {
- auto setCheckedWithoutSignaling = [](QCheckBox* const w, const bool checked)
- {
- w->blockSignals(true);
- w->setChecked(checked);
- w->blockSignals(false);
- };
-
- setCheckedWithoutSignaling(ui.ch_internal, true);
- setCheckedWithoutSignaling(ui.ch_ladspa, true);
- setCheckedWithoutSignaling(ui.ch_dssi, true);
- setCheckedWithoutSignaling(ui.ch_lv2, true);
- setCheckedWithoutSignaling(ui.ch_vst, true);
- setCheckedWithoutSignaling(ui.ch_vst3, true);
- setCheckedWithoutSignaling(ui.ch_clap, true);
- setCheckedWithoutSignaling(ui.ch_jsfx, true);
- setCheckedWithoutSignaling(ui.ch_kits, true);
-
- setCheckedWithoutSignaling(ui.ch_instruments, true);
- setCheckedWithoutSignaling(ui.ch_effects, true);
- setCheckedWithoutSignaling(ui.ch_midi, true);
- setCheckedWithoutSignaling(ui.ch_other, true);
-
- setCheckedWithoutSignaling(ui.ch_native, true);
- setCheckedWithoutSignaling(ui.ch_bridged, false);
- setCheckedWithoutSignaling(ui.ch_bridged_wine, false);
-
- setCheckedWithoutSignaling(ui.ch_favorites, false);
- setCheckedWithoutSignaling(ui.ch_rtsafe, false);
- setCheckedWithoutSignaling(ui.ch_stereo, false);
- setCheckedWithoutSignaling(ui.ch_cv, false);
- setCheckedWithoutSignaling(ui.ch_gui, false);
- setCheckedWithoutSignaling(ui.ch_inline_display, false);
-
- if (ui.ch_au->isEnabled())
- setCheckedWithoutSignaling(ui.ch_au, true);
-
- setCheckedWithoutSignaling(ui.ch_cat_all, true);
- setCheckedWithoutSignaling(ui.ch_cat_delay, false);
- setCheckedWithoutSignaling(ui.ch_cat_distortion, false);
- setCheckedWithoutSignaling(ui.ch_cat_dynamics, false);
- setCheckedWithoutSignaling(ui.ch_cat_eq, false);
- setCheckedWithoutSignaling(ui.ch_cat_filter, false);
- setCheckedWithoutSignaling(ui.ch_cat_modulator, false);
- setCheckedWithoutSignaling(ui.ch_cat_synth, false);
- setCheckedWithoutSignaling(ui.ch_cat_utility, false);
- setCheckedWithoutSignaling(ui.ch_cat_other, false);
-
- ui.lineEdit->blockSignals(true);
- ui.lineEdit->clear();
- ui.lineEdit->blockSignals(false);
-
- checkFilters();
- }
-
- // --------------------------------------------------------------------------------------------------------------------
-
- void PluginListDialog::checkPlugin(const int row)
- {
- if (row >= 0)
- {
- ui.b_add->setEnabled(true);
-
- const PluginInfo info = asPluginInfo(ui.tableWidget->item(row, TW_NAME)->data(Qt::UserRole + UR_PLUGIN_INFO));
-
- const bool isSynth = info.hints & PLUGIN_IS_SYNTH;
- const bool isEffect = info.audioIns > 0 && info.audioOuts > 0 && !isSynth;
- const bool isMidi = info.audioIns == 0 && info.audioOuts == 0 && info.midiIns > 0 && info.midiOuts > 0;
-
- QString ptype;
- /**/ if (isSynth)
- ptype = "Instrument";
- else if (isEffect)
- ptype = "Effect";
- else if (isMidi)
- ptype = "MIDI Plugin";
- else
- ptype = "Other";
-
- QString parch;
- /**/ if (info.build == BINARY_NATIVE)
- parch = tr("Native");
- else if (info.build == BINARY_POSIX32)
- parch = "posix32";
- else if (info.build == BINARY_POSIX64)
- parch = "posix64";
- else if (info.build == BINARY_WIN32)
- parch = "win32";
- else if (info.build == BINARY_WIN64)
- parch = "win64";
- else if (info.build == BINARY_OTHER)
- parch = tr("Other");
- else if (info.build == BINARY_WIN32)
- parch = tr("Unknown");
-
- ui.l_format->setText(getPluginTypeAsString(static_cast<PluginType>(info.type)));
-
- ui.l_type->setText(ptype);
- ui.l_arch->setText(parch);
- ui.l_id->setText(QString::number(info.uniqueId));
- ui.l_ains->setText(QString::number(info.audioIns));
- ui.l_aouts->setText(QString::number(info.audioOuts));
- ui.l_cvins->setText(QString::number(info.cvIns));
- ui.l_cvouts->setText(QString::number(info.cvOuts));
- ui.l_mins->setText(QString::number(info.midiIns));
- ui.l_mouts->setText(QString::number(info.midiOuts));
- ui.l_pins->setText(QString::number(info.parameterIns));
- ui.l_pouts->setText(QString::number(info.parameterOuts));
- ui.l_gui->setText(info.hints & PLUGIN_HAS_CUSTOM_UI ? tr("Yes") : tr("No"));
- ui.l_idisp->setText(info.hints & PLUGIN_HAS_INLINE_DISPLAY ? tr("Yes") : tr("No"));
- ui.l_bridged->setText(info.hints & PLUGIN_IS_BRIDGE ? tr("Yes") : tr("No"));
- ui.l_synth->setText(isSynth ? tr("Yes") : tr("No"));
- }
- else
- {
- ui.b_add->setEnabled(false);
- ui.l_format->setText("---");
- ui.l_type->setText("---");
- ui.l_arch->setText("---");
- ui.l_id->setText("---");
- ui.l_ains->setText("---");
- ui.l_aouts->setText("---");
- ui.l_cvins->setText("---");
- ui.l_cvouts->setText("---");
- ui.l_mins->setText("---");
- ui.l_mouts->setText("---");
- ui.l_pins->setText("---");
- ui.l_pouts->setText("---");
- ui.l_gui->setText("---");
- ui.l_idisp->setText("---");
- ui.l_bridged->setText("---");
- ui.l_synth->setText("---");
- }
- }
-
- // --------------------------------------------------------------------------------------------------------------------
-
- void PluginListDialog::refreshPlugins()
- {
- refreshPluginsStop();
-
- p->discovery.dialog = new PluginRefreshDialog(this);
-
- QObject::connect(p->discovery.dialog->b_start, &QPushButton::clicked,
- this, &PluginListDialog::refreshPluginsStart);
- QObject::connect(p->discovery.dialog->b_skip, &QPushButton::clicked,
- this, &PluginListDialog::refreshPluginsSkip);
- QObject::connect(p->discovery.dialog, &QDialog::finished,
- this, &PluginListDialog::refreshPluginsStop);
-
- p->discovery.dialog->exec();
- }
-
- void PluginListDialog::refreshPluginsStart()
- {
- // remove old plugins
- #ifndef CARLA_FRONTEND_ONLY_EMBEDDABLE_PLUGINS
- p->plugins.internal.clear();
- p->plugins.ladspa.clear();
- p->plugins.dssi.clear();
- #endif
- p->plugins.lv2.clear();
- p->plugins.vst2.clear();
- p->plugins.vst3.clear();
- p->plugins.clap.clear();
- #ifndef CARLA_FRONTEND_ONLY_EMBEDDABLE_PLUGINS
- #ifdef CARLA_OS_MAC
- p->plugins.au.clear();
- #endif
- p->plugins.jsfx.clear();
- p->plugins.kits.clear();
- #endif
- p->discovery.dialog->b_start->setEnabled(false);
- p->discovery.dialog->b_skip->setEnabled(true);
- p->discovery.ignoreCache = p->discovery.dialog->ch_all->isChecked();
- p->discovery.checkInvalid =
- p->discovery.dialog->ch_invalid->isChecked();
- if (p->discovery.ignoreCache)
- p->plugins.cache.clear();
-
- // start discovery again
- p->discovery.restart();
-
- if (p->timerId == 0)
- p->timerId = startTimer(0);
- }
-
- void PluginListDialog::refreshPluginsStop()
- {
- // stop previous discovery if still running
- if (p->discovery.handle != nullptr)
- {
- carla_plugin_discovery_stop(p->discovery.handle);
- p->discovery.handle = nullptr;
- }
-
- if (p->discovery.dialog)
- {
- p->discovery.dialog->close();
- p->discovery.dialog = nullptr;
- }
-
- if (p->timerId != 0)
- {
- killTimer(p->timerId);
- p->timerId = 0;
- addPluginsToTable();
- }
- }
-
- void PluginListDialog::refreshPluginsSkip()
- {
- if (p->discovery.handle != nullptr)
- carla_plugin_discovery_skip(p->discovery.handle);
- }
-
- // --------------------------------------------------------------------------------------------------------------------
-
- void PluginListDialog::saveSettings()
- {
- QSafeSettings settings("falkTX", "CarlaDatabase3");
-
- settings.setValue("PluginDatabase/Geometry", saveGeometry());
- settings.setValue("PluginDatabase/TableGeometry", ui.tableWidget->horizontalHeader()->saveState());
- settings.setValue("PluginDatabase/ShowEffects", ui.ch_effects->isChecked());
- settings.setValue("PluginDatabase/ShowInstruments", ui.ch_instruments->isChecked());
- settings.setValue("PluginDatabase/ShowMIDI", ui.ch_midi->isChecked());
- settings.setValue("PluginDatabase/ShowOther", ui.ch_other->isChecked());
- settings.setValue("PluginDatabase/ShowInternal", ui.ch_internal->isChecked());
- settings.setValue("PluginDatabase/ShowLADSPA", ui.ch_ladspa->isChecked());
- settings.setValue("PluginDatabase/ShowDSSI", ui.ch_dssi->isChecked());
- settings.setValue("PluginDatabase/ShowLV2", ui.ch_lv2->isChecked());
- settings.setValue("PluginDatabase/ShowVST2", ui.ch_vst->isChecked());
- settings.setValue("PluginDatabase/ShowVST3", ui.ch_vst3->isChecked());
- settings.setValue("PluginDatabase/ShowCLAP", ui.ch_clap->isChecked());
- settings.setValue("PluginDatabase/ShowAU", ui.ch_au->isChecked());
- settings.setValue("PluginDatabase/ShowJSFX", ui.ch_jsfx->isChecked());
- settings.setValue("PluginDatabase/ShowKits", ui.ch_kits->isChecked());
- settings.setValue("PluginDatabase/ShowNative", ui.ch_native->isChecked());
- settings.setValue("PluginDatabase/ShowBridged", ui.ch_bridged->isChecked());
- settings.setValue("PluginDatabase/ShowBridgedWine", ui.ch_bridged_wine->isChecked());
- settings.setValue("PluginDatabase/ShowFavorites", ui.ch_favorites->isChecked());
- settings.setValue("PluginDatabase/ShowRtSafe", ui.ch_rtsafe->isChecked());
- settings.setValue("PluginDatabase/ShowHasCV", ui.ch_cv->isChecked());
- settings.setValue("PluginDatabase/ShowHasGUI", ui.ch_gui->isChecked());
- settings.setValue("PluginDatabase/ShowHasInlineDisplay", ui.ch_inline_display->isChecked());
- settings.setValue("PluginDatabase/ShowStereoOnly", ui.ch_stereo->isChecked());
- settings.setValue("PluginDatabase/SearchText", ui.lineEdit->text());
-
- if (ui.ch_cat_all->isChecked())
- {
- settings.setValue("PluginDatabase/ShowCategory", "all");
- }
- else
- {
- QCarlaString categories;
- if (ui.ch_cat_delay->isChecked())
- categories += ":delay";
- if (ui.ch_cat_distortion->isChecked())
- categories += ":distortion";
- if (ui.ch_cat_dynamics->isChecked())
- categories += ":dynamics";
- if (ui.ch_cat_eq->isChecked())
- categories += ":eq";
- if (ui.ch_cat_filter->isChecked())
- categories += ":filter";
- if (ui.ch_cat_modulator->isChecked())
- categories += ":modulator";
- if (ui.ch_cat_synth->isChecked())
- categories += ":synth";
- if (ui.ch_cat_utility->isChecked())
- categories += ":utility";
- if (ui.ch_cat_other->isChecked())
- categories += ":other";
- if (categories.isNotEmpty())
- categories += ":";
- settings.setValue("PluginDatabase/ShowCategory", categories);
- }
-
- settings.setValue("PluginListDialog/Favorites", asVariant(p->plugins.favorites));
- }
-
- // --------------------------------------------------------------------------------------------------------------------
-
- PluginListDialog*
- carla_frontend_createPluginListDialog(void* const parent)
- {
- const HostSettings hostSettings = {};
- return new PluginListDialog(reinterpret_cast<QWidget*>(parent), hostSettings);
- }
-
- const PluginListDialogResults*
- carla_frontend_execPluginListDialog(PluginListDialog* const dialog)
- {
- if (dialog->exec())
- {
- static PluginListDialogResults ret;
- static CarlaString category;
- static CarlaString filename;
- static CarlaString name;
- static CarlaString label;
- static CarlaString maker;
-
- const PluginInfo& plugin(dialog->getSelectedPluginInfo());
-
- category = plugin.category.toUtf8();
- filename = plugin.filename.toUtf8();
- name = plugin.name.toUtf8();
- label = plugin.label.toUtf8();
- maker = plugin.maker.toUtf8();
-
- ret.build = plugin.build;
- ret.type = plugin.type;
- ret.hints = plugin.hints;
- ret.category = category;
- ret.filename = filename;
- ret.name = name;
- ret.label = label;
- ret.maker = maker;
- ret.uniqueId = plugin.uniqueId;
- ret.audioIns = plugin.audioIns;
- ret.audioOuts = plugin.audioOuts;
- ret.cvIns = plugin.cvIns;
- ret.cvOuts = plugin.cvOuts;
- ret.midiIns = plugin.midiIns;
- ret.midiOuts = plugin.midiOuts;
- ret.parameterIns = plugin.parameterIns;
- ret.parameterOuts = plugin.parameterOuts;
-
- return &ret;
- }
-
- return nullptr;
- }
-
- // --------------------------------------------------------------------------------------------------------------------
-
- const PluginListDialogResults*
- carla_frontend_createAndExecPluginListDialog(void* const parent/*, const HostSettings& hostSettings*/)
- {
- const HostSettings hostSettings = {};
- PluginListDialog gui(reinterpret_cast<QWidget*>(parent), hostSettings);
-
- return carla_frontend_execPluginListDialog(&gui);
- }
-
- // --------------------------------------------------------------------------------------------------------------------
|