tracktion-engine 3.0-10-g034fdde4aa5
Tracktion Engine — High level data model for audio applications

« « « Anklang Documentation
Loading...
Searching...
No Matches
tracktion_PluginManager.cpp
Go to the documentation of this file.
1 /*
2 ,--. ,--. ,--. ,--.
3 ,-' '-.,--.--.,--,--.,---.| |,-.,-' '-.`--' ,---. ,--,--, Copyright 2024
4 '-. .-'| .--' ,-. | .--'| /'-. .-',--.| .-. || \ Tracktion Software
5 | | | | \ '-' \ `--.| \ \ | | | |' '-' '| || | Corporation
6 `---' `--' `--`--'`---'`--'`--' `---' `--' `---' `--''--' www.tracktion.com
7
8 Tracktion Engine uses a GPL/commercial licence - see LICENCE.md for details.
9*/
10
11namespace tracktion { inline namespace engine
12{
13
14// Defined in ExternalPlugin.cpp to clean up plugins waiting to be deleted
15extern void cleanUpDanglingPlugins();
16
17static const char* commandLineUID = "PluginScan";
18
19inline juce::MemoryBlock createScanMessage (const juce::XmlElement& xml)
20{
22 xml.writeTo (mo, juce::XmlElement::TextFormat().withoutHeader().singleLine());
23 return mo.getMemoryBlock();
24}
25
27{
28 PluginScanMasterProcess (Engine& e) : engine (e) {}
29
30 bool ensureSlaveIsLaunched()
31 {
32 if (launched)
33 return true;
34
35 crashed = false;
36 // don't get stdout or strerr from the child process. We don't do anything with it and it fills up the pipe and hangs
38 commandLineUID, 0, 0);
39
40 if (launched)
41 {
42 TRACKTION_LOG ("----- Launched Plugin Scan Process");
43 }
44 else
45 {
46 TRACKTION_LOG_ERROR ("Failed to launch child process");
47 showVirusCheckerWarning();
48 }
49
50 return launched;
51 }
52
53 bool sendScanRequest (juce::AudioPluginFormat& format,
54 const juce::String& fileOrIdentifier, int requestID)
55 {
56 juce::XmlElement m ("SCAN");
57 m.setAttribute ("id", requestID);
58 m.setAttribute ("type", format.getName());
59 m.setAttribute ("file", fileOrIdentifier);
60
61 return sendMessageToWorker (createScanMessage (m));
62 }
63
64 bool waitForReply (int requestID, const juce::String& fileOrIdentifier,
67 {
68 #if ! TRACKTION_LOG_ENABLED
69 juce::ignoreUnused (fileOrIdentifier);
70 #endif
71
72 auto start = juce::Time::getCurrentTime();
73
74 for (;;)
75 {
76 auto reply = findReply (requestID);
77
78 auto elapsed = juce::Time::getCurrentTime() - start;
79
80 if (reply == nullptr || ! reply->hasTagName ("FOUND"))
81 {
82 if (crashed)
83 {
84 TRACKTION_LOG_ERROR ("Plugin crashed: " + fileOrIdentifier);
85 return false;
86 }
87
88 if (scanner.shouldExit() || ! launched)
89 {
90 TRACKTION_LOG ("Plugin scan cancelled");
91 return false;
92 }
93
94 juce::Thread::sleep (10);
95 continue;
96 }
97
98 if (reply->getNumChildElements() == 0)
99 TRACKTION_LOG ("No plugins found in: " + fileOrIdentifier);
100
101 for (auto e : reply->getChildIterator())
102 {
104
105 if (desc.loadFromXml (*e))
106 {
107 auto newDesc = new juce::PluginDescription (desc);
108 newDesc->lastInfoUpdateTime = juce::Time::getCurrentTime();
109 result.add (newDesc);
110
111 TRACKTION_LOG ("Added " + desc.pluginFormatName + ": " + desc.name + " [" + elapsed.getDescription() + "]");
112 }
113 else
114 {
116 }
117 }
118
119 return true;
120 }
121 }
122
123 void handleMessage (const juce::XmlElement& xml)
124 {
125 if (xml.hasTagName ("FOUND"))
126 {
127 const juce::ScopedLock sl (replyLock);
128 replies.add (new juce::XmlElement (xml));
129 }
130 }
131
132 void handleConnectionLost() override
133 {
134 crashed = true;
135 }
136
137 volatile bool launched = false, crashed = false;
138
139private:
140 Engine& engine;
142 juce::CriticalSection replyLock;
143 bool hasShownVirusCheckerWarning = false;
144
145 void showVirusCheckerWarning()
146 {
147 if (! hasShownVirusCheckerWarning)
148 {
149 hasShownVirusCheckerWarning = true;
150
151 engine
152 .getUIBehaviour().showWarningAlert ("Plugin Scanning...",
153 TRANS("There are some problems in launching a child-process to scan for plugins.")
155 + TRANS("If you have a virus-checker or firewall running, you may need to temporarily disable it for the scan to work correctly."));
156 }
157 }
158
159 std::unique_ptr<juce::XmlElement> findReply (int requestID)
160 {
161 for (int i = replies.size(); --i >= 0;)
162 if (replies.getUnchecked(i)->getIntAttribute ("id") == requestID)
164
165 return {};
166 }
167
168 void handleMessageFromWorker (const juce::MemoryBlock& mb) override
169 {
170 if (auto xml = juce::parseXML (mb.toString()))
171 handleMessage (*xml);
172 }
173
175};
176
177//==============================================================================
179 private juce::AsyncUpdater
180{
182 {
183 pluginFormatManager.addDefaultFormats();
184 }
185
186 void handleConnectionMade() override {}
187
188 void handleConnectionLost() override
189 {
190 std::exit (0);
191 }
192
193 void handleScanMessage (int requestID, const juce::String& formatName, const juce::String& fileOrIdentifier)
194 {
195 juce::XmlElement result ("FOUND");
196 result.setAttribute ("id", requestID);
197
198 for (int i = 0; i < pluginFormatManager.getNumFormats(); ++i)
199 {
200 auto format = pluginFormatManager.getFormat (i);
201
202 if (format->getName() == formatName)
203 {
205 format->findAllTypesForFile (found, fileOrIdentifier);
206
207 for (auto pd : found)
208 result.addChildElement (pd->createXml().release());
209
210 break;
211 }
212 }
213
214 sendMessageToCoordinator (createScanMessage (result));
215 }
216
217 void handleMessage (const juce::XmlElement& xml)
218 {
219 if (xml.hasTagName ("SCAN"))
220 handleScanMessage (xml.getIntAttribute ("id"),
221 xml.getStringAttribute ("type"),
222 xml.getStringAttribute ("file"));
223 }
224
225private:
226 juce::AudioPluginFormatManager pluginFormatManager;
228
229 void handleMessageFromCoordinator (const juce::MemoryBlock& mb) override
230 {
231 if (auto xml = juce::parseXML (mb.toString()))
232 {
233 pendingMessages.add (xml.release());
235 }
236 }
237
238 void handleMessageSafely (const juce::XmlElement& m)
239 {
240 #if JUCE_WINDOWS
241 __try
242 {
243 #endif
244
245 handleMessage (m);
246
247 #if JUCE_WINDOWS
248 }
249 __except (1)
250 {
252 }
253 #endif
254 }
255
256 void handleAsyncUpdate() override
257 {
258 while (pendingMessages.size() > 0)
259 if (auto xml = pendingMessages.removeAndReturn (0))
260 handleMessageSafely (*xml);
261 }
262
264};
265
266
267//==============================================================================
268#if JUCE_MAC
269static void killWithoutMercy (int)
270{
271 kill (getpid(), SIGKILL);
272}
273
274static void setupSignalHandling()
275{
276 const int signals[] = { SIGFPE, SIGILL, SIGSEGV, SIGBUS, SIGABRT };
277
278 for (int sig : signals)
279 {
280 ::signal (sig, killWithoutMercy);
281 ::siginterrupt (sig, 1);
282 }
283}
284#endif
285
286bool PluginManager::startChildProcessPluginScan (const juce::String& commandLine)
287{
289
290 if (slave->initialiseFromCommandLine (commandLine, commandLineUID))
291 {
292 #if JUCE_MAC
293 setupSignalHandling();
294 #endif
295
296 slave.release(); // allow the slave object to stay alive - it'll handle its own deletion.
297 return true;
298 }
299
300 return false;
301}
302
303//==============================================================================
305{
306 CustomScanner (Engine& e) : engine (e) {}
307
308 bool findPluginTypesFor (juce::AudioPluginFormat& format,
310 const juce::String& fileOrIdentifier) override
311 {
313
314 if (engine.getPluginManager().usesSeparateProcessForScanning()
315 && shouldUseSeparateProcessToScan (format))
316 {
317 if (masterProcess != nullptr && masterProcess->crashed)
318 masterProcess = nullptr;
319
320 if (masterProcess == nullptr)
321 masterProcess = std::make_unique<PluginScanMasterProcess> (engine);
322
323 if (masterProcess->ensureSlaveIsLaunched())
324 {
325 auto requestID = juce::Random().nextInt();
326
327 if (! shouldExit()
328 && masterProcess->sendScanRequest (format, fileOrIdentifier, requestID)
329 && ! shouldExit())
330 {
331 if (masterProcess->waitForReply (requestID, fileOrIdentifier, result, *this))
332 return true;
333
334 // if there's a crash, give it a second chance with a fresh child process,
335 // in case the real culprit was whatever plugin preceded this one.
336 if (masterProcess->crashed && ! shouldExit())
337 {
338 masterProcess = nullptr;
339 masterProcess = std::make_unique<PluginScanMasterProcess> (engine);
340
341 return masterProcess->ensureSlaveIsLaunched()
342 && ! shouldExit()
343 && masterProcess->sendScanRequest (format, fileOrIdentifier, requestID)
344 && ! shouldExit()
345 && masterProcess->waitForReply (requestID, fileOrIdentifier, result, *this);
346 }
347 }
348
349 return false;
350 }
351
352 // panic! Can't run the slave for some reason, so just do it here..
353 TRACKTION_LOG_ERROR ("Falling back to scanning in main process..");
354 masterProcess.reset();
355 }
356
357 format.findAllTypesForFile (result, fileOrIdentifier);
358 return true;
359 }
360
361 static bool shouldUseSeparateProcessToScan (juce::AudioPluginFormat& format)
362 {
363 auto name = format.getName();
364
365 return name.containsIgnoreCase ("VST")
366 || name.containsIgnoreCase ("AudioUnit")
367 || name.containsIgnoreCase ("LADSPA");
368 }
369
370 void scanFinished() override
371 {
372 TRACKTION_LOG ("----- Ended Plugin Scan");
373 masterProcess.reset();
374
375 if (auto callback = engine.getPluginManager().scanCompletedCallback)
376 callback();
377 }
378
379 Engine& engine;
381};
382
383//==============================================================================
384inline SettingID getPluginListPropertyName()
385{
386 #if JUCE_64BIT
387 return SettingID::knownPluginList64;
388 #else
389 return SettingID::knownPluginList;
390 #endif
391}
392
393//==============================================================================
394PluginManager::BuiltInType::BuiltInType (const juce::String& t) : type (t) {}
395PluginManager::BuiltInType::~BuiltInType() {}
396
397//==============================================================================
398PluginManager::PluginManager (Engine& e)
399 : engine (e)
400{
401 createPluginInstance = [this] (const juce::PluginDescription& description, double rate, int blockSize, juce::String& errorMessage)
402 {
403 return std::unique_ptr<juce::AudioPluginInstance> (pluginFormatManager.createPluginInstance (description, rate,
404 blockSize, errorMessage));
405 };
406}
407
408void PluginManager::initialise()
409{
410 createBuiltInType<VolumeAndPanPlugin>();
411 createBuiltInType<VCAPlugin>();
412 createBuiltInType<LevelMeterPlugin>();
413 createBuiltInType<EqualiserPlugin>();
414 createBuiltInType<ReverbPlugin>();
415 createBuiltInType<CompressorPlugin>();
416 createBuiltInType<ChorusPlugin>();
417 createBuiltInType<DelayPlugin>();
418 createBuiltInType<PhaserPlugin>();
419 createBuiltInType<PitchShiftPlugin>();
420 createBuiltInType<LowPassPlugin>();
421 createBuiltInType<SamplerPlugin>();
422 createBuiltInType<FourOscPlugin>();
423 createBuiltInType<MidiModifierPlugin>();
424 createBuiltInType<MidiPatchBayPlugin>();
425 createBuiltInType<PatchBayPlugin>();
426 createBuiltInType<AuxSendPlugin>();
427 createBuiltInType<AuxReturnPlugin>();
428 createBuiltInType<TextPlugin>();
429 createBuiltInType<FreezePointPlugin>();
430 createBuiltInType<InsertPlugin>();
431
432 #if TRACKTION_ENABLE_REWIRE
433 createBuiltInType<ReWirePlugin>();
434 #endif
435
436 initialised = true;
437 pluginFormatManager.addDefaultFormats();
438
439 if (auto patchFormat = createCmajorPatchPluginFormat (engine))
440 pluginFormatManager.addFormat (patchFormat.release());
441
442 knownPluginList.setCustomScanner (std::make_unique<CustomScanner> (engine));
443
444 auto xml = engine.getPropertyStorage().getXmlProperty (getPluginListPropertyName());
445
446 if (xml != nullptr)
447 knownPluginList.recreateFromXml (*xml);
448
449 knownPluginList.addChangeListener (this);
450}
451
452PluginManager::~PluginManager()
453{
454 knownPluginList.removeChangeListener (this);
455 cleanUpDanglingPlugins();
456}
457
458#if TRACKTION_AIR_WINDOWS
459void PluginManager::initialiseAirWindows()
460{
461 createBuiltInType<AirWindowsADClip7>();
462 createBuiltInType<AirWindowsADT>();
463 createBuiltInType<AirWindowsAQuickVoiceClip>();
464 createBuiltInType<AirWindowsAcceleration>();
465 createBuiltInType<AirWindowsAir>();
466 createBuiltInType<AirWindowsAtmosphereBuss>();
467 createBuiltInType<AirWindowsAtmosphereChannel>();
468 createBuiltInType<AirWindowsAura>();
469 createBuiltInType<AirWindowsAverage>();
470 createBuiltInType<AirWindowsBassDrive>();
471 createBuiltInType<AirWindowsBassKit>();
472 createBuiltInType<AirWindowsBiquad>();
473 createBuiltInType<AirWindowsBiquad2>();
474 createBuiltInType<AirWindowsBitGlitter>();
475 createBuiltInType<AirWindowsBitShiftGain>();
476 createBuiltInType<AirWindowsBite>();
477 createBuiltInType<AirWindowsBlockParty>();
478 createBuiltInType<AirWindowsBrassRider>();
479 createBuiltInType<AirWindowsBuildATPDF>();
480 createBuiltInType<AirWindowsBussColors4>();
481 createBuiltInType<AirWindowsButterComp>();
482 createBuiltInType<AirWindowsButterComp2>();
483 createBuiltInType<AirWindowsC5RawBuss>();
484 createBuiltInType<AirWindowsC5RawChannel>();
485 createBuiltInType<AirWindowsCStrip>();
486 createBuiltInType<AirWindowsCapacitor>();
487 createBuiltInType<AirWindowsChannel4>();
488 createBuiltInType<AirWindowsChannel5>();
489 createBuiltInType<AirWindowsChannel6>();
490 createBuiltInType<AirWindowsChannel7>();
491 createBuiltInType<AirWindowsChorus>();
492 createBuiltInType<AirWindowsChorusEnsemble>();
493 createBuiltInType<AirWindowsClipOnly>();
494 createBuiltInType<AirWindowsCoils>();
495 createBuiltInType<AirWindowsCojones>();
496 createBuiltInType<AirWindowsCompresaturator>();
497 createBuiltInType<AirWindowsConsole4Buss>();
498 createBuiltInType<AirWindowsConsole4Channel>();
499 createBuiltInType<AirWindowsConsole5Buss>();
500 createBuiltInType<AirWindowsConsole5Channel>();
501 createBuiltInType<AirWindowsConsole5DarkCh>();
502 createBuiltInType<AirWindowsConsole6Buss>();
503 createBuiltInType<AirWindowsConsole6Channel>();
504 createBuiltInType<AirWindowsCrunchyGrooveWear>();
505 createBuiltInType<AirWindowsCrystal>();
506 createBuiltInType<AirWindowsDCVoltage>();
507 createBuiltInType<AirWindowsDeBess>();
508 createBuiltInType<AirWindowsDeEss>();
509 createBuiltInType<AirWindowsDeHiss>();
510 createBuiltInType<AirWindowsDeRez>();
511 createBuiltInType<AirWindowsDeRez2>();
512 createBuiltInType<AirWindowsDeckwrecka>();
513 createBuiltInType<AirWindowsDensity>();
514 createBuiltInType<AirWindowsDesk>();
515 createBuiltInType<AirWindowsDesk4>();
516 createBuiltInType<AirWindowsDistance>();
517 createBuiltInType<AirWindowsDistance2>();
518 createBuiltInType<AirWindowsDitherFloat>();
519 createBuiltInType<AirWindowsDitherMeDiskers>();
520 createBuiltInType<AirWindowsDitherMeTimbers>();
521 createBuiltInType<AirWindowsDitherbox>();
522 createBuiltInType<AirWindowsDoublePaul>();
523 createBuiltInType<AirWindowsDrive>();
524 createBuiltInType<AirWindowsDrumSlam>();
525 createBuiltInType<AirWindowsDubCenter>();
526 createBuiltInType<AirWindowsDubSub>();
527 createBuiltInType<AirWindowsDustBunny>();
528 createBuiltInType<AirWindowsDyno>();
529 createBuiltInType<AirWindowsEQ>();
530 createBuiltInType<AirWindowsEdIsDim>();
531 createBuiltInType<AirWindowsElectroHat>();
532 createBuiltInType<AirWindowsEnergy>();
533 createBuiltInType<AirWindowsEnsemble>();
534 createBuiltInType<AirWindowsEveryTrim>();
535 createBuiltInType<AirWindowsFacet>();
536 createBuiltInType<AirWindowsFathomFive>();
537 createBuiltInType<AirWindowsFloor>();
538 createBuiltInType<AirWindowsFocus>();
539 createBuiltInType<AirWindowsFracture>();
540 createBuiltInType<AirWindowsFromTape>();
541 createBuiltInType<AirWindowsGatelope>();
542 createBuiltInType<AirWindowsGolem>();
543 createBuiltInType<AirWindowsGringer>();
544 createBuiltInType<AirWindowsGrooveWear>();
545 createBuiltInType<AirWindowsGuitarConditioner>();
546 createBuiltInType<AirWindowsHardVacuum>();
547 createBuiltInType<AirWindowsHermeTrim>();
548 createBuiltInType<AirWindowsHermepass>();
549 createBuiltInType<AirWindowsHighGlossDither>();
550 createBuiltInType<AirWindowsHighImpact>();
551 createBuiltInType<AirWindowsHighpass>();
552 createBuiltInType<AirWindowsHighpass2>();
553 createBuiltInType<AirWindowsHolt>();
554 createBuiltInType<AirWindowsHombre>();
555 createBuiltInType<AirWindowsInterstage>();
556 createBuiltInType<AirWindowsIronOxide5>();
557 createBuiltInType<AirWindowsIronOxideClassic>();
558 createBuiltInType<AirWindowsLeftoMono>();
559 createBuiltInType<AirWindowsLogical4>();
560 createBuiltInType<AirWindowsLoud>();
561 createBuiltInType<AirWindowsLowpass>();
562 createBuiltInType<AirWindowsLowpass2>();
563 createBuiltInType<AirWindowsMV>();
564 createBuiltInType<AirWindowsMelt>();
565 createBuiltInType<AirWindowsMidSide>();
566 createBuiltInType<AirWindowsMoNoam>();
567 createBuiltInType<AirWindowsMojo>();
568 createBuiltInType<AirWindowsMonitoring>();
569 createBuiltInType<AirWindowsNCSeventeen>();
570 createBuiltInType<AirWindowsNaturalizeDither>();
571 createBuiltInType<AirWindowsNodeDither>();
572 createBuiltInType<AirWindowsNoise>();
573 createBuiltInType<AirWindowsNonlinearSpace>();
574 createBuiltInType<AirWindowsNotJustAnotherCD>();
575 createBuiltInType<AirWindowsNotJustAnotherDither>();
576 createBuiltInType<AirWindowsOneCornerClip>();
577 createBuiltInType<AirWindowsPDBuss>();
578 createBuiltInType<AirWindowsPDChannel>();
579 createBuiltInType<AirWindowsPafnuty>();
580 createBuiltInType<AirWindowsPaulDither>();
581 createBuiltInType<AirWindowsPeaksOnly>();
582 createBuiltInType<AirWindowsPhaseNudge>();
583 createBuiltInType<AirWindowsPocketVerbs>();
584 createBuiltInType<AirWindowsPodcast>();
585 createBuiltInType<AirWindowsPodcastDeluxe>();
586 createBuiltInType<AirWindowsPoint>();
587 createBuiltInType<AirWindowsPop>();
588 createBuiltInType<AirWindowsPowerSag>();
589 createBuiltInType<AirWindowsPowerSag2>();
590 createBuiltInType<AirWindowsPressure4>();
591 createBuiltInType<AirWindowsPurestAir>();
592 createBuiltInType<AirWindowsPurestConsoleBuss>();
593 createBuiltInType<AirWindowsPurestConsoleChannel>();
594 createBuiltInType<AirWindowsPurestDrive>();
595 createBuiltInType<AirWindowsPurestEcho>();
596 createBuiltInType<AirWindowsPurestGain>();
597 createBuiltInType<AirWindowsPurestSquish>();
598 createBuiltInType<AirWindowsPurestWarm>();
599 createBuiltInType<AirWindowsPyewacket>();
600 createBuiltInType<AirWindowsRawGlitters>();
601 createBuiltInType<AirWindowsRawTimbers>();
602 createBuiltInType<AirWindowsRecurve>();
603 createBuiltInType<AirWindowsRemap>();
604 createBuiltInType<AirWindowsResEQ>();
605 createBuiltInType<AirWindowsRighteous4>();
606 createBuiltInType<AirWindowsRightoMono>();
607 createBuiltInType<AirWindowsSideDull>();
608 createBuiltInType<AirWindowsSidepass>();
609 createBuiltInType<AirWindowsSingleEndedTriode>();
610 createBuiltInType<AirWindowsSlew>();
611 createBuiltInType<AirWindowsSlew2>();
612 createBuiltInType<AirWindowsSlewOnly>();
613 createBuiltInType<AirWindowsSmooth>();
614 createBuiltInType<AirWindowsSoftGate>();
615 createBuiltInType<AirWindowsSpatializeDither>();
616 createBuiltInType<AirWindowsSpiral>();
617 createBuiltInType<AirWindowsSpiral2>();
618 createBuiltInType<AirWindowsStarChild>();
619 createBuiltInType<AirWindowsStereoFX>();
620 createBuiltInType<AirWindowsStudioTan>();
621 createBuiltInType<AirWindowsSubsOnly>();
622 createBuiltInType<AirWindowsSurge>();
623 createBuiltInType<AirWindowsSurgeTide>();
624 createBuiltInType<AirWindowsSwell>();
625 createBuiltInType<AirWindowsTPDFDither>();
626 createBuiltInType<AirWindowsTapeDelay>();
627 createBuiltInType<AirWindowsTapeDither>();
628 createBuiltInType<AirWindowsTapeDust>();
629 createBuiltInType<AirWindowsTapeFat>();
630 createBuiltInType<AirWindowsThunder>();
631 createBuiltInType<AirWindowsToTape5>();
632 createBuiltInType<AirWindowsToVinyl4>();
633 createBuiltInType<AirWindowsToneSlant>();
634 createBuiltInType<AirWindowsTransDesk>();
635 createBuiltInType<AirWindowsTremolo>();
636 createBuiltInType<AirWindowsTubeDesk>();
637 createBuiltInType<AirWindowsUnBox>();
638 createBuiltInType<AirWindowsVariMu>();
639 createBuiltInType<AirWindowsVibrato>();
640 createBuiltInType<AirWindowsVinylDither>();
641 createBuiltInType<AirWindowsVoiceOfTheStarship>();
642 createBuiltInType<AirWindowsVoiceTrick>();
643 createBuiltInType<AirWindowsWider>();
644 createBuiltInType<AirWindowscurve>();
645 createBuiltInType<AirWindowsuLawDecode>();
646 createBuiltInType<AirWindowsuLawEncode>();
647}
648#endif
649
651{
652 std::unique_ptr<juce::XmlElement> xml (knownPluginList.createXml());
653 engine.getPropertyStorage().setXmlProperty (getPluginListPropertyName(), *xml);
654}
655
656Plugin::Ptr PluginManager::createExistingPlugin (Edit& ed, const juce::ValueTree& v)
657{
658 if (auto p = createPlugin (ed, v, false))
659 {
660 p->initialiseFully();
661 return p;
662 }
663
664 return {};
665}
666
667Plugin::Ptr PluginManager::createNewPlugin (Edit& ed, const juce::ValueTree& v)
668{
669 if (auto p = createPlugin (ed, v, true))
670 {
671 p->initialiseFully();
672 return p;
673 }
674
675 return {};
676}
677
678Plugin::Ptr PluginManager::createNewPlugin (Edit& ed, const juce::String& type, const juce::PluginDescription& desc)
679{
680 jassert (initialised); // must call PluginManager::initialise() before this!
681 jassert ((type == ExternalPlugin::xmlTypeName) == type.equalsIgnoreCase (ExternalPlugin::xmlTypeName));
682
683 if (type.equalsIgnoreCase (ExternalPlugin::xmlTypeName))
684 return new ExternalPlugin (PluginCreationInfo (ed, ExternalPlugin::create (ed.engine, desc), true));
685
686 if (type.equalsIgnoreCase (RackInstance::xmlTypeName))
687 {
688 // If you're creating a RackInstance, you need to specify the Rack index!
690
691 RackType::Ptr rackType;
692 auto rackIndex = desc.fileOrIdentifier.getTrailingIntValue();
693
694 if (desc.fileOrIdentifier.startsWith (RackType::getRackPresetPrefix()))
695 {
696 if (rackIndex >= 0)
697 rackType = ed.engine.getEngineBehaviour().createPresetRackType (rackIndex, ed);
698 else
699 rackType = ed.getRackList().addNewRack();
700 }
701 else
702 {
703 rackType = ed.getRackList().getRackType (rackIndex);
704 }
705
706 if (rackType != nullptr)
707 return new RackInstance (PluginCreationInfo (ed, RackInstance::create (*rackType), true));
708 }
709
710 for (auto builtIn : builtInTypes)
711 {
712 if (builtIn->type == type)
713 {
714 auto v = createValueTree (IDs::PLUGIN,
715 IDs::type, type);
716
717 if (ed.engine.getPluginManager().areGUIsLockedByDefault())
718 v.setProperty (IDs::windowLocked, true, nullptr);
719
720 if (auto p = builtIn->create (PluginCreationInfo (ed, v, true)))
721 return p;
722 }
723 }
724
725 return {};
726}
727
728juce::Array<juce::PluginDescription> PluginManager::getARACompatiblePlugDescriptions()
729{
730 jassert (initialised); // must call PluginManager::initialise() before this!
731
733
734 for (const auto& p : knownPluginList.getTypes())
735 {
736 if (p.pluginFormatName != "VST3")
737 continue;
738
739 if (p.name.containsIgnoreCase ("Melodyne"))
740 {
741 auto version = p.version.trim().removeCharacters ("V").upToFirstOccurrenceOf (".", false, true);
742
743 if (version.getIntValue() >= 4)
744 descs.add (p);
745 }
746 }
747
748 return descs;
749}
750
751bool PluginManager::areGUIsLockedByDefault()
752{
753 return engine.getPropertyStorage().getProperty (SettingID::filterGui, true);
754}
755
756void PluginManager::setGUIsLockedByDefault (bool b)
757{
758 engine.getPropertyStorage().setProperty (SettingID::filterGui, b);
759}
760
761bool PluginManager::doubleClickToOpenWindows()
762{
763 return engine.getPropertyStorage().getProperty (SettingID::windowsDoubleClick, false);
764}
765
766void PluginManager::setDoubleClickToOpenWindows (bool b)
767{
768 engine.getPropertyStorage().setProperty (SettingID::windowsDoubleClick, b);
769}
770
771int PluginManager::getNumberOfThreadsForScanning()
772{
774 static_cast<int> (engine.getPropertyStorage().getProperty (SettingID::numThreadsForPluginScanning, 1)));
775}
776
777void PluginManager::setNumberOfThreadsForScanning (int numThreads)
778{
779 engine.getPropertyStorage().setProperty (SettingID::numThreadsForPluginScanning,
781}
782
783bool PluginManager::usesSeparateProcessForScanning()
784{
786 return engine.getPropertyStorage().getProperty (SettingID::useSeparateProcessForScanning, true);
787 return false;
788}
789
790void PluginManager::setUsesSeparateProcessForScanning (bool b)
791{
792 engine.getPropertyStorage().setProperty (SettingID::useSeparateProcessForScanning, b);
793}
794
795Plugin::Ptr PluginManager::createPlugin (Edit& ed, const juce::ValueTree& v, bool isNew)
796{
797 jassert (initialised); // must call PluginManager::initialise() before this!
798
799 if (! v.isValid())
800 return {};
801
802 auto type = v[IDs::type].toString();
803 PluginCreationInfo info (ed, v, isNew);
804
805 EditItemID::readOrCreateNewID (ed, v);
806
807 if (type == ExternalPlugin::xmlTypeName)
808 return new ExternalPlugin (info);
809
810 if (type == RackInstance::xmlTypeName)
811 return new RackInstance (info);
812
813 for (auto builtIn : builtInTypes)
814 if (builtIn->type == type)
815 if (auto af = builtIn->create (info))
816 return af;
817
818 if (auto af = engine.getEngineBehaviour().createCustomPlugin (info))
819 return af;
820
821 TRACKTION_LOG_ERROR ("Failed to create plugin: " + type);
822 return {};
823}
824
825//==============================================================================
826void PluginManager::registerBuiltInType (std::unique_ptr<BuiltInType> t)
827{
828 for (auto builtIn : builtInTypes)
829 if (builtIn->type == t->type)
830 return;
831
832 builtInTypes.add (t.release());
833}
834
835//==============================================================================
836PluginCache::PluginCache (Edit& ed) : edit (ed)
837{
838 startTimer (1000);
839}
840
841PluginCache::~PluginCache()
842{
843 activePlugins.clear();
844}
845
846Plugin::Ptr PluginCache::getPluginFor (EditItemID pluginID) const
847{
848 if (! pluginID.isValid())
849 return {};
850
851 const juce::ScopedLock sl (lock);
852
853 for (auto p : activePlugins)
854 if (EditItemID::fromProperty (p->state, IDs::id) == pluginID)
855 return *p;
856
857 return {};
858}
859
860Plugin::Ptr PluginCache::getPluginFor (const juce::ValueTree& v) const
861{
862 const juce::ScopedLock sl (lock);
863
864 for (auto p : activePlugins)
865 if (p->state == v)
866 return *p;
867
868 return {};
869}
870
871Plugin::Ptr PluginCache::getPluginFor (juce::AudioProcessor& ap) const
872{
873 const juce::ScopedLock sl (lock);
874
875 for (auto p : activePlugins)
876 if (p->getWrappedAudioProcessor() == &ap)
877 return *p;
878
879 return {};
880}
881
882Plugin::Ptr PluginCache::getOrCreatePluginFor (const juce::ValueTree& v)
883{
884 const juce::ScopedLock sl (lock);
885
886 if (auto f = getPluginFor (v))
887 return f;
888
889 if (auto f = edit.engine.getPluginManager().createExistingPlugin (edit, v))
890 {
891 jassert (juce::MessageManager::getInstance()->currentThreadHasLockedMessageManager()
892 || dynamic_cast<ExternalPlugin*> (f.get()) == nullptr);
893
894 return addPluginToCache (f);
895 }
896
897 return {};
898}
899
900Plugin::Ptr PluginCache::createNewPlugin (const juce::ValueTree& v)
901{
902 const juce::ScopedLock sl (lock);
903 auto p = addPluginToCache (edit.engine.getPluginManager().createNewPlugin (edit, v));
904
905 if (p != nullptr && newPluginAddedCallback != nullptr)
907
908 return p;
909}
910
911Plugin::Ptr PluginCache::createNewPlugin (const juce::String& type, const juce::PluginDescription& desc)
912{
913 jassert (type.isNotEmpty());
914
915 const juce::ScopedLock sl (lock);
916 auto p = addPluginToCache (edit.engine.getPluginManager().createNewPlugin (edit, type, desc));
917
918 if (p != nullptr && newPluginAddedCallback != nullptr)
920
921 return p;
922}
923
924Plugin::Array PluginCache::getPlugins() const
925{
926 const juce::ScopedLock sl (lock);
927 return activePlugins;
928}
929
930Plugin::Ptr PluginCache::addPluginToCache (Plugin::Ptr p)
931{
932 if (p == nullptr)
933 {
935 return {};
936 }
937
938 if (auto existing = getPluginFor (p->state))
939 {
941 return existing;
942 }
943
944 jassert (! activePlugins.contains (p));
945 activePlugins.add (p);
946
947 return p;
948}
949
951{
952 Plugin::Array toDelete;
953
954 {
955 const juce::ScopedLock sl (lock);
956
957 for (int i = activePlugins.size(); --i >= 0;)
958 {
959 if (auto f = activePlugins.getObjectPointer (i))
960 {
961 if (f->getReferenceCount() == 1)
962 {
963 toDelete.add (f);
964 activePlugins.remove (i);
965 }
966 }
967 }
968 }
969}
970
971}} // namespace tracktion { inline namespace engine
void add(const ElementType &newElement)
AudioPluginFormat * getFormat(int index) const
void addFormat(AudioPluginFormat *)
void addChangeListener(ChangeListener *listener)
void removeChangeListener(ChangeListener *listener)
virtual void changeListenerCallback(ChangeBroadcaster *source)=0
bool sendMessageToWorker(const MemoryBlock &)
bool launchWorkerProcess(const File &executableToLaunch, const String &commandLineUniqueID, int timeoutMs=0, int streamFlags=ChildProcess::wantStdOut|ChildProcess::wantStdErr)
bool sendMessageToCoordinator(const MemoryBlock &)
static File JUCE_CALLTYPE getSpecialLocation(const SpecialLocationType type)
bool isValid() const noexcept
const String & toString() const noexcept
bool shouldExit() const noexcept
void recreateFromXml(const XmlElement &xml)
std::unique_ptr< XmlElement > createXml() const
void setCustomScanner(std::unique_ptr< CustomScanner > newScanner)
String toString() const
MemoryBlock getMemoryBlock() const
int size() const noexcept
ObjectClass * getUnchecked(int index) const noexcept
ObjectClass * removeAndReturn(int indexToRemove)
ObjectClass * add(ObjectClass *newObject)
bool loadFromXml(const XmlElement &xml)
static void JUCE_CALLTYPE terminate()
int nextInt() noexcept
int size() const noexcept
void remove(int indexToRemove)
ObjectClass * getObjectPointer(int index) const noexcept
bool contains(const ObjectClass *objectToLookFor) const noexcept
ObjectClass * add(ObjectClass *newObject)
bool startsWith(StringRef text) const noexcept
int getTrailingIntValue() const noexcept
bool isNotEmpty() const noexcept
static int getNumCpus() noexcept
static Time JUCE_CALLTYPE getCurrentTime() noexcept
virtual void timerCallback()=0
void addChildElement(XmlElement *newChildElement) noexcept
void writeTo(OutputStream &output, const TextFormat &format={}) const
bool hasTagName(StringRef possibleTagName) const noexcept
int getIntAttribute(StringRef attributeName, int defaultReturnValue=0) const
const String & getStringAttribute(StringRef attributeName) const noexcept
void setAttribute(const Identifier &attributeName, const String &newValue)
Engine & engine
A reference to the Engine.
virtual Plugin::Ptr createCustomPlugin(PluginCreationInfo)
This will be called if the PluginManager doesn't know how to create a Plugin for the given info.
virtual bool canScanPluginsOutOfProcess()
Return true if your application supports scanning plugins out of process.
The Engine is the central class for all tracktion sessions.
PropertyStorage & getPropertyStorage() const
Returns the PropertyStorage user settings customisable XML file.
UIBehaviour & getUIBehaviour() const
Returns the UIBehaviour class.
EngineBehaviour & getEngineBehaviour() const
Returns the EngineBehaviour instance.
PluginManager & getPluginManager() const
Returns the PluginManager instance.
std::function< void(const Plugin &)> newPluginAddedCallback
Callback which can be set to be notified of when a new plugin is added.
virtual void showWarningAlert(const juce::String &title, const juce::String &message)
Should display a dismissable alert window.
T exit(T... args)
getpid
T is_pointer_v
#define TRANS(stringLiteral)
#define jassert(expression)
#define JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(className)
#define jassertfalse
kill
NewLine newLine
Type jlimit(Type lowerLimit, Type upperLimit, Type valueToConstrain) noexcept
std::unique_ptr< XmlElement > parseXML(const String &textToParse)
void ignoreUnused(Types &&...) noexcept
SettingID
A list of settings the engine will get and set.
#define CRASH_TRACER
This macro adds the current location to a stack which gets logged if a crash happens.