Get rid of JUCE for discovery and utils
[carla.git] / source / discovery / carla-discovery.cpp
blob7da407c218a58fd9e90f811e348370186905b253
1 // SPDX-FileCopyrightText: 2011-2024 Filipe Coelho <falktx@falktx.com>
2 // SPDX-License-Identifier: GPL-2.0-or-later
4 #include "CarlaBackendUtils.hpp"
5 #include "CarlaLibUtils.hpp"
6 #include "CarlaMathUtils.hpp"
7 #include "CarlaScopeUtils.hpp"
9 #include "CarlaMIDI.h"
10 #include "LinkedList.hpp"
12 #include "CarlaLadspaUtils.hpp"
13 #include "CarlaDssiUtils.hpp"
14 #include "CarlaLv2Utils.hpp"
15 #include "CarlaVst2Utils.hpp"
16 #include "CarlaVst3Utils.hpp"
17 #include "CarlaClapUtils.hpp"
19 #ifndef BUILDING_CARLA_FOR_WINE
20 # include "CarlaPipeUtils.cpp"
21 #endif
23 #ifdef CARLA_OS_MAC
24 # include "CarlaMacUtils.cpp"
25 # include <AudioToolbox/AudioUnit.h>
26 # ifdef __aarch64__
27 # include <spawn.h>
28 # endif
29 #endif
31 #ifdef CARLA_OS_WIN
32 # include <pthread.h>
33 # include <objbase.h>
34 #endif
36 #ifdef BUILD_BRIDGE
37 # undef HAVE_FLUIDSYNTH
38 # undef HAVE_YSFX
39 #endif
41 #ifdef HAVE_FLUIDSYNTH
42 # include <fluidsynth.h>
43 #endif
45 #include <iostream>
46 #include <sstream>
48 #include "water/files/File.h"
50 #ifndef BUILD_BRIDGE
51 # include "CarlaDssiUtils.cpp"
52 # include "CarlaJsfxUtils.hpp"
53 # include "../backend/utils/CachedPlugins.cpp"
54 #endif
56 // must be last
57 #ifdef BUILDING_CARLA_FOR_WINE
58 # include "../jackbridge/JackBridge.hpp"
59 #endif
61 #define MAX_DISCOVERY_AUDIO_IO 64
62 #define MAX_DISCOVERY_CV_IO 32
64 #define DISCOVERY_OUT(x, y) \
65 if (gPipe != nullptr) { std::stringstream s; s << y; gPipe->writeDiscoveryMessage(x, s.str().c_str()); } \
66 else { std::cout << "\ncarla-discovery::" << x << "::" << y << std::endl; }
68 using water::File;
70 CARLA_BACKEND_USE_NAMESPACE
72 // --------------------------------------------------------------------------------------------------------------------
73 // Dummy values to test plugins with
75 static constexpr const uint32_t kBufferSize = 512;
76 static constexpr const double kSampleRate = 44100.0;
77 static constexpr const int32_t kSampleRatei = 44100;
78 static constexpr const float kSampleRatef = 44100.0f;
80 // --------------------------------------------------------------------------------------------------------------------
81 // Dynamic discovery
83 #ifndef BUILDING_CARLA_FOR_WINE
84 class DiscoveryPipe : public CarlaPipeClient
86 public:
87 DiscoveryPipe() {}
89 ~DiscoveryPipe()
91 writeExitingMessageAndWait();
94 bool writeDiscoveryMessage(const char* const key, const char* const value) const noexcept
96 CARLA_SAFE_ASSERT_RETURN(key != nullptr && key[0] != '\0', false);
97 CARLA_SAFE_ASSERT_RETURN(value != nullptr, false);
99 const CarlaMutexLocker cml(pData->writeLock);
101 if (! writeAndFixMessage(key))
102 return false;
103 if (! writeAndFixMessage(value))
104 return false;
106 syncMessages();
107 return true;
110 protected:
111 bool msgReceived(const char* const msg) noexcept
113 carla_stdout("discovery msgReceived %s", msg);
114 return true;
117 #else
118 class DiscoveryPipe
120 void* pipe;
122 public:
123 DiscoveryPipe() noexcept : pipe(nullptr) {}
125 ~DiscoveryPipe()
127 jackbridge_discovery_pipe_destroy(pipe);
130 bool initPipeClient(const char* argv[])
132 if (jackbridge_is_ok())
133 pipe = jackbridge_discovery_pipe_create(argv);
135 return pipe != nullptr;
138 bool writeDiscoveryMessage(const char* const key, const char* const value) const noexcept
140 CARLA_SAFE_ASSERT_RETURN(key != nullptr && key[0] != '\0', false);
141 CARLA_SAFE_ASSERT_RETURN(value != nullptr, false);
143 jackbridge_discovery_pipe_message(pipe, key, value);
144 return true;
147 #endif
149 CarlaScopedPointer<DiscoveryPipe> gPipe;
151 // --------------------------------------------------------------------------------------------------------------------
152 // Don't print ELF/EXE related errors since discovery can find multi-architecture binaries
154 static void print_lib_error(const char* const filename)
156 const char* const error = lib_error(filename);
158 if (error != nullptr &&
159 std::strstr(error, "wrong ELF class") == nullptr &&
160 std::strstr(error, "invalid ELF header") == nullptr &&
161 std::strstr(error, "Bad EXE format") == nullptr &&
162 std::strstr(error, "no suitable image found") == nullptr &&
163 std::strstr(error, "not a valid Win32 application") == nullptr)
165 DISCOVERY_OUT("error", error);
169 // --------------------------------------------------------------------------------------------------------------------
170 // Carla Cached API
172 #ifndef BUILD_BRIDGE
173 static void print_cached_plugin(const CarlaCachedPluginInfo* const pinfo)
175 if (! pinfo->valid)
176 return;
178 DISCOVERY_OUT("init", "------------");
179 DISCOVERY_OUT("build", BINARY_NATIVE);
180 DISCOVERY_OUT("hints", pinfo->hints);
181 DISCOVERY_OUT("category", getPluginCategoryAsString(pinfo->category));
182 DISCOVERY_OUT("name", pinfo->name);
183 DISCOVERY_OUT("maker", pinfo->maker);
184 DISCOVERY_OUT("label", pinfo->label);
185 DISCOVERY_OUT("audio.ins", pinfo->audioIns);
186 DISCOVERY_OUT("audio.outs", pinfo->audioOuts);
187 DISCOVERY_OUT("cv.ins", pinfo->cvIns);
188 DISCOVERY_OUT("cv.outs", pinfo->cvOuts);
189 DISCOVERY_OUT("midi.ins", pinfo->midiIns);
190 DISCOVERY_OUT("midi.outs", pinfo->midiOuts);
191 DISCOVERY_OUT("parameters.ins", pinfo->parameterIns);
192 DISCOVERY_OUT("parameters.outs", pinfo->parameterOuts);
193 DISCOVERY_OUT("end", "------------");
196 static void do_cached_check(const PluginType type)
198 const char* plugPath = std::getenv("CARLA_DISCOVERY_PATH");
200 if (plugPath == nullptr)
202 switch (type)
204 case PLUGIN_LV2:
205 plugPath = std::getenv("LV2_PATH");
206 break;
207 case PLUGIN_SFZ:
208 plugPath = std::getenv("SFZ_PATH");
209 break;
210 default:
211 plugPath = nullptr;
212 break;
216 const uint count = carla_get_cached_plugin_count(type, plugPath);
218 for (uint i=0; i<count; ++i)
220 const CarlaCachedPluginInfo* pinfo = carla_get_cached_plugin_info(type, i);
221 CARLA_SAFE_ASSERT_CONTINUE(pinfo != nullptr);
223 print_cached_plugin(pinfo);
226 #endif // ! BUILD_BRIDGE
228 // --------------------------------------------------------------------------------------------------------------------
229 // LADSPA
231 static void do_ladspa_check(lib_t& libHandle, const char* const filename, const bool doInit)
233 LADSPA_Descriptor_Function descFn = lib_symbol<LADSPA_Descriptor_Function>(libHandle, "ladspa_descriptor");
235 if (descFn == nullptr)
237 DISCOVERY_OUT("error", "Not a LADSPA plugin");
238 return;
241 const LADSPA_Descriptor* descriptor;
244 descriptor = descFn(0);
246 if (descriptor == nullptr)
248 DISCOVERY_OUT("error", "Binary doesn't contain any plugins");
249 return;
252 if (doInit && descriptor->instantiate != nullptr && descriptor->cleanup != nullptr)
254 LADSPA_Handle handle = descriptor->instantiate(descriptor, kSampleRatei);
256 if (handle == nullptr)
258 DISCOVERY_OUT("error", "Failed to init first LADSPA plugin");
259 return;
262 descriptor->cleanup(handle);
264 lib_close(libHandle);
265 libHandle = lib_open(filename);
267 if (libHandle == nullptr)
269 print_lib_error(filename);
270 return;
273 descFn = lib_symbol<LADSPA_Descriptor_Function>(libHandle, "ladspa_descriptor");
275 if (descFn == nullptr)
277 DISCOVERY_OUT("error", "Not a LADSPA plugin (#2)");
278 return;
283 unsigned long i = 0;
285 while ((descriptor = descFn(i++)) != nullptr)
287 if (descriptor->instantiate == nullptr)
289 DISCOVERY_OUT("error", "Plugin '" << descriptor->Name << "' has no instantiate()");
290 continue;
292 if (descriptor->cleanup == nullptr)
294 DISCOVERY_OUT("error", "Plugin '" << descriptor->Name << "' has no cleanup()");
295 continue;
297 if (descriptor->run == nullptr)
299 DISCOVERY_OUT("error", "Plugin '" << descriptor->Name << "' has no run()");
300 continue;
302 if (! LADSPA_IS_HARD_RT_CAPABLE(descriptor->Properties))
304 DISCOVERY_OUT("warning", "Plugin '" << descriptor->Name << "' is not hard real-time capable");
307 uint hints = 0x0;
308 uint audioIns = 0;
309 uint audioOuts = 0;
310 uint parametersIns = 0;
311 uint parametersOuts = 0;
312 uint parametersTotal = 0;
314 if (LADSPA_IS_HARD_RT_CAPABLE(descriptor->Properties))
315 hints |= PLUGIN_IS_RTSAFE;
317 for (unsigned long j=0; j < descriptor->PortCount; ++j)
319 CARLA_ASSERT(descriptor->PortNames[j] != nullptr);
320 const LADSPA_PortDescriptor portDescriptor = descriptor->PortDescriptors[j];
322 if (LADSPA_IS_PORT_AUDIO(portDescriptor))
324 if (LADSPA_IS_PORT_INPUT(portDescriptor))
325 audioIns += 1;
326 else if (LADSPA_IS_PORT_OUTPUT(portDescriptor))
327 audioOuts += 1;
329 else if (LADSPA_IS_PORT_CONTROL(portDescriptor))
331 if (LADSPA_IS_PORT_INPUT(portDescriptor))
332 parametersIns += 1;
333 else if (LADSPA_IS_PORT_OUTPUT(portDescriptor) && std::strcmp(descriptor->PortNames[j], "latency") != 0 && std::strcmp(descriptor->PortNames[j], "_latency") != 0)
334 parametersOuts += 1;
336 parametersTotal += 1;
340 CARLA_SAFE_ASSERT_CONTINUE(audioIns <= MAX_DISCOVERY_AUDIO_IO);
341 CARLA_SAFE_ASSERT_CONTINUE(audioOuts <= MAX_DISCOVERY_AUDIO_IO);
343 if (doInit)
345 // -----------------------------------------------------------------------
346 // start crash-free plugin test
348 LADSPA_Handle handle = descriptor->instantiate(descriptor, kSampleRatei);
350 if (handle == nullptr)
352 DISCOVERY_OUT("error", "Failed to init LADSPA plugin");
353 continue;
356 // Test quick init and cleanup
357 descriptor->cleanup(handle);
359 handle = descriptor->instantiate(descriptor, kSampleRatei);
361 if (handle == nullptr)
363 DISCOVERY_OUT("error", "Failed to init LADSPA plugin (#2)");
364 continue;
367 LADSPA_Data* bufferParams = new LADSPA_Data[parametersTotal];
368 LADSPA_Data bufferAudio[kBufferSize][MAX_DISCOVERY_AUDIO_IO];
369 LADSPA_Data min, max, def;
371 for (unsigned long j=0, iA=0, iC=0; j < descriptor->PortCount; ++j)
373 const LADSPA_PortDescriptor portDescriptor = descriptor->PortDescriptors[j];
374 const LADSPA_PortRangeHint portRangeHints = descriptor->PortRangeHints[j];
375 const char* const portName = descriptor->PortNames[j];
377 if (LADSPA_IS_PORT_AUDIO(portDescriptor))
379 carla_zeroFloats(bufferAudio[iA], kBufferSize);
380 descriptor->connect_port(handle, j, bufferAudio[iA++]);
382 else if (LADSPA_IS_PORT_CONTROL(portDescriptor))
384 // min value
385 if (LADSPA_IS_HINT_BOUNDED_BELOW(portRangeHints.HintDescriptor))
386 min = portRangeHints.LowerBound;
387 else
388 min = 0.0f;
390 // max value
391 if (LADSPA_IS_HINT_BOUNDED_ABOVE(portRangeHints.HintDescriptor))
392 max = portRangeHints.UpperBound;
393 else
394 max = 1.0f;
396 if (min > max)
398 DISCOVERY_OUT("warning", "Parameter '" << portName << "' is broken: min > max");
399 max = min + 0.1f;
401 else if (carla_isEqual(min, max))
403 DISCOVERY_OUT("warning", "Parameter '" << portName << "' is broken: max == min");
404 max = min + 0.1f;
407 // default value
408 def = get_default_ladspa_port_value(portRangeHints.HintDescriptor, min, max);
410 if (LADSPA_IS_HINT_SAMPLE_RATE(portRangeHints.HintDescriptor))
412 min *= kSampleRatef;
413 max *= kSampleRatef;
414 def *= kSampleRatef;
417 if (LADSPA_IS_PORT_OUTPUT(portDescriptor) && (std::strcmp(portName, "latency") == 0 || std::strcmp(portName, "_latency") == 0))
419 // latency parameter
420 def = 0.0f;
422 else
424 if (def < min)
425 def = min;
426 else if (def > max)
427 def = max;
430 bufferParams[iC] = def;
431 descriptor->connect_port(handle, j, &bufferParams[iC++]);
435 if (descriptor->activate != nullptr)
436 descriptor->activate(handle);
438 descriptor->run(handle, kBufferSize);
440 if (descriptor->deactivate != nullptr)
441 descriptor->deactivate(handle);
443 descriptor->cleanup(handle);
445 delete[] bufferParams;
447 // end crash-free plugin test
448 // -----------------------------------------------------------------------
451 DISCOVERY_OUT("init", "------------");
452 DISCOVERY_OUT("build", BINARY_NATIVE);
453 DISCOVERY_OUT("hints", hints);
454 DISCOVERY_OUT("category", getPluginCategoryAsString(getPluginCategoryFromName(descriptor->Name)));
455 DISCOVERY_OUT("name", descriptor->Name);
456 DISCOVERY_OUT("label", descriptor->Label);
457 DISCOVERY_OUT("maker", descriptor->Maker);
458 DISCOVERY_OUT("uniqueId", descriptor->UniqueID);
459 DISCOVERY_OUT("audio.ins", audioIns);
460 DISCOVERY_OUT("audio.outs", audioOuts);
461 DISCOVERY_OUT("parameters.ins", parametersIns);
462 DISCOVERY_OUT("parameters.outs", parametersOuts);
463 DISCOVERY_OUT("end", "------------");
467 // --------------------------------------------------------------------------------------------------------------------
468 // DSSI
470 static void do_dssi_check(lib_t& libHandle, const char* const filename, const bool doInit)
472 DSSI_Descriptor_Function descFn = lib_symbol<DSSI_Descriptor_Function>(libHandle, "dssi_descriptor");
474 if (descFn == nullptr)
476 DISCOVERY_OUT("error", "Not a DSSI plugin");
477 return;
480 const DSSI_Descriptor* descriptor;
483 descriptor = descFn(0);
485 if (descriptor == nullptr)
487 DISCOVERY_OUT("error", "Binary doesn't contain any plugins");
488 return;
491 const LADSPA_Descriptor* const ldescriptor(descriptor->LADSPA_Plugin);
493 if (ldescriptor == nullptr)
495 DISCOVERY_OUT("error", "DSSI plugin doesn't provide the LADSPA interface");
496 return;
499 if (doInit && ldescriptor->instantiate != nullptr && ldescriptor->cleanup != nullptr)
501 LADSPA_Handle handle = ldescriptor->instantiate(ldescriptor, kSampleRatei);
503 if (handle == nullptr)
505 DISCOVERY_OUT("error", "Failed to init first LADSPA plugin");
506 return;
509 ldescriptor->cleanup(handle);
511 lib_close(libHandle);
512 libHandle = lib_open(filename);
514 if (libHandle == nullptr)
516 print_lib_error(filename);
517 return;
520 descFn = lib_symbol<DSSI_Descriptor_Function>(libHandle, "dssi_descriptor");
522 if (descFn == nullptr)
524 DISCOVERY_OUT("error", "Not a DSSI plugin (#2)");
525 return;
530 unsigned long i = 0;
532 while ((descriptor = descFn(i++)) != nullptr)
534 const LADSPA_Descriptor* const ldescriptor = descriptor->LADSPA_Plugin;
536 if (ldescriptor == nullptr)
538 DISCOVERY_OUT("error", "Plugin has no LADSPA interface");
539 continue;
541 if (descriptor->DSSI_API_Version != DSSI_VERSION_MAJOR)
543 DISCOVERY_OUT("error", "Plugin '" << ldescriptor->Name << "' uses an unsupported DSSI spec version " << descriptor->DSSI_API_Version);
544 continue;
546 if (ldescriptor->instantiate == nullptr)
548 DISCOVERY_OUT("error", "Plugin '" << ldescriptor->Name << "' has no instantiate()");
549 continue;
551 if (ldescriptor->cleanup == nullptr)
553 DISCOVERY_OUT("error", "Plugin '" << ldescriptor->Name << "' has no cleanup()");
554 continue;
556 if (ldescriptor->run == nullptr && descriptor->run_synth == nullptr)
558 DISCOVERY_OUT("error", "Plugin '" << ldescriptor->Name << "' has no run() or run_synth()");
559 continue;
561 if (descriptor->run_synth == nullptr && descriptor->run_multiple_synths != nullptr)
563 DISCOVERY_OUT("error", "Plugin '" << ldescriptor->Name << "' requires run_multiple_synths which is not supported");
564 continue;
566 if (! LADSPA_IS_HARD_RT_CAPABLE(ldescriptor->Properties))
568 DISCOVERY_OUT("warning", "Plugin '" << ldescriptor->Name << "' is not hard real-time capable");
571 uint hints = 0x0;
572 uint audioIns = 0;
573 uint audioOuts = 0;
574 uint midiIns = 0;
575 uint parametersIns = 0;
576 uint parametersOuts = 0;
577 uint parametersTotal = 0;
579 if (LADSPA_IS_HARD_RT_CAPABLE(ldescriptor->Properties))
580 hints |= PLUGIN_IS_RTSAFE;
582 for (unsigned long j=0; j < ldescriptor->PortCount; ++j)
584 CARLA_ASSERT(ldescriptor->PortNames[j] != nullptr);
585 const LADSPA_PortDescriptor portDescriptor = ldescriptor->PortDescriptors[j];
587 if (LADSPA_IS_PORT_AUDIO(portDescriptor))
589 if (LADSPA_IS_PORT_INPUT(portDescriptor))
590 audioIns += 1;
591 else if (LADSPA_IS_PORT_OUTPUT(portDescriptor))
592 audioOuts += 1;
594 else if (LADSPA_IS_PORT_CONTROL(portDescriptor))
596 if (LADSPA_IS_PORT_INPUT(portDescriptor))
597 parametersIns += 1;
598 else if (LADSPA_IS_PORT_OUTPUT(portDescriptor) && std::strcmp(ldescriptor->PortNames[j], "latency") != 0 && std::strcmp(ldescriptor->PortNames[j], "_latency") != 0)
599 parametersOuts += 1;
601 parametersTotal += 1;
605 CARLA_SAFE_ASSERT_CONTINUE(audioIns <= MAX_DISCOVERY_AUDIO_IO);
606 CARLA_SAFE_ASSERT_CONTINUE(audioOuts <= MAX_DISCOVERY_AUDIO_IO);
608 if (descriptor->run_synth != nullptr)
609 midiIns = 1;
611 if (midiIns > 0 && audioIns == 0 && audioOuts > 0)
612 hints |= PLUGIN_IS_SYNTH;
614 #ifndef BUILD_BRIDGE
615 if (const char* const ui = find_dssi_ui(filename, ldescriptor->Label))
617 hints |= PLUGIN_HAS_CUSTOM_UI;
618 delete[] ui;
620 #endif
622 if (doInit)
624 // -----------------------------------------------------------------------
625 // start crash-free plugin test
627 LADSPA_Handle handle = ldescriptor->instantiate(ldescriptor, kSampleRatei);
629 if (handle == nullptr)
631 DISCOVERY_OUT("error", "Failed to init DSSI plugin");
632 continue;
635 // Test quick init and cleanup
636 ldescriptor->cleanup(handle);
638 handle = ldescriptor->instantiate(ldescriptor, kSampleRatei);
640 if (handle == nullptr)
642 DISCOVERY_OUT("error", "Failed to init DSSI plugin (#2)");
643 continue;
646 LADSPA_Data* bufferParams = new LADSPA_Data[parametersTotal];
647 LADSPA_Data bufferAudio[kBufferSize][MAX_DISCOVERY_AUDIO_IO];
648 LADSPA_Data min, max, def;
650 for (unsigned long j=0, iA=0, iC=0; j < ldescriptor->PortCount; ++j)
652 const LADSPA_PortDescriptor portDescriptor = ldescriptor->PortDescriptors[j];
653 const LADSPA_PortRangeHint portRangeHints = ldescriptor->PortRangeHints[j];
654 const char* const portName = ldescriptor->PortNames[j];
656 if (LADSPA_IS_PORT_AUDIO(portDescriptor))
658 carla_zeroFloats(bufferAudio[iA], kBufferSize);
659 ldescriptor->connect_port(handle, j, bufferAudio[iA++]);
661 else if (LADSPA_IS_PORT_CONTROL(portDescriptor))
663 // min value
664 if (LADSPA_IS_HINT_BOUNDED_BELOW(portRangeHints.HintDescriptor))
665 min = portRangeHints.LowerBound;
666 else
667 min = 0.0f;
669 // max value
670 if (LADSPA_IS_HINT_BOUNDED_ABOVE(portRangeHints.HintDescriptor))
671 max = portRangeHints.UpperBound;
672 else
673 max = 1.0f;
675 if (min > max)
677 DISCOVERY_OUT("warning", "Parameter '" << portName << "' is broken: min > max");
678 max = min + 0.1f;
680 else if (carla_isEqual(min, max))
682 DISCOVERY_OUT("warning", "Parameter '" << portName << "' is broken: max == min");
683 max = min + 0.1f;
686 // default value
687 def = get_default_ladspa_port_value(portRangeHints.HintDescriptor, min, max);
689 if (LADSPA_IS_HINT_SAMPLE_RATE(portRangeHints.HintDescriptor))
691 min *= kSampleRatef;
692 max *= kSampleRatef;
693 def *= kSampleRatef;
696 if (LADSPA_IS_PORT_OUTPUT(portDescriptor) && (std::strcmp(portName, "latency") == 0 || std::strcmp(portName, "_latency") == 0))
698 // latency parameter
699 def = 0.0f;
701 else
703 if (def < min)
704 def = min;
705 else if (def > max)
706 def = max;
709 bufferParams[iC] = def;
710 ldescriptor->connect_port(handle, j, &bufferParams[iC++]);
714 // select first midi-program if available
715 if (descriptor->get_program != nullptr && descriptor->select_program != nullptr)
717 if (const DSSI_Program_Descriptor* const pDesc = descriptor->get_program(handle, 0))
718 descriptor->select_program(handle, pDesc->Bank, pDesc->Program);
721 if (ldescriptor->activate != nullptr)
722 ldescriptor->activate(handle);
724 if (descriptor->run_synth != nullptr)
726 snd_seq_event_t midiEvents[2];
727 carla_zeroStructs(midiEvents, 2);
729 const unsigned long midiEventCount = 2;
731 midiEvents[0].type = SND_SEQ_EVENT_NOTEON;
732 midiEvents[0].data.note.note = 64;
733 midiEvents[0].data.note.velocity = 100;
735 midiEvents[1].type = SND_SEQ_EVENT_NOTEOFF;
736 midiEvents[1].data.note.note = 64;
737 midiEvents[1].data.note.velocity = 0;
738 midiEvents[1].time.tick = kBufferSize/2;
740 descriptor->run_synth(handle, kBufferSize, midiEvents, midiEventCount);
742 else
743 ldescriptor->run(handle, kBufferSize);
745 if (ldescriptor->deactivate != nullptr)
746 ldescriptor->deactivate(handle);
748 ldescriptor->cleanup(handle);
750 delete[] bufferParams;
752 // end crash-free plugin test
753 // -----------------------------------------------------------------------
756 DISCOVERY_OUT("init", "------------");
757 DISCOVERY_OUT("build", BINARY_NATIVE);
758 DISCOVERY_OUT("category", ((hints & PLUGIN_IS_SYNTH)
759 ? "synth"
760 : getPluginCategoryAsString(getPluginCategoryFromName(ldescriptor->Name))));
761 DISCOVERY_OUT("hints", hints);
762 DISCOVERY_OUT("name", ldescriptor->Name);
763 DISCOVERY_OUT("label", ldescriptor->Label);
764 DISCOVERY_OUT("maker", ldescriptor->Maker);
765 DISCOVERY_OUT("uniqueId", ldescriptor->UniqueID);
766 DISCOVERY_OUT("audio.ins", audioIns);
767 DISCOVERY_OUT("audio.outs", audioOuts);
768 DISCOVERY_OUT("midi.ins", midiIns);
769 DISCOVERY_OUT("parameters.ins", parametersIns);
770 DISCOVERY_OUT("parameters.outs", parametersOuts);
771 DISCOVERY_OUT("end", "------------");
775 // --------------------------------------------------------------------------------------------------------------------
776 // LV2
778 #ifndef BUILD_BRIDGE
779 static void do_lv2_check(const char* const bundle, const bool doInit)
781 Lv2WorldClass& lv2World(Lv2WorldClass::getInstance());
783 Lilv::Node bundleNode(lv2World.new_file_uri(nullptr, bundle));
784 CARLA_SAFE_ASSERT_RETURN(bundleNode.is_uri(),);
786 CarlaString sBundle(bundleNode.as_uri());
788 if (! sBundle.endsWith("/"))
789 sBundle += "/";
791 // Load bundle
792 lv2World.load_bundle(sBundle);
794 // Load plugins in this bundle
795 const Lilv::Plugins lilvPlugins(lv2World.get_all_plugins());
797 // Get all plugin URIs in this bundle
798 CarlaStringList URIs;
800 LILV_FOREACH(plugins, it, lilvPlugins)
802 Lilv::Plugin lilvPlugin(lilv_plugins_get(lilvPlugins, it));
804 if (const char* const uri = lilvPlugin.get_uri().as_string())
805 URIs.appendUnique(uri);
808 if (URIs.isEmpty())
810 DISCOVERY_OUT("warning", "LV2 Bundle doesn't provide any plugins");
811 return;
814 // Get & check every plugin-instance
815 for (CarlaStringList::Itenerator it=URIs.begin2(); it.valid(); it.next())
817 const char* const URI = it.getValue(nullptr);
818 CARLA_SAFE_ASSERT_CONTINUE(URI != nullptr);
820 CarlaScopedPointer<const LV2_RDF_Descriptor> rdfDescriptor(lv2_rdf_new(URI, false));
822 if (rdfDescriptor == nullptr || rdfDescriptor->URI == nullptr)
824 DISCOVERY_OUT("error", "Failed to find LV2 plugin '" << URI << "'");
825 continue;
828 if (doInit)
830 // test if lib is loadable, twice
831 const lib_t libHandle1 = lib_open(rdfDescriptor->Binary);
833 if (libHandle1 == nullptr)
835 print_lib_error(rdfDescriptor->Binary);
836 delete rdfDescriptor;
837 continue;
840 lib_close(libHandle1);
842 const lib_t libHandle2 = lib_open(rdfDescriptor->Binary);
844 if (libHandle2 == nullptr)
846 print_lib_error(rdfDescriptor->Binary);
847 delete rdfDescriptor;
848 continue;
851 lib_close(libHandle2);
854 const LilvPlugin* const cPlugin(lv2World.getPluginFromURI(URI));
855 CARLA_SAFE_ASSERT_CONTINUE(cPlugin != nullptr);
857 Lilv::Plugin lilvPlugin(cPlugin);
858 CARLA_SAFE_ASSERT_CONTINUE(lilvPlugin.get_uri().is_uri());
860 print_cached_plugin(get_cached_plugin_lv2(lv2World, lilvPlugin));
863 #endif // ! BUILD_BRIDGE
865 // --------------------------------------------------------------------------------------------------------------------
866 // VST2
868 // Check if plugin is currently processing
869 static bool gVstIsProcessing = false;
871 // Check if plugin needs idle
872 static bool gVstNeedsIdle = false;
874 // Check if plugin wants midi
875 static bool gVstWantsMidi = false;
877 // Check if plugin wants time
878 static bool gVstWantsTime = false;
880 // Current uniqueId for VST shell plugins
881 static intptr_t gVstCurrentUniqueId = 0;
883 // Supported Carla features
884 static intptr_t vstHostCanDo(const char* const feature)
886 carla_debug("vstHostCanDo(\"%s\")", feature);
888 if (std::strcmp(feature, "supplyIdle") == 0)
889 return 1;
890 if (std::strcmp(feature, "sendVstEvents") == 0)
891 return 1;
892 if (std::strcmp(feature, "sendVstMidiEvent") == 0)
893 return 1;
894 if (std::strcmp(feature, "sendVstMidiEventFlagIsRealtime") == 0)
895 return 1;
896 if (std::strcmp(feature, "sendVstTimeInfo") == 0)
898 gVstWantsTime = true;
899 return 1;
901 if (std::strcmp(feature, "receiveVstEvents") == 0)
902 return 1;
903 if (std::strcmp(feature, "receiveVstMidiEvent") == 0)
904 return 1;
905 if (std::strcmp(feature, "receiveVstTimeInfo") == 0)
906 return -1;
907 if (std::strcmp(feature, "reportConnectionChanges") == 0)
908 return -1;
909 if (std::strcmp(feature, "acceptIOChanges") == 0)
910 return 1;
911 if (std::strcmp(feature, "sizeWindow") == 0)
912 return 1;
913 if (std::strcmp(feature, "offline") == 0)
914 return -1;
915 if (std::strcmp(feature, "openFileSelector") == 0)
916 return -1;
917 if (std::strcmp(feature, "closeFileSelector") == 0)
918 return -1;
919 if (std::strcmp(feature, "startStopProcess") == 0)
920 return 1;
921 if (std::strcmp(feature, "supportShell") == 0)
922 return 1;
923 if (std::strcmp(feature, "shellCategory") == 0)
924 return 1;
925 if (std::strcmp(feature, "NIMKPIVendorSpecificCallbacks") == 0)
926 return -1;
928 // non-official features found in some plugins:
929 // "asyncProcessing"
930 // "editFile"
932 // unimplemented
933 carla_stderr("vstHostCanDo(\"%s\") - unknown feature", feature);
934 return 0;
937 // Host-side callback
938 static intptr_t VSTCALLBACK vstHostCallback(AEffect* const effect, const int32_t opcode, const int32_t index, const intptr_t value, void* const ptr, const float opt)
940 carla_debug("vstHostCallback(%p, %i:%s, %i, " P_INTPTR ", %p, %f)",
941 effect, opcode, vstMasterOpcode2str(opcode), index, value, ptr, static_cast<double>(opt));
943 static VstTimeInfo timeInfo;
944 intptr_t ret = 0;
946 switch (opcode)
948 case audioMasterAutomate:
949 ret = 1;
950 break;
952 case audioMasterVersion:
953 ret = kVstVersion;
954 break;
956 case audioMasterCurrentId:
957 ret = gVstCurrentUniqueId;
958 break;
960 case DECLARE_VST_DEPRECATED(audioMasterWantMidi):
961 if (gVstWantsMidi) { DISCOVERY_OUT("warning", "Plugin requested MIDI more than once"); }
963 gVstWantsMidi = true;
964 ret = 1;
965 break;
967 case audioMasterGetTime:
968 if (! gVstIsProcessing) { DISCOVERY_OUT("warning", "Plugin requested timeInfo out of process"); }
969 if (! gVstWantsTime) { DISCOVERY_OUT("warning", "Plugin requested timeInfo but didn't ask if host could do \"sendVstTimeInfo\""); }
971 carla_zeroStruct(timeInfo);
972 timeInfo.sampleRate = kSampleRate;
974 // Tempo
975 timeInfo.tempo = 120.0;
976 timeInfo.flags |= kVstTempoValid;
978 // Time Signature
979 timeInfo.timeSigNumerator = 4;
980 timeInfo.timeSigDenominator = 4;
981 timeInfo.flags |= kVstTimeSigValid;
983 ret = (intptr_t)&timeInfo;
984 break;
986 case DECLARE_VST_DEPRECATED(audioMasterTempoAt):
987 ret = 120 * 10000;
988 break;
990 case DECLARE_VST_DEPRECATED(audioMasterGetNumAutomatableParameters):
991 ret = carla_minPositive(effect->numParams, static_cast<int>(MAX_DEFAULT_PARAMETERS));
992 break;
994 case DECLARE_VST_DEPRECATED(audioMasterGetParameterQuantization):
995 ret = 1; // full single float precision
996 break;
998 case DECLARE_VST_DEPRECATED(audioMasterNeedIdle):
999 if (gVstNeedsIdle) { DISCOVERY_OUT("warning", "Plugin requested idle more than once"); }
1001 gVstNeedsIdle = true;
1002 ret = 1;
1003 break;
1005 case audioMasterGetSampleRate:
1006 ret = kSampleRatei;
1007 break;
1009 case audioMasterGetBlockSize:
1010 ret = kBufferSize;
1011 break;
1013 case DECLARE_VST_DEPRECATED(audioMasterWillReplaceOrAccumulate):
1014 ret = 1; // replace
1015 break;
1017 case audioMasterGetCurrentProcessLevel:
1018 ret = gVstIsProcessing ? kVstProcessLevelRealtime : kVstProcessLevelUser;
1019 break;
1021 case audioMasterGetAutomationState:
1022 ret = kVstAutomationOff;
1023 break;
1025 case audioMasterGetVendorString:
1026 CARLA_SAFE_ASSERT_BREAK(ptr != nullptr);
1027 std::strcpy((char*)ptr, "falkTX");
1028 ret = 1;
1029 break;
1031 case audioMasterGetProductString:
1032 CARLA_SAFE_ASSERT_BREAK(ptr != nullptr);
1033 std::strcpy((char*)ptr, "Carla-Discovery");
1034 ret = 1;
1035 break;
1037 case audioMasterGetVendorVersion:
1038 ret = CARLA_VERSION_HEX;
1039 break;
1041 case audioMasterCanDo:
1042 CARLA_SAFE_ASSERT_BREAK(ptr != nullptr);
1043 ret = vstHostCanDo((const char*)ptr);
1044 break;
1046 case audioMasterGetLanguage:
1047 ret = kVstLangEnglish;
1048 break;
1050 default:
1051 carla_stdout("vstHostCallback(%p, %i:%s, %i, " P_INTPTR ", %p, %f)",
1052 effect, opcode, vstMasterOpcode2str(opcode), index, value, ptr, static_cast<double>(opt));
1053 break;
1056 return ret;
1059 static bool do_vst2_check(lib_t& libHandle, const char* const filename, const bool doInit)
1061 VST_Function vstFn = nullptr;
1063 #ifdef CARLA_OS_MAC
1064 BundleLoader bundleLoader;
1066 if (libHandle == nullptr)
1068 if (! bundleLoader.load(filename))
1070 #ifdef __aarch64__
1071 return true;
1072 #else
1073 DISCOVERY_OUT("error", "Failed to load VST2 bundle executable");
1074 return false;
1075 #endif
1078 vstFn = bundleLoader.getSymbol<VST_Function>(CFSTR("main_macho"));
1080 if (vstFn == nullptr)
1081 vstFn = bundleLoader.getSymbol<VST_Function>(CFSTR("VSTPluginMain"));
1083 if (vstFn == nullptr)
1085 DISCOVERY_OUT("error", "Not a VST2 plugin");
1086 return false;
1089 else
1090 #endif
1092 vstFn = lib_symbol<VST_Function>(libHandle, "VSTPluginMain");
1094 if (vstFn == nullptr)
1096 vstFn = lib_symbol<VST_Function>(libHandle, "main");
1098 if (vstFn == nullptr)
1100 DISCOVERY_OUT("error", "Not a VST plugin");
1101 return false;
1106 AEffect* effect = vstFn(vstHostCallback);
1108 if (effect == nullptr || effect->magic != kEffectMagic)
1110 DISCOVERY_OUT("error", "Failed to init VST plugin, or VST magic failed");
1111 return false;
1114 if (effect->uniqueID == 0)
1116 DISCOVERY_OUT("warning", "Plugin doesn't have an Unique ID when first loaded");
1119 effect->dispatcher(effect, DECLARE_VST_DEPRECATED(effIdentify), 0, 0, nullptr, 0.0f);
1120 effect->dispatcher(effect, DECLARE_VST_DEPRECATED(effSetBlockSizeAndSampleRate), 0, kBufferSize, nullptr, kSampleRatef);
1121 effect->dispatcher(effect, effSetSampleRate, 0, 0, nullptr, kSampleRatef);
1122 effect->dispatcher(effect, effSetBlockSize, 0, kBufferSize, nullptr, 0.0f);
1123 effect->dispatcher(effect, effSetProcessPrecision, 0, kVstProcessPrecision32, nullptr, 0.0f);
1125 effect->dispatcher(effect, effOpen, 0, 0, nullptr, 0.0f);
1127 if (effect->numPrograms > 0)
1128 effect->dispatcher(effect, effSetProgram, 0, 0, nullptr, 0.0f);
1130 const bool isShell = (effect->dispatcher(effect, effGetPlugCategory, 0, 0, nullptr, 0.0f) == kPlugCategShell);
1132 if (effect->uniqueID == 0 && !isShell)
1134 DISCOVERY_OUT("error", "Plugin doesn't have an Unique ID after being open");
1135 effect->dispatcher(effect, effClose, 0, 0, nullptr, 0.0f);
1136 return false;
1139 gVstCurrentUniqueId = effect->uniqueID;
1141 char strBuf[STR_MAX+1];
1142 CarlaString cName;
1143 CarlaString cProduct;
1144 CarlaString cVendor;
1145 PluginCategory category;
1146 LinkedList<intptr_t> uniqueIds;
1148 if (isShell)
1150 for (;;)
1152 carla_zeroChars(strBuf, STR_MAX+1);
1154 gVstCurrentUniqueId = effect->dispatcher(effect, effShellGetNextPlugin, 0, 0, strBuf, 0.0f);
1156 if (gVstCurrentUniqueId == 0)
1157 break;
1159 uniqueIds.append(gVstCurrentUniqueId);
1162 effect->dispatcher(effect, effClose, 0, 0, nullptr, 0.0f);
1163 effect = nullptr;
1165 else
1167 uniqueIds.append(gVstCurrentUniqueId);
1170 for (LinkedList<intptr_t>::Itenerator it = uniqueIds.begin2(); it.valid(); it.next())
1172 gVstCurrentUniqueId = it.getValue(0);
1174 if (effect == nullptr)
1176 effect = vstFn(vstHostCallback);
1178 effect->dispatcher(effect, DECLARE_VST_DEPRECATED(effIdentify), 0, 0, nullptr, 0.0f);
1179 effect->dispatcher(effect, DECLARE_VST_DEPRECATED(effSetBlockSizeAndSampleRate), 0, kBufferSize, nullptr, kSampleRatef);
1180 effect->dispatcher(effect, effSetSampleRate, 0, 0, nullptr, kSampleRatef);
1181 effect->dispatcher(effect, effSetBlockSize, 0, kBufferSize, nullptr, 0.0f);
1182 effect->dispatcher(effect, effSetProcessPrecision, 0, kVstProcessPrecision32, nullptr, 0.0f);
1184 effect->dispatcher(effect, effOpen, 0, 0, nullptr, 0.0f);
1186 if (effect->numPrograms > 0)
1187 effect->dispatcher(effect, effSetProgram, 0, 0, nullptr, 0.0f);
1190 // get name
1191 carla_zeroChars(strBuf, STR_MAX+1);
1193 if (effect->dispatcher(effect, effGetEffectName, 0, 0, strBuf, 0.0f) == 1)
1194 cName = strBuf;
1195 else
1196 cName.clear();
1198 // get product
1199 carla_zeroChars(strBuf, STR_MAX+1);
1201 if (effect->dispatcher(effect, effGetProductString, 0, 0, strBuf, 0.0f) == 1)
1202 cProduct = strBuf;
1203 else
1204 cProduct.clear();
1206 // get vendor
1207 carla_zeroChars(strBuf, STR_MAX+1);
1209 if (effect->dispatcher(effect, effGetVendorString, 0, 0, strBuf, 0.0f) == 1)
1210 cVendor = strBuf;
1211 else
1212 cVendor.clear();
1214 // get category
1215 switch (effect->dispatcher(effect, effGetPlugCategory, 0, 0, nullptr, 0.0f))
1217 case kPlugCategSynth:
1218 category = PLUGIN_CATEGORY_SYNTH;
1219 break;
1220 case kPlugCategAnalysis:
1221 category = PLUGIN_CATEGORY_UTILITY;
1222 break;
1223 case kPlugCategMastering:
1224 category = PLUGIN_CATEGORY_DYNAMICS;
1225 break;
1226 case kPlugCategRoomFx:
1227 category = PLUGIN_CATEGORY_DELAY;
1228 break;
1229 case kPlugCategRestoration:
1230 category = PLUGIN_CATEGORY_UTILITY;
1231 break;
1232 case kPlugCategGenerator:
1233 category = PLUGIN_CATEGORY_SYNTH;
1234 break;
1235 default:
1236 if (effect->flags & effFlagsIsSynth)
1237 category = PLUGIN_CATEGORY_SYNTH;
1238 else
1239 category = PLUGIN_CATEGORY_NONE;
1240 break;
1243 // get everything else
1244 uint hints = 0x0;
1245 uint audioIns = static_cast<uint>(std::max(0, effect->numInputs));
1246 uint audioOuts = static_cast<uint>(std::max(0, effect->numOutputs));
1247 uint midiIns = 0;
1248 uint midiOuts = 0;
1249 uint parameters = static_cast<uint>(std::max(0, effect->numParams));
1251 if (effect->flags & effFlagsHasEditor)
1253 hints |= PLUGIN_HAS_CUSTOM_UI;
1254 #ifndef BUILD_BRIDGE
1255 hints |= PLUGIN_HAS_CUSTOM_EMBED_UI;
1256 #endif
1259 if (effect->flags & effFlagsIsSynth)
1261 hints |= PLUGIN_IS_SYNTH;
1262 midiIns = 1;
1265 if (vstPluginCanDo(effect, "receiveVstEvents") || vstPluginCanDo(effect, "receiveVstMidiEvent") || (effect->flags & effFlagsIsSynth) != 0)
1266 midiIns = 1;
1268 if (vstPluginCanDo(effect, "sendVstEvents") || vstPluginCanDo(effect, "sendVstMidiEvent"))
1269 midiOuts = 1;
1271 CARLA_SAFE_ASSERT_CONTINUE(audioIns <= MAX_DISCOVERY_AUDIO_IO);
1272 CARLA_SAFE_ASSERT_CONTINUE(audioOuts <= MAX_DISCOVERY_AUDIO_IO);
1274 // -----------------------------------------------------------------------
1275 // start crash-free plugin test
1277 if (doInit)
1279 if (gVstNeedsIdle)
1280 effect->dispatcher(effect, DECLARE_VST_DEPRECATED(effIdle), 0, 0, nullptr, 0.0f);
1282 effect->dispatcher(effect, effMainsChanged, 0, 1, nullptr, 0.0f);
1283 effect->dispatcher(effect, effStartProcess, 0, 0, nullptr, 0.0f);
1285 if (gVstNeedsIdle)
1286 effect->dispatcher(effect, DECLARE_VST_DEPRECATED(effIdle), 0, 0, nullptr, 0.0f);
1288 // Plugin might call wantMidi() during resume
1289 if (midiIns == 0 && gVstWantsMidi)
1291 midiIns = 1;
1294 float* bufferAudioIn[MAX_DISCOVERY_AUDIO_IO];
1295 float* bufferAudioOut[MAX_DISCOVERY_AUDIO_IO];
1297 if (audioIns == 0)
1299 bufferAudioIn[0] = nullptr;
1301 else
1303 for (uint j=0; j < audioIns; ++j)
1305 bufferAudioIn[j] = new float[kBufferSize];
1306 carla_zeroFloats(bufferAudioIn[j], kBufferSize);
1310 if (audioOuts == 0)
1312 bufferAudioOut[0] = nullptr;
1314 else
1316 for (uint j=0; j < audioOuts; ++j)
1318 bufferAudioOut[j] = new float[kBufferSize];
1319 carla_zeroFloats(bufferAudioOut[j], kBufferSize);
1323 struct VstEventsFixed {
1324 int32_t numEvents;
1325 intptr_t reserved;
1326 VstEvent* data[2];
1328 VstEventsFixed()
1329 : numEvents(0),
1330 reserved(0)
1332 data[0] = data[1] = nullptr;
1334 } events;
1336 VstMidiEvent midiEvents[2];
1337 carla_zeroStructs(midiEvents, 2);
1339 midiEvents[0].type = kVstMidiType;
1340 midiEvents[0].byteSize = sizeof(VstMidiEvent);
1341 midiEvents[0].midiData[0] = char(MIDI_STATUS_NOTE_ON);
1342 midiEvents[0].midiData[1] = 64;
1343 midiEvents[0].midiData[2] = 100;
1345 midiEvents[1].type = kVstMidiType;
1346 midiEvents[1].byteSize = sizeof(VstMidiEvent);
1347 midiEvents[1].midiData[0] = char(MIDI_STATUS_NOTE_OFF);
1348 midiEvents[1].midiData[1] = 64;
1349 midiEvents[1].deltaFrames = kBufferSize/2;
1351 events.numEvents = 2;
1352 events.data[0] = (VstEvent*)&midiEvents[0];
1353 events.data[1] = (VstEvent*)&midiEvents[1];
1355 // processing
1356 gVstIsProcessing = true;
1358 if (midiIns > 0)
1359 effect->dispatcher(effect, effProcessEvents, 0, 0, &events, 0.0f);
1361 if ((effect->flags & effFlagsCanReplacing) > 0 && effect->processReplacing != nullptr && effect->processReplacing != effect->DECLARE_VST_DEPRECATED(process))
1362 effect->processReplacing(effect, bufferAudioIn, bufferAudioOut, kBufferSize);
1363 else if (effect->DECLARE_VST_DEPRECATED(process) != nullptr)
1364 effect->DECLARE_VST_DEPRECATED(process)(effect, bufferAudioIn, bufferAudioOut, kBufferSize);
1365 else
1366 DISCOVERY_OUT("error", "Plugin doesn't have a process function");
1368 gVstIsProcessing = false;
1370 effect->dispatcher(effect, effStopProcess, 0, 0, nullptr, 0.0f);
1371 effect->dispatcher(effect, effMainsChanged, 0, 0, nullptr, 0.0f);
1373 if (gVstNeedsIdle)
1374 effect->dispatcher(effect, DECLARE_VST_DEPRECATED(effIdle), 0, 0, nullptr, 0.0f);
1376 for (uint j=0; j < audioIns; ++j)
1377 delete[] bufferAudioIn[j];
1378 for (uint j=0; j < audioOuts; ++j)
1379 delete[] bufferAudioOut[j];
1382 // end crash-free plugin test
1383 // -----------------------------------------------------------------------
1385 DISCOVERY_OUT("init", "------------");
1386 DISCOVERY_OUT("build", BINARY_NATIVE);
1387 DISCOVERY_OUT("hints", hints);
1388 DISCOVERY_OUT("category", getPluginCategoryAsString(category));
1389 DISCOVERY_OUT("name", cName.buffer());
1390 DISCOVERY_OUT("label", cProduct.buffer());
1391 DISCOVERY_OUT("maker", cVendor.buffer());
1392 DISCOVERY_OUT("uniqueId", gVstCurrentUniqueId);
1393 DISCOVERY_OUT("audio.ins", audioIns);
1394 DISCOVERY_OUT("audio.outs", audioOuts);
1395 DISCOVERY_OUT("midi.ins", midiIns);
1396 DISCOVERY_OUT("midi.outs", midiOuts);
1397 DISCOVERY_OUT("parameters.ins", parameters);
1398 DISCOVERY_OUT("end", "------------");
1400 gVstWantsMidi = false;
1401 gVstWantsTime = false;
1403 if (! isShell)
1404 break;
1406 effect->dispatcher(effect, effClose, 0, 0, nullptr, 0.0f);
1407 effect = nullptr;
1410 uniqueIds.clear();
1412 if (effect != nullptr)
1414 if (gVstNeedsIdle)
1415 effect->dispatcher(effect, DECLARE_VST_DEPRECATED(effIdle), 0, 0, nullptr, 0.0f);
1417 effect->dispatcher(effect, effClose, 0, 0, nullptr, 0.0f);
1420 return false;
1422 #ifndef CARLA_OS_MAC
1423 // unused
1424 (void)filename;
1425 #endif
1428 // --------------------------------------------------------------------------------------------------------------------
1429 // VST3
1431 struct carla_v3_host_application : v3_host_application_cpp {
1432 carla_v3_host_application()
1434 query_interface = v3_query_interface_static<v3_host_application_iid>;
1435 ref = v3_ref_static;
1436 unref = v3_unref_static;
1437 app.get_name = carla_get_name;
1438 app.create_instance = carla_create_instance;
1441 private:
1442 static v3_result V3_API carla_get_name(void*, v3_str_128 name)
1444 static constexpr const char hostname[] = "Carla-Discovery\0";
1446 for (size_t i=0; i<sizeof(hostname); ++i)
1447 name[i] = hostname[i];
1449 return V3_OK;
1452 static v3_result V3_API carla_create_instance(void*, v3_tuid, v3_tuid, void**)
1454 return V3_NOT_IMPLEMENTED;
1457 CARLA_DECLARE_NON_COPYABLE(carla_v3_host_application)
1458 CARLA_PREVENT_HEAP_ALLOCATION
1461 struct carla_v3_param_value_queue : v3_param_value_queue_cpp {
1462 carla_v3_param_value_queue()
1464 query_interface = v3_query_interface_static<v3_param_value_queue_iid>;
1465 ref = v3_ref_static;
1466 unref = v3_unref_static;
1467 queue.get_param_id = carla_get_param_id;
1468 queue.get_point_count = carla_get_point_count;
1469 queue.get_point = carla_get_point;
1470 queue.add_point = carla_add_point;
1473 private:
1474 static v3_param_id V3_API carla_get_param_id(void*) { return 0; }
1475 static int32_t V3_API carla_get_point_count(void*) { return 0; }
1476 static v3_result V3_API carla_get_point(void*, int32_t, int32_t*, double*) { return V3_NOT_IMPLEMENTED; }
1477 static v3_result V3_API carla_add_point(void*, int32_t, double, int32_t*) { return V3_NOT_IMPLEMENTED; }
1479 CARLA_DECLARE_NON_COPYABLE(carla_v3_param_value_queue)
1480 CARLA_PREVENT_HEAP_ALLOCATION
1483 struct carla_v3_param_changes : v3_param_changes_cpp {
1484 carla_v3_param_changes()
1486 query_interface = v3_query_interface_static<v3_param_changes_iid>;
1487 ref = v3_ref_static;
1488 unref = v3_unref_static;
1489 changes.get_param_count = carla_get_param_count;
1490 changes.get_param_data = carla_get_param_data;
1491 changes.add_param_data = carla_add_param_data;
1494 private:
1495 static int32_t V3_API carla_get_param_count(void*) { return 0; }
1496 static v3_param_value_queue** V3_API carla_get_param_data(void*, int32_t) { return nullptr; }
1497 static v3_param_value_queue** V3_API carla_add_param_data(void*, const v3_param_id*, int32_t*) { return nullptr; }
1499 CARLA_DECLARE_NON_COPYABLE(carla_v3_param_changes)
1500 CARLA_PREVENT_HEAP_ALLOCATION
1503 struct carla_v3_event_list : v3_event_list_cpp {
1504 carla_v3_event_list()
1506 query_interface = v3_query_interface_static<v3_event_list_iid>;
1507 ref = v3_ref_static;
1508 unref = v3_unref_static;
1509 list.get_event_count = carla_get_event_count;
1510 list.get_event = carla_get_event;
1511 list.add_event = carla_add_event;
1514 private:
1515 static uint32_t V3_API carla_get_event_count(void*) { return 0; }
1516 static v3_result V3_API carla_get_event(void*, int32_t, v3_event*) { return V3_NOT_IMPLEMENTED; }
1517 static v3_result V3_API carla_add_event(void*, v3_event*) { return V3_NOT_IMPLEMENTED; }
1519 CARLA_DECLARE_NON_COPYABLE(carla_v3_event_list)
1520 CARLA_PREVENT_HEAP_ALLOCATION
1523 static bool v3_exit_false(const V3_EXITFN v3_exit)
1525 v3_exit();
1526 return false;
1529 static bool do_vst3_check(lib_t& libHandle, const char* const filename, const bool doInit)
1531 V3_ENTRYFN v3_entry = nullptr;
1532 V3_EXITFN v3_exit = nullptr;
1533 V3_GETFN v3_get = nullptr;
1535 #ifdef CARLA_OS_MAC
1536 BundleLoader bundleLoader;
1537 #endif
1539 // if passed filename is not a plugin binary directly, inspect bundle and find one
1540 if (libHandle == nullptr)
1542 #ifdef CARLA_OS_MAC
1543 if (! bundleLoader.load(filename))
1545 #ifdef __aarch64__
1546 return true;
1547 #else
1548 DISCOVERY_OUT("error", "Failed to load VST3 bundle executable");
1549 return false;
1550 #endif
1553 v3_entry = bundleLoader.getSymbol<V3_ENTRYFN>(CFSTR(V3_ENTRYFNNAME));
1554 v3_exit = bundleLoader.getSymbol<V3_EXITFN>(CFSTR(V3_EXITFNNAME));
1555 v3_get = bundleLoader.getSymbol<V3_GETFN>(CFSTR(V3_GETFNNAME));
1556 #else
1557 water::String binaryfilename = filename;
1559 if (!binaryfilename.endsWithChar(CARLA_OS_SEP))
1560 binaryfilename += CARLA_OS_SEP_STR;
1562 binaryfilename += "Contents" CARLA_OS_SEP_STR V3_CONTENT_DIR CARLA_OS_SEP_STR;
1563 binaryfilename += water::File(filename).getFileNameWithoutExtension();
1564 #ifdef CARLA_OS_WIN
1565 binaryfilename += ".vst3";
1566 #else
1567 binaryfilename += ".so";
1568 #endif
1570 if (! water::File(binaryfilename).existsAsFile())
1572 DISCOVERY_OUT("error", "Failed to find a suitable VST3 bundle binary");
1573 return false;
1576 libHandle = lib_open(binaryfilename.toRawUTF8());
1578 if (libHandle == nullptr)
1580 print_lib_error(filename);
1581 return false;
1583 #endif
1586 #ifndef CARLA_OS_MAC
1587 v3_entry = lib_symbol<V3_ENTRYFN>(libHandle, V3_ENTRYFNNAME);
1588 v3_exit = lib_symbol<V3_EXITFN>(libHandle, V3_EXITFNNAME);
1589 v3_get = lib_symbol<V3_GETFN>(libHandle, V3_GETFNNAME);
1590 #endif
1592 // ensure entry and exit points are available
1593 if (v3_entry == nullptr || v3_exit == nullptr || v3_get == nullptr)
1595 DISCOVERY_OUT("error", "Not a VST3 plugin");
1596 return false;
1599 // call entry point
1600 #if defined(CARLA_OS_MAC)
1601 v3_entry(bundleLoader.getRef());
1602 #elif defined(CARLA_OS_WIN)
1603 v3_entry();
1604 #else
1605 v3_entry(libHandle);
1606 #endif
1608 carla_v3_host_application hostApplication;
1609 carla_v3_host_application* hostApplicationPtr = &hostApplication;
1610 v3_funknown** const hostContext = (v3_funknown**)&hostApplicationPtr;
1612 // fetch initial factory
1613 v3_plugin_factory** factory1 = v3_get();
1614 CARLA_SAFE_ASSERT_RETURN(factory1 != nullptr, v3_exit_false(v3_exit));
1616 // get factory info
1617 v3_factory_info factoryInfo = {};
1618 CARLA_SAFE_ASSERT_RETURN(v3_cpp_obj(factory1)->get_factory_info(factory1, &factoryInfo) == V3_OK,
1619 v3_exit_false(v3_exit));
1621 // get num classes
1622 const int32_t numClasses = v3_cpp_obj(factory1)->num_classes(factory1);
1623 CARLA_SAFE_ASSERT_RETURN(numClasses > 0, v3_exit_false(v3_exit));
1625 // query 2nd factory
1626 v3_plugin_factory_2** factory2 = nullptr;
1627 if (v3_cpp_obj_query_interface(factory1, v3_plugin_factory_2_iid, &factory2) == V3_OK)
1629 CARLA_SAFE_ASSERT_RETURN(factory2 != nullptr, v3_exit_false(v3_exit));
1631 else
1633 CARLA_SAFE_ASSERT(factory2 == nullptr);
1634 factory2 = nullptr;
1637 // query 3rd factory
1638 v3_plugin_factory_3** factory3 = nullptr;
1639 if (factory2 != nullptr && v3_cpp_obj_query_interface(factory2, v3_plugin_factory_3_iid, &factory3) == V3_OK)
1641 CARLA_SAFE_ASSERT_RETURN(factory3 != nullptr, v3_exit_false(v3_exit));
1643 else
1645 CARLA_SAFE_ASSERT(factory3 == nullptr);
1646 factory3 = nullptr;
1649 // set host context (application) if 3rd factory provided
1650 if (factory3 != nullptr)
1651 v3_cpp_obj(factory3)->set_host_context(factory3, hostContext);
1653 // go through all relevant classes
1654 for (int32_t i=0; i<numClasses; ++i)
1656 v3_result res;
1658 // v3_class_info_2 is ABI compatible with v3_class_info
1659 union {
1660 v3_class_info v1;
1661 v3_class_info_2 v2;
1662 } classInfo = {};
1664 if (factory2 != nullptr)
1665 v3_cpp_obj(factory2)->get_class_info_2(factory2, i, &classInfo.v2);
1666 else
1667 v3_cpp_obj(factory1)->get_class_info(factory1, i, &classInfo.v1);
1669 // safety check
1670 CARLA_SAFE_ASSERT_CONTINUE(classInfo.v1.cardinality == 0x7FFFFFFF);
1672 // only check for audio plugins
1673 if (std::strcmp(classInfo.v1.category, "Audio Module Class") != 0)
1674 continue;
1676 // create instance
1677 void* instance = nullptr;
1678 res = v3_cpp_obj(factory1)->create_instance(factory1, classInfo.v1.class_id, v3_component_iid, &instance);
1679 CARLA_SAFE_ASSERT_INT_CONTINUE(res == V3_OK, res);
1680 CARLA_SAFE_ASSERT_CONTINUE(instance != nullptr);
1682 // initialize instance
1683 v3_component** const component = static_cast<v3_component**>(instance);
1685 res = v3_cpp_obj_initialize(component, hostContext);
1686 CARLA_SAFE_ASSERT_INT_CONTINUE(res == V3_OK, res);
1688 // create edit controller
1689 v3_edit_controller** controller = nullptr;
1690 bool shouldTerminateController;
1691 if (v3_cpp_obj_query_interface(component, v3_edit_controller_iid, &controller) != V3_OK)
1692 controller = nullptr;
1694 if (controller != nullptr)
1696 // got edit controller from casting component, assume they belong to the same object
1697 shouldTerminateController = false;
1699 else
1701 // try to create edit controller from factory
1702 v3_tuid uid = {};
1703 if (v3_cpp_obj(component)->get_controller_class_id(component, uid) == V3_OK)
1705 instance = nullptr;
1706 if (v3_cpp_obj(factory1)->create_instance(factory1, uid, v3_edit_controller_iid, &instance) == V3_OK)
1707 controller = static_cast<v3_edit_controller**>(instance);
1710 if (controller == nullptr)
1712 DISCOVERY_OUT("warning", "Plugin '" << classInfo.v1.name << "' does not have an edit controller");
1713 v3_cpp_obj_terminate(component);
1714 v3_cpp_obj_unref(component);
1715 continue;
1718 // component is separate from controller, needs its dedicated initialize and terminate
1719 shouldTerminateController = true;
1720 v3_cpp_obj_initialize(controller, hostContext);
1723 // connect component to controller
1724 v3_connection_point** connComponent = nullptr;
1725 if (v3_cpp_obj_query_interface(component, v3_connection_point_iid, &connComponent) != V3_OK)
1726 connComponent = nullptr;
1728 v3_connection_point** connController = nullptr;
1729 if (v3_cpp_obj_query_interface(controller, v3_connection_point_iid, &connController) != V3_OK)
1730 connController = nullptr;
1732 if (connComponent != nullptr && connController != nullptr)
1734 v3_cpp_obj(connComponent)->connect(connComponent, connController);
1735 v3_cpp_obj(connController)->connect(connController, connComponent);
1738 // fill in all the details
1739 uint hints = 0x0;
1740 int audioIns = 0;
1741 int audioOuts = 0;
1742 int cvIns = 0;
1743 int cvOuts = 0;
1744 int parameterIns = 0;
1745 int parameterOuts = 0;
1747 const int32_t numAudioInputBuses = v3_cpp_obj(component)->get_bus_count(component, V3_AUDIO, V3_INPUT);
1748 const int32_t numEventInputBuses = v3_cpp_obj(component)->get_bus_count(component, V3_EVENT, V3_INPUT);
1749 const int32_t numAudioOutputBuses = v3_cpp_obj(component)->get_bus_count(component, V3_AUDIO, V3_OUTPUT);
1750 const int32_t numEventOutputBuses = v3_cpp_obj(component)->get_bus_count(component, V3_EVENT, V3_OUTPUT);
1751 const int32_t numParameters = v3_cpp_obj(controller)->get_parameter_count(controller);
1753 CARLA_SAFE_ASSERT(numAudioInputBuses >= 0);
1754 CARLA_SAFE_ASSERT(numEventInputBuses >= 0);
1755 CARLA_SAFE_ASSERT(numAudioOutputBuses >= 0);
1756 CARLA_SAFE_ASSERT(numEventOutputBuses >= 0);
1757 CARLA_SAFE_ASSERT(numParameters >= 0);
1759 for (int32_t b=0; b<numAudioInputBuses; ++b)
1761 v3_bus_info busInfo = {};
1762 res = v3_cpp_obj(component)->get_bus_info(component, V3_AUDIO, V3_INPUT, b, &busInfo);
1763 CARLA_SAFE_ASSERT_INT_BREAK(res == V3_OK, res);
1765 if (busInfo.flags & V3_IS_CONTROL_VOLTAGE)
1766 cvIns += busInfo.channel_count;
1767 else
1768 audioIns += busInfo.channel_count;
1771 for (int32_t b=0; b<numAudioOutputBuses; ++b)
1773 v3_bus_info busInfo = {};
1774 res = v3_cpp_obj(component)->get_bus_info(component, V3_AUDIO, V3_OUTPUT, b, &busInfo);
1775 CARLA_SAFE_ASSERT_INT_BREAK(res == V3_OK, res);
1777 if (busInfo.flags & V3_IS_CONTROL_VOLTAGE)
1778 cvOuts += busInfo.channel_count;
1779 else
1780 audioOuts += busInfo.channel_count;
1783 for (int32_t p=0; p<numParameters; ++p)
1785 v3_param_info paramInfo = {};
1786 res = v3_cpp_obj(controller)->get_parameter_info(controller, p, &paramInfo);
1787 CARLA_SAFE_ASSERT_INT_BREAK(res == V3_OK, res);
1789 if (paramInfo.flags & (V3_PARAM_IS_BYPASS|V3_PARAM_IS_HIDDEN|V3_PARAM_PROGRAM_CHANGE))
1790 continue;
1792 if (paramInfo.flags & V3_PARAM_READ_ONLY)
1793 ++parameterOuts;
1794 else
1795 ++parameterIns;
1798 CARLA_SAFE_ASSERT_CONTINUE(audioIns <= MAX_DISCOVERY_AUDIO_IO);
1799 CARLA_SAFE_ASSERT_CONTINUE(audioOuts <= MAX_DISCOVERY_AUDIO_IO);
1800 CARLA_SAFE_ASSERT_CONTINUE(cvIns <= MAX_DISCOVERY_CV_IO);
1801 CARLA_SAFE_ASSERT_CONTINUE(cvOuts <= MAX_DISCOVERY_CV_IO);
1803 #ifdef V3_VIEW_PLATFORM_TYPE_NATIVE
1804 if (v3_plugin_view** const view = v3_cpp_obj(controller)->create_view(controller, "editor"))
1806 if (v3_cpp_obj(view)->is_platform_type_supported(view, V3_VIEW_PLATFORM_TYPE_NATIVE) == V3_TRUE)
1808 hints |= PLUGIN_HAS_CUSTOM_UI;
1809 #ifndef BUILD_BRIDGE
1810 hints |= PLUGIN_HAS_CUSTOM_EMBED_UI;
1811 #endif
1814 v3_cpp_obj_unref(view);
1816 #endif
1818 if (factory2 != nullptr && std::strstr(classInfo.v2.sub_categories, "Instrument") != nullptr)
1819 hints |= PLUGIN_IS_SYNTH;
1821 if (doInit)
1823 v3_audio_processor** processor = nullptr;
1824 v3_process_setup setup = { V3_REALTIME, V3_SAMPLE_32, kBufferSize, kSampleRate };
1826 res = v3_cpp_obj_query_interface(component, v3_audio_processor_iid, &processor);
1827 CARLA_SAFE_ASSERT_INT_BREAK(res == V3_OK, res);
1828 CARLA_SAFE_ASSERT_BREAK(processor != nullptr);
1830 res = v3_cpp_obj(processor)->can_process_sample_size(processor, V3_SAMPLE_32);
1831 CARLA_SAFE_ASSERT_INT_BREAK(res == V3_OK, res);
1833 res = v3_cpp_obj(component)->set_active(component, true);
1834 CARLA_SAFE_ASSERT_INT_BREAK(res == V3_OK, res);
1836 res = v3_cpp_obj(processor)->setup_processing(processor, &setup);
1837 CARLA_SAFE_ASSERT_INT_BREAK(res == V3_OK, res);
1839 res = v3_cpp_obj(component)->set_active(component, false);
1840 CARLA_SAFE_ASSERT_INT_BREAK(res == V3_OK, res);
1842 v3_audio_bus_buffers* const inputsBuffers = numAudioInputBuses > 0
1843 ? new v3_audio_bus_buffers[numAudioInputBuses]
1844 : nullptr;
1846 v3_audio_bus_buffers* const outputsBuffers = numAudioOutputBuses > 0
1847 ? new v3_audio_bus_buffers[numAudioOutputBuses]
1848 : nullptr;
1850 for (int32_t b=0; b<numAudioInputBuses; ++b)
1852 v3_bus_info busInfo = {};
1853 carla_zeroStruct(inputsBuffers[b]);
1855 res = v3_cpp_obj(component)->get_bus_info(component, V3_AUDIO, V3_INPUT, b, &busInfo);
1856 CARLA_SAFE_ASSERT_INT_BREAK(res == V3_OK, res);
1858 res = v3_cpp_obj(component)->activate_bus(component, V3_AUDIO, V3_INPUT, b, true);
1859 CARLA_SAFE_ASSERT_INT_BREAK(res == V3_OK, res);
1861 inputsBuffers[b].num_channels = busInfo.channel_count;
1864 for (int32_t b=0; b<numAudioOutputBuses; ++b)
1866 v3_bus_info busInfo = {};
1867 carla_zeroStruct(outputsBuffers[b]);
1869 res = v3_cpp_obj(component)->get_bus_info(component, V3_AUDIO, V3_OUTPUT, b, &busInfo);
1870 CARLA_SAFE_ASSERT_INT_BREAK(res == V3_OK, res);
1872 res = v3_cpp_obj(component)->activate_bus(component, V3_AUDIO, V3_OUTPUT, b, true);
1873 CARLA_SAFE_ASSERT_INT_BREAK(res == V3_OK, res);
1875 outputsBuffers[b].num_channels = busInfo.channel_count;
1878 res = v3_cpp_obj(component)->set_active(component, true);
1879 CARLA_SAFE_ASSERT_INT_BREAK(res == V3_OK, res);
1881 res = v3_cpp_obj(processor)->set_processing(processor, true);
1882 CARLA_SAFE_ASSERT_INT_BREAK(res == V3_OK || res == V3_NOT_IMPLEMENTED, res);
1884 float* bufferAudioIn[MAX_DISCOVERY_AUDIO_IO + MAX_DISCOVERY_CV_IO];
1885 float* bufferAudioOut[MAX_DISCOVERY_AUDIO_IO + MAX_DISCOVERY_CV_IO];
1887 for (int j=0; j < audioIns + cvIns; ++j)
1889 bufferAudioIn[j] = new float[kBufferSize];
1890 carla_zeroFloats(bufferAudioIn[j], kBufferSize);
1893 for (int j=0; j < audioOuts + cvOuts; ++j)
1895 bufferAudioOut[j] = new float[kBufferSize];
1896 carla_zeroFloats(bufferAudioOut[j], kBufferSize);
1899 for (int32_t b = 0, j = 0; b < numAudioInputBuses; ++b)
1901 inputsBuffers[b].channel_buffers_32 = bufferAudioIn + j;
1902 j += inputsBuffers[b].num_channels;
1905 for (int32_t b = 0, j = 0; b < numAudioOutputBuses; ++b)
1907 outputsBuffers[b].channel_buffers_32 = bufferAudioOut + j;
1908 j += outputsBuffers[b].num_channels;
1911 carla_v3_event_list eventList;
1912 carla_v3_event_list* eventListPtr = &eventList;
1914 carla_v3_param_changes paramChanges;
1915 carla_v3_param_changes* paramChangesPtr = &paramChanges;
1917 v3_process_context processContext = {};
1918 processContext.sample_rate = kSampleRate;
1920 v3_process_data processData = {
1921 V3_REALTIME,
1922 V3_SAMPLE_32,
1923 kBufferSize,
1924 numAudioInputBuses,
1925 numAudioOutputBuses,
1926 inputsBuffers,
1927 outputsBuffers,
1928 (v3_param_changes**)&paramChangesPtr,
1929 (v3_param_changes**)&paramChangesPtr,
1930 (v3_event_list**)&eventListPtr,
1931 (v3_event_list**)&eventListPtr,
1932 &processContext
1934 res = v3_cpp_obj(processor)->process(processor, &processData);
1935 CARLA_SAFE_ASSERT_INT_BREAK(res == V3_OK, res);
1937 delete[] inputsBuffers;
1938 delete[] outputsBuffers;
1940 for (int j=0; j < audioIns + cvIns; ++j)
1941 delete[] bufferAudioIn[j];
1942 for (int j=0; j < audioOuts + cvOuts; ++j)
1943 delete[] bufferAudioOut[j];
1945 res = v3_cpp_obj(processor)->set_processing(processor, false);
1946 CARLA_SAFE_ASSERT_INT_BREAK(res == V3_OK || res == V3_NOT_IMPLEMENTED, res);
1948 res = v3_cpp_obj(component)->set_active(component, false);
1949 CARLA_SAFE_ASSERT_INT_BREAK(res == V3_OK, res);
1951 v3_cpp_obj_unref(processor);
1954 // disconnect and unref connection points
1955 if (connComponent != nullptr && connController != nullptr)
1957 v3_cpp_obj(connComponent)->disconnect(connComponent, connController);
1958 v3_cpp_obj(connController)->disconnect(connController, connComponent);
1961 if (connComponent != nullptr)
1962 v3_cpp_obj_unref(connComponent);
1964 if (connController != nullptr)
1965 v3_cpp_obj_unref(connController);
1967 if (shouldTerminateController)
1968 v3_cpp_obj_terminate(controller);
1970 v3_cpp_obj_unref(controller);
1972 v3_cpp_obj_terminate(component);
1973 v3_cpp_obj_unref(component);
1975 DISCOVERY_OUT("init", "------------");
1976 DISCOVERY_OUT("build", BINARY_NATIVE);
1977 DISCOVERY_OUT("hints", hints);
1978 DISCOVERY_OUT("category", getPluginCategoryAsString(factory2 != nullptr ? getPluginCategoryFromV3SubCategories(classInfo.v2.sub_categories)
1979 : getPluginCategoryFromName(classInfo.v1.name)));
1980 DISCOVERY_OUT("name", classInfo.v1.name);
1981 DISCOVERY_OUT("label", tuid2str(classInfo.v1.class_id));
1982 DISCOVERY_OUT("maker", (factory2 != nullptr ? classInfo.v2.vendor : factoryInfo.vendor));
1983 DISCOVERY_OUT("audio.ins", audioIns);
1984 DISCOVERY_OUT("audio.outs", audioOuts);
1985 DISCOVERY_OUT("cv.ins", cvIns);
1986 DISCOVERY_OUT("cv.outs", cvOuts);
1987 DISCOVERY_OUT("midi.ins", numEventInputBuses);
1988 DISCOVERY_OUT("midi.outs", numEventOutputBuses);
1989 DISCOVERY_OUT("parameters.ins", parameterIns);
1990 DISCOVERY_OUT("parameters.outs", parameterOuts);
1991 DISCOVERY_OUT("end", "------------");
1994 // unref interfaces
1995 if (factory3 != nullptr)
1996 v3_cpp_obj_unref(factory3);
1998 if (factory2 != nullptr)
1999 v3_cpp_obj_unref(factory2);
2001 v3_cpp_obj_unref(factory1);
2003 v3_exit();
2004 return false;
2007 // --------------------------------------------------------------------------------------------------------------------
2008 // AU
2010 #ifdef CARLA_OS_MAC
2011 typedef AudioComponentPlugInInterface* (*FactoryFn)(const AudioComponentDescription*);
2013 typedef OSStatus (*InitializeFn)(void*);
2014 typedef OSStatus (*UninitializeFn)(void*);
2015 typedef OSStatus (*GetPropertyInfoFn)(void*, AudioUnitPropertyID, AudioUnitScope, AudioUnitElement, UInt32*, Boolean*);
2016 typedef OSStatus (*GetPropertyFn)(void*, AudioUnitPropertyID, AudioUnitScope, AudioUnitElement, void*, UInt32*);
2017 typedef OSStatus (*MIDIEventFn)(void*, UInt32, UInt32, UInt32, UInt32);
2019 static constexpr FourCharCode getFourCharCodeFromString(const char str[4])
2021 return (str[0] << 24) + (str[1] << 16) + (str[2] << 8) + str[3];
2024 static bool do_au_check(const char* const filename, const bool doInit)
2026 BundleLoader bundleLoader;
2028 if (! bundleLoader.load(filename))
2030 #ifdef __aarch64__
2031 return true;
2032 #else
2033 DISCOVERY_OUT("error", "Failed to load AU bundle executable");
2034 return false;
2035 #endif
2038 const CFTypeRef componentsRef = CFBundleGetValueForInfoDictionaryKey(bundleLoader.getRef(), CFSTR("AudioComponents"));
2040 if (componentsRef == nullptr || CFGetTypeID(componentsRef) != CFArrayGetTypeID())
2042 DISCOVERY_OUT("error", "Not an AU component");
2043 return false;
2046 const CFArrayRef components = static_cast<CFArrayRef>(componentsRef);
2048 for (uint32_t c = 0, count = CFArrayGetCount(components); c < count; ++c)
2050 const CFTypeRef componentRef = CFArrayGetValueAtIndex(components, c);
2051 CARLA_SAFE_ASSERT_CONTINUE(componentRef != nullptr);
2052 CARLA_SAFE_ASSERT_CONTINUE(CFGetTypeID(componentRef) == CFDictionaryGetTypeID());
2054 const CFDictionaryRef component = static_cast<CFDictionaryRef>(componentRef);
2056 CFStringRef componentName = nullptr;
2057 CARLA_SAFE_ASSERT_CONTINUE(CFDictionaryGetValueIfPresent(component, CFSTR("name"), (const void **)&componentName));
2059 CFStringRef componentFactoryFunction = nullptr;
2060 CARLA_SAFE_ASSERT_CONTINUE(CFDictionaryGetValueIfPresent(component, CFSTR("factoryFunction"), (const void **)&componentFactoryFunction));
2062 CFStringRef componentType = nullptr;
2063 CARLA_SAFE_ASSERT_CONTINUE(CFDictionaryGetValueIfPresent(component, CFSTR("type"), (const void **)&componentType));
2064 CARLA_SAFE_ASSERT_CONTINUE(CFStringGetLength(componentType) == 4);
2066 CFStringRef componentSubType = nullptr;
2067 CARLA_SAFE_ASSERT_CONTINUE(CFDictionaryGetValueIfPresent(component, CFSTR("subtype"), (const void **)&componentSubType));
2068 CARLA_SAFE_ASSERT_CONTINUE(CFStringGetLength(componentSubType) == 4);
2070 CFStringRef componentManufacturer = nullptr;
2071 CARLA_SAFE_ASSERT_CONTINUE(CFDictionaryGetValueIfPresent(component, CFSTR("manufacturer"), (const void **)&componentManufacturer));
2072 CARLA_SAFE_ASSERT_CONTINUE(CFStringGetLength(componentManufacturer) == 4);
2074 const FactoryFn factoryFn = bundleLoader.getSymbol<FactoryFn>(componentFactoryFunction);
2075 CARLA_SAFE_ASSERT_CONTINUE(factoryFn != nullptr);
2077 char label[15] = {};
2078 CFStringGetCString(componentType, label, 5, kCFStringEncodingASCII);
2079 CFStringGetCString(componentSubType, label + 5, 5, kCFStringEncodingASCII);
2080 CFStringGetCString(componentManufacturer, label + 10, 5, kCFStringEncodingASCII);
2082 const AudioComponentDescription desc = {
2083 getFourCharCodeFromString(label),
2084 getFourCharCodeFromString(label + 5),
2085 getFourCharCodeFromString(label + 10),
2086 0, 0
2089 CARLA_SAFE_ASSERT_CONTINUE(desc.componentType != 0);
2090 CARLA_SAFE_ASSERT_CONTINUE(desc.componentSubType != 0);
2091 CARLA_SAFE_ASSERT_CONTINUE(desc.componentManufacturer != 0);
2093 label[4] = label[9] = ',';
2095 AudioComponentPlugInInterface* const interface = factoryFn(&desc);
2096 CARLA_SAFE_ASSERT_CONTINUE(interface != nullptr);
2098 const InitializeFn auInitialize = (InitializeFn)interface->Lookup(kAudioUnitInitializeSelect);
2099 const UninitializeFn auUninitialize = (UninitializeFn)interface->Lookup(kAudioUnitUninitializeSelect);
2100 const GetPropertyInfoFn auGetPropertyInfo = (GetPropertyInfoFn)interface->Lookup(kAudioUnitGetPropertyInfoSelect);
2101 const GetPropertyFn auGetProperty = (GetPropertyFn)interface->Lookup(kAudioUnitGetPropertySelect);
2102 const MIDIEventFn auMIDIEvent = (MIDIEventFn)interface->Lookup(kMusicDeviceMIDIEventSelect);
2104 if (auInitialize == nullptr || auUninitialize == nullptr)
2105 continue;
2106 if (auGetPropertyInfo == nullptr || auGetProperty == nullptr)
2107 continue;
2109 if (interface->Open(interface, (AudioUnit)(void*)0x1) == noErr)
2111 uint hints = 0x0;
2112 uint audioIns = 0;
2113 uint audioOuts = 0;
2114 uint midiIns = 0;
2115 uint midiOuts = 0;
2116 uint parametersIns = 0;
2117 uint parametersOuts = 0;
2118 PluginCategory category;
2120 switch (desc.componentType)
2122 case kAudioUnitType_Effect:
2123 case kAudioUnitType_MusicEffect:
2124 category = PLUGIN_CATEGORY_NONE;
2125 break;
2126 case kAudioUnitType_Generator:
2127 case kAudioUnitType_MusicDevice:
2128 category = PLUGIN_CATEGORY_SYNTH;
2129 break;
2130 case kAudioUnitType_MIDIProcessor:
2131 case kAudioUnitType_Mixer:
2132 case kAudioUnitType_Panner:
2133 case kAudioUnitType_SpeechSynthesizer:
2134 category = PLUGIN_CATEGORY_UTILITY;
2135 break;
2136 case kAudioUnitType_FormatConverter:
2137 case kAudioUnitType_OfflineEffect:
2138 case kAudioUnitType_Output:
2139 category = PLUGIN_CATEGORY_OTHER;
2140 break;
2141 default:
2142 category = PLUGIN_CATEGORY_NONE;
2143 break;
2146 UInt32 outDataSize;
2147 Boolean outWritable = false;
2149 // audio port count
2150 outDataSize = 0;
2151 if (auGetPropertyInfo(interface, kAudioUnitProperty_SupportedNumChannels, kAudioUnitScope_Global, 0, &outDataSize, &outWritable) == noErr && outDataSize != 0 && outDataSize % sizeof(AUChannelInfo) == 0)
2153 const uint32_t numChannels = outDataSize / sizeof(AUChannelInfo);
2154 AUChannelInfo* const channelInfo = new AUChannelInfo[numChannels];
2156 if (auGetProperty(interface, kAudioUnitProperty_SupportedNumChannels, kAudioUnitScope_Global, 0, channelInfo, &outDataSize) == noErr && outDataSize == numChannels * sizeof(AUChannelInfo))
2158 AUChannelInfo* highestInfo = &channelInfo[0];
2160 for (uint32_t i=1; i<numChannels; ++i)
2162 if (channelInfo[i].inChannels > highestInfo->inChannels && channelInfo[i].outChannels > highestInfo->outChannels)
2163 highestInfo = &channelInfo[i];
2166 audioIns = highestInfo->inChannels;
2167 audioOuts = highestInfo->outChannels;
2171 // parameter count
2172 outDataSize = 0;
2173 if (auGetPropertyInfo(interface, kAudioUnitProperty_ParameterList, kAudioUnitScope_Global, 0, &outDataSize, &outWritable) == noErr && outDataSize != 0 && outDataSize % sizeof(AudioUnitParameterID) == 0)
2175 const uint32_t numParams = outDataSize / sizeof(AudioUnitParameterID);
2176 AudioUnitParameterID* const paramIds = new AudioUnitParameterID[numParams];
2178 if (auGetProperty(interface, kAudioUnitProperty_ParameterList, kAudioUnitScope_Global, 0, paramIds, &outDataSize) == noErr && outDataSize == numParams * sizeof(AudioUnitParameterID))
2180 AudioUnitParameterInfo info;
2182 for (uint32_t i=0; i<numParams; ++i)
2184 carla_zeroStruct(info);
2186 outDataSize = 0;
2187 if (auGetPropertyInfo(interface, kAudioUnitProperty_ParameterInfo, kAudioUnitScope_Global, paramIds[i], &outDataSize, &outWritable) != noErr)
2188 break;
2189 if (outDataSize != sizeof(AudioUnitParameterInfo))
2190 break;
2191 if (auGetProperty(interface, kAudioUnitProperty_ParameterInfo, kAudioUnitScope_Global, paramIds[i], &info, &outDataSize) != noErr)
2192 break;
2194 if ((info.flags & kAudioUnitParameterFlag_IsReadable) == 0)
2195 continue;
2197 if (info.flags & kAudioUnitParameterFlag_IsWritable)
2198 ++parametersIns;
2199 else
2200 ++parametersOuts;
2204 delete[] paramIds;
2207 // MIDI input
2208 if (auMIDIEvent != nullptr && auInitialize(interface) == noErr)
2210 if (auMIDIEvent(interface, 0x90, 60, 64, 0) == noErr)
2211 midiIns = 1;
2213 auUninitialize(interface);
2216 // MIDI output
2217 outDataSize = 0;
2218 outWritable = false;
2219 if (auGetPropertyInfo(interface, kAudioUnitProperty_MIDIOutputCallback, kAudioUnitScope_Global, 0, &outDataSize, &outWritable) == noErr && outDataSize == sizeof(AUMIDIOutputCallbackStruct) && outWritable)
2220 midiOuts = 1;
2222 // hints
2223 if (category == PLUGIN_CATEGORY_SYNTH)
2224 hints |= PLUGIN_IS_SYNTH;
2226 outDataSize = 0;
2227 if (auGetPropertyInfo(interface, kAudioUnitProperty_CocoaUI, kAudioUnitScope_Global, 0, &outDataSize, &outWritable) == noErr && outDataSize == sizeof(AudioUnitCocoaViewInfo))
2229 hints |= PLUGIN_HAS_CUSTOM_UI;
2230 #ifndef BUILD_BRIDGE
2231 /* FIXME only enable this after doing custom AU hosting
2232 hints |= PLUGIN_HAS_CUSTOM_EMBED_UI;
2234 #endif
2237 if (doInit)
2239 // test valid scopes
2240 outDataSize = 0;
2241 if (auGetPropertyInfo(interface, kAudioUnitProperty_ElementCount, kAudioUnitScope_Input, 0, &outDataSize, &outWritable) == noErr && outDataSize == sizeof(UInt32))
2243 UInt32 count = 0;
2244 if (auGetProperty(interface, kAudioUnitProperty_ElementCount, kAudioUnitScope_Input, 0, &count, &outDataSize) == noErr && outDataSize == sizeof(UInt32) && count != 0)
2249 // TODO
2252 const CFIndex componentNameLen = CFStringGetLength(componentName);
2253 char* const nameBuffer = new char[componentNameLen + 1];
2254 const char* name;
2255 const char* maker;
2257 if (CFStringGetCString(componentName, nameBuffer, componentNameLen + 1, kCFStringEncodingUTF8))
2259 if (char* const sep = std::strstr(nameBuffer, ": "))
2261 sep[0] = sep[1] = '\0';
2262 name = sep + 2;
2263 maker = nameBuffer;
2265 else
2267 name = nameBuffer;
2268 maker = nameBuffer + componentNameLen;
2271 else
2273 nameBuffer[0] = '\0';
2274 name = maker = nameBuffer;
2277 interface->Close(interface);
2279 DISCOVERY_OUT("init", "------------");
2280 DISCOVERY_OUT("build", BINARY_NATIVE);
2281 DISCOVERY_OUT("hints", hints);
2282 DISCOVERY_OUT("category", getPluginCategoryAsString(category));
2283 DISCOVERY_OUT("name", name);
2284 DISCOVERY_OUT("label", label);
2285 DISCOVERY_OUT("maker", maker);
2286 DISCOVERY_OUT("audio.ins", audioIns);
2287 DISCOVERY_OUT("audio.outs", audioOuts);
2288 DISCOVERY_OUT("midi.ins", midiIns);
2289 DISCOVERY_OUT("midi.outs", midiOuts);
2290 DISCOVERY_OUT("parameters.ins", parametersIns);
2291 DISCOVERY_OUT("parameters.outs", parametersOuts);
2292 DISCOVERY_OUT("end", "------------");
2294 delete[] nameBuffer;
2298 return false;
2300 #endif // CARLA_OS_MAC
2302 // --------------------------------------------------------------------------------------------------------------------
2303 // CLAP
2305 struct carla_clap_host : clap_host_t {
2306 carla_clap_host()
2308 clap_version = CLAP_VERSION;
2309 host_data = this;
2310 name = "Carla-Discovery";
2311 vendor = "falkTX";
2312 url = "https://kx.studio/carla";
2313 version = CARLA_VERSION_STRING;
2314 get_extension = carla_get_extension;
2315 request_restart = carla_request_restart;
2316 request_process = carla_request_process;
2317 request_callback = carla_request_callback;
2320 private:
2321 static const void* CLAP_ABI carla_get_extension(const clap_host_t* const host, const char* const extension_id)
2323 carla_stdout("carla_get_extension %p %s", host, extension_id);
2324 return nullptr;
2327 static void CLAP_ABI carla_request_restart(const clap_host_t* const host)
2329 carla_stdout("carla_request_restart %p", host);
2332 static void CLAP_ABI carla_request_process(const clap_host_t* const host)
2334 carla_stdout("carla_request_process %p", host);
2337 static void CLAP_ABI carla_request_callback(const clap_host_t* const host)
2339 carla_stdout("carla_request_callback %p", host);
2343 static bool clap_deinit_false(const clap_plugin_entry_t* const entry)
2345 entry->deinit();
2346 return false;
2349 static bool do_clap_check(lib_t& libHandle, const char* const filename, const bool doInit)
2351 const clap_plugin_entry_t* entry = nullptr;
2353 #ifdef CARLA_OS_MAC
2354 BundleLoader bundleLoader;
2356 // if passed filename is not a plugin binary directly, inspect bundle and find one
2357 if (libHandle == nullptr)
2359 if (! bundleLoader.load(filename))
2361 #ifdef __aarch64__
2362 return true;
2363 #else
2364 DISCOVERY_OUT("error", "Failed to load CLAP bundle executable");
2365 return false;
2366 #endif
2369 entry = bundleLoader.getSymbol<const clap_plugin_entry_t*>(CFSTR("clap_entry"));
2371 else
2372 #endif
2374 entry = lib_symbol<const clap_plugin_entry_t*>(libHandle, "clap_entry");
2377 // ensure entry points are available
2378 if (entry == nullptr || entry->init == nullptr || entry->deinit == nullptr || entry->get_factory == nullptr)
2380 DISCOVERY_OUT("error", "Not a CLAP plugin");
2381 return false;
2384 // ensure compatible version
2385 if (!clap_version_is_compatible(entry->clap_version))
2387 DISCOVERY_OUT("error", "Incompatible CLAP plugin");
2388 return false;
2391 const water::String pluginPath(water::File(filename).getParentDirectory().getFullPathName());
2393 if (!entry->init(pluginPath.toRawUTF8()))
2395 DISCOVERY_OUT("error", "CLAP plugin failed to initialize");
2396 return false;
2399 const clap_plugin_factory_t* const factory = static_cast<const clap_plugin_factory_t*>(
2400 entry->get_factory(CLAP_PLUGIN_FACTORY_ID));
2401 CARLA_SAFE_ASSERT_RETURN(factory != nullptr
2402 && factory->get_plugin_count != nullptr
2403 && factory->get_plugin_descriptor != nullptr
2404 && factory->create_plugin != nullptr, clap_deinit_false(entry));
2406 if (const uint32_t count = factory->get_plugin_count(factory))
2408 const carla_clap_host host;
2410 for (uint32_t i=0; i<count; ++i)
2412 const clap_plugin_descriptor_t* const desc = factory->get_plugin_descriptor(factory, i);
2413 CARLA_SAFE_ASSERT_CONTINUE(desc != nullptr);
2415 const clap_plugin_t* const plugin = factory->create_plugin(factory, &host, desc->id);
2416 CARLA_SAFE_ASSERT_CONTINUE(plugin != nullptr);
2418 // FIXME this is not needed per spec, but JUCE-based CLAP plugins crash without it :(
2419 if (!plugin->init(plugin))
2421 plugin->destroy(plugin);
2422 continue;
2425 uint hints = 0x0;
2426 uint audioIns = 0;
2427 uint audioOuts = 0;
2428 uint midiIns = 0;
2429 uint midiOuts = 0;
2430 uint parametersIns = 0;
2431 uint parametersOuts = 0;
2432 PluginCategory category = PLUGIN_CATEGORY_NONE;
2434 const clap_plugin_audio_ports_t* const audioPorts = static_cast<const clap_plugin_audio_ports_t*>(
2435 plugin->get_extension(plugin, CLAP_EXT_AUDIO_PORTS));
2437 const clap_plugin_note_ports_t* const notePorts = static_cast<const clap_plugin_note_ports_t*>(
2438 plugin->get_extension(plugin, CLAP_EXT_NOTE_PORTS));
2440 const clap_plugin_params_t* const params = static_cast<const clap_plugin_params_t*>(
2441 plugin->get_extension(plugin, CLAP_EXT_PARAMS));
2443 #ifdef CLAP_WINDOW_API_NATIVE
2444 const clap_plugin_gui_t* const gui = static_cast<const clap_plugin_gui_t*>(
2445 plugin->get_extension(plugin, CLAP_EXT_GUI));
2446 #endif
2448 if (audioPorts != nullptr)
2450 clap_audio_port_info_t info;
2452 const uint32_t inPorts = audioPorts->count(plugin, true);
2453 for (uint32_t j=0; j<inPorts; ++j)
2455 if (!audioPorts->get(plugin, j, true, &info))
2456 break;
2458 audioIns += info.channel_count;
2461 const uint32_t outPorts = audioPorts->count(plugin, false);
2462 for (uint32_t j=0; j<outPorts; ++j)
2464 if (!audioPorts->get(plugin, j, false, &info))
2465 break;
2467 audioOuts += info.channel_count;
2471 if (notePorts != nullptr)
2473 clap_note_port_info_t info;
2475 const uint32_t inPorts = notePorts->count(plugin, true);
2476 for (uint32_t j=0; j<inPorts; ++j)
2478 if (!notePorts->get(plugin, j, true, &info))
2479 break;
2481 if (info.supported_dialects & CLAP_NOTE_DIALECT_MIDI)
2482 ++midiIns;
2485 const uint32_t outPorts = notePorts->count(plugin, false);
2486 for (uint32_t j=0; j<outPorts; ++j)
2488 if (!notePorts->get(plugin, j, false, &info))
2489 break;
2491 if (info.supported_dialects & CLAP_NOTE_DIALECT_MIDI)
2492 ++midiOuts;
2496 if (params != nullptr)
2498 clap_param_info_t info;
2500 const uint32_t numParams = params->count(plugin);
2501 for (uint32_t j=0; j<numParams; ++j)
2503 if (!params->get_info(plugin, j, &info))
2504 break;
2506 if (info.flags & (CLAP_PARAM_IS_HIDDEN|CLAP_PARAM_IS_BYPASS))
2507 continue;
2509 if (info.flags & CLAP_PARAM_IS_READONLY)
2510 ++parametersOuts;
2511 else
2512 ++parametersIns;
2516 if (desc->features != nullptr)
2517 category = getPluginCategoryFromClapFeatures(desc->features);
2519 if (category == PLUGIN_CATEGORY_SYNTH)
2520 hints |= PLUGIN_IS_SYNTH;
2522 #ifdef CLAP_WINDOW_API_NATIVE
2523 if (gui != nullptr)
2525 hints |= PLUGIN_HAS_CUSTOM_UI;
2526 #ifndef BUILD_BRIDGE
2527 if (gui->is_api_supported(plugin, CLAP_WINDOW_API_NATIVE, false))
2528 hints |= PLUGIN_HAS_CUSTOM_EMBED_UI;
2529 #endif
2531 #endif
2533 if (doInit)
2535 // -----------------------------------------------------------------------
2536 // start crash-free plugin test
2538 // FIXME already initiated before, because broken plugins etc
2539 // plugin->init(plugin);
2541 // TODO
2543 // end crash-free plugin test
2544 // -----------------------------------------------------------------------
2547 plugin->destroy(plugin);
2549 DISCOVERY_OUT("init", "------------");
2550 DISCOVERY_OUT("build", BINARY_NATIVE);
2551 DISCOVERY_OUT("hints", hints);
2552 DISCOVERY_OUT("category", getPluginCategoryAsString(category));
2553 DISCOVERY_OUT("name", desc->name);
2554 DISCOVERY_OUT("label", desc->id);
2555 DISCOVERY_OUT("maker", desc->vendor);
2556 DISCOVERY_OUT("audio.ins", audioIns);
2557 DISCOVERY_OUT("audio.outs", audioOuts);
2558 DISCOVERY_OUT("midi.ins", midiIns);
2559 DISCOVERY_OUT("midi.outs", midiOuts);
2560 DISCOVERY_OUT("parameters.ins", parametersIns);
2561 DISCOVERY_OUT("parameters.outs", parametersOuts);
2562 DISCOVERY_OUT("end", "------------");
2566 entry->deinit();
2567 return false;
2570 // --------------------------------------------------------------------------------------------------------------------
2571 // fluidsynth (dls, sf2, sfz)
2573 #ifdef HAVE_FLUIDSYNTH
2574 static void do_fluidsynth_check(const char* const filename, const PluginType type, const bool doInit)
2576 const water::File file(filename);
2578 if (! file.existsAsFile())
2580 DISCOVERY_OUT("error", "Requested file is not valid or does not exist");
2581 return;
2584 if (type == PLUGIN_SF2 && ! fluid_is_soundfont(filename))
2586 DISCOVERY_OUT("error", "Not a SF2 file");
2587 return;
2590 int programs = 0;
2592 if (doInit)
2594 fluid_settings_t* const f_settings = new_fluid_settings();
2595 CARLA_SAFE_ASSERT_RETURN(f_settings != nullptr,);
2597 fluid_synth_t* const f_synth = new_fluid_synth(f_settings);
2598 CARLA_SAFE_ASSERT_RETURN(f_synth != nullptr,);
2600 const int f_id_test = fluid_synth_sfload(f_synth, filename, 0);
2602 if (f_id_test < 0)
2604 DISCOVERY_OUT("error", "Failed to load SF2 file");
2605 return;
2608 #if FLUIDSYNTH_VERSION_MAJOR >= 2
2609 const int f_id = f_id_test;
2610 #else
2611 const uint f_id = static_cast<uint>(f_id_test);
2612 #endif
2614 if (fluid_sfont_t* const f_sfont = fluid_synth_get_sfont_by_id(f_synth, f_id))
2616 #if FLUIDSYNTH_VERSION_MAJOR >= 2
2617 fluid_sfont_iteration_start(f_sfont);
2618 for (; fluid_sfont_iteration_next(f_sfont);)
2619 ++programs;
2620 #else
2621 fluid_preset_t f_preset;
2623 f_sfont->iteration_start(f_sfont);
2624 for (; f_sfont->iteration_next(f_sfont, &f_preset);)
2625 ++programs;
2626 #endif
2629 delete_fluid_synth(f_synth);
2630 delete_fluid_settings(f_settings);
2633 CarlaString name(file.getFileNameWithoutExtension().toRawUTF8());
2634 CarlaString label(name);
2636 // 2 channels
2637 DISCOVERY_OUT("init", "------------");
2638 DISCOVERY_OUT("build", BINARY_NATIVE);
2639 DISCOVERY_OUT("hints", PLUGIN_IS_SYNTH);
2640 DISCOVERY_OUT("category", "synth");
2641 DISCOVERY_OUT("name", name.buffer());
2642 DISCOVERY_OUT("label", label.buffer());
2643 DISCOVERY_OUT("audio.outs", 2);
2644 DISCOVERY_OUT("midi.ins", 1);
2645 DISCOVERY_OUT("parameters.ins", 13); // defined in Carla
2646 DISCOVERY_OUT("parameters.outs", 1);
2647 DISCOVERY_OUT("end", "------------");
2649 // 16 channels
2650 if (doInit && (name.isEmpty() || programs <= 1))
2651 return;
2653 name += " (16 outputs)";
2655 DISCOVERY_OUT("init", "------------");
2656 DISCOVERY_OUT("build", BINARY_NATIVE);
2657 DISCOVERY_OUT("hints", PLUGIN_IS_SYNTH);
2658 DISCOVERY_OUT("category", "synth");
2659 DISCOVERY_OUT("name", name.buffer());
2660 DISCOVERY_OUT("label", label.buffer());
2661 DISCOVERY_OUT("audio.outs", 32);
2662 DISCOVERY_OUT("midi.ins", 1);
2663 DISCOVERY_OUT("parameters.ins", 13); // defined in Carla
2664 DISCOVERY_OUT("parameters.outs", 1);
2665 DISCOVERY_OUT("end", "------------");
2667 #endif // HAVE_FLUIDSYNTH
2669 // --------------------------------------------------------------------------------------------------------------------
2670 // JSFX
2672 #ifdef HAVE_YSFX
2673 static void do_jsfx_check(const char* const filename, bool doInit)
2675 const water::File file(filename);
2677 ysfx_config_u config(ysfx_config_new());
2679 ysfx_register_builtin_audio_formats(config.get());
2680 ysfx_guess_file_roots(config.get(), filename);
2681 ysfx_set_log_reporter(config.get(), &CarlaJsfxLogging::logErrorsOnly);
2683 ysfx_u effect(ysfx_new(config.get()));
2685 uint hints = 0;
2687 // do not attempt to compile it, because the import path is not known
2688 (void)doInit;
2690 if (! ysfx_load_file(effect.get(), filename, 0))
2692 DISCOVERY_OUT("error", "Cannot read the JSFX header");
2693 return;
2696 const char* const name = ysfx_get_name(effect.get());
2698 // author and category are extracted from the pseudo-tags
2699 const char* const author = ysfx_get_author(effect.get());
2700 const CB::PluginCategory category = CarlaJsfxCategories::getFromEffect(effect.get());
2702 const uint32_t audioIns = ysfx_get_num_inputs(effect.get());
2703 const uint32_t audioOuts = ysfx_get_num_outputs(effect.get());
2705 const uint32_t midiIns = 1;
2706 const uint32_t midiOuts = 1;
2708 uint32_t parameters = 0;
2709 for (uint32_t sliderIndex = 0; sliderIndex < ysfx_max_sliders; ++sliderIndex)
2711 if (ysfx_slider_exists(effect.get(), sliderIndex))
2712 ++parameters;
2715 DISCOVERY_OUT("init", "------------");
2716 DISCOVERY_OUT("build", BINARY_NATIVE);
2717 DISCOVERY_OUT("hints", hints);
2718 DISCOVERY_OUT("category", getPluginCategoryAsString(category));
2719 DISCOVERY_OUT("name", name);
2720 DISCOVERY_OUT("maker", author);
2721 DISCOVERY_OUT("label", filename);
2722 DISCOVERY_OUT("audio.ins", audioIns);
2723 DISCOVERY_OUT("audio.outs", audioOuts);
2724 DISCOVERY_OUT("midi.ins", midiIns);
2725 DISCOVERY_OUT("midi.outs", midiOuts);
2726 DISCOVERY_OUT("parameters.ins", parameters);
2727 DISCOVERY_OUT("end", "------------");
2729 #endif // HAVE_YSFX
2731 // --------------------------------------------------------------------------------------------------------------------
2732 // main entry point
2734 int main(int argc, const char* argv[])
2736 if (argc != 3 && argc != 7)
2738 carla_stdout("usage: %s <type> </path/to/plugin>", argv[0]);
2739 return 1;
2742 const char* const stype = argv[1];
2743 const char* const filename = argv[2];
2744 const PluginType type = getPluginTypeFromString(stype);
2746 CarlaString filenameCheck(filename);
2747 filenameCheck.toLower();
2749 bool openLib;
2750 lib_t handle = nullptr;
2752 switch (type)
2754 case PLUGIN_LADSPA:
2755 case PLUGIN_DSSI:
2756 // only available as single binary
2757 openLib = true;
2758 break;
2760 case PLUGIN_VST2:
2761 case PLUGIN_CLAP:
2762 #ifdef CARLA_OS_MAC
2763 // bundle on macOS
2764 openLib = false;
2765 #else
2766 // single binary on all else
2767 openLib = true;
2768 #endif
2769 break;
2771 case PLUGIN_VST3:
2772 #if defined(CARLA_OS_WIN)
2773 // either file or bundle on Windows
2774 openLib = water::File(filename).existsAsFile();
2775 #else
2776 // bundle on all else
2777 openLib = false;
2778 #endif
2779 break;
2781 default:
2782 openLib = false;
2783 break;
2786 if (type != PLUGIN_SF2 && filenameCheck.contains("fluidsynth", true))
2788 DISCOVERY_OUT("info", "skipping fluidsynth based plugin");
2789 return 0;
2792 // ----------------------------------------------------------------------------------------------------------------
2793 // Initialize OS features
2795 // we want stuff in English so we can parse error messages
2796 ::setlocale(LC_ALL, "C");
2797 #ifndef CARLA_OS_WIN
2798 carla_setenv("LC_ALL", "C");
2799 #endif
2801 #ifdef CARLA_OS_WIN
2802 OleInitialize(nullptr);
2803 CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED);
2804 #ifndef __WINPTHREADS_VERSION
2805 // (non-portable) initialization of statically linked pthread library
2806 pthread_win32_process_attach_np();
2807 pthread_win32_thread_attach_np();
2808 #endif
2809 #endif
2811 // ----------------------------------------------------------------------------------------------------------------
2812 // Initialize pipe
2814 if (argc == 7)
2816 gPipe = new DiscoveryPipe;
2818 if (! gPipe->initPipeClient(argv))
2819 return 1;
2822 // ----------------------------------------------------------------------------------------------------------------
2824 if (openLib)
2826 handle = lib_open(filename);
2828 if (handle == nullptr)
2830 print_lib_error(filename);
2831 gPipe = nullptr;
2832 return 1;
2836 // never do init for dssi-vst, takes too long and it's crashy
2837 bool doInit = ! filenameCheck.contains("dssi-vst", true);
2839 if (doInit && getenv("CARLA_DISCOVERY_NO_PROCESSING_CHECKS") != nullptr)
2840 doInit = false;
2842 // ----------------------------------------------------------------------------------------------------------------
2844 if (doInit && openLib && handle != nullptr)
2846 // test fast loading & unloading DLL without initializing the plugin(s)
2847 if (! lib_close(handle))
2849 print_lib_error(filename);
2850 gPipe = nullptr;
2851 return 1;
2854 handle = lib_open(filename);
2856 if (handle == nullptr)
2858 print_lib_error(filename);
2859 gPipe = nullptr;
2860 return 1;
2864 #ifndef BUILD_BRIDGE
2865 if (std::strcmp(filename, ":all") == 0)
2867 do_cached_check(type);
2868 gPipe = nullptr;
2869 return 0;
2871 #endif
2873 #ifdef CARLA_OS_MAC
2874 // Plugin might be in quarentine due to Apple stupid notarization rules, let's remove that if possible
2875 switch (type)
2877 case PLUGIN_LADSPA:
2878 case PLUGIN_DSSI:
2879 case PLUGIN_VST2:
2880 case PLUGIN_VST3:
2881 case PLUGIN_AU:
2882 case PLUGIN_CLAP:
2883 removeFileFromQuarantine(filename);
2884 break;
2885 default:
2886 break;
2888 #endif
2890 // some macOS plugins have not been yet ported to arm64, re-run them in x86_64 mode if discovery fails
2891 bool retryAsX64lugin = false;
2893 switch (type)
2895 case PLUGIN_LADSPA:
2896 do_ladspa_check(handle, filename, doInit);
2897 break;
2899 case PLUGIN_DSSI:
2900 do_dssi_check(handle, filename, doInit);
2901 break;
2903 #ifndef BUILD_BRIDGE
2904 case PLUGIN_LV2:
2905 do_lv2_check(filename, doInit);
2906 break;
2907 #endif
2909 case PLUGIN_VST2:
2910 retryAsX64lugin = do_vst2_check(handle, filename, doInit);
2911 break;
2913 case PLUGIN_VST3:
2914 retryAsX64lugin = do_vst3_check(handle, filename, doInit);
2915 break;
2917 case PLUGIN_AU:
2918 #ifdef CARLA_OS_MAC
2919 retryAsX64lugin = do_au_check(filename, doInit);
2920 #else
2921 DISCOVERY_OUT("error", "AU support not available");
2922 #endif
2923 break;
2925 case PLUGIN_JSFX:
2926 #ifdef HAVE_YSFX
2927 do_jsfx_check(filename, doInit);
2928 #else
2929 DISCOVERY_OUT("error", "JSFX support not available");
2930 #endif
2931 break;
2933 case PLUGIN_CLAP:
2934 retryAsX64lugin = do_clap_check(handle, filename, doInit);
2935 break;
2937 case PLUGIN_DLS:
2938 case PLUGIN_GIG:
2939 case PLUGIN_SF2:
2940 #ifdef HAVE_FLUIDSYNTH
2941 do_fluidsynth_check(filename, type, doInit);
2942 #else
2943 DISCOVERY_OUT("error", "SF2 support not available");
2944 #endif
2945 break;
2947 default:
2948 break;
2951 if (openLib && handle != nullptr)
2952 lib_close(handle);
2954 if (retryAsX64lugin)
2956 #if defined(CARLA_OS_MAC) && defined(__aarch64__)
2957 DISCOVERY_OUT("warning", "No plugins found while scanning in arm64 mode, will try x86_64 now");
2959 cpu_type_t pref = CPU_TYPE_X86_64;
2960 pid_t pid = -1;
2962 posix_spawnattr_t attr;
2963 posix_spawnattr_init(&attr);
2964 CARLA_SAFE_ASSERT_RETURN(posix_spawnattr_setbinpref_np(&attr, 1, &pref, nullptr) == 0, 1);
2965 CARLA_SAFE_ASSERT_RETURN(posix_spawn(&pid, argv[0], nullptr, &attr, (char* const*)argv, nullptr) == 0, 1);
2966 posix_spawnattr_destroy(&attr);
2968 if (pid > 0)
2970 int status;
2971 waitpid(pid, &status, 0);
2973 #endif
2976 gPipe = nullptr;
2978 // ----------------------------------------------------------------------------------------------------------------
2980 #ifdef CARLA_OS_WIN
2981 #ifndef __WINPTHREADS_VERSION
2982 pthread_win32_thread_detach_np();
2983 pthread_win32_process_detach_np();
2984 #endif
2985 CoUninitialize();
2986 OleUninitialize();
2987 #endif
2989 return 0;
2992 // --------------------------------------------------------------------------------------------------------------------