3 * Copyright (C) 2011-2023 Filipe Coelho <falktx@falktx.com>
4 * SPDX-License-Identifier: GPL-2.0-or-later
7 #include "pluginlistdialog.hpp"
8 #include "pluginrefreshdialog.hpp"
11 # pragma clang diagnostic push
12 # pragma clang diagnostic ignored "-Wdeprecated-copy-with-user-provided-copy"
13 # pragma clang diagnostic ignored "-Wdeprecated-register"
14 #elif defined(__GNUC__) && __GNUC__ >= 8
15 # pragma GCC diagnostic push
16 # pragma GCC diagnostic ignored "-Wclass-memaccess"
17 # pragma GCC diagnostic ignored "-Wdeprecated-copy"
20 #include <QtCore/QDir>
21 #include <QtCore/QFileInfo>
22 #include <QtCore/QList>
23 #include <QtCore/QTimer>
26 # pragma clang diagnostic pop
27 #elif defined(__GNUC__) && __GNUC__ >= 8
28 # pragma GCC diagnostic pop
31 #include "qcarlastring.hpp"
32 #include "qsafesettings.hpp"
34 #include "CarlaBackendUtils.hpp"
35 #include "CarlaJuceUtils.hpp"
36 #include "CarlaUtils.h"
38 #include "CarlaString.hpp"
42 CARLA_BACKEND_USE_NAMESPACE
44 // --------------------------------------------------------------------------------------------------------------------
45 // getenv with a fallback value if unset
48 const char* getEnvWithFallback(const char* const env
, const char* const fallback
)
50 if (const char* const value
= std::getenv(env
))
56 // --------------------------------------------------------------------------------------------------------------------
57 // Plugin paths (from env vars first, then default locations)
60 #ifndef CARLA_FRONTEND_ONLY_EMBEDDABLE_PLUGINS
68 #ifndef CARLA_FRONTEND_ONLY_EMBEDDABLE_PLUGINS
76 // get common env vars
77 const QString HOME
= QDir::toNativeSeparators(QDir::homePath());
79 #if defined(CARLA_OS_WIN)
80 const char *const envAPPDATA
= std::getenv("APPDATA");
81 const char *const envLOCALAPPDATA
= getEnvWithFallback("LOCALAPPDATA", envAPPDATA
);
82 const char *const envPROGRAMFILES
= std::getenv("PROGRAMFILES");
83 const char* const envPROGRAMFILESx86
= std::getenv("PROGRAMFILES(x86)");
84 const char *const envCOMMONPROGRAMFILES
= std::getenv("COMMONPROGRAMFILES");
85 const char* const envCOMMONPROGRAMFILESx86
= std::getenv("COMMONPROGRAMFILES(x86)");
87 // Small integrity tests
88 if (envAPPDATA
== nullptr)
90 qFatal("APPDATA variable not set, cannot continue");
94 if (envPROGRAMFILES
== nullptr)
96 qFatal("PROGRAMFILES variable not set, cannot continue");
100 if (envCOMMONPROGRAMFILES
== nullptr)
102 qFatal("COMMONPROGRAMFILES variable not set, cannot continue");
106 const QCarlaString
APPDATA(envAPPDATA
);
107 const QCarlaString
LOCALAPPDATA(envLOCALAPPDATA
);
108 const QCarlaString
PROGRAMFILES(envPROGRAMFILES
);
109 const QCarlaString
COMMONPROGRAMFILES(envCOMMONPROGRAMFILES
);
110 #elif !defined(CARLA_OS_MAC)
111 const QCarlaString
CONFIG_HOME(getEnvWithFallback("XDG_CONFIG_HOME", (HOME
+ "/.config").toUtf8()));
114 #ifndef CARLA_FRONTEND_ONLY_EMBEDDABLE_PLUGINS
115 // now set paths, listing format path spec if available
116 if (const char *const envLADSPA
= std::getenv("LADSPA_PATH"))
122 // no official spec, use common paths
123 #if defined(CARLA_OS_WIN)
124 ladspa
= APPDATA
+ "\\LADSPA";
125 ladspa
+= ";" + PROGRAMFILES
+ "\\LADSPA";
126 #elif defined(CARLA_OS_HAIKU)
127 ladspa
= HOME
+ "/.ladspa";
128 ladspa
+= ":/system/add-ons/media/ladspaplugins";
129 ladspa
+= ":/system/lib/ladspa";
130 #elif defined(CARLA_OS_MAC)
131 ladspa
= HOME
+ "/Library/Audio/Plug-Ins/LADSPA";
132 ladspa
+= ":/Library/Audio/Plug-Ins/LADSPA";
134 ladspa
= HOME
+ "/.ladspa";
135 ladspa
+= ":/usr/local/lib/ladspa";
136 ladspa
+= ":/usr/lib/ladspa";
140 if (const char *const envDSSI
= std::getenv("DSSI_PATH"))
146 // no official spec, use common paths
147 #if defined(CARLA_OS_WIN)
148 dssi
= APPDATA
+ "\\DSSI";
149 dssi
+= ";" + PROGRAMFILES
+ "\\DSSI";
150 #elif defined(CARLA_OS_HAIKU)
151 dssi
= HOME
+ "/.dssi";
152 dssi
+= ":/system/add-ons/media/dssiplugins";
153 dssi
+= ":/system/lib/dssi";
154 #elif defined(CARLA_OS_MAC)
155 dssi
= HOME
+ "/Library/Audio/Plug-Ins/DSSI";
156 dssi
+= ":/Library/Audio/Plug-Ins/DSSI";
158 dssi
= HOME
+ "/.dssi";
159 dssi
+= ":/usr/local/lib/dssi";
160 dssi
+= ":/usr/lib/dssi";
163 #endif // !CARLA_FRONTEND_ONLY_EMBEDDABLE_PLUGINS
165 if (const char *const envLV2
= std::getenv("LV2_PATH"))
171 // https://lv2plug.in/pages/filesystem-hierarchy-standard.html
172 #if defined(CARLA_OS_WIN)
173 lv2
= APPDATA
+ "\\LV2";
174 lv2
+= ";" + COMMONPROGRAMFILES
+ "\\LV2";
175 #elif defined(CARLA_OS_HAIKU)
176 lv2
= HOME
+ "/.lv2";
177 lv2
+= ":/system/add-ons/media/lv2plugins";
178 #elif defined(CARLA_OS_MAC)
179 lv2
= HOME
+ "/Library/Audio/Plug-Ins/LV2";
180 lv2
+= ":/Library/Audio/Plug-Ins/LV2";
182 lv2
= HOME
+ "/.lv2";
183 lv2
+= ":/usr/local/lib/lv2";
184 lv2
+= ":/usr/lib/lv2";
188 if (const char *const envVST2
= std::getenv("VST_PATH"))
194 #if defined(CARLA_OS_WIN)
195 // https://helpcenter.steinberg.de/hc/en-us/articles/115000177084
196 vst2
= PROGRAMFILES
+ "\\VSTPlugins";
197 vst2
+= ";" + PROGRAMFILES
+ "\\Steinberg\\VSTPlugins";
198 vst2
+= ";" + COMMONPROGRAMFILES
+ "\\VST2";
199 vst2
+= ";" + COMMONPROGRAMFILES
+ "\\Steinberg\\VST2";
200 #elif defined(CARLA_OS_HAIKU)
201 vst2
= HOME
+ "/.vst";
202 vst2
+= ":/system/add-ons/media/vstplugins";
203 #elif defined(CARLA_OS_MAC)
204 // https://helpcenter.steinberg.de/hc/en-us/articles/115000171310
205 vst2
= HOME
+ "/Library/Audio/Plug-Ins/VST";
206 vst2
+= ":/Library/Audio/Plug-Ins/VST";
208 // no official spec, use common paths
209 vst2
= HOME
+ "/.vst";
210 vst2
+= ":" + HOME
+ "/.lxvst";
211 vst2
+= ":/usr/local/lib/vst";
212 vst2
+= ":/usr/local/lib/lxvst";
213 vst2
+= ":/usr/lib/vst";
214 vst2
+= ":/usr/lib/lxvst";
218 if (const char *const envVST3
= std::getenv("VST3_PATH"))
224 // https://steinbergmedia.github.io/vst3_dev_portal/pages/Technical+Documentation/Locations+Format/Plugin+Locations.html
225 #if defined(CARLA_OS_WIN)
226 vst3
= LOCALAPPDATA
+ "\\Programs\\Common\\VST3";
227 vst3
+= ";" + COMMONPROGRAMFILES
+ "\\VST3";
228 #elif defined(CARLA_OS_HAIKU)
229 vst3
= HOME
+ "/.vst3";
230 vst3
+= ":/system/add-ons/media/vst3plugins";
231 #elif defined(CARLA_OS_MAC)
232 vst3
= HOME
+ "/Library/Audio/Plug-Ins/VST3";
233 vst3
+= ":/Library/Audio/Plug-Ins/VST3";
235 vst3
= HOME
+ "/.vst3";
236 vst3
+= ":/usr/local/lib/vst3";
237 vst3
+= ":/usr/lib/vst3";
241 if (const char *const envCLAP
= std::getenv("CLAP_PATH"))
247 // https://github.com/free-audio/clap/blob/main/include/clap/entry.h
248 #if defined(CARLA_OS_WIN)
249 clap
= LOCALAPPDATA
+ "\\Programs\\Common\\CLAP";
250 clap
+= ";" + COMMONPROGRAMFILES
+ "\\CLAP";
251 #elif defined(CARLA_OS_HAIKU)
252 clap
= HOME
+ "/.clap";
253 clap
+= ":/system/add-ons/media/clapplugins";
254 #elif defined(CARLA_OS_MAC)
255 clap
= HOME
+ "/Library/Audio/Plug-Ins/CLAP";
256 clap
+= ":/Library/Audio/Plug-Ins/CLAP";
258 clap
= HOME
+ "/.clap";
259 clap
+= ":/usr/local/lib/clap";
260 clap
+= ":/usr/lib/clap";
264 #ifndef CARLA_FRONTEND_ONLY_EMBEDDABLE_PLUGINS
265 if (const char *const envJSFX
= std::getenv("JSFX_PATH"))
271 // REAPER user data directory
272 #if defined(CARLA_OS_WIN)
273 jsfx
= APPDATA
+ "\\REAPER\\Effects";
274 #elif defined(CARLA_OS_MAC)
275 jsfx
= HOME
+ "/Library/Application Support/REAPER/Effects";
277 jsfx
= CONFIG_HOME
+ "/REAPER/Effects";
281 if (const char *const envSF2
= std::getenv("SF2_PATH"))
287 #if defined(CARLA_OS_WIN)
288 sf2
= APPDATA
+ "\\SF2";
290 sf2
= HOME
+ "/.sounds/sf2";
291 sf2
+= ":" + HOME
+ "/.sounds/sf3";
292 sf2
+= ":/usr/share/sounds/sf2";
293 sf2
+= ":/usr/share/sounds/sf3";
294 sf2
+= ":/usr/share/soundfonts";
298 if (const char *const envSFZ
= std::getenv("SFZ_PATH"))
304 #if defined(CARLA_OS_WIN)
305 sfz
= APPDATA
+ "\\SFZ";
307 sfz
= HOME
+ "/.sounds/sfz";
308 sfz
+= ":/usr/share/sounds/sfz";
311 #endif // !CARLA_FRONTEND_ONLY_EMBEDDABLE_PLUGINS
314 if (envPROGRAMFILESx86
!= nullptr)
316 const QCarlaString
PROGRAMFILESx86(envPROGRAMFILESx86
);
317 #ifndef CARLA_FRONTEND_ONLY_EMBEDDABLE_PLUGINS
318 ladspa
+= ";" + PROGRAMFILESx86
+ "\\LADSPA";
319 dssi
+= ";" + PROGRAMFILESx86
+ "\\DSSI";
321 vst2
+= ";" + PROGRAMFILESx86
+ "\\VSTPlugins";
322 vst2
+= ";" + PROGRAMFILESx86
+ "\\Steinberg\\VSTPlugins";
325 if (envCOMMONPROGRAMFILESx86
!= nullptr)
327 const QCarlaString
COMMONPROGRAMFILESx86(envCOMMONPROGRAMFILESx86
);
328 vst3
+= COMMONPROGRAMFILESx86
+ "\\VST3";
329 clap
+= COMMONPROGRAMFILESx86
+ "\\CLAP";
331 #elif !defined(CARLA_FRONTEND_ONLY_EMBEDDABLE_PLUGINS)
332 QCarlaString winePrefix
;
334 if (const char* const envWINEPREFIX
= std::getenv("WINEPREFIX"))
335 winePrefix
= envWINEPREFIX
;
337 if (winePrefix
.isEmpty())
338 winePrefix
= HOME
+ "/.wine";
340 if (QDir(winePrefix
).exists())
342 vst2
+= ":" + winePrefix
+ "/drive_c/Program Files/VstPlugins";
343 vst2
+= ":" + winePrefix
+ "/drive_c/Program Files/Steinberg/VstPlugins";
344 vst2
+= ":" + winePrefix
+ "/drive_c/Program Files/Common Files/VST2";
345 vst3
+= ":" + winePrefix
+ "/drive_c/Program Files/Common Files/VST3";
346 clap
+= ":" + winePrefix
+ "/drive_c/Program Files/Common Files/CLAP";
348 #ifdef CARLA_OS_64BIT
349 if (QDir(winePrefix
+ "/drive_c/Program Files (x86)").exists())
351 vst2
+= ":" + winePrefix
+ "/drive_c/Program Files (x86)/VstPlugins";
352 vst2
+= ":" + winePrefix
+ "/drive_c/Program Files (x86)/Steinberg/VstPlugins";
353 vst2
+= ":" + winePrefix
+ "/drive_c/Program Files (x86)/Common Files/VST2";
354 vst3
+= ":" + winePrefix
+ "/drive_c/Program Files (x86)/Common Files/VST3";
355 clap
+= ":" + winePrefix
+ "/drive_c/Program Files (x86)/Common Files/CLAP";
363 // --------------------------------------------------------------------------------------------------------------------
364 // Backwards-compatible horizontalAdvance/width call, depending on Qt version
367 int fontMetricsHorizontalAdvance(const QFontMetrics
& fontMetrics
, const QString
& string
)
369 #if QT_VERSION >= 0x50b00
370 return fontMetrics
.horizontalAdvance(string
);
372 return fontMetrics
.width(string
);
376 // --------------------------------------------------------------------------------------------------------------------
377 // Qt-compatible plugin info
379 // base details, nicely packed and POD-only so we can directly use as binary
380 struct PluginInfoHeader
{
391 uint16_t parameterIns
;
392 uint16_t parameterOuts
;
395 // full details, now with non-POD types
396 struct PluginInfo
: PluginInfoHeader
{
404 // convert PluginInfo to Qt types
405 static QVariant
asByteArray(const PluginInfo
& info
)
409 // start with the POD data, stored as-is
410 qdata
.append(reinterpret_cast<const char*>(&info
), sizeof(PluginInfoHeader
));
412 // then all the strings, with a null terminating byte
414 const QByteArray
qcategory(info
.category
.toUtf8());
415 qdata
+= qcategory
.constData();
420 const QByteArray
qfilename(info
.filename
.toUtf8());
421 qdata
+= qfilename
.constData();
426 const QByteArray
qname(info
.name
.toUtf8());
427 qdata
+= qname
.constData();
432 const QByteArray
qlabel(info
.label
.toUtf8());
433 qdata
+= qlabel
.constData();
438 const QByteArray
qmaker(info
.maker
.toUtf8());
439 qdata
+= qmaker
.constData();
446 static QVariant
asVariant(const PluginInfo
& info
)
448 return QVariant(asByteArray(info
));
451 // convert Qt types to PluginInfo
452 static PluginInfo
asPluginInfo(const QByteArray
&qdata
)
454 // make sure data is big enough to fit POD data + 5 strings
455 CARLA_SAFE_ASSERT_RETURN(static_cast<size_t>(qdata
.size()) >= sizeof(PluginInfoHeader
) + sizeof(char) * 5, {});
457 // read POD data first
458 const PluginInfoHeader
* const data
= reinterpret_cast<const PluginInfoHeader
*>(qdata
.constData());
460 PluginInfo info
= {};
461 info
.build
= data
->build
;
462 info
.type
= data
->type
;
463 info
.hints
= data
->hints
;
464 info
.uniqueId
= data
->uniqueId
;
465 info
.audioIns
= data
->audioIns
;
466 info
.audioOuts
= data
->audioOuts
;
467 info
.cvIns
= data
->cvIns
;
468 info
.cvOuts
= data
->cvOuts
;
469 info
.midiIns
= data
->midiIns
;
470 info
.midiOuts
= data
->midiOuts
;
471 info
.parameterIns
= data
->parameterIns
;
472 info
.parameterOuts
= data
->parameterOuts
;
474 // then all the strings, keeping the same order as in `asVariant`
475 const char* sdata
= reinterpret_cast<const char*>(data
+ 1);
477 info
.category
= QString::fromUtf8(sdata
);
478 sdata
+= info
.category
.size() + 1;
480 info
.filename
= QString::fromUtf8(sdata
);
481 sdata
+= info
.filename
.size() + 1;
483 info
.name
= QString::fromUtf8(sdata
);
484 sdata
+= info
.name
.size() + 1;
486 info
.label
= QString::fromUtf8(sdata
);
487 sdata
+= info
.label
.size() + 1;
489 info
.maker
= QString::fromUtf8(sdata
);
490 sdata
+= info
.maker
.size() + 1;
495 static PluginInfo
asPluginInfo(const QVariant
& var
)
497 return asPluginInfo(var
.toByteArray());
500 static QList
<PluginInfo
> asPluginInfoList(const QVariant
& var
)
502 QCarlaByteArray
qdata(var
.toByteArray());
504 QList
<PluginInfo
> plist
;
506 while (!qdata
.isEmpty())
508 const PluginInfo info
= asPluginInfo(qdata
);
509 CARLA_SAFE_ASSERT_RETURN(info
.build
!= BINARY_NONE
, {});
512 qdata
= qdata
.sliced(sizeof(PluginInfoHeader
)
513 + info
.category
.size() + info
.filename
.size() + info
.name
.size()
514 + info
.label
.size() + info
.maker
.size() + 5);
520 // --------------------------------------------------------------------------------------------------------------------
521 // Qt-compatible plugin favorite
523 // base details, nicely packed and POD-only so we can directly use as binary
524 struct PluginFavoriteHeader
{
529 // full details, now with non-POD types
530 struct PluginFavorite
: PluginFavoriteHeader
{
540 PluginFavorite(uint16_t t
, uint64_t u
, const QString
& f
, const QString
& l
)
541 : filename(f
), label(l
)
547 bool operator==(const PluginFavorite
& other
) const
549 return type
== other
.type
&& uniqueId
== other
.uniqueId
&& filename
== other
.filename
&& label
== other
.label
;
553 // convert PluginFavorite to Qt types
554 static QByteArray
asByteArray(const PluginFavorite
& fav
)
558 // start with the POD data, stored as-is
559 qdata
.append(reinterpret_cast<const char*>(&fav
), sizeof(PluginFavoriteHeader
));
561 // then all the strings, with a null terminating byte
563 const QByteArray
qfilename(fav
.filename
.toUtf8());
564 qdata
+= qfilename
.constData();
569 const QByteArray
qlabel(fav
.label
.toUtf8());
570 qdata
+= qlabel
.constData();
577 static QVariant
asVariant(const QList
<PluginFavorite
>& favlist
)
581 for (const PluginFavorite
&fav
: favlist
)
582 qdata
+= asByteArray(fav
);
584 return QVariant(qdata
);
587 // convert Qt types to PluginInfo
588 static PluginFavorite
asPluginFavorite(const QByteArray
& qdata
)
590 // make sure data is big enough to fit POD data + 3 strings
591 CARLA_SAFE_ASSERT_RETURN(static_cast<size_t>(qdata
.size()) >= sizeof(PluginFavoriteHeader
) + sizeof(char) * 3, {});
593 // read POD data first
594 const PluginFavoriteHeader
* const data
= reinterpret_cast<const PluginFavoriteHeader
*>(qdata
.constData());
595 PluginFavorite fav
= { data
->type
, data
->uniqueId
, {}, {} };
597 // then all the strings, keeping the same order as in `asVariant`
598 const char* sdata
= reinterpret_cast<const char*>(data
+ 1);
600 fav
.filename
= QString::fromUtf8(sdata
);
601 sdata
+= fav
.filename
.size() + 1;
603 fav
.label
= QString::fromUtf8(sdata
);
604 sdata
+= fav
.label
.size() + 1;
609 static QList
<PluginFavorite
> asPluginFavoriteList(const QVariant
& var
)
611 QCarlaByteArray
qdata(var
.toByteArray());
613 QList
<PluginFavorite
> favlist
;
615 while (!qdata
.isEmpty())
617 const PluginFavorite fav
= asPluginFavorite(qdata
);
618 CARLA_SAFE_ASSERT_RETURN(fav
.type
!= PLUGIN_NONE
, {});
621 qdata
= qdata
.sliced(sizeof(PluginFavoriteHeader
) + fav
.filename
.size() + fav
.label
.size() + 2);
627 // create PluginFavorite from PluginInfo data
628 static PluginFavorite
asPluginFavorite(const PluginInfo
& info
)
630 return PluginFavorite(info
.type
, info
.uniqueId
, info
.filename
, info
.label
);
633 // --------------------------------------------------------------------------------------------------------------------
634 // discovery callbacks
636 static void discoveryCallback(void* const ptr
, const CarlaPluginDiscoveryInfo
* const info
, const char* const sha1sum
)
638 static_cast<PluginListDialog
*>(ptr
)->addPluginInfo(info
, sha1sum
);
641 static bool checkCacheCallback(void* const ptr
, const char* const filename
, const char* const sha1sum
)
643 if (sha1sum
== nullptr)
646 return static_cast<PluginListDialog
*>(ptr
)->checkPluginCache(filename
, sha1sum
);
649 // --------------------------------------------------------------------------------------------------------------------
651 struct PluginListDialog::PrivateData
{
652 int lastTableWidgetIndex
= 0;
654 PluginInfo retPlugin
;
656 // To be changed by parent
657 bool hasLoadedLv2Plugins
= false;
660 BinaryType btype
= BINARY_NATIVE
;
661 PluginType ptype
= PLUGIN_NONE
;
662 bool firstInit
= true;
663 bool ignoreCache
= false;
664 bool checkInvalid
= false;
665 bool usePluginBridges
= false;
666 bool useWineBridges
= false;
667 CarlaPluginDiscoveryHandle handle
= nullptr;
669 CarlaScopedPointer
<PluginRefreshDialog
> dialog
;
677 if (handle
!= nullptr)
678 carla_plugin_discovery_stop(handle
);
681 #ifndef CARLA_FRONTEND_ONLY_EMBEDDABLE_PLUGINS
684 if (handle
!= nullptr)
686 carla_plugin_discovery_stop(handle
);
690 if (!usePluginBridges
)
694 #ifdef CARLA_OS_WIN64
695 // look for win32 plugins on win64
696 if (btype
== BINARY_NATIVE
)
698 btype
= BINARY_WIN32
;
700 tool
= carla_get_library_folder();
701 tool
+= CARLA_OS_SEP_STR
"carla-discovery-win32.exe";
703 if (QFile(tool
).exists())
708 // no other types to try
710 #else // CARLA_OS_WIN
713 // try 32bit plugins on 64bit systems, skipping macOS where 32bit is no longer supported
714 if (btype
== BINARY_NATIVE
)
716 btype
= BINARY_POSIX32
;
718 tool
= carla_get_library_folder();
719 tool
+= CARLA_OS_SEP_STR
"carla-discovery-posix32";
721 if (QFile(tool
).exists())
730 #ifdef CARLA_OS_64BIT
731 if (btype
== BINARY_NATIVE
|| btype
== BINARY_POSIX32
)
733 btype
= BINARY_WIN64
;
735 tool
= carla_get_library_folder();
736 tool
+= CARLA_OS_SEP_STR
"carla-discovery-win64.exe";
738 if (QFile(tool
).exists())
743 if (btype
!= BINARY_WIN32
)
745 btype
= BINARY_WIN32
;
747 tool
= carla_get_library_folder();
748 tool
+= CARLA_OS_SEP_STR
"carla-discovery-win32.exe";
750 if (QFile(tool
).exists())
755 #endif // CARLA_OS_WIN
757 #endif // CARLA_FRONTEND_ONLY_EMBEDDABLE_PLUGINS
761 btype
= BINARY_NATIVE
;
763 tool
= carla_get_library_folder();
764 tool
+= CARLA_OS_SEP_STR
"carla-discovery-native";
774 #ifndef CARLA_FRONTEND_ONLY_EMBEDDABLE_PLUGINS
775 std::vector
<PluginInfo
> internal
;
776 std::vector
<PluginInfo
> ladspa
;
777 std::vector
<PluginInfo
> dssi
;
779 std::vector
<PluginInfo
> lv2
;
780 std::vector
<PluginInfo
> vst2
;
781 std::vector
<PluginInfo
> vst3
;
782 std::vector
<PluginInfo
> clap
;
783 #ifndef CARLA_FRONTEND_ONLY_EMBEDDABLE_PLUGINS
785 std::vector
<PluginInfo
> au
;
787 std::vector
<PluginInfo
> jsfx
;
788 std::vector
<PluginInfo
> kits
;
790 QMap
<QString
, QList
<PluginInfo
>> cache
;
791 QList
<PluginFavorite
> favorites
;
793 bool add(const PluginInfo
& pinfo
)
797 #ifndef CARLA_FRONTEND_ONLY_EMBEDDABLE_PLUGINS
798 case PLUGIN_INTERNAL
: internal
.push_back(pinfo
); return true;
799 case PLUGIN_LADSPA
: ladspa
.push_back(pinfo
); return true;
800 case PLUGIN_DSSI
: dssi
.push_back(pinfo
); return true;
802 case PLUGIN_LV2
: lv2
.push_back(pinfo
); return true;
803 case PLUGIN_VST2
: vst2
.push_back(pinfo
); return true;
804 case PLUGIN_VST3
: vst3
.push_back(pinfo
); return true;
805 case PLUGIN_CLAP
: clap
.push_back(pinfo
); return true;
806 #ifndef CARLA_FRONTEND_ONLY_EMBEDDABLE_PLUGINS
808 case PLUGIN_AU
: au
.push_back(pinfo
); return true;
810 case PLUGIN_JSFX
: jsfx
.push_back(pinfo
); return true;
812 case PLUGIN_SFZ
: kits
.push_back(pinfo
); return true;
814 default: return false;
820 // --------------------------------------------------------------------------------------------------------------------
821 // Plugin List Dialog
823 PluginListDialog::PluginListDialog(QWidget
* const parent
, const HostSettings
* const hostSettings
)
829 // ----------------------------------------------------------------------------------------------------------------
830 // Set-up global discovery options
832 p
->discovery
.usePluginBridges
= hostSettings
->showPluginBridges
;
833 p
->discovery
.useWineBridges
= hostSettings
->showWineBridges
;
836 carla_plugin_discovery_set_option(ENGINE_OPTION_WINE_AUTO_PREFIX
, hostSettings
->wineAutoPrefix
, nullptr);
837 carla_plugin_discovery_set_option(ENGINE_OPTION_WINE_EXECUTABLE
, 0, hostSettings
->wineExecutable
);
838 carla_plugin_discovery_set_option(ENGINE_OPTION_WINE_FALLBACK_PREFIX
, 0, hostSettings
->wineFallbackPrefix
);
841 // ----------------------------------------------------------------------------------------------------------------
844 ui
.b_add
->setEnabled(false);
846 ui
.tab_info
->tabBar()->hide();
847 ui
.tab_reqs
->tabBar()->hide();
849 #ifdef CARLA_FRONTEND_ONLY_EMBEDDABLE_PLUGINS
850 ui
.ch_internal
->hide();
851 ui
.ch_ladspa
->hide();
857 ui
.ch_inline_display
->hide();
858 ui
.toolBox
->setItemEnabled(3, false);
861 // do not resize info frame so much
862 const QLayout
*const infoLayout
= ui
.tw_info
->layout();
863 const QMargins infoMargins
= infoLayout
->contentsMargins();
864 ui
.tab_info
->setMinimumWidth(infoMargins
.left() + infoMargins
.right() + infoLayout
->spacing() * 3
865 + fontMetricsHorizontalAdvance(ui
.la_id
->fontMetrics(), "Has Custom GUI: 9999999999"));
867 // start with no plugin selected
870 // custom action that listens for Ctrl+F shortcut
871 addAction(ui
.act_focus_search
);
873 #ifdef CARLA_OS_64BIT
874 ui
.ch_bridged
->setText(tr("Bridged (32bit)"));
876 ui
.ch_bridged
->setChecked(false);
877 ui
.ch_bridged
->setEnabled(false);
880 #if !(defined(CARLA_OS_LINUX) || defined(CARLA_OS_MAC))
881 ui
.ch_bridged_wine
->setChecked(false);
882 ui
.ch_bridged_wine
->setEnabled(false);
886 setWindowModality(Qt::WindowModal
);
888 ui
.ch_au
->setChecked(false);
889 ui
.ch_au
->setEnabled(false);
890 ui
.ch_au
->setVisible(false);
893 setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint
);
895 // ----------------------------------------------------------------------------------------------------------------
900 // ----------------------------------------------------------------------------------------------------------------
901 // Disable bridges if not enabled in settings
904 // NOTE: We Assume win32 carla build will not run win64 plugins
905 if (WINDOWS
and not kIs64bit
) or not host
.showPluginBridges
:
906 ui
.ch_native
.setChecked(True
)
907 ui
.ch_native
.setEnabled(False
)
908 ui
.ch_native
.setVisible(True
)
909 ui
.ch_bridged
.setChecked(False
)
910 ui
.ch_bridged
.setEnabled(False
)
911 ui
.ch_bridged
.setVisible(False
)
912 ui
.ch_bridged_wine
.setChecked(False
)
913 ui
.ch_bridged_wine
.setEnabled(False
)
914 ui
.ch_bridged_wine
.setVisible(False
)
916 elif
not host
.showWineBridges
:
917 ui
.ch_bridged_wine
.setChecked(False
)
918 ui
.ch_bridged_wine
.setEnabled(False
)
919 ui
.ch_bridged_wine
.setVisible(False
)
922 // ----------------------------------------------------------------------------------------------------------------
925 if (hostSettings
->useSystemIcons
)
928 ui
.b_add
.setIcon(getIcon('list-add', 16, 'svgz'))
929 ui
.b_cancel
.setIcon(getIcon('dialog-cancel', 16, 'svgz'))
930 ui
.b_clear_filters
.setIcon(getIcon('edit-clear', 16, 'svgz'))
931 ui
.b_refresh
.setIcon(getIcon('view-refresh', 16, 'svgz'))
932 QTableWidgetItem
* const hhi
= ui
.tableWidget
->horizontalHeaderItem(TW_FAVORITE
);
933 hhi
.setIcon(getIcon('bookmarks', 16, 'svgz'))
937 // ----------------------------------------------------------------------------------------------------------------
938 // Set-up connections
940 QObject::connect(this, &QDialog::finished
, this, &PluginListDialog::saveSettings
);
941 QObject::connect(ui
.b_add
, &QPushButton::clicked
, this, &QDialog::accept
);
942 QObject::connect(ui
.b_cancel
, &QPushButton::clicked
, this, &QDialog::reject
);
944 QObject::connect(ui
.b_refresh
, &QPushButton::clicked
, this, &PluginListDialog::refreshPlugins
);
945 QObject::connect(ui
.b_clear_filters
, &QPushButton::clicked
, this, &PluginListDialog::clearFilters
);
946 QObject::connect(ui
.lineEdit
, &QLineEdit::textChanged
, this, &PluginListDialog::checkFilters
);
947 QObject::connect(ui
.tableWidget
, &QTableWidget::currentCellChanged
, this, &PluginListDialog::checkPlugin
);
948 QObject::connect(ui
.tableWidget
, &QTableWidget::cellClicked
, this, &PluginListDialog::cellClicked
);
949 QObject::connect(ui
.tableWidget
, &QTableWidget::cellDoubleClicked
, this, &PluginListDialog::cellDoubleClicked
);
951 QObject::connect(ui
.ch_internal
, &QCheckBox::clicked
, this, &PluginListDialog::checkFilters
);
952 QObject::connect(ui
.ch_ladspa
, &QCheckBox::clicked
, this, &PluginListDialog::checkFilters
);
953 QObject::connect(ui
.ch_dssi
, &QCheckBox::clicked
, this, &PluginListDialog::checkFilters
);
954 QObject::connect(ui
.ch_lv2
, &QCheckBox::clicked
, this, &PluginListDialog::checkFilters
);
955 QObject::connect(ui
.ch_vst
, &QCheckBox::clicked
, this, &PluginListDialog::checkFilters
);
956 QObject::connect(ui
.ch_vst3
, &QCheckBox::clicked
, this, &PluginListDialog::checkFilters
);
957 QObject::connect(ui
.ch_clap
, &QCheckBox::clicked
, this, &PluginListDialog::checkFilters
);
958 QObject::connect(ui
.ch_au
, &QCheckBox::clicked
, this, &PluginListDialog::checkFilters
);
959 QObject::connect(ui
.ch_jsfx
, &QCheckBox::clicked
, this, &PluginListDialog::checkFilters
);
960 QObject::connect(ui
.ch_kits
, &QCheckBox::clicked
, this, &PluginListDialog::checkFilters
);
961 QObject::connect(ui
.ch_effects
, &QCheckBox::clicked
, this, &PluginListDialog::checkFilters
);
962 QObject::connect(ui
.ch_instruments
, &QCheckBox::clicked
, this, &PluginListDialog::checkFilters
);
963 QObject::connect(ui
.ch_midi
, &QCheckBox::clicked
, this, &PluginListDialog::checkFilters
);
964 QObject::connect(ui
.ch_other
, &QCheckBox::clicked
, this, &PluginListDialog::checkFilters
);
965 QObject::connect(ui
.ch_native
, &QCheckBox::clicked
, this, &PluginListDialog::checkFilters
);
966 QObject::connect(ui
.ch_bridged
, &QCheckBox::clicked
, this, &PluginListDialog::checkFilters
);
967 QObject::connect(ui
.ch_bridged_wine
, &QCheckBox::clicked
, this, &PluginListDialog::checkFilters
);
968 QObject::connect(ui
.ch_favorites
, &QCheckBox::clicked
, this, &PluginListDialog::checkFilters
);
969 QObject::connect(ui
.ch_rtsafe
, &QCheckBox::clicked
, this, &PluginListDialog::checkFilters
);
970 QObject::connect(ui
.ch_cv
, &QCheckBox::clicked
, this, &PluginListDialog::checkFilters
);
971 QObject::connect(ui
.ch_gui
, &QCheckBox::clicked
, this, &PluginListDialog::checkFilters
);
972 QObject::connect(ui
.ch_inline_display
, &QCheckBox::clicked
, this, &PluginListDialog::checkFilters
);
973 QObject::connect(ui
.ch_stereo
, &QCheckBox::clicked
, this, &PluginListDialog::checkFilters
);
974 QObject::connect(ui
.ch_cat_all
, &QCheckBox::clicked
, this, &PluginListDialog::checkFiltersCategoryAll
);
975 QObject::connect(ui
.ch_cat_delay
, &QCheckBox::clicked
, this, &PluginListDialog::checkFiltersCategorySpecific
);
976 QObject::connect(ui
.ch_cat_distortion
, &QCheckBox::clicked
, this, &PluginListDialog::checkFiltersCategorySpecific
);
977 QObject::connect(ui
.ch_cat_dynamics
, &QCheckBox::clicked
, this, &PluginListDialog::checkFiltersCategorySpecific
);
978 QObject::connect(ui
.ch_cat_eq
, &QCheckBox::clicked
, this, &PluginListDialog::checkFiltersCategorySpecific
);
979 QObject::connect(ui
.ch_cat_filter
, &QCheckBox::clicked
, this, &PluginListDialog::checkFiltersCategorySpecific
);
980 QObject::connect(ui
.ch_cat_modulator
, &QCheckBox::clicked
, this, &PluginListDialog::checkFiltersCategorySpecific
);
981 QObject::connect(ui
.ch_cat_synth
, &QCheckBox::clicked
, this, &PluginListDialog::checkFiltersCategorySpecific
);
982 QObject::connect(ui
.ch_cat_utility
, &QCheckBox::clicked
, this, &PluginListDialog::checkFiltersCategorySpecific
);
983 QObject::connect(ui
.ch_cat_other
, &QCheckBox::clicked
, this, &PluginListDialog::checkFiltersCategorySpecific
);
985 QObject::connect(ui
.act_focus_search
, &QAction::triggered
, this, &PluginListDialog::focusSearchFieldAndSelectAll
);
988 PluginListDialog::~PluginListDialog()
991 killTimer(p
->timerId
);
996 // --------------------------------------------------------------------------------------------------------------------
999 const PluginInfo
& PluginListDialog::getSelectedPluginInfo() const
1001 return p
->retPlugin
;
1004 void PluginListDialog::addPluginInfo(const CarlaPluginDiscoveryInfo
* const info
, const char* const sha1sum
)
1006 if (info
== nullptr)
1008 if (sha1sum
!= nullptr)
1010 QSafeSettings
settings("falkTX", "CarlaDatabase3");
1011 settings
.setValue(QString("PluginCache/%1").arg(sha1sum
), QByteArray());
1013 const QString
qsha1sum(sha1sum
);
1014 p
->plugins
.cache
[qsha1sum
] = {};
1019 PluginInfo pinfo
= {};
1020 pinfo
.build
= static_cast<uint16_t>(info
->btype
);
1021 pinfo
.type
= static_cast<uint16_t>(info
->ptype
);
1022 pinfo
.hints
= info
->metadata
.hints
;
1023 pinfo
.uniqueId
= info
->uniqueId
;
1024 pinfo
.audioIns
= static_cast<uint16_t>(info
->io
.audioIns
);
1025 pinfo
.audioOuts
= static_cast<uint16_t>(info
->io
.audioOuts
);
1026 pinfo
.cvIns
= static_cast<uint16_t>(info
->io
.cvIns
);
1027 pinfo
.cvOuts
= static_cast<uint16_t>(info
->io
.cvOuts
);
1028 pinfo
.midiIns
= static_cast<uint16_t>(info
->io
.midiIns
);
1029 pinfo
.midiOuts
= static_cast<uint16_t>(info
->io
.midiOuts
);
1030 pinfo
.parameterIns
= static_cast<uint16_t>(info
->io
.parameterIns
);
1031 pinfo
.parameterOuts
= static_cast<uint16_t>(info
->io
.parameterOuts
);
1032 pinfo
.category
= getPluginCategoryAsString(info
->metadata
.category
);
1033 pinfo
.filename
= QString::fromUtf8(info
->filename
);
1034 pinfo
.name
= QString::fromUtf8(info
->metadata
.name
);
1035 pinfo
.label
= QString::fromUtf8(info
->label
);
1036 pinfo
.maker
= QString::fromUtf8(info
->metadata
.maker
);
1038 if (sha1sum
!= nullptr)
1040 QSafeSettings
settings("falkTX", "CarlaDatabase3");
1041 const QString
qsha1sum(sha1sum
);
1042 const QString key
= QString("PluginCache/%1").arg(sha1sum
);
1044 // single sha1sum can contain >1 plugin
1046 if (p
->plugins
.cache
.contains(qsha1sum
))
1047 qdata
= settings
.valueByteArray(key
);
1048 qdata
+= asVariant(pinfo
).toByteArray();
1050 settings
.setValue(key
, qdata
);
1052 p
->plugins
.cache
[qsha1sum
].append(pinfo
);
1055 #ifdef CARLA_FRONTEND_ONLY_EMBEDDABLE_PLUGINS
1056 if ((pinfo
.hints
& PLUGIN_HAS_CUSTOM_EMBED_UI
) == 0x0)
1060 p
->plugins
.add(pinfo
);
1063 bool PluginListDialog::checkPluginCache(const char* const filename
, const char* const sha1sum
)
1065 // sha1sum is always valid for this call
1066 const QString
qsha1sum(sha1sum
);
1068 if (filename
!= nullptr)
1069 p
->discovery
.dialog
->progressBar
->setFormat(filename
);
1071 if (!p
->plugins
.cache
.contains(qsha1sum
))
1074 const QList
<PluginInfo
>& plist(p
->plugins
.cache
[qsha1sum
]);
1076 if (plist
.isEmpty())
1077 return p
->discovery
.ignoreCache
|| !p
->discovery
.checkInvalid
;
1079 // if filename does not match, abort (hash collision?)
1080 if (filename
== nullptr || plist
.first().filename
!= filename
)
1082 p
->plugins
.cache
.remove(qsha1sum
);
1086 for (const PluginInfo
& info
: plist
)
1088 #ifdef CARLA_FRONTEND_ONLY_EMBEDDABLE_PLUGINS
1089 if ((info
.hints
& PLUGIN_HAS_CUSTOM_EMBED_UI
) == 0x0)
1092 p
->plugins
.add(info
);
1098 void PluginListDialog::setPluginPath(const PluginType ptype
, const char* const path
)
1103 p
->paths
.lv2
= path
;
1106 p
->paths
.vst2
= path
;
1109 p
->paths
.vst3
= path
;
1112 p
->paths
.clap
= path
;
1114 #ifndef CARLA_FRONTEND_ONLY_EMBEDDABLE_PLUGINS
1116 p
->paths
.ladspa
= path
;
1119 p
->paths
.dssi
= path
;
1122 p
->paths
.sf2
= path
;
1125 p
->paths
.sfz
= path
;
1128 p
->paths
.jsfx
= path
;
1136 // --------------------------------------------------------------------------------------------------------------------
1137 // protected methods
1139 void PluginListDialog::done(const int r
)
1141 if (r
== QDialog::Accepted
&& ui
.tableWidget
->currentRow() >= 0)
1143 QTableWidgetItem
* const widget
= ui
.tableWidget
->item(ui
.tableWidget
->currentRow(), TW_NAME
);
1144 p
->retPlugin
= asPluginInfo(widget
->data(Qt::UserRole
+ UR_PLUGIN_INFO
));
1154 void PluginListDialog::showEvent(QShowEvent
* const event
)
1156 focusSearchFieldAndSelectAll();
1157 QDialog::showEvent(event
);
1159 // Set up initial discovery
1160 if (p
->discovery
.firstInit
)
1162 p
->discovery
.firstInit
= false;
1164 p
->discovery
.dialog
= new PluginRefreshDialog(this);
1165 p
->discovery
.dialog
->b_start
->setEnabled(false);
1166 p
->discovery
.dialog
->b_skip
->setEnabled(true);
1167 p
->discovery
.dialog
->ch_updated
->setChecked(true);
1168 p
->discovery
.dialog
->ch_invalid
->setChecked(false);
1169 p
->discovery
.dialog
->group
->setEnabled(false);
1170 p
->discovery
.dialog
->progressBar
->setFormat("Starting initial discovery...");
1172 QObject::connect(p
->discovery
.dialog
->b_skip
, &QPushButton::clicked
,
1173 this, &PluginListDialog::refreshPluginsSkip
);
1174 QObject::connect(p
->discovery
.dialog
, &QDialog::finished
,
1175 this, &PluginListDialog::refreshPluginsStop
);
1177 p
->timerId
= startTimer(0);
1179 QTimer::singleShot(0, p
->discovery
.dialog
, &QDialog::exec
);
1183 void PluginListDialog::timerEvent(QTimerEvent
* const event
)
1185 if (event
->timerId() == p
->timerId
)
1188 // discovery in progress, keep it going
1189 if (p
->discovery
.handle
!= nullptr)
1191 if (!carla_plugin_discovery_idle(p
->discovery
.handle
))
1193 carla_plugin_discovery_stop(p
->discovery
.handle
);
1194 p
->discovery
.handle
= nullptr;
1199 // start next discovery
1201 switch (p
->discovery
.ptype
)
1204 #ifndef CARLA_FRONTEND_ONLY_EMBEDDABLE_PLUGINS
1205 if (p
->discovery
.btype
== BINARY_NATIVE
)
1207 ui
.label
->setText(tr("Discovering internal plugins..."));
1208 p
->discovery
.ptype
= PLUGIN_INTERNAL
;
1212 case PLUGIN_INTERNAL
:
1213 ui
.label
->setText(tr("Discovering LADSPA plugins..."));
1214 path
= p
->paths
.ladspa
;
1215 p
->discovery
.ptype
= PLUGIN_LADSPA
;
1218 ui
.label
->setText(tr("Discovering DSSI plugins..."));
1219 path
= p
->paths
.dssi
;
1220 p
->discovery
.ptype
= PLUGIN_DSSI
;
1224 if (p
->discovery
.btype
== BINARY_NATIVE
&& p
->paths
.lv2
.isNotEmpty())
1226 ui
.label
->setText(tr("Discovering LV2 plugins..."));
1227 path
= p
->paths
.lv2
;
1228 p
->discovery
.ptype
= PLUGIN_LV2
;
1233 ui
.label
->setText(tr("Discovering VST2 plugins..."));
1234 path
= p
->paths
.vst2
;
1235 p
->discovery
.ptype
= PLUGIN_VST2
;
1238 ui
.label
->setText(tr("Discovering VST3 plugins..."));
1239 path
= p
->paths
.vst3
;
1240 p
->discovery
.ptype
= PLUGIN_VST3
;
1243 ui
.label
->setText(tr("Discovering CLAP plugins..."));
1244 path
= p
->paths
.clap
;
1245 p
->discovery
.ptype
= PLUGIN_CLAP
;
1248 #ifndef CARLA_FRONTEND_ONLY_EMBEDDABLE_PLUGINS
1250 if (p
->discovery
.btype
== BINARY_POSIX32
|| p
->discovery
.btype
== BINARY_POSIX64
)
1252 ui
.label
->setText(tr("Discovering AU plugins..."));
1253 p
->discovery
.ptype
= PLUGIN_AU
;
1259 if (p
->discovery
.btype
== BINARY_NATIVE
&& p
->paths
.jsfx
.isNotEmpty())
1261 ui
.label
->setText(tr("Discovering JSFX plugins..."));
1262 path
= p
->paths
.jsfx
;
1263 p
->discovery
.ptype
= PLUGIN_JSFX
;
1268 if (p
->discovery
.btype
== BINARY_NATIVE
&& p
->paths
.sf2
.isNotEmpty())
1270 ui
.label
->setText(tr("Discovering SF2 kits..."));
1271 path
= p
->paths
.sf2
;
1272 p
->discovery
.ptype
= PLUGIN_SF2
;
1277 if (p
->discovery
.btype
== BINARY_NATIVE
&& p
->paths
.sfz
.isNotEmpty())
1279 ui
.label
->setText(tr("Discovering SFZ kits..."));
1280 path
= p
->paths
.sfz
;
1281 p
->discovery
.ptype
= PLUGIN_SFZ
;
1288 // discovery complete?
1291 #ifndef CARLA_FRONTEND_ONLY_EMBEDDABLE_PLUGINS
1292 if (p
->discovery
.nextTool())
1294 // tool has nothing to search, go to next one
1295 if (p
->discovery
.ptype
== PLUGIN_NONE
)
1298 // there is still to do, break out of loop
1303 refreshPluginsStop();
1308 if (p
->timerId
== 0)
1311 if (p
->discovery
.dialog
)
1312 p
->discovery
.dialog
->progressBar
->setFormat(ui
.label
->text());
1314 p
->discovery
.handle
= carla_plugin_discovery_start(p
->discovery
.tool
.toUtf8().constData(),
1317 path
.toUtf8().constData(),
1318 discoveryCallback
, checkCacheCallback
, this);
1322 QDialog::timerEvent(event
);
1325 // --------------------------------------------------------------------------------------------------------------------
1328 void PluginListDialog::addPluginsToTable()
1330 // ----------------------------------------------------------------------------------------------------------------
1331 // sum plugins first, creating all needed rows in advance
1333 ui
.tableWidget
->setSortingEnabled(false);
1334 ui
.tableWidget
->clearContents();
1336 #ifdef CARLA_FRONTEND_ONLY_EMBEDDABLE_PLUGINS
1337 ui
.tableWidget
->setRowCount(
1338 int(p
->plugins
.lv2
.size() + p
->plugins
.vst2
.size() + p
->plugins
.vst3
.size() + p
->plugins
.clap
.size()));
1340 constexpr const char* const txt
= "Have %1 LV2, %2 VST2, %3 VST3 and %4 CLAP plugins";
1342 ui
.label
->setText(tr(txt
)
1343 .arg(QString::number(p
->plugins
.lv2
.size()))
1344 .arg(QString::number(p
->plugins
.vst2
.size()))
1345 .arg(QString::number(p
->plugins
.vst3
.size()))
1346 .arg(QString::number(p
->plugins
.clap
.size())));
1348 ui
.tableWidget
->setRowCount(
1349 int(p
->plugins
.internal
.size() + p
->plugins
.ladspa
.size() + p
->plugins
.dssi
.size() +
1350 p
->plugins
.lv2
.size() + p
->plugins
.vst2
.size() + p
->plugins
.vst3
.size() + p
->plugins
.clap
.size() +
1352 p
->plugins
.au
.size() +
1354 p
->plugins
.jsfx
.size() + p
->plugins
.kits
.size()));
1356 constexpr const char* const txt
= "Have %1 Internal, %2 LADSPA, %3 DSSI, %4 LV2, %5 VST2, %6 VST3, %7 CLAP"
1358 ", %8 AudioUnit and %9 JSFX plugins, plus %10 Sound Kits"
1360 " and %8 JSFX plugins, plus %9 Sound Kits";
1362 ui
.label
->setText(tr(txt
)
1363 .arg(QString::number(p
->plugins
.internal
.size()))
1364 .arg(QString::number(p
->plugins
.ladspa
.size()))
1365 .arg(QString::number(p
->plugins
.dssi
.size()))
1366 .arg(QString::number(p
->plugins
.lv2
.size()))
1367 .arg(QString::number(p
->plugins
.vst2
.size()))
1368 .arg(QString::number(p
->plugins
.vst3
.size()))
1369 .arg(QString::number(p
->plugins
.clap
.size()))
1371 .arg(QString::number(p
->plugins
.au
.size()))
1373 .arg(QString::number(p
->plugins
.jsfx
.size()))
1374 .arg(QString::number(p
->plugins
.kits
.size())));
1377 // ----------------------------------------------------------------------------------------------------------------
1378 // now add all plugins to the table
1380 auto addPluginToTable
= [=](const PluginInfo
& info
) {
1381 const int index
= p
->lastTableWidgetIndex
++;
1382 const bool isFav
= p
->plugins
.favorites
.contains(asPluginFavorite(info
));
1384 QTableWidgetItem
* const itemFav
= new QTableWidgetItem
;
1385 itemFav
->setCheckState(isFav
? Qt::Checked
: Qt::Unchecked
);
1386 itemFav
->setText(isFav
? " " : " ");
1388 const QString pluginText
= (info
.name
+ info
.label
+ info
.maker
+ info
.filename
).toLower();
1389 ui
.tableWidget
->setItem(index
, TW_FAVORITE
, itemFav
);
1390 ui
.tableWidget
->setItem(index
, TW_NAME
, new QTableWidgetItem(info
.name
));
1391 ui
.tableWidget
->setItem(index
, TW_LABEL
, new QTableWidgetItem(info
.label
));
1392 ui
.tableWidget
->setItem(index
, TW_MAKER
, new QTableWidgetItem(info
.maker
));
1393 ui
.tableWidget
->setItem(index
, TW_BINARY
, new QTableWidgetItem(QFileInfo(info
.filename
).fileName()));
1395 QTableWidgetItem
*const itemName
= ui
.tableWidget
->item(index
, TW_NAME
);
1396 itemName
->setData(Qt::UserRole
+ UR_PLUGIN_INFO
, asVariant(info
));
1397 itemName
->setData(Qt::UserRole
+ UR_SEARCH_TEXT
, pluginText
);
1400 p
->lastTableWidgetIndex
= 0;
1402 #ifndef CARLA_FRONTEND_ONLY_EMBEDDABLE_PLUGINS
1403 for (const PluginInfo
&plugin
: p
->plugins
.internal
)
1404 addPluginToTable(plugin
);
1406 for (const PluginInfo
&plugin
: p
->plugins
.ladspa
)
1407 addPluginToTable(plugin
);
1409 for (const PluginInfo
&plugin
: p
->plugins
.dssi
)
1410 addPluginToTable(plugin
);
1413 for (const PluginInfo
&plugin
: p
->plugins
.lv2
)
1414 addPluginToTable(plugin
);
1416 for (const PluginInfo
&plugin
: p
->plugins
.vst2
)
1417 addPluginToTable(plugin
);
1419 for (const PluginInfo
&plugin
: p
->plugins
.vst3
)
1420 addPluginToTable(plugin
);
1422 for (const PluginInfo
& plugin
: p
->plugins
.clap
)
1423 addPluginToTable(plugin
);
1425 #ifndef CARLA_FRONTEND_ONLY_EMBEDDABLE_PLUGINS
1427 for (const PluginInfo
& plugin
: p
->plugins
.au
)
1428 addPluginToTable(plugin
);
1431 for (const PluginInfo
& plugin
: p
->plugins
.jsfx
)
1432 addPluginToTable(plugin
);
1434 for (const PluginInfo
& plugin
: p
->plugins
.kits
)
1435 addPluginToTable(plugin
);
1438 CARLA_SAFE_ASSERT_INT2(p
->lastTableWidgetIndex
== ui
.tableWidget
->rowCount(),
1439 p
->lastTableWidgetIndex
, ui
.tableWidget
->rowCount());
1441 // ----------------------------------------------------------------------------------------------------------------
1442 // and reenable sorting + filtering
1444 ui
.tableWidget
->setSortingEnabled(true);
1447 checkPlugin(ui
.tableWidget
->currentRow());
1450 void PluginListDialog::loadSettings()
1452 const QSafeSettings
settings("falkTX", "CarlaDatabase3");
1454 restoreGeometry(settings
.valueByteArray("PluginDatabase/Geometry"));
1455 ui
.ch_effects
->setChecked(settings
.valueBool("PluginDatabase/ShowEffects", true));
1456 ui
.ch_instruments
->setChecked(settings
.valueBool("PluginDatabase/ShowInstruments", true));
1457 ui
.ch_midi
->setChecked(settings
.valueBool("PluginDatabase/ShowMIDI", true));
1458 ui
.ch_other
->setChecked(settings
.valueBool("PluginDatabase/ShowOther", true));
1459 ui
.ch_internal
->setChecked(settings
.valueBool("PluginDatabase/ShowInternal", true));
1460 ui
.ch_ladspa
->setChecked(settings
.valueBool("PluginDatabase/ShowLADSPA", true));
1461 ui
.ch_dssi
->setChecked(settings
.valueBool("PluginDatabase/ShowDSSI", true));
1462 ui
.ch_lv2
->setChecked(settings
.valueBool("PluginDatabase/ShowLV2", true));
1463 ui
.ch_vst
->setChecked(settings
.valueBool("PluginDatabase/ShowVST2", true));
1464 ui
.ch_vst3
->setChecked(settings
.valueBool("PluginDatabase/ShowVST3", true));
1465 ui
.ch_clap
->setChecked(settings
.valueBool("PluginDatabase/ShowCLAP", true));
1467 ui
.ch_au
->setChecked(settings
.valueBool("PluginDatabase/ShowAU", true));
1469 ui
.ch_jsfx
->setChecked(settings
.valueBool("PluginDatabase/ShowJSFX", true));
1470 ui
.ch_kits
->setChecked(settings
.valueBool("PluginDatabase/ShowKits", true));
1471 ui
.ch_native
->setChecked(settings
.valueBool("PluginDatabase/ShowNative", true));
1472 ui
.ch_bridged
->setChecked(settings
.valueBool("PluginDatabase/ShowBridged", true));
1473 ui
.ch_bridged_wine
->setChecked(settings
.valueBool("PluginDatabase/ShowBridgedWine", true));
1474 ui
.ch_favorites
->setChecked(settings
.valueBool("PluginDatabase/ShowFavorites", false));
1475 ui
.ch_rtsafe
->setChecked(settings
.valueBool("PluginDatabase/ShowRtSafe", false));
1476 ui
.ch_cv
->setChecked(settings
.valueBool("PluginDatabase/ShowHasCV", false));
1477 ui
.ch_gui
->setChecked(settings
.valueBool("PluginDatabase/ShowHasGUI", false));
1478 ui
.ch_inline_display
->setChecked(settings
.valueBool("PluginDatabase/ShowHasInlineDisplay", false));
1479 ui
.ch_stereo
->setChecked(settings
.valueBool("PluginDatabase/ShowStereoOnly", false));
1480 ui
.lineEdit
->setText(settings
.valueString("PluginDatabase/SearchText", ""));
1482 const QString categories
= settings
.valueString("PluginDatabase/ShowCategory", "all");
1483 if (categories
== "all" or categories
.length() < 2)
1485 ui
.ch_cat_all
->setChecked(true);
1486 ui
.ch_cat_delay
->setChecked(false);
1487 ui
.ch_cat_distortion
->setChecked(false);
1488 ui
.ch_cat_dynamics
->setChecked(false);
1489 ui
.ch_cat_eq
->setChecked(false);
1490 ui
.ch_cat_filter
->setChecked(false);
1491 ui
.ch_cat_modulator
->setChecked(false);
1492 ui
.ch_cat_synth
->setChecked(false);
1493 ui
.ch_cat_utility
->setChecked(false);
1494 ui
.ch_cat_other
->setChecked(false);
1498 ui
.ch_cat_all
->setChecked(false);
1499 ui
.ch_cat_delay
->setChecked(categories
.contains(":delay:"));
1500 ui
.ch_cat_distortion
->setChecked(categories
.contains(":distortion:"));
1501 ui
.ch_cat_dynamics
->setChecked(categories
.contains(":dynamics:"));
1502 ui
.ch_cat_eq
->setChecked(categories
.contains(":eq:"));
1503 ui
.ch_cat_filter
->setChecked(categories
.contains(":filter:"));
1504 ui
.ch_cat_modulator
->setChecked(categories
.contains(":modulator:"));
1505 ui
.ch_cat_synth
->setChecked(categories
.contains(":synth:"));
1506 ui
.ch_cat_utility
->setChecked(categories
.contains(":utility:"));
1507 ui
.ch_cat_other
->setChecked(categories
.contains(":other:"));
1510 const QByteArray tableGeometry
= settings
.valueByteArray("PluginDatabase/TableGeometry");
1511 QHeaderView
* const horizontalHeader
= ui
.tableWidget
->horizontalHeader();
1512 if (! tableGeometry
.isNull())
1514 horizontalHeader
->restoreState(tableGeometry
);
1518 ui
.tableWidget
->setColumnWidth(TW_NAME
, 250);
1519 ui
.tableWidget
->setColumnWidth(TW_LABEL
, 200);
1520 ui
.tableWidget
->setColumnWidth(TW_MAKER
, 150);
1521 ui
.tableWidget
->sortByColumn(TW_NAME
, Qt::AscendingOrder
);
1524 horizontalHeader
->setSectionResizeMode(TW_FAVORITE
, QHeaderView::Fixed
);
1525 ui
.tableWidget
->setColumnWidth(TW_FAVORITE
, 24);
1526 ui
.tableWidget
->setSortingEnabled(true);
1528 p
->plugins
.favorites
= asPluginFavoriteList(settings
.valueByteArray("PluginListDialog/Favorites"));
1530 // load entire plugin cache
1531 const QStringList keys
= settings
.allKeys();
1532 for (const QCarlaString key
: keys
)
1534 if (!key
.startsWith("PluginCache/"))
1537 const QByteArray
data(settings
.valueByteArray(key
));
1540 p
->plugins
.cache
.insert(key
.sliced(12), {});
1542 p
->plugins
.cache
.insert(key
.sliced(12), asPluginInfoList(data
));
1545 #ifdef CARLA_FRONTEND_ONLY_EMBEDDABLE_PLUGINS
1546 // these are not visible, force their value
1547 ui
.ch_native
->setChecked(true);
1548 ui
.ch_bridged
->setChecked(false);
1549 ui
.ch_bridged_wine
->setChecked(false);
1550 ui
.ch_inline_display
->setChecked(false);
1554 // --------------------------------------------------------------------------------------------------------------------
1557 void PluginListDialog::cellClicked(const int row
, const int column
)
1559 if (column
!= TW_FAVORITE
)
1562 const PluginInfo info
= asPluginInfo(ui
.tableWidget
->item(row
, TW_NAME
)->data(Qt::UserRole
+ UR_PLUGIN_INFO
));
1563 const PluginFavorite fav
= asPluginFavorite(info
);
1564 const bool isFavorite
= p
->plugins
.favorites
.contains(fav
);
1566 if (ui
.tableWidget
->item(row
, TW_FAVORITE
)->checkState() == Qt::Checked
)
1569 p
->plugins
.favorites
.append(fav
);
1571 else if (isFavorite
)
1573 p
->plugins
.favorites
.removeAll(fav
);
1576 QSafeSettings
settings("falkTX", "CarlaDatabase3");
1577 settings
.setValue("PluginListDialog/Favorites", asVariant(p
->plugins
.favorites
));
1580 void PluginListDialog::cellDoubleClicked(int, const int column
)
1582 if (column
!= TW_FAVORITE
)
1583 done(QDialog::Accepted
);
1586 void PluginListDialog::focusSearchFieldAndSelectAll()
1588 ui
.lineEdit
->setFocus();
1589 ui
.lineEdit
->selectAll();
1592 void PluginListDialog::checkFilters()
1594 const QCarlaString text
= ui
.lineEdit
->text().toLower();
1596 const bool hideEffects
= !ui
.ch_effects
->isChecked();
1597 const bool hideInstruments
= !ui
.ch_instruments
->isChecked();
1598 const bool hideMidi
= !ui
.ch_midi
->isChecked();
1599 const bool hideOther
= !ui
.ch_other
->isChecked();
1601 const bool hideInternal
= !ui
.ch_internal
->isChecked();
1602 const bool hideLadspa
= !ui
.ch_ladspa
->isChecked();
1603 const bool hideDSSI
= !ui
.ch_dssi
->isChecked();
1604 const bool hideLV2
= !ui
.ch_lv2
->isChecked();
1605 const bool hideVST2
= !ui
.ch_vst
->isChecked();
1606 const bool hideVST3
= !ui
.ch_vst3
->isChecked();
1607 const bool hideCLAP
= !ui
.ch_clap
->isChecked();
1608 const bool hideAU
= !ui
.ch_au
->isChecked();
1609 const bool hideJSFX
= !ui
.ch_jsfx
->isChecked();
1610 const bool hideKits
= !ui
.ch_kits
->isChecked();
1612 const bool hideNative
= !ui
.ch_native
->isChecked();
1613 const bool hideBridged
= !ui
.ch_bridged
->isChecked();
1614 const bool hideBridgedWine
= !ui
.ch_bridged_wine
->isChecked();
1616 const bool hideNonFavs
= ui
.ch_favorites
->isChecked();
1617 const bool hideNonRtSafe
= ui
.ch_rtsafe
->isChecked();
1618 const bool hideNonCV
= ui
.ch_cv
->isChecked();
1619 const bool hideNonGui
= ui
.ch_gui
->isChecked();
1620 const bool hideNonIDisp
= ui
.ch_inline_display
->isChecked();
1621 const bool hideNonStereo
= ui
.ch_stereo
->isChecked();
1623 #if defined(CARLA_OS_WIN64)
1624 static constexpr const BinaryType nativeBins
[2] = { BINARY_WIN32
, BINARY_WIN64
};
1625 static constexpr const BinaryType wineBins
[2] = { BINARY_NONE
, BINARY_NONE
};
1626 #elif defined(CARLA_OS_WIN32)
1627 static constexpr const BinaryType nativeBins
[2] = { BINARY_WIN32
, BINARY_NONE
};
1628 static constexpr const BinaryType wineBins
[2] = { BINARY_NONE
, BINARY_NONE
};
1629 #elif defined(CARLA_OS_MAC)
1630 static constexpr const BinaryType nativeBins
[2] = { BINARY_POSIX64
, BINARY_NONE
};
1631 static constexpr const BinaryType wineBins
[2] = { BINARY_WIN32
, BINARY_WIN64
};
1633 static constexpr const BinaryType nativeBins
[2] = { BINARY_POSIX32
, BINARY_POSIX64
};
1634 static constexpr const BinaryType wineBins
[2] = { BINARY_WIN32
, BINARY_WIN64
};
1637 for (int i
=0, c
=ui
.tableWidget
->rowCount(); i
<c
; ++i
)
1639 const PluginInfo info
= asPluginInfo(ui
.tableWidget
->item(i
, TW_NAME
)->data(Qt::UserRole
+ UR_PLUGIN_INFO
));
1640 const QString ptext
= ui
.tableWidget
->item(i
, TW_NAME
)->data(Qt::UserRole
+ UR_SEARCH_TEXT
).toString();
1642 const uint16_t aIns
= info
.audioIns
;
1643 const uint16_t aOuts
= info
.audioOuts
;
1644 const uint16_t cvIns
= info
.cvIns
;
1645 const uint16_t cvOuts
= info
.cvOuts
;
1646 const uint16_t mIns
= info
.midiIns
;
1647 const uint16_t mOuts
= info
.midiOuts
;
1648 const uint32_t phints
= info
.hints
;
1649 const uint16_t ptype
= info
.type
;
1650 const QString categ
= info
.category
;
1651 const bool isSynth
= phints
& PLUGIN_IS_SYNTH
;
1652 const bool isEffect
= aIns
> 0 && aOuts
> 0 && !isSynth
;
1653 const bool isMidi
= aIns
== 0 && aOuts
== 0 && mIns
> 0 && mOuts
> 0;
1654 const bool isKit
= ptype
== PLUGIN_SF2
|| ptype
== PLUGIN_SFZ
;
1655 const bool isOther
= !(isEffect
|| isSynth
|| isMidi
|| isKit
);
1656 const bool isNative
= info
.build
== BINARY_NATIVE
;
1657 const bool isRtSafe
= phints
& PLUGIN_IS_RTSAFE
;
1658 const bool isStereo
= (aIns
== 2 && aOuts
== 2) || (isSynth
&& aOuts
== 2);
1659 const bool hasCV
= cvIns
+ cvOuts
> 0;
1660 const bool hasGui
= phints
& PLUGIN_HAS_CUSTOM_UI
;
1661 const bool hasIDisp
= phints
& PLUGIN_HAS_INLINE_DISPLAY
;
1662 const bool isBridged
= !isNative
&& (nativeBins
[0] == info
.build
|| nativeBins
[1] == info
.build
);
1663 const bool isBridgedWine
= !isNative
&& (wineBins
[0] == info
.build
|| wineBins
[1] == info
.build
);
1665 const auto hasText
= [text
, ptext
]() {
1666 const QStringList textSplit
= text
.strip().split(' ');
1667 for (const QString
& t
: textSplit
)
1668 if (ptext
.contains(t
))
1673 /**/ if (hideEffects
&& isEffect
)
1674 ui
.tableWidget
->hideRow(i
);
1675 else if (hideInstruments
&& isSynth
)
1676 ui
.tableWidget
->hideRow(i
);
1677 else if (hideMidi
&& isMidi
)
1678 ui
.tableWidget
->hideRow(i
);
1679 else if (hideOther
&& isOther
)
1680 ui
.tableWidget
->hideRow(i
);
1681 else if (hideKits
&& isKit
)
1682 ui
.tableWidget
->hideRow(i
);
1683 else if (hideInternal
&& ptype
== PLUGIN_INTERNAL
)
1684 ui
.tableWidget
->hideRow(i
);
1685 else if (hideLadspa
&& ptype
== PLUGIN_LADSPA
)
1686 ui
.tableWidget
->hideRow(i
);
1687 else if (hideDSSI
&& ptype
== PLUGIN_DSSI
)
1688 ui
.tableWidget
->hideRow(i
);
1689 else if (hideLV2
&& ptype
== PLUGIN_LV2
)
1690 ui
.tableWidget
->hideRow(i
);
1691 else if (hideVST2
&& ptype
== PLUGIN_VST2
)
1692 ui
.tableWidget
->hideRow(i
);
1693 else if (hideVST3
&& ptype
== PLUGIN_VST3
)
1694 ui
.tableWidget
->hideRow(i
);
1695 else if (hideCLAP
&& ptype
== PLUGIN_CLAP
)
1696 ui
.tableWidget
->hideRow(i
);
1697 else if (hideAU
&& ptype
== PLUGIN_AU
)
1698 ui
.tableWidget
->hideRow(i
);
1699 else if (hideJSFX
&& ptype
== PLUGIN_JSFX
)
1700 ui
.tableWidget
->hideRow(i
);
1701 else if (hideNative
&& isNative
)
1702 ui
.tableWidget
->hideRow(i
);
1703 else if (hideBridged
&& isBridged
)
1704 ui
.tableWidget
->hideRow(i
);
1705 else if (hideBridgedWine
&& isBridgedWine
)
1706 ui
.tableWidget
->hideRow(i
);
1707 else if (hideNonRtSafe
&& not isRtSafe
)
1708 ui
.tableWidget
->hideRow(i
);
1709 else if (hideNonCV
&& not hasCV
)
1710 ui
.tableWidget
->hideRow(i
);
1711 else if (hideNonGui
&& not hasGui
)
1712 ui
.tableWidget
->hideRow(i
);
1713 else if (hideNonIDisp
&& not hasIDisp
)
1714 ui
.tableWidget
->hideRow(i
);
1715 else if (hideNonStereo
&& not isStereo
)
1716 ui
.tableWidget
->hideRow(i
);
1717 else if (text
.isNotEmpty() && ! hasText())
1718 ui
.tableWidget
->hideRow(i
);
1719 else if (hideNonFavs
&& !p
->plugins
.favorites
.contains(asPluginFavorite(info
)))
1720 ui
.tableWidget
->hideRow(i
);
1721 else if (ui
.ch_cat_all
->isChecked() or
1722 (ui
.ch_cat_delay
->isChecked() && categ
== "delay") or
1723 (ui
.ch_cat_distortion
->isChecked() && categ
== "distortion") or
1724 (ui
.ch_cat_dynamics
->isChecked() && categ
== "dynamics") or
1725 (ui
.ch_cat_eq
->isChecked() && categ
== "eq") or
1726 (ui
.ch_cat_filter
->isChecked() && categ
== "filter") or
1727 (ui
.ch_cat_modulator
->isChecked() && categ
== "modulator") or
1728 (ui
.ch_cat_synth
->isChecked() && categ
== "synth") or
1729 (ui
.ch_cat_utility
->isChecked() && categ
== "utility") or
1730 (ui
.ch_cat_other
->isChecked() && categ
== "other"))
1731 ui
.tableWidget
->showRow(i
);
1733 ui
.tableWidget
->hideRow(i
);
1737 void PluginListDialog::checkFiltersCategoryAll(const bool clicked
)
1739 const bool notClicked
= !clicked
;
1740 ui
.ch_cat_delay
->setChecked(notClicked
);
1741 ui
.ch_cat_distortion
->setChecked(notClicked
);
1742 ui
.ch_cat_dynamics
->setChecked(notClicked
);
1743 ui
.ch_cat_eq
->setChecked(notClicked
);
1744 ui
.ch_cat_filter
->setChecked(notClicked
);
1745 ui
.ch_cat_modulator
->setChecked(notClicked
);
1746 ui
.ch_cat_synth
->setChecked(notClicked
);
1747 ui
.ch_cat_utility
->setChecked(notClicked
);
1748 ui
.ch_cat_other
->setChecked(notClicked
);
1752 void PluginListDialog::checkFiltersCategorySpecific(bool clicked
)
1756 ui
.ch_cat_all
->setChecked(false);
1758 else if (! (ui
.ch_cat_delay
->isChecked() ||
1759 ui
.ch_cat_distortion
->isChecked() ||
1760 ui
.ch_cat_dynamics
->isChecked() ||
1761 ui
.ch_cat_eq
->isChecked() ||
1762 ui
.ch_cat_filter
->isChecked() ||
1763 ui
.ch_cat_modulator
->isChecked() ||
1764 ui
.ch_cat_synth
->isChecked() ||
1765 ui
.ch_cat_utility
->isChecked() ||
1766 ui
.ch_cat_other
->isChecked()))
1768 ui
.ch_cat_all
->setChecked(true);
1773 void PluginListDialog::clearFilters()
1775 auto setCheckedWithoutSignaling
= [](QCheckBox
* const w
, const bool checked
)
1777 w
->blockSignals(true);
1778 w
->setChecked(checked
);
1779 w
->blockSignals(false);
1782 setCheckedWithoutSignaling(ui
.ch_internal
, true);
1783 setCheckedWithoutSignaling(ui
.ch_ladspa
, true);
1784 setCheckedWithoutSignaling(ui
.ch_dssi
, true);
1785 setCheckedWithoutSignaling(ui
.ch_lv2
, true);
1786 setCheckedWithoutSignaling(ui
.ch_vst
, true);
1787 setCheckedWithoutSignaling(ui
.ch_vst3
, true);
1788 setCheckedWithoutSignaling(ui
.ch_clap
, true);
1789 setCheckedWithoutSignaling(ui
.ch_jsfx
, true);
1790 setCheckedWithoutSignaling(ui
.ch_kits
, true);
1792 setCheckedWithoutSignaling(ui
.ch_instruments
, true);
1793 setCheckedWithoutSignaling(ui
.ch_effects
, true);
1794 setCheckedWithoutSignaling(ui
.ch_midi
, true);
1795 setCheckedWithoutSignaling(ui
.ch_other
, true);
1797 setCheckedWithoutSignaling(ui
.ch_native
, true);
1798 setCheckedWithoutSignaling(ui
.ch_bridged
, false);
1799 setCheckedWithoutSignaling(ui
.ch_bridged_wine
, false);
1801 setCheckedWithoutSignaling(ui
.ch_favorites
, false);
1802 setCheckedWithoutSignaling(ui
.ch_rtsafe
, false);
1803 setCheckedWithoutSignaling(ui
.ch_stereo
, false);
1804 setCheckedWithoutSignaling(ui
.ch_cv
, false);
1805 setCheckedWithoutSignaling(ui
.ch_gui
, false);
1806 setCheckedWithoutSignaling(ui
.ch_inline_display
, false);
1808 if (ui
.ch_au
->isEnabled())
1809 setCheckedWithoutSignaling(ui
.ch_au
, true);
1811 setCheckedWithoutSignaling(ui
.ch_cat_all
, true);
1812 setCheckedWithoutSignaling(ui
.ch_cat_delay
, false);
1813 setCheckedWithoutSignaling(ui
.ch_cat_distortion
, false);
1814 setCheckedWithoutSignaling(ui
.ch_cat_dynamics
, false);
1815 setCheckedWithoutSignaling(ui
.ch_cat_eq
, false);
1816 setCheckedWithoutSignaling(ui
.ch_cat_filter
, false);
1817 setCheckedWithoutSignaling(ui
.ch_cat_modulator
, false);
1818 setCheckedWithoutSignaling(ui
.ch_cat_synth
, false);
1819 setCheckedWithoutSignaling(ui
.ch_cat_utility
, false);
1820 setCheckedWithoutSignaling(ui
.ch_cat_other
, false);
1822 ui
.lineEdit
->blockSignals(true);
1823 ui
.lineEdit
->clear();
1824 ui
.lineEdit
->blockSignals(false);
1829 // --------------------------------------------------------------------------------------------------------------------
1831 void PluginListDialog::checkPlugin(const int row
)
1835 ui
.b_add
->setEnabled(true);
1837 const PluginInfo info
= asPluginInfo(ui
.tableWidget
->item(row
, TW_NAME
)->data(Qt::UserRole
+ UR_PLUGIN_INFO
));
1839 const bool isSynth
= info
.hints
& PLUGIN_IS_SYNTH
;
1840 const bool isEffect
= info
.audioIns
> 0 && info
.audioOuts
> 0 && !isSynth
;
1841 const bool isMidi
= info
.audioIns
== 0 && info
.audioOuts
== 0 && info
.midiIns
> 0 && info
.midiOuts
> 0;
1845 ptype
= "Instrument";
1849 ptype
= "MIDI Plugin";
1854 /**/ if (info
.build
== BINARY_NATIVE
)
1855 parch
= tr("Native");
1856 else if (info
.build
== BINARY_POSIX32
)
1858 else if (info
.build
== BINARY_POSIX64
)
1860 else if (info
.build
== BINARY_WIN32
)
1862 else if (info
.build
== BINARY_WIN64
)
1864 else if (info
.build
== BINARY_OTHER
)
1865 parch
= tr("Other");
1866 else if (info
.build
== BINARY_WIN32
)
1867 parch
= tr("Unknown");
1869 ui
.l_format
->setText(getPluginTypeAsString(static_cast<PluginType
>(info
.type
)));
1871 ui
.l_type
->setText(ptype
);
1872 ui
.l_arch
->setText(parch
);
1873 ui
.l_id
->setText(QString::number(info
.uniqueId
));
1874 ui
.l_ains
->setText(QString::number(info
.audioIns
));
1875 ui
.l_aouts
->setText(QString::number(info
.audioOuts
));
1876 ui
.l_cvins
->setText(QString::number(info
.cvIns
));
1877 ui
.l_cvouts
->setText(QString::number(info
.cvOuts
));
1878 ui
.l_mins
->setText(QString::number(info
.midiIns
));
1879 ui
.l_mouts
->setText(QString::number(info
.midiOuts
));
1880 ui
.l_pins
->setText(QString::number(info
.parameterIns
));
1881 ui
.l_pouts
->setText(QString::number(info
.parameterOuts
));
1882 ui
.l_gui
->setText(info
.hints
& PLUGIN_HAS_CUSTOM_UI
? tr("Yes") : tr("No"));
1883 ui
.l_idisp
->setText(info
.hints
& PLUGIN_HAS_INLINE_DISPLAY
? tr("Yes") : tr("No"));
1884 ui
.l_bridged
->setText(info
.hints
& PLUGIN_IS_BRIDGE
? tr("Yes") : tr("No"));
1885 ui
.l_synth
->setText(isSynth
? tr("Yes") : tr("No"));
1889 ui
.b_add
->setEnabled(false);
1890 ui
.l_format
->setText("---");
1891 ui
.l_type
->setText("---");
1892 ui
.l_arch
->setText("---");
1893 ui
.l_id
->setText("---");
1894 ui
.l_ains
->setText("---");
1895 ui
.l_aouts
->setText("---");
1896 ui
.l_cvins
->setText("---");
1897 ui
.l_cvouts
->setText("---");
1898 ui
.l_mins
->setText("---");
1899 ui
.l_mouts
->setText("---");
1900 ui
.l_pins
->setText("---");
1901 ui
.l_pouts
->setText("---");
1902 ui
.l_gui
->setText("---");
1903 ui
.l_idisp
->setText("---");
1904 ui
.l_bridged
->setText("---");
1905 ui
.l_synth
->setText("---");
1909 // --------------------------------------------------------------------------------------------------------------------
1911 void PluginListDialog::refreshPlugins()
1913 refreshPluginsStop();
1915 p
->discovery
.dialog
= new PluginRefreshDialog(this);
1917 QObject::connect(p
->discovery
.dialog
->b_start
, &QPushButton::clicked
,
1918 this, &PluginListDialog::refreshPluginsStart
);
1919 QObject::connect(p
->discovery
.dialog
->b_skip
, &QPushButton::clicked
,
1920 this, &PluginListDialog::refreshPluginsSkip
);
1921 QObject::connect(p
->discovery
.dialog
, &QDialog::finished
,
1922 this, &PluginListDialog::refreshPluginsStop
);
1924 p
->discovery
.dialog
->exec();
1927 void PluginListDialog::refreshPluginsStart()
1929 // remove old plugins
1930 #ifndef CARLA_FRONTEND_ONLY_EMBEDDABLE_PLUGINS
1931 p
->plugins
.internal
.clear();
1932 p
->plugins
.ladspa
.clear();
1933 p
->plugins
.dssi
.clear();
1935 p
->plugins
.lv2
.clear();
1936 p
->plugins
.vst2
.clear();
1937 p
->plugins
.vst3
.clear();
1938 p
->plugins
.clap
.clear();
1939 #ifndef CARLA_FRONTEND_ONLY_EMBEDDABLE_PLUGINS
1941 p
->plugins
.au
.clear();
1943 p
->plugins
.jsfx
.clear();
1944 p
->plugins
.kits
.clear();
1946 p
->discovery
.dialog
->b_start
->setEnabled(false);
1947 p
->discovery
.dialog
->b_skip
->setEnabled(true);
1948 p
->discovery
.ignoreCache
= p
->discovery
.dialog
->ch_all
->isChecked();
1949 p
->discovery
.checkInvalid
=
1950 p
->discovery
.dialog
->ch_invalid
->isChecked();
1951 if (p
->discovery
.ignoreCache
)
1952 p
->plugins
.cache
.clear();
1954 // start discovery again
1955 p
->discovery
.restart();
1957 if (p
->timerId
== 0)
1958 p
->timerId
= startTimer(0);
1961 void PluginListDialog::refreshPluginsStop()
1963 // stop previous discovery if still running
1964 if (p
->discovery
.handle
!= nullptr)
1966 carla_plugin_discovery_stop(p
->discovery
.handle
);
1967 p
->discovery
.handle
= nullptr;
1970 if (p
->discovery
.dialog
)
1972 p
->discovery
.dialog
->close();
1973 p
->discovery
.dialog
= nullptr;
1976 if (p
->timerId
!= 0)
1978 killTimer(p
->timerId
);
1980 addPluginsToTable();
1984 void PluginListDialog::refreshPluginsSkip()
1986 if (p
->discovery
.handle
!= nullptr)
1987 carla_plugin_discovery_skip(p
->discovery
.handle
);
1990 // --------------------------------------------------------------------------------------------------------------------
1992 void PluginListDialog::saveSettings()
1994 QSafeSettings
settings("falkTX", "CarlaDatabase3");
1996 settings
.setValue("PluginDatabase/Geometry", saveGeometry());
1997 settings
.setValue("PluginDatabase/TableGeometry", ui
.tableWidget
->horizontalHeader()->saveState());
1998 settings
.setValue("PluginDatabase/ShowEffects", ui
.ch_effects
->isChecked());
1999 settings
.setValue("PluginDatabase/ShowInstruments", ui
.ch_instruments
->isChecked());
2000 settings
.setValue("PluginDatabase/ShowMIDI", ui
.ch_midi
->isChecked());
2001 settings
.setValue("PluginDatabase/ShowOther", ui
.ch_other
->isChecked());
2002 settings
.setValue("PluginDatabase/ShowInternal", ui
.ch_internal
->isChecked());
2003 settings
.setValue("PluginDatabase/ShowLADSPA", ui
.ch_ladspa
->isChecked());
2004 settings
.setValue("PluginDatabase/ShowDSSI", ui
.ch_dssi
->isChecked());
2005 settings
.setValue("PluginDatabase/ShowLV2", ui
.ch_lv2
->isChecked());
2006 settings
.setValue("PluginDatabase/ShowVST2", ui
.ch_vst
->isChecked());
2007 settings
.setValue("PluginDatabase/ShowVST3", ui
.ch_vst3
->isChecked());
2008 settings
.setValue("PluginDatabase/ShowCLAP", ui
.ch_clap
->isChecked());
2009 settings
.setValue("PluginDatabase/ShowAU", ui
.ch_au
->isChecked());
2010 settings
.setValue("PluginDatabase/ShowJSFX", ui
.ch_jsfx
->isChecked());
2011 settings
.setValue("PluginDatabase/ShowKits", ui
.ch_kits
->isChecked());
2012 settings
.setValue("PluginDatabase/ShowNative", ui
.ch_native
->isChecked());
2013 settings
.setValue("PluginDatabase/ShowBridged", ui
.ch_bridged
->isChecked());
2014 settings
.setValue("PluginDatabase/ShowBridgedWine", ui
.ch_bridged_wine
->isChecked());
2015 settings
.setValue("PluginDatabase/ShowFavorites", ui
.ch_favorites
->isChecked());
2016 settings
.setValue("PluginDatabase/ShowRtSafe", ui
.ch_rtsafe
->isChecked());
2017 settings
.setValue("PluginDatabase/ShowHasCV", ui
.ch_cv
->isChecked());
2018 settings
.setValue("PluginDatabase/ShowHasGUI", ui
.ch_gui
->isChecked());
2019 settings
.setValue("PluginDatabase/ShowHasInlineDisplay", ui
.ch_inline_display
->isChecked());
2020 settings
.setValue("PluginDatabase/ShowStereoOnly", ui
.ch_stereo
->isChecked());
2021 settings
.setValue("PluginDatabase/SearchText", ui
.lineEdit
->text());
2023 if (ui
.ch_cat_all
->isChecked())
2025 settings
.setValue("PluginDatabase/ShowCategory", "all");
2029 QCarlaString categories
;
2030 if (ui
.ch_cat_delay
->isChecked())
2031 categories
+= ":delay";
2032 if (ui
.ch_cat_distortion
->isChecked())
2033 categories
+= ":distortion";
2034 if (ui
.ch_cat_dynamics
->isChecked())
2035 categories
+= ":dynamics";
2036 if (ui
.ch_cat_eq
->isChecked())
2037 categories
+= ":eq";
2038 if (ui
.ch_cat_filter
->isChecked())
2039 categories
+= ":filter";
2040 if (ui
.ch_cat_modulator
->isChecked())
2041 categories
+= ":modulator";
2042 if (ui
.ch_cat_synth
->isChecked())
2043 categories
+= ":synth";
2044 if (ui
.ch_cat_utility
->isChecked())
2045 categories
+= ":utility";
2046 if (ui
.ch_cat_other
->isChecked())
2047 categories
+= ":other";
2048 if (categories
.isNotEmpty())
2050 settings
.setValue("PluginDatabase/ShowCategory", categories
);
2053 settings
.setValue("PluginListDialog/Favorites", asVariant(p
->plugins
.favorites
));
2056 // --------------------------------------------------------------------------------------------------------------------
2059 carla_frontend_createPluginListDialog(void* const parent
, const HostSettings
* const hostSettings
)
2061 return new PluginListDialog(reinterpret_cast<QWidget
*>(parent
), hostSettings
);
2065 carla_frontend_destroyPluginListDialog(PluginListDialog
* const dialog
)
2072 carla_frontend_setPluginListDialogPath(PluginListDialog
* const dialog
, const int ptype
, const char* const path
)
2074 dialog
->setPluginPath(static_cast<PluginType
>(ptype
), path
);
2077 const PluginListDialogResults
*
2078 carla_frontend_execPluginListDialog(PluginListDialog
* const dialog
)
2082 static PluginListDialogResults ret
;
2083 static CarlaString category
;
2084 static CarlaString filename
;
2085 static CarlaString name
;
2086 static CarlaString label
;
2087 static CarlaString maker
;
2089 const PluginInfo
& plugin(dialog
->getSelectedPluginInfo());
2091 category
= plugin
.category
.toUtf8();
2092 filename
= plugin
.filename
.toUtf8();
2093 name
= plugin
.name
.toUtf8();
2094 label
= plugin
.label
.toUtf8();
2095 maker
= plugin
.maker
.toUtf8();
2097 ret
.build
= plugin
.build
;
2098 ret
.type
= plugin
.type
;
2099 ret
.hints
= plugin
.hints
;
2100 ret
.category
= category
;
2101 ret
.filename
= filename
;
2105 ret
.uniqueId
= plugin
.uniqueId
;
2106 ret
.audioIns
= plugin
.audioIns
;
2107 ret
.audioOuts
= plugin
.audioOuts
;
2108 ret
.cvIns
= plugin
.cvIns
;
2109 ret
.cvOuts
= plugin
.cvOuts
;
2110 ret
.midiIns
= plugin
.midiIns
;
2111 ret
.midiOuts
= plugin
.midiOuts
;
2112 ret
.parameterIns
= plugin
.parameterIns
;
2113 ret
.parameterOuts
= plugin
.parameterOuts
;
2121 // --------------------------------------------------------------------------------------------------------------------
2123 // const PluginListDialogResults*
2124 // carla_frontend_createAndExecPluginListDialog(void* const parent, const HostSettings* const hostSettings)
2126 // PluginListDialog gui(reinterpret_cast<QWidget*>(parent), hostSettings);
2128 // return carla_frontend_execPluginListDialog(&gui);
2131 // --------------------------------------------------------------------------------------------------------------------