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"
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"
24 # include "CarlaMacUtils.cpp"
25 # include <AudioToolbox/AudioUnit.h>
37 # undef HAVE_FLUIDSYNTH
41 #ifdef HAVE_FLUIDSYNTH
42 # include <fluidsynth.h>
48 #include "water/files/File.h"
51 # include "CarlaDssiUtils.cpp"
52 # include "CarlaJsfxUtils.hpp"
53 # include "../backend/utils/CachedPlugins.cpp"
57 #ifdef BUILDING_CARLA_FOR_WINE
58 # include "../jackbridge/JackBridge.hpp"
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; }
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 // --------------------------------------------------------------------------------------------------------------------
83 #ifndef BUILDING_CARLA_FOR_WINE
84 class DiscoveryPipe
: public CarlaPipeClient
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
))
103 if (! writeAndFixMessage(value
))
111 bool msgReceived(const char* const msg
) noexcept
113 carla_stdout("discovery msgReceived %s", msg
);
123 DiscoveryPipe() noexcept
: pipe(nullptr) {}
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
);
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 // --------------------------------------------------------------------------------------------------------------------
173 static void print_cached_plugin(const CarlaCachedPluginInfo
* const pinfo
)
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)
205 plugPath
= std::getenv("LV2_PATH");
208 plugPath
= std::getenv("SFZ_PATH");
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 // --------------------------------------------------------------------------------------------------------------------
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");
241 const LADSPA_Descriptor
* descriptor
;
244 descriptor
= descFn(0);
246 if (descriptor
== nullptr)
248 DISCOVERY_OUT("error", "Binary doesn't contain any plugins");
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");
262 descriptor
->cleanup(handle
);
264 lib_close(libHandle
);
265 libHandle
= lib_open(filename
);
267 if (libHandle
== nullptr)
269 print_lib_error(filename
);
273 descFn
= lib_symbol
<LADSPA_Descriptor_Function
>(libHandle
, "ladspa_descriptor");
275 if (descFn
== nullptr)
277 DISCOVERY_OUT("error", "Not a LADSPA plugin (#2)");
285 while ((descriptor
= descFn(i
++)) != nullptr)
287 if (descriptor
->instantiate
== nullptr)
289 DISCOVERY_OUT("error", "Plugin '" << descriptor
->Name
<< "' has no instantiate()");
292 if (descriptor
->cleanup
== nullptr)
294 DISCOVERY_OUT("error", "Plugin '" << descriptor
->Name
<< "' has no cleanup()");
297 if (descriptor
->run
== nullptr)
299 DISCOVERY_OUT("error", "Plugin '" << descriptor
->Name
<< "' has no run()");
302 if (! LADSPA_IS_HARD_RT_CAPABLE(descriptor
->Properties
))
304 DISCOVERY_OUT("warning", "Plugin '" << descriptor
->Name
<< "' is not hard real-time capable");
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
))
326 else if (LADSPA_IS_PORT_OUTPUT(portDescriptor
))
329 else if (LADSPA_IS_PORT_CONTROL(portDescriptor
))
331 if (LADSPA_IS_PORT_INPUT(portDescriptor
))
333 else if (LADSPA_IS_PORT_OUTPUT(portDescriptor
) && std::strcmp(descriptor
->PortNames
[j
], "latency") != 0 && std::strcmp(descriptor
->PortNames
[j
], "_latency") != 0)
336 parametersTotal
+= 1;
340 CARLA_SAFE_ASSERT_CONTINUE(audioIns
<= MAX_DISCOVERY_AUDIO_IO
);
341 CARLA_SAFE_ASSERT_CONTINUE(audioOuts
<= MAX_DISCOVERY_AUDIO_IO
);
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");
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)");
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
))
385 if (LADSPA_IS_HINT_BOUNDED_BELOW(portRangeHints
.HintDescriptor
))
386 min
= portRangeHints
.LowerBound
;
391 if (LADSPA_IS_HINT_BOUNDED_ABOVE(portRangeHints
.HintDescriptor
))
392 max
= portRangeHints
.UpperBound
;
398 DISCOVERY_OUT("warning", "Parameter '" << portName
<< "' is broken: min > max");
401 else if (carla_isEqual(min
, max
))
403 DISCOVERY_OUT("warning", "Parameter '" << portName
<< "' is broken: max == min");
408 def
= get_default_ladspa_port_value(portRangeHints
.HintDescriptor
, min
, max
);
410 if (LADSPA_IS_HINT_SAMPLE_RATE(portRangeHints
.HintDescriptor
))
417 if (LADSPA_IS_PORT_OUTPUT(portDescriptor
) && (std::strcmp(portName
, "latency") == 0 || std::strcmp(portName
, "_latency") == 0))
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 // --------------------------------------------------------------------------------------------------------------------
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");
480 const DSSI_Descriptor
* descriptor
;
483 descriptor
= descFn(0);
485 if (descriptor
== nullptr)
487 DISCOVERY_OUT("error", "Binary doesn't contain any plugins");
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");
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");
509 ldescriptor
->cleanup(handle
);
511 lib_close(libHandle
);
512 libHandle
= lib_open(filename
);
514 if (libHandle
== nullptr)
516 print_lib_error(filename
);
520 descFn
= lib_symbol
<DSSI_Descriptor_Function
>(libHandle
, "dssi_descriptor");
522 if (descFn
== nullptr)
524 DISCOVERY_OUT("error", "Not a DSSI plugin (#2)");
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");
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
);
546 if (ldescriptor
->instantiate
== nullptr)
548 DISCOVERY_OUT("error", "Plugin '" << ldescriptor
->Name
<< "' has no instantiate()");
551 if (ldescriptor
->cleanup
== nullptr)
553 DISCOVERY_OUT("error", "Plugin '" << ldescriptor
->Name
<< "' has no cleanup()");
556 if (ldescriptor
->run
== nullptr && descriptor
->run_synth
== nullptr)
558 DISCOVERY_OUT("error", "Plugin '" << ldescriptor
->Name
<< "' has no run() or run_synth()");
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");
566 if (! LADSPA_IS_HARD_RT_CAPABLE(ldescriptor
->Properties
))
568 DISCOVERY_OUT("warning", "Plugin '" << ldescriptor
->Name
<< "' is not hard real-time capable");
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
))
591 else if (LADSPA_IS_PORT_OUTPUT(portDescriptor
))
594 else if (LADSPA_IS_PORT_CONTROL(portDescriptor
))
596 if (LADSPA_IS_PORT_INPUT(portDescriptor
))
598 else if (LADSPA_IS_PORT_OUTPUT(portDescriptor
) && std::strcmp(ldescriptor
->PortNames
[j
], "latency") != 0 && std::strcmp(ldescriptor
->PortNames
[j
], "_latency") != 0)
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)
611 if (midiIns
> 0 && audioIns
== 0 && audioOuts
> 0)
612 hints
|= PLUGIN_IS_SYNTH
;
615 if (const char* const ui
= find_dssi_ui(filename
, ldescriptor
->Label
))
617 hints
|= PLUGIN_HAS_CUSTOM_UI
;
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");
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)");
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
))
664 if (LADSPA_IS_HINT_BOUNDED_BELOW(portRangeHints
.HintDescriptor
))
665 min
= portRangeHints
.LowerBound
;
670 if (LADSPA_IS_HINT_BOUNDED_ABOVE(portRangeHints
.HintDescriptor
))
671 max
= portRangeHints
.UpperBound
;
677 DISCOVERY_OUT("warning", "Parameter '" << portName
<< "' is broken: min > max");
680 else if (carla_isEqual(min
, max
))
682 DISCOVERY_OUT("warning", "Parameter '" << portName
<< "' is broken: max == min");
687 def
= get_default_ladspa_port_value(portRangeHints
.HintDescriptor
, min
, max
);
689 if (LADSPA_IS_HINT_SAMPLE_RATE(portRangeHints
.HintDescriptor
))
696 if (LADSPA_IS_PORT_OUTPUT(portDescriptor
) && (std::strcmp(portName
, "latency") == 0 || std::strcmp(portName
, "_latency") == 0))
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
);
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
)
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 // --------------------------------------------------------------------------------------------------------------------
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("/"))
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
);
810 DISCOVERY_OUT("warning", "LV2 Bundle doesn't provide any plugins");
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
<< "'");
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
;
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
;
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 // --------------------------------------------------------------------------------------------------------------------
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)
890 if (std::strcmp(feature
, "sendVstEvents") == 0)
892 if (std::strcmp(feature
, "sendVstMidiEvent") == 0)
894 if (std::strcmp(feature
, "sendVstMidiEventFlagIsRealtime") == 0)
896 if (std::strcmp(feature
, "sendVstTimeInfo") == 0)
898 gVstWantsTime
= true;
901 if (std::strcmp(feature
, "receiveVstEvents") == 0)
903 if (std::strcmp(feature
, "receiveVstMidiEvent") == 0)
905 if (std::strcmp(feature
, "receiveVstTimeInfo") == 0)
907 if (std::strcmp(feature
, "reportConnectionChanges") == 0)
909 if (std::strcmp(feature
, "acceptIOChanges") == 0)
911 if (std::strcmp(feature
, "sizeWindow") == 0)
913 if (std::strcmp(feature
, "offline") == 0)
915 if (std::strcmp(feature
, "openFileSelector") == 0)
917 if (std::strcmp(feature
, "closeFileSelector") == 0)
919 if (std::strcmp(feature
, "startStopProcess") == 0)
921 if (std::strcmp(feature
, "supportShell") == 0)
923 if (std::strcmp(feature
, "shellCategory") == 0)
925 if (std::strcmp(feature
, "NIMKPIVendorSpecificCallbacks") == 0)
928 // non-official features found in some plugins:
933 carla_stderr("vstHostCanDo(\"%s\") - unknown feature", feature
);
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
;
948 case audioMasterAutomate
:
952 case audioMasterVersion
:
956 case audioMasterCurrentId
:
957 ret
= gVstCurrentUniqueId
;
960 case DECLARE_VST_DEPRECATED(audioMasterWantMidi
):
961 if (gVstWantsMidi
) { DISCOVERY_OUT("warning", "Plugin requested MIDI more than once"); }
963 gVstWantsMidi
= true;
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
;
975 timeInfo
.tempo
= 120.0;
976 timeInfo
.flags
|= kVstTempoValid
;
979 timeInfo
.timeSigNumerator
= 4;
980 timeInfo
.timeSigDenominator
= 4;
981 timeInfo
.flags
|= kVstTimeSigValid
;
983 ret
= (intptr_t)&timeInfo
;
986 case DECLARE_VST_DEPRECATED(audioMasterTempoAt
):
990 case DECLARE_VST_DEPRECATED(audioMasterGetNumAutomatableParameters
):
991 ret
= carla_minPositive(effect
->numParams
, static_cast<int>(MAX_DEFAULT_PARAMETERS
));
994 case DECLARE_VST_DEPRECATED(audioMasterGetParameterQuantization
):
995 ret
= 1; // full single float precision
998 case DECLARE_VST_DEPRECATED(audioMasterNeedIdle
):
999 if (gVstNeedsIdle
) { DISCOVERY_OUT("warning", "Plugin requested idle more than once"); }
1001 gVstNeedsIdle
= true;
1005 case audioMasterGetSampleRate
:
1009 case audioMasterGetBlockSize
:
1013 case DECLARE_VST_DEPRECATED(audioMasterWillReplaceOrAccumulate
):
1017 case audioMasterGetCurrentProcessLevel
:
1018 ret
= gVstIsProcessing
? kVstProcessLevelRealtime
: kVstProcessLevelUser
;
1021 case audioMasterGetAutomationState
:
1022 ret
= kVstAutomationOff
;
1025 case audioMasterGetVendorString
:
1026 CARLA_SAFE_ASSERT_BREAK(ptr
!= nullptr);
1027 std::strcpy((char*)ptr
, "falkTX");
1031 case audioMasterGetProductString
:
1032 CARLA_SAFE_ASSERT_BREAK(ptr
!= nullptr);
1033 std::strcpy((char*)ptr
, "Carla-Discovery");
1037 case audioMasterGetVendorVersion
:
1038 ret
= CARLA_VERSION_HEX
;
1041 case audioMasterCanDo
:
1042 CARLA_SAFE_ASSERT_BREAK(ptr
!= nullptr);
1043 ret
= vstHostCanDo((const char*)ptr
);
1046 case audioMasterGetLanguage
:
1047 ret
= kVstLangEnglish
;
1051 carla_stdout("vstHostCallback(%p, %i:%s, %i, " P_INTPTR
", %p, %f)",
1052 effect
, opcode
, vstMasterOpcode2str(opcode
), index
, value
, ptr
, static_cast<double>(opt
));
1059 static bool do_vst2_check(lib_t
& libHandle
, const char* const filename
, const bool doInit
)
1061 VST_Function vstFn
= nullptr;
1064 BundleLoader bundleLoader
;
1066 if (libHandle
== nullptr)
1068 if (! bundleLoader
.load(filename
))
1073 DISCOVERY_OUT("error", "Failed to load VST2 bundle executable");
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");
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");
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");
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
);
1139 gVstCurrentUniqueId
= effect
->uniqueID
;
1141 char strBuf
[STR_MAX
+1];
1143 CarlaString cProduct
;
1144 CarlaString cVendor
;
1145 PluginCategory category
;
1146 LinkedList
<intptr_t> uniqueIds
;
1152 carla_zeroChars(strBuf
, STR_MAX
+1);
1154 gVstCurrentUniqueId
= effect
->dispatcher(effect
, effShellGetNextPlugin
, 0, 0, strBuf
, 0.0f
);
1156 if (gVstCurrentUniqueId
== 0)
1159 uniqueIds
.append(gVstCurrentUniqueId
);
1162 effect
->dispatcher(effect
, effClose
, 0, 0, nullptr, 0.0f
);
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
);
1191 carla_zeroChars(strBuf
, STR_MAX
+1);
1193 if (effect
->dispatcher(effect
, effGetEffectName
, 0, 0, strBuf
, 0.0f
) == 1)
1199 carla_zeroChars(strBuf
, STR_MAX
+1);
1201 if (effect
->dispatcher(effect
, effGetProductString
, 0, 0, strBuf
, 0.0f
) == 1)
1207 carla_zeroChars(strBuf
, STR_MAX
+1);
1209 if (effect
->dispatcher(effect
, effGetVendorString
, 0, 0, strBuf
, 0.0f
) == 1)
1215 switch (effect
->dispatcher(effect
, effGetPlugCategory
, 0, 0, nullptr, 0.0f
))
1217 case kPlugCategSynth
:
1218 category
= PLUGIN_CATEGORY_SYNTH
;
1220 case kPlugCategAnalysis
:
1221 category
= PLUGIN_CATEGORY_UTILITY
;
1223 case kPlugCategMastering
:
1224 category
= PLUGIN_CATEGORY_DYNAMICS
;
1226 case kPlugCategRoomFx
:
1227 category
= PLUGIN_CATEGORY_DELAY
;
1229 case kPlugCategRestoration
:
1230 category
= PLUGIN_CATEGORY_UTILITY
;
1232 case kPlugCategGenerator
:
1233 category
= PLUGIN_CATEGORY_SYNTH
;
1236 if (effect
->flags
& effFlagsIsSynth
)
1237 category
= PLUGIN_CATEGORY_SYNTH
;
1239 category
= PLUGIN_CATEGORY_NONE
;
1243 // get everything else
1245 uint audioIns
= static_cast<uint
>(std::max(0, effect
->numInputs
));
1246 uint audioOuts
= static_cast<uint
>(std::max(0, effect
->numOutputs
));
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
;
1259 if (effect
->flags
& effFlagsIsSynth
)
1261 hints
|= PLUGIN_IS_SYNTH
;
1265 if (vstPluginCanDo(effect
, "receiveVstEvents") || vstPluginCanDo(effect
, "receiveVstMidiEvent") || (effect
->flags
& effFlagsIsSynth
) != 0)
1268 if (vstPluginCanDo(effect
, "sendVstEvents") || vstPluginCanDo(effect
, "sendVstMidiEvent"))
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
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
);
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
)
1294 float* bufferAudioIn
[MAX_DISCOVERY_AUDIO_IO
];
1295 float* bufferAudioOut
[MAX_DISCOVERY_AUDIO_IO
];
1299 bufferAudioIn
[0] = nullptr;
1303 for (uint j
=0; j
< audioIns
; ++j
)
1305 bufferAudioIn
[j
] = new float[kBufferSize
];
1306 carla_zeroFloats(bufferAudioIn
[j
], kBufferSize
);
1312 bufferAudioOut
[0] = nullptr;
1316 for (uint j
=0; j
< audioOuts
; ++j
)
1318 bufferAudioOut
[j
] = new float[kBufferSize
];
1319 carla_zeroFloats(bufferAudioOut
[j
], kBufferSize
);
1323 struct VstEventsFixed
{
1332 data
[0] = data
[1] = nullptr;
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];
1356 gVstIsProcessing
= true;
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
);
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
);
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;
1406 effect
->dispatcher(effect
, effClose
, 0, 0, nullptr, 0.0f
);
1412 if (effect
!= nullptr)
1415 effect
->dispatcher(effect
, DECLARE_VST_DEPRECATED(effIdle
), 0, 0, nullptr, 0.0f
);
1417 effect
->dispatcher(effect
, effClose
, 0, 0, nullptr, 0.0f
);
1422 #ifndef CARLA_OS_MAC
1428 // --------------------------------------------------------------------------------------------------------------------
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
;
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
];
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
;
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
;
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
;
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
)
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;
1536 BundleLoader bundleLoader
;
1539 // if passed filename is not a plugin binary directly, inspect bundle and find one
1540 if (libHandle
== nullptr)
1543 if (! bundleLoader
.load(filename
))
1548 DISCOVERY_OUT("error", "Failed to load VST3 bundle executable");
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
));
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();
1565 binaryfilename
+= ".vst3";
1567 binaryfilename
+= ".so";
1570 if (! water::File(binaryfilename
).existsAsFile())
1572 DISCOVERY_OUT("error", "Failed to find a suitable VST3 bundle binary");
1576 libHandle
= lib_open(binaryfilename
.toRawUTF8());
1578 if (libHandle
== nullptr)
1580 print_lib_error(filename
);
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
);
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");
1600 #if defined(CARLA_OS_MAC)
1601 v3_entry(bundleLoader
.getRef());
1602 #elif defined(CARLA_OS_WIN)
1605 v3_entry(libHandle
);
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
));
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
));
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
));
1633 CARLA_SAFE_ASSERT(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
));
1645 CARLA_SAFE_ASSERT(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
)
1658 // v3_class_info_2 is ABI compatible with v3_class_info
1664 if (factory2
!= nullptr)
1665 v3_cpp_obj(factory2
)->get_class_info_2(factory2
, i
, &classInfo
.v2
);
1667 v3_cpp_obj(factory1
)->get_class_info(factory1
, i
, &classInfo
.v1
);
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)
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;
1701 // try to create edit controller from factory
1703 if (v3_cpp_obj(component
)->get_controller_class_id(component
, uid
) == V3_OK
)
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
);
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
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
;
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
;
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
, ¶mInfo
);
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
))
1792 if (paramInfo
.flags
& V3_PARAM_READ_ONLY
)
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
;
1814 v3_cpp_obj_unref(view
);
1818 if (factory2
!= nullptr && std::strstr(classInfo
.v2
.sub_categories
, "Instrument") != nullptr)
1819 hints
|= PLUGIN_IS_SYNTH
;
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
]
1846 v3_audio_bus_buffers
* const outputsBuffers
= numAudioOutputBuses
> 0
1847 ? new v3_audio_bus_buffers
[numAudioOutputBuses
]
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
= ¶mChanges
;
1917 v3_process_context processContext
= {};
1918 processContext
.sample_rate
= kSampleRate
;
1920 v3_process_data processData
= {
1925 numAudioOutputBuses
,
1928 (v3_param_changes
**)¶mChangesPtr
,
1929 (v3_param_changes
**)¶mChangesPtr
,
1930 (v3_event_list
**)&eventListPtr
,
1931 (v3_event_list
**)&eventListPtr
,
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", "------------");
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
);
2007 // --------------------------------------------------------------------------------------------------------------------
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
))
2033 DISCOVERY_OUT("error", "Failed to load AU bundle executable");
2038 const CFTypeRef componentsRef
= CFBundleGetValueForInfoDictionaryKey(bundleLoader
.getRef(), CFSTR("AudioComponents"));
2040 if (componentsRef
== nullptr || CFGetTypeID(componentsRef
) != CFArrayGetTypeID())
2042 DISCOVERY_OUT("error", "Not an AU component");
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),
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)
2106 if (auGetPropertyInfo
== nullptr || auGetProperty
== nullptr)
2109 if (interface
->Open(interface
, (AudioUnit
)(void*)0x1) == noErr
)
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
;
2126 case kAudioUnitType_Generator
:
2127 case kAudioUnitType_MusicDevice
:
2128 category
= PLUGIN_CATEGORY_SYNTH
;
2130 case kAudioUnitType_MIDIProcessor
:
2131 case kAudioUnitType_Mixer
:
2132 case kAudioUnitType_Panner
:
2133 case kAudioUnitType_SpeechSynthesizer
:
2134 category
= PLUGIN_CATEGORY_UTILITY
;
2136 case kAudioUnitType_FormatConverter
:
2137 case kAudioUnitType_OfflineEffect
:
2138 case kAudioUnitType_Output
:
2139 category
= PLUGIN_CATEGORY_OTHER
;
2142 category
= PLUGIN_CATEGORY_NONE
;
2147 Boolean outWritable
= false;
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
;
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
);
2187 if (auGetPropertyInfo(interface
, kAudioUnitProperty_ParameterInfo
, kAudioUnitScope_Global
, paramIds
[i
], &outDataSize
, &outWritable
) != noErr
)
2189 if (outDataSize
!= sizeof(AudioUnitParameterInfo
))
2191 if (auGetProperty(interface
, kAudioUnitProperty_ParameterInfo
, kAudioUnitScope_Global
, paramIds
[i
], &info
, &outDataSize
) != noErr
)
2194 if ((info
.flags
& kAudioUnitParameterFlag_IsReadable
) == 0)
2197 if (info
.flags
& kAudioUnitParameterFlag_IsWritable
)
2208 if (auMIDIEvent
!= nullptr && auInitialize(interface
) == noErr
)
2210 if (auMIDIEvent(interface
, 0x90, 60, 64, 0) == noErr
)
2213 auUninitialize(interface
);
2218 outWritable
= false;
2219 if (auGetPropertyInfo(interface
, kAudioUnitProperty_MIDIOutputCallback
, kAudioUnitScope_Global
, 0, &outDataSize
, &outWritable
) == noErr
&& outDataSize
== sizeof(AUMIDIOutputCallbackStruct
) && outWritable
)
2223 if (category
== PLUGIN_CATEGORY_SYNTH
)
2224 hints
|= PLUGIN_IS_SYNTH
;
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;
2239 // test valid scopes
2241 if (auGetPropertyInfo(interface
, kAudioUnitProperty_ElementCount
, kAudioUnitScope_Input
, 0, &outDataSize
, &outWritable
) == noErr
&& outDataSize
== sizeof(UInt32
))
2244 if (auGetProperty(interface
, kAudioUnitProperty_ElementCount
, kAudioUnitScope_Input
, 0, &count
, &outDataSize
) == noErr
&& outDataSize
== sizeof(UInt32
) && count
!= 0)
2252 const CFIndex componentNameLen
= CFStringGetLength(componentName
);
2253 char* const nameBuffer
= new char[componentNameLen
+ 1];
2257 if (CFStringGetCString(componentName
, nameBuffer
, componentNameLen
+ 1, kCFStringEncodingUTF8
))
2259 if (char* const sep
= std::strstr(nameBuffer
, ": "))
2261 sep
[0] = sep
[1] = '\0';
2268 maker
= nameBuffer
+ componentNameLen
;
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
;
2300 #endif // CARLA_OS_MAC
2302 // --------------------------------------------------------------------------------------------------------------------
2305 struct carla_clap_host
: clap_host_t
{
2308 clap_version
= CLAP_VERSION
;
2310 name
= "Carla-Discovery";
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
;
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
);
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
)
2349 static bool do_clap_check(lib_t
& libHandle
, const char* const filename
, const bool doInit
)
2351 const clap_plugin_entry_t
* entry
= nullptr;
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
))
2364 DISCOVERY_OUT("error", "Failed to load CLAP bundle executable");
2369 entry
= bundleLoader
.getSymbol
<const clap_plugin_entry_t
*>(CFSTR("clap_entry"));
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");
2384 // ensure compatible version
2385 if (!clap_version_is_compatible(entry
->clap_version
))
2387 DISCOVERY_OUT("error", "Incompatible CLAP plugin");
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");
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
);
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
));
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
))
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
))
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
))
2481 if (info
.supported_dialects
& CLAP_NOTE_DIALECT_MIDI
)
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
))
2491 if (info
.supported_dialects
& CLAP_NOTE_DIALECT_MIDI
)
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
))
2506 if (info
.flags
& (CLAP_PARAM_IS_HIDDEN
|CLAP_PARAM_IS_BYPASS
))
2509 if (info
.flags
& CLAP_PARAM_IS_READONLY
)
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
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
;
2535 // -----------------------------------------------------------------------
2536 // start crash-free plugin test
2538 // FIXME already initiated before, because broken plugins etc
2539 // plugin->init(plugin);
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", "------------");
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");
2584 if (type
== PLUGIN_SF2
&& ! fluid_is_soundfont(filename
))
2586 DISCOVERY_OUT("error", "Not a SF2 file");
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);
2604 DISCOVERY_OUT("error", "Failed to load SF2 file");
2608 #if FLUIDSYNTH_VERSION_MAJOR >= 2
2609 const int f_id
= f_id_test
;
2611 const uint f_id
= static_cast<uint
>(f_id_test
);
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
);)
2621 fluid_preset_t f_preset
;
2623 f_sfont
->iteration_start(f_sfont
);
2624 for (; f_sfont
->iteration_next(f_sfont
, &f_preset
);)
2629 delete_fluid_synth(f_synth
);
2630 delete_fluid_settings(f_settings
);
2633 CarlaString
name(file
.getFileNameWithoutExtension().toRawUTF8());
2634 CarlaString
label(name
);
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", "------------");
2650 if (doInit
&& (name
.isEmpty() || programs
<= 1))
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 // --------------------------------------------------------------------------------------------------------------------
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()));
2687 // do not attempt to compile it, because the import path is not known
2690 if (! ysfx_load_file(effect
.get(), filename
, 0))
2692 DISCOVERY_OUT("error", "Cannot read the JSFX header");
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
))
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", "------------");
2731 // --------------------------------------------------------------------------------------------------------------------
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]);
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();
2750 lib_t handle
= nullptr;
2756 // only available as single binary
2766 // single binary on all else
2772 #if defined(CARLA_OS_WIN)
2773 // either file or bundle on Windows
2774 openLib
= water::File(filename
).existsAsFile();
2776 // bundle on all else
2786 if (type
!= PLUGIN_SF2
&& filenameCheck
.contains("fluidsynth", true))
2788 DISCOVERY_OUT("info", "skipping fluidsynth based plugin");
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");
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();
2811 // ----------------------------------------------------------------------------------------------------------------
2816 gPipe
= new DiscoveryPipe
;
2818 if (! gPipe
->initPipeClient(argv
))
2822 // ----------------------------------------------------------------------------------------------------------------
2826 handle
= lib_open(filename
);
2828 if (handle
== nullptr)
2830 print_lib_error(filename
);
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)
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
);
2854 handle
= lib_open(filename
);
2856 if (handle
== nullptr)
2858 print_lib_error(filename
);
2864 #ifndef BUILD_BRIDGE
2865 if (std::strcmp(filename
, ":all") == 0)
2867 do_cached_check(type
);
2874 // Plugin might be in quarentine due to Apple stupid notarization rules, let's remove that if possible
2883 removeFileFromQuarantine(filename
);
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;
2896 do_ladspa_check(handle
, filename
, doInit
);
2900 do_dssi_check(handle
, filename
, doInit
);
2903 #ifndef BUILD_BRIDGE
2905 do_lv2_check(filename
, doInit
);
2910 retryAsX64lugin
= do_vst2_check(handle
, filename
, doInit
);
2914 retryAsX64lugin
= do_vst3_check(handle
, filename
, doInit
);
2919 retryAsX64lugin
= do_au_check(filename
, doInit
);
2921 DISCOVERY_OUT("error", "AU support not available");
2927 do_jsfx_check(filename
, doInit
);
2929 DISCOVERY_OUT("error", "JSFX support not available");
2934 retryAsX64lugin
= do_clap_check(handle
, filename
, doInit
);
2940 #ifdef HAVE_FLUIDSYNTH
2941 do_fluidsynth_check(filename
, type
, doInit
);
2943 DISCOVERY_OUT("error", "SF2 support not available");
2951 if (openLib
&& handle
!= nullptr)
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
;
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
);
2971 waitpid(pid
, &status
, 0);
2978 // ----------------------------------------------------------------------------------------------------------------
2981 #ifndef __WINPTHREADS_VERSION
2982 pthread_win32_thread_detach_np();
2983 pthread_win32_process_detach_np();
2992 // --------------------------------------------------------------------------------------------------------------------