11namespace tracktion {
inline namespace engine
30 if (
auto pi = plugin.getAudioPluginInstance())
31 pi->addListener (
this);
40 if (
auto pi = plugin.getAudioPluginInstance())
41 pi->removeListener (
this);
60 processorChanged =
true;
71 for (
auto param : item.getAutomatableParameters())
72 if (! getModifiersOfType<Modifier> (*param).isEmpty())
78 void updateFromPlugin()
80 TRACKTION_ASSERT_MESSAGE_THREAD
81 bool wasLatencyChange =
false;
83 if (
auto pi = plugin.getAudioPluginInstance())
85 if (plugin.latencySamples != pi->getLatencySamples())
87 wasLatencyChange =
true;
89 if (plugin.isInstancePrepared)
91 plugin.latencySamples = pi->getLatencySamples();
92 plugin.latencySeconds = plugin.latencySamples / plugin.sampleRate;
100 pi->refreshParameterList();
104 for (
auto p : plugin.autoParamForParamNumbers)
108 p->unregisterAsListener();
109 p->registerAsListener();
121 if (! wasLatencyChange && ! hasAnyModifiers (plugin))
122 plugin.refreshParameterValues();
128 void handleAsyncUpdate()
override
132 paramChanged =
false;
135 if (processorChanged)
137 processorChanged =
false;
142 bool paramChanged =
false, processorChanged =
false;
155 while (plugins.
size() > 0)
158 clearSingletonInstance();
172 bool releaseNextDanglingPlugin()
174 if (plugins.
size() > 0)
183 void timerCallback()
override
206 bool recursive =
false;
213void cleanUpDanglingPlugins()
215 #if JUCE_MODAL_LOOPS_PERMITTED
216 if (
auto d = AsyncPluginDeleter::getInstanceWithoutCreating())
218 for (
int count = 400; --count > 0 && d->releaseNextDanglingPlugin();)
223 juce::MessageManager::getInstance()->runDispatchLoopUntil (10);
228 AsyncPluginDeleter::deleteInstance();
232#if JUCE_PLUGINHOST_VST
235 ExtraVSTCallbacks (Edit& ed) : edit (ed) {}
239 auto sampleRate = edit.engine.getDeviceManager().getSampleRate();
240 return (
juce::int64) (10000.0 * edit.tempoSequence.getTempoAt (TimePosition::fromSamples (samplePos, sampleRate)).getBpm());
244 int getAutomationState()
override
246 auto& am = edit.getAutomationRecordManager();
248 bool r = am.isReadingAutomation();
249 bool w = am.isWritingAutomation();
251 return r ? (w ? 4 : 2) : (w ? 3 : 1);
256 ExtraVSTCallbacks() =
delete;
282 loopStart.
set (loopTimeRange.getStart());
283 loopEnd.
set (loopTimeRange.getEnd());
284 currentPos.
set (time);
297 result.setFrameRate (getFrameRate());
300 auto localTime = time.load();
302 result.setIsPlaying (isPlaying);
303 result.setIsRecording (transport.isRecording());
304 result.setEditOriginTime (transport.getTimeWhenStarted().inSeconds());
305 result.setIsLooping (transport.looping);
307 if (transport.looping)
310 result.setTimeInSeconds (localTime.inSeconds());
311 result.setTimeInSamples (toSamples (localTime, plugin.sampleRate));
314 result.setBpm (currentPos.
getTempo());
318 result.setPpqPositionOfLastBarStart (ppqPositionOfLastBarStart);
319 result.setPpqPosition (
std::max (ppqPositionOfLastBarStart, currentPos.
getPPQTime()));
325 ExternalPlugin& plugin;
326 tempo::Sequence::Position currentPos {
createPosition (plugin.edit.tempoSequence) };
327 tempo::Sequence::Position loopStart {
createPosition (plugin.edit.tempoSequence) };
328 tempo::Sequence::Position loopEnd {
createPosition (plugin.edit.tempoSequence) };
332 AudioPlayHead::FrameRateType getFrameRate()
const
334 switch (plugin.edit.getTimecodeFormat().getFPS())
336 case 24:
return AudioPlayHead::fps24;
337 case 25:
return AudioPlayHead::fps25;
338 case 29:
return AudioPlayHead::fps30drop;
339 case 30:
return AudioPlayHead::fps30;
343 return AudioPlayHead::fps30;
356 jassert (state.hasType (IDs::LAYOUT));
357 auto& targetBuses = (isInput ? busesLayout.
inputBuses
361 auto buses = state.getChildWithName (isInput ? IDs::INPUTS : IDs::OUTPUTS);
367 if (! v.hasType (IDs::BUS))
370 const int busIdx = v[IDs::index];
371 maxNumBuses =
std::max (maxNumBuses, busIdx + 1);
375 for (
int actualIdx = plugin.
getBusCount (isInput) - 1; actualIdx < busIdx; ++actualIdx)
376 if (! plugin.
addBus (isInput))
379 for (
int actualIdx = targetBuses.size() - 1; actualIdx < busIdx; ++actualIdx)
382 const auto layout = v[IDs::layout].
toString();
384 if (layout.isNotEmpty())
390 while (maxNumBuses < targetBuses.size())
395 targetBuses.removeLast();
403 if (
auto* mb = layout.getBinaryData())
406 readBusLayout (busesLayout, v, plugin,
true);
407 readBusLayout (busesLayout, v, plugin,
false);
415 auto& buses = (isInput ? layout.inputBuses : layout.outputBuses);
419 for (
int busIdx = 0; busIdx < buses.size(); ++busIdx)
421 auto& set = buses.getReference (busIdx);
422 juce::String layoutName = set.isDisabled() ?
"disabled" : set.getSpeakerArrangementAsString();
424 auto bus = createValueTree (IDs::BUS,
426 IDs::layout, layoutName);
428 v.addChild (bus, -1,
nullptr);
436 auto inputs = createBusLayout (layout,
true);
437 auto outputs = createBusLayout (layout,
false);
439 if (inputs.getNumChildren() == 0 && outputs.getNumChildren() == 0)
443 v.addChild (inputs, -1,
nullptr);
444 v.addChild (outputs, -1,
nullptr);
453 auto v = createBusesLayout (layout);
458 v.writeToStream (os);
464 void restoreChannelLayout (ExternalPlugin& plugin)
475 if (
auto bus = ap.
getBus (input, 0))
477 if (bus->getCurrentLayout().size() < 2)
479 for (
int i = 0; i < juce::AudioChannelSet::maxChannelsOfNamedLayout; i++)
481 auto set = bus->supportedLayoutWithChannels (i);
483 if (! set.isDisabled() && set.size() == 2)
491 bus->setCurrentLayout (bestSet);
497 if (
auto ap = plugin.getAudioPluginInstance())
499 if (plugin.state.hasProperty (IDs::layout))
501 plugin.setBusesLayout (readBusesLayout (plugin.state.getProperty (IDs::layout), *ap));
506 if (plugin.isAU() || plugin.isVST3())
509 setDefaultChannelConfig (*ap,
true);
510 setDefaultChannelConfig (*ap,
false);
519 auto v = createValueTree (IDs::PLUGIN,
520 IDs::type, xmlTypeName,
524 IDs::name, desc.
name,
527 if (e.getPluginManager().areGUIsLockedByDefault())
528 v.setProperty (IDs::windowLocked,
true,
nullptr);
535 if (pluginInstance !=
nullptr)
539 return TRANS(
"ERROR! - This plugin couldn't be loaded!");
544const char* ExternalPlugin::xmlTypeName =
"vst";
548 if (! fullyInitialised)
551 fullyInitialised =
true;
553 doFullInitialisation();
554 restorePluginStateFromValueTree (state);
555 buildParameterList();
556 restoreChannelLayout (*
this);
560void ExternalPlugin::forceFullReinitialise()
565 fullyInitialised =
false;
569 if (isInstancePrepared && pluginInstance->getSampleRate() > 0 && pluginInstance->getBlockSize() > 0)
571 pluginInstance->prepareToPlay (pluginInstance->getSampleRate(), pluginInstance->getBlockSize());
575 SelectionManager::refreshAllPropertyPanelsShowing (*
this);
578 t->refreshCurrentAutoParam();
581void ExternalPlugin::updateDebugName()
586void ExternalPlugin::buildParameterList()
589 autoParamForParamNumbers.clear();
590 clearParameterList();
593 addAutomatableParameter (dryGain);
594 addAutomatableParameter (wetGain);
596 if (pluginInstance !=
nullptr)
598 auto& parameters = pluginInstance->getParameters();
599 jassert (parameters.size() < 80000);
600 const auto maxAutoParams =
std::min (80000, parameters.size());
602 for (
int i = 0; i < maxAutoParams; ++i)
604 auto parameter = parameters.getUnchecked (i);
606 if (parameter->isAutomatable() && ! isParameterBlacklisted (*
this, *pluginInstance, *parameter))
608 auto nm = parameter->getName (1024);
610 bool emptyName = nm.isEmpty();
616 if (alreadyUsedParamNames.
find (nm.toStdString()) != alreadyUsedParamNames.
end())
618 count = alreadyUsedParamNames[nm.toStdString()] + 1;
619 alreadyUsedParamNames[nm.toStdString()] =
count;
620 nm <<
" (" <<
count <<
")";
624 alreadyUsedParamNames[nm.toStdString()] =
count;
631 parameterID = paramWithID->paramID;
633 auto p =
new ExternalAutomatableParameter (parameterID, nm, *
this, i, { 0.0f, 1.0f });
634 addAutomatableParameter (*p);
635 autoParamForParamNumbers.add (p);
636 p->valueChangedByPlugin();
638 if (count >= 2 && ! emptyName)
639 p->setDisplayName (nm);
644 autoParamForParamNumbers.add (
nullptr);
650 buildParameterTree();
653void ExternalPlugin::refreshParameterValues()
655 for (
auto p : autoParamForParamNumbers)
657 p->valueChangedByPlugin();
663 for (
auto d : engine.getPluginManager().knownPluginList.getTypes())
664 if (d.uniqueId == uid)
667 if (deprecatedUid != 0)
668 for (
auto d : engine.getPluginManager().knownPluginList.getTypes())
669 if (d.deprecatedUid == deprecatedUid)
681 for (
auto d : pm.knownPluginList.getTypes())
682 if (d.fileOrIdentifier == fileOrID)
697 auto& pm = engine.getPluginManager();
701 for (
auto d : pm.knownPluginList.getTypes())
702 if (d.name == nameToFind && d.pluginFormatName ==
format)
708 if (
auto p = findName (name))
712 if (
auto p = findName (name +
" (64 bit)"))
715 if (
auto p = findName (name +
" (64-bit)"))
725 auto& pm = engine.getPluginManager();
727 if (
auto p = pm.knownPluginList.getTypeForIdentifierString (createIdentifierString (desc)))
732 if (
auto p = pm.knownPluginList.getTypeForIdentifierString (
"VST" + createIdentifierString (desc)))
735 if (
auto p = pm.knownPluginList.getTypeForIdentifierString (
"AudioUnit" + createIdentifierString (desc)))
747 auto file = d.fileOrIdentifier.toLowerCase();
748 if (file.endsWith (
".vst3"))
return "VST3";
749 if (file.endsWith (
".vst") || file.endsWith (
".dll"))
return "VST";
750 if (file.startsWith (
"audiounit:"))
return "AudioUnit";
754 if (
auto p = findDescForName (engine, desc.
name, getPreferredFormat (desc)))
757 for (
auto d : pm.knownPluginList.getTypes())
758 if (d.name == desc.name)
761 for (
auto d : pm.knownPluginList.getTypes())
762 if (
juce::File::createFileWithoutCheckingPath (d.fileOrIdentifier).getFileNameWithoutExtension() == desc.name)
766 if (
auto p = findDescForUID (0x4D44414A, 0x4D44414A))
773void ExternalPlugin::processingChanged()
775 Plugin::processingChanged();
779 if (pluginInstance ==
nullptr)
780 forceFullReinitialise();
784 clearParameterList();
785 autoParamForParamNumbers.clear();
786 getParameterTree().clear();
788 deletePluginInstance();
792void ExternalPlugin::doFullInitialisation()
794 if (
auto foundDesc = findMatchingPlugin())
797 identiferString = createIdentifierString (desc);
800 if (processing && pluginInstance ==
nullptr && engine.getEngineBehaviour().shouldLoadPlugin (*
this))
808 callBlocking ([
this, &foundDesc]
811 loadError = createPluginInstance (*foundDesc);
814 if (pluginInstance !=
nullptr)
816 #if JUCE_PLUGINHOST_VST
817 if (
auto xml = juce::VSTPluginFormat::getVSTXML (pluginInstance.
get()))
818 vstXML.reset (VSTXML::createFor (*xml));
823 pluginInstance->setPlayHead (playhead.get());
824 supportsMPE = pluginInstance->supportsMPE();
826 engine.getEngineBehaviour().doAdditionalInitialisation (*
this);
830 TRACKTION_LOG_ERROR (loadError);
838 juce::MessageManager::callAsync ([
this, pluginRef =
makeSafeRef (*
this)]
840 if (pluginRef ==
nullptr)
843 if (
auto t =
getOwnerTrack(); t !=
nullptr && pluginInstance !=
nullptr)
845 auto n = t->getName();
846 auto c = t->getColour();
848 pluginInstance->updateTrackProperties ({n, c});
856 for (
auto param : autoParamForParamNumbers)
857 if (param !=
nullptr)
858 param->unregisterAsListener();
864void ExternalPlugin::flushPluginStateToValueTree()
866 Plugin::flushPluginStateToValueTree();
868 auto* um = getUndoManager();
873 state.setProperty (IDs::name, desc.
name, um);
874 itemID.writeID (state, um);
875 state.setProperty (IDs::uid, getPluginUID(), um);
879 if (pluginInstance !=
nullptr)
881 if (pluginInstance->getNumPrograms() > 0)
882 state.setProperty (IDs::programNum, pluginInstance->getCurrentProgram(), um);
884 TRACKTION_ASSERT_MESSAGE_THREAD
887 pluginInstance->suspendProcessing (
true);
888 pluginInstance->getStateInformation (chunk);
890 pluginInstance->suspendProcessing (
false);
892 engine.getEngineBehaviour().saveCustomPluginProperties (state, *pluginInstance, um);
894 if (chunk.getSize() > 0)
895 state.setProperty (IDs::state, chunk.toBase64Encoding(), um);
897 state.removeProperty (IDs::state, um);
899 flushBusesLayoutToValueTree();
903void ExternalPlugin::flushBusesLayoutToValueTree()
908 if (
auto ap = getAudioPluginInstance())
910 auto* um = getUndoManager();
915 state.setProperty (IDs::layout, mb, um);
917 state.removeProperty (IDs::layout, um);
921void ExternalPlugin::restorePluginStateFromValueTree (
const juce::ValueTree& v)
925 if (v.hasProperty (IDs::state))
927 s = v.getProperty (IDs::state).
toString();
931 auto vstDataTree = v.getChildWithName (IDs::VSTDATA);
933 if (vstDataTree.isValid())
935 s = vstDataTree.getProperty (IDs::DATA).toString();
938 s = vstDataTree.getProperty (IDs::__TEXT).toString();
942 if (pluginInstance !=
nullptr && s.
isNotEmpty())
946 if (getNumPrograms() > 1)
947 setCurrentProgram (v.getProperty (IDs::programNum),
false);
953 callBlocking ([
this, &chunk]() { pluginInstance->setStateInformation (chunk.
getData(), (
int) chunk.
getSize()); });
959 auto s = state.getProperty (IDs::state).
toString();
966void ExternalPlugin::updateFromMirroredPluginIfNeeded (Plugin& changedPlugin)
968 TRACKTION_ASSERT_MESSAGE_THREAD
970 if (changedPlugin.itemID == masterPluginID)
972 if (
auto other =
dynamic_cast<ExternalPlugin*
> (&changedPlugin))
974 if (other->pluginInstance !=
nullptr && other->desc.isDuplicateOf (desc))
977 other->pluginInstance->getStateInformation (chunk);
980 pluginInstance->setStateInformation (chunk.
getData(), (
int) chunk.
getSize());
989 static constexpr int lowChannel = 2, highChannel = 16;
991 void reset()
noexcept
993 for (
auto& s : sourceAndChannel)
994 s = MidiMessageArray::notMPE;
997 void clearChannel (
int channel)
noexcept
999 sourceAndChannel[channel] = MidiMessageArray::notMPE;
1004 auto channel = m.getChannel();
1006 if (channel < lowChannel || channel > highChannel)
1009 auto sourceAndChannelID = (((
uint32_t) m.mpeSourceID << 5) | (
uint32_t) (channel - 1));
1011 if ((*m.getRawData() & 0xf0) != 0xf0)
1015 if (applyRemapIfExisting (channel, sourceAndChannelID, m))
1018 for (
int chan = lowChannel; chan <= highChannel; ++chan)
1019 if (applyRemapIfExisting (chan, sourceAndChannelID, m))
1022 if (sourceAndChannel[channel] == MidiMessageArray::notMPE)
1024 lastUsed[channel] = counter;
1025 sourceAndChannel[channel] = sourceAndChannelID;
1029 auto chan = getBestChanToReuse();
1030 sourceAndChannel[chan] = sourceAndChannelID;
1031 lastUsed[chan] = counter;
1032 m.setChannel (chan);
1036 uint32_t sourceAndChannel[17] = {};
1040 int getBestChanToReuse()
const noexcept
1042 for (
int chan = lowChannel; chan <= highChannel; ++chan)
1043 if (sourceAndChannel[chan] == MidiMessageArray::notMPE)
1046 auto bestChan = lowChannel;
1047 auto bestLastUse = counter;
1049 for (
int chan = lowChannel; chan <= highChannel; ++chan)
1051 if (lastUsed[chan] < bestLastUse)
1053 bestLastUse = lastUsed[chan];
1063 if (sourceAndChannel[channel] == sourceAndChannelID)
1065 if (m.isNoteOff() || m.isAllNotesOff() || m.isResetAllControllers())
1066 sourceAndChannel[channel] = MidiMessageArray::notMPE;
1068 lastUsed[channel] = counter;
1070 m.setChannel (channel);
1083 auto um = getUndoManager();
1088 dryValue.referTo (state, IDs::dry, um);
1089 wetValue.referTo (state, IDs::wet, um, 1.0f);
1091 dryGain->attachToCurrentValue (dryValue);
1092 wetGain->attachToCurrentValue (wetValue);
1097 setEnabled (state.getProperty (IDs::enabled,
true));
1098 desc.
name = state[IDs::name];
1100 identiferString = createIdentifierString (desc);
1105ExternalPlugin::~ExternalPlugin()
1107 TRACKTION_ASSERT_MESSAGE_THREAD
1109 notifyListenersOfDeletion();
1110 windowState->hideWindowForShutdown();
1113 dryGain->detachFromCurrentValue();
1114 wetGain->detachFromCurrentValue();
1117 deletePluginInstance();
1127 if (mpeRemapper ==
nullptr)
1130 mpeRemapper->reset();
1132 if (pluginInstance !=
nullptr)
1138 if (! isInstancePrepared)
1140 pluginInstance->prepareToPlay (info.sampleRate, info.blockSizeSamples);
1141 isInstancePrepared =
true;
1143 else if (info.sampleRate != lastSampleRate || info.blockSizeSamples != lastBlockSizeSamples)
1145 pluginInstance->prepareToPlay (info.sampleRate, info.blockSizeSamples);
1148 lastSampleRate = info.sampleRate;
1149 lastBlockSizeSamples = info.blockSizeSamples;
1151 latencySamples = pluginInstance->getLatencySamples();
1152 latencySeconds = latencySamples / info.sampleRate;
1156 desc = pluginInstance->getPluginDescription();
1160 pluginInstance->setPlayHead (
nullptr);
1162 pluginInstance->setPlayHead (playhead.get());
1168 latencySeconds = 0.0;
1169 isInstancePrepared =
false;
1175 if (pluginInstance !=
nullptr)
1180 pluginInstance->setPlayHead (
nullptr);
1182 if (playhead !=
nullptr)
1183 playhead->setCurrentContext (
nullptr);
1189 if (pluginInstance !=
nullptr)
1193 pluginInstance->
reset();
1201 if (shouldEnable != isEnabled())
1203 if (pluginInstance !=
nullptr)
1204 pluginInstance->
reset();
1206 propertiesChanged();
1211void ExternalPlugin::prepareIncomingMidiMessages (
MidiMessageArray& incoming,
int numSamples,
bool isPlaying)
1213 if (incoming.isAllNotesOff)
1217 activeNotes.iterate ([&eventsSentOnChannel,
this, isPlaying] (
int chan,
int noteNumber)
1221 if ((eventsSentOnChannel & (1u << chan)) == 0)
1223 eventsSentOnChannel |= (1u << chan);
1244 activeNotes.reset();
1245 mpeRemapper->reset();
1251 layout.setLowerZone (15);
1254 for (
auto itr : layoutBuffer)
1256 auto result = itr.getMessage();
1257 int samplePosition = itr.samplePosition;
1259 midiBuffer.
addEvent (result, samplePosition);
1264 for (
auto& m : incoming)
1267 mpeRemapper->remapMidiChannelIfNeeded (m);
1271 if (activeNotes.isNoteActive (m.getChannel(), m.getNoteNumber()))
1274 activeNotes.startNote (m.getChannel(), m.getNoteNumber());
1276 else if (m.isNoteOff())
1278 activeNotes.clearNote (m.getChannel(), m.getNoteNumber());
1286 if (! incoming.isEmpty())
1289 int numBytes, midiEventPos;
1293 for (juce::MidiBuffer::Iterator iter (midiBuffer); iter.getNextEvent (midiData, numBytes, midiEventPos);)
1305 if (pluginInstance !=
nullptr && (processedBypass || isEnabled()))
1311 if (playhead !=
nullptr)
1312 playhead->setCurrentContext (&fc);
1324 auto numInputChannels = pluginInstance->getTotalNumInputChannels();
1325 auto numOutputChannels = pluginInstance->getTotalNumOutputChannels();
1326 auto numChansToProcess =
std::max (
std::max (1, numInputChannels), numOutputChannels);
1328 if (destNumChans == numChansToProcess)
1330 processPluginBlock (fc, processedBypass);
1335 auto& buffer = asb.
buffer;
1338 for (
int i = 0; i < numChansToProcess; ++i)
1340 if (i < destNumChans)
1346 if (destNumChans == 1 && numInputChannels == 2)
1351 else if (destNumChans == 2 && numInputChannels == 1)
1362 processPluginBlock (fc2, processedBypass);
1365 for (
int i = 0; i < destNumChans; ++i)
1367 if (i < numChansToProcess)
1369 else if (i < 2 && numChansToProcess > 0)
1381 if (processedBypass)
1382 pluginInstance->processBlockBypassed (asb.
buffer, midiBuffer);
1384 pluginInstance->processBlock (asb.
buffer, midiBuffer);
1393 for (
auto itr : midiBuffer)
1395 const auto& msg = itr.getMessage();
1396 int midiEventPos = itr.samplePosition;
1398 auto midiData = msg.getRawData();
1399 auto numBytes = msg.getRawDataSize();
1409void ExternalPlugin::processPluginBlock (
const PluginRenderContext& fc,
bool processedBypass)
1414 auto dry = dryGain->getCurrentValue();
1415 auto wet = wetGain->getCurrentValue();
1417 if (dry <= 0.00004f)
1419 if (processedBypass)
1420 pluginInstance->processBlockBypassed (asb, midiBuffer);
1422 pluginInstance->processBlock (asb, midiBuffer);
1424 zeroDenormalisedValuesIfNeeded (asb);
1431 auto numChans = asb.getNumChannels();
1434 for (
int i = 0; i < numChans; ++i)
1437 if (processedBypass)
1438 pluginInstance->processBlockBypassed (asb, midiBuffer);
1440 pluginInstance->processBlock (asb, midiBuffer);
1442 zeroDenormalisedValuesIfNeeded (asb);
1447 for (
int i = 0; i < numChans; ++i)
1448 asb.addFrom (i, 0, dryAudio.buffer.getReadPointer (i), fc.
bufferNumSamples, dry);
1455 return std::max (1, getNumOutputs());
1461 if (pluginInstance !=
nullptr)
1473 const int num = pluginInstance->getTotalNumInputChannels();
1475 for (
int i = 0; i < num; ++i)
1477 auto name = getChannelName (pluginInstance->getBus (
true, 0), i);
1478 ins->
add (name.isNotEmpty() ? name :
TRANS(
"Unnamed"));
1482 if (outs !=
nullptr)
1484 const int num = pluginInstance->getTotalNumOutputChannels();
1486 for (
int i = 0; i < num; ++i)
1488 auto name = getChannelName (pluginInstance->getBus (
false, 0), i);
1489 outs->
add (name.isNotEmpty() ? name :
TRANS(
"Unnamed"));
1495bool ExternalPlugin::noTail()
1498 return pluginInstance ==
nullptr || pluginInstance->getTailLengthSeconds() <= 0.0;
1501double ExternalPlugin::getTailLength()
const
1504 return pluginInstance ? pluginInstance->getTailLengthSeconds() : 0.0;
1527int ExternalPlugin::getNumPrograms()
const
1529 return pluginInstance ? pluginInstance->getNumPrograms() : 0;
1532int ExternalPlugin::getCurrentProgram()
const
1534 return pluginInstance ? pluginInstance->getCurrentProgram() : 0;
1539 if (index == getCurrentProgram())
1540 return getCurrentProgramName();
1542 if (pluginInstance !=
nullptr)
1543 return pluginInstance->getProgramName (index);
1550 ignoreUnused (note, midiChannel, name);
1552 if (takesMidiInput())
1553 if (pluginInstance !=
nullptr)
1554 return pluginInstance->hasNameForMidiNoteNumber (note, midiChannel, name);
1562 if (takesMidiInput() && isSynth() && getNumPrograms() > 0)
1564 programNum += (bank * 128);
1566 if (programNum >= 0 && programNum < getNumPrograms())
1567 name = getProgramName (programNum);
1569 name =
TRANS(
"Unnamed");
1577juce::String ExternalPlugin::getNumberedProgramName (
int i)
1579 auto s = getProgramName(i);
1582 s =
"(" +
TRANS(
"Unnamed") +
")";
1589 return pluginInstance ? pluginInstance->getProgramName (pluginInstance->getCurrentProgram())
1593void ExternalPlugin::setCurrentProgramName (
const juce::String& name)
1597 if (pluginInstance !=
nullptr)
1598 pluginInstance->changeProgramName (pluginInstance->getCurrentProgram(), name);
1601void ExternalPlugin::setCurrentProgram (
int index,
bool sendChangeMessage)
1603 if (pluginInstance !=
nullptr && getNumPrograms() > 0)
1609 if (index != getCurrentProgram())
1611 pluginInstance->setCurrentProgram (index);
1612 state.setProperty (IDs::programNum, index,
nullptr);
1614 if (sendChangeMessage)
1617 refreshParameterValues();
1623bool ExternalPlugin::takesMidiInput()
1625 return pluginInstance && pluginInstance->acceptsMidi();
1630 return !
isDisabled() && pluginInstance ==
nullptr;
1635 return engine.getEngineBehaviour().isPluginDisabled (identiferString);
1638int ExternalPlugin::getNumInputs()
const {
return pluginInstance ? pluginInstance->getTotalNumInputChannels() : 0; }
1639int ExternalPlugin::getNumOutputs()
const {
return pluginInstance ? pluginInstance->getTotalNumOutputChannels() : 0; }
1643 if (pluginInstance !=
nullptr)
1647 if (! baseClassNeedsInitialising())
1650 jassert (baseClassNeedsInitialising());
1654 pluginInstance->releaseResources();
1655 isInstancePrepared =
false;
1657 if (pluginInstance->setBusesLayout (layout))
1661 if (
auto r = getOwnerRackType())
1662 r->checkConnections();
1664 flushBusesLayoutToValueTree();
1676 if (pluginInstance !=
nullptr)
1678 if (
auto bus = pluginInstance->getBus (isInput, busIndex))
1682 if (! baseClassNeedsInitialising())
1687 pluginInstance->releaseResources();
1688 isInstancePrepared =
false;
1690 jassert (baseClassNeedsInitialising());
1692 if (bus->setCurrentLayout (set))
1696 if (
auto r = getOwnerRackType())
1697 r->checkConnections();
1699 flushBusesLayoutToValueTree();
1715 auto& dm = engine.getDeviceManager();
1718 pluginInstance = engine.getPluginManager().createPluginInstance (description, dm.getSampleRate(), dm.getBlockSize(), error);
1720 if (pluginInstance !=
nullptr)
1722 pluginInstance->enableAllBuses();
1729void ExternalPlugin::deletePluginInstance()
1731 processorChangedManager.reset();
1732 AsyncPluginDeleter::getInstance()->deletePlugin (pluginInstance.
release());
1736void ExternalPlugin::buildParameterTree()
const
1738 auto& paramTree = getParameterTree();
1740 if (paramTree.rootNode->subNodes.size() > 0)
1744 paramTree.rootNode->addSubNode (
new AutomatableParameterTree::TreeNode (getAutomatableParameter (0)));
1745 paramTree.rootNode->addSubNode (
new AutomatableParameterTree::TreeNode (getAutomatableParameter (1)));
1751 for (
int i = 0; i < vstXML->paramTree.size(); ++i)
1753 if (
auto param =
dynamic_cast<const VSTXML::Param*
> (vstXML->paramTree[i]))
1755 if (
auto externalParameter = autoParamForParamNumbers[param->paramID])
1757 paramTree.rootNode->addSubNode (
new AutomatableParameterTree::TreeNode (externalParameter));
1758 paramsInTree.
add (param->paramID);
1762 if (
auto group =
dynamic_cast<const VSTXML::Group*
> (vstXML->paramTree[i]))
1764 auto treeNode =
new AutomatableParameterTree::TreeNode (group->name);
1765 paramTree.rootNode->addSubNode (treeNode);
1766 buildParameterTree (group, treeNode, paramsInTree);
1771 for (
int i = 0; i < getNumAutomatableParameters(); ++i)
1772 if (
auto vstParam =
dynamic_cast<ExternalAutomatableParameter*
> (getAutomatableParameter (i).get()))
1773 if (! paramsInTree.
contains (vstParam->getParameterIndex()))
1774 paramTree.rootNode->addSubNode (
new AutomatableParameterTree::TreeNode (autoParamForParamNumbers [vstParam->getParameterIndex()]));
1777void ExternalPlugin::buildParameterTree (
const VSTXML::Group* group,
1778 AutomatableParameterTree::TreeNode* treeNode,
1781 for (
int i = 0; i < group->paramTree.size(); ++i)
1783 if (
auto param =
dynamic_cast<const VSTXML::Param*
> (group->paramTree[i]))
1785 if (
auto externalParameter = autoParamForParamNumbers[param->paramID])
1787 treeNode->addSubNode (
new AutomatableParameterTree::TreeNode (externalParameter));
1788 paramsInTree.
add (param->paramID);
1792 if (
auto subGroup =
dynamic_cast<const VSTXML::Group*
> (group->paramTree[i]))
1794 auto subTreeNode =
new AutomatableParameterTree::TreeNode (subGroup->name);
1795 treeNode->addSubNode (subTreeNode);
1796 buildParameterTree (subGroup, subTreeNode, paramsInTree);
1809 return pluginInstance.
get();
1814 if (v == state &&
id == IDs::layout)
1816 if (isFlushingLayoutToState)
1819 if (
auto ap = getAudioPluginInstance())
1821 auto stateLayout = readBusesLayout (v.getProperty(IDs::layout), *ap);
1829 Plugin::valueTreePropertyChanged (v,
id);
1835 return engine.getEngineBehaviour().getReferencedItems (*
this);
1838void ExternalPlugin::reassignReferencedItem (
const ReferencedItem& itm, ProjectItemID newID,
double newStartTime)
1840 engine.getEngineBehaviour().reassignReferencedItem (*
this, itm, newID, newStartTime);
1851 if (
auto inst = plugin.getAudioPluginInstance())
1853 editor.reset (inst->createEditorIfNeeded());
1855 if (editor ==
nullptr)
1858 addAndMakeVisible (*editor);
1862 resizeToFitEditor (
true);
1865 bool allowWindowResizing()
override
1867 if (isCmajorPatchPluginFormat (plugin.desc))
1868 return editor !=
nullptr && editor->isResizable();
1871 return plugin.isVST3()
1872 && plugin.getVendor().containsIgnoreCase (
"Celemony");
1877 if (editor !=
nullptr)
1878 return editor->getConstrainer();
1883 void resized()
override
1885 if (editor !=
nullptr)
1886 editor->setBounds (getLocalBounds());
1891 if (c == editor.get())
1893 plugin.edit.pluginChanged (plugin);
1894 resizeToFitEditor (
false);
1898 void resizeToFitEditor (
bool force)
1900 if (force || ! allowWindowResizing())
1902 setSize (
std::max (8, editor !=
nullptr ? editor->getWidth() : 0),
1903 std::max (8, editor !=
nullptr ? editor->getHeight() : 0));
1907 void visibilityChanged()
override
1909 if (editor !=
nullptr && isShowing())
1911 if (editor->isShowing())
1912 editor->grabKeyboardFocus();
1914 editor->toFront (
true);
1929 if (ed->editor !=
nullptr)
1936PluginWetDryAutomatableParam::PluginWetDryAutomatableParam (
const juce::String& xmlTag,
const juce::String& name, Plugin& owner)
1937 : AutomatableParameter (xmlTag, name, owner, { 0.0f, 1.0f })
1941PluginWetDryAutomatableParam::~PluginWetDryAutomatableParam()
1943 notifyListenersOfDeletion();
1946juce::String PluginWetDryAutomatableParam::valueToString (
float value)
1951float PluginWetDryAutomatableParam::stringToValue (
const juce::String& s)
void triggerAsyncUpdate()
void cancelPendingUpdate() noexcept
int getNumChannels() const noexcept
void copyFrom(int destChannel, int destStartSample, const AudioBuffer &source, int sourceChannel, int sourceStartSample, int numSamples) noexcept
Type *const * getArrayOfWritePointers() noexcept
static AudioChannelSet JUCE_CALLTYPE disabled()
static AudioChannelSet fromAbbreviatedString(const String &set)
static String JUCE_CALLTYPE getChannelTypeName(ChannelType)
Bus * getBus(bool isInput, int busIndex) noexcept
BusesLayout getBusesLayout() const
bool removeBus(bool isInput)
int getBusCount(bool isInput) const noexcept
bool addBus(bool isInput)
AudioChannelSet getChannelLayoutOfBus(bool isInput, int busIndex) const noexcept
void enterModalState(bool takeKeyboardFocus=true, ModalComponentManager::Callback *callback=nullptr, bool deleteWhenDismissed=false)
static Type decibelsToGain(Type decibels, Type minusInfinityDb=Type(defaultMinusInfinitydB))
static Type gainToDecibels(Type gain, Type minusInfinityDb=Type(defaultMinusInfinitydB))
static String toString(Type decibels, int decimalPlaces=2, Type minusInfinityDb=Type(defaultMinusInfinitydB), bool shouldIncludeSuffix=true, StringRef customMinusInfinityString={})
static File createFileWithoutCheckingPath(const String &absolutePath) noexcept
bool isValid() const noexcept
const String & toString() const noexcept
static MidiBuffer setZoneLayout(MPEZoneLayout layout)
bool fromBase64Encoding(StringRef encodedString)
void * getData() noexcept
size_t getSize() const noexcept
bool isEmpty() const noexcept
bool addEvent(const MidiMessage &midiMessage, int sampleNumber)
static MidiMessage allNotesOff(int channel) noexcept
static MidiMessage controllerEvent(int channel, int controllerType, int value) noexcept
static MidiMessage noteOff(int channel, int noteNumber, float velocity) noexcept
static MidiMessage allControllersOff(int channel) noexcept
int size() const noexcept
bool isEmpty() const noexcept
void removeLast(int howManyToRemove=1, bool deleteObjects=true)
ObjectClass * add(ObjectClass *newObject)
ObjectClass * getLast() const noexcept
bool add(const ElementType &newElement) noexcept
bool contains(const ElementType &elementToLookFor) const noexcept
void add(String stringToAdd)
bool isEmpty() const noexcept
static String toHexString(IntegerType number)
int hashCode() const noexcept
int64 getHexValue64() const noexcept
bool isNotEmpty() const noexcept
void stopTimer() noexcept
void startTimer(int intervalInMilliseconds) noexcept
static ValueTree readFromData(const void *data, size_t numBytes)
An audio scratch buffer that has pooled storage.
juce::AudioBuffer< float > & buffer
The buffer to use.
Base class for elements that have some kind of automatable parameters.
void restoreChangedParametersFromState()
Restores the value of any explicitly set parameters.
void saveChangedParametersToState()
Saves the explicit value of any parameters that have deviated to the state.
const EditItemID itemID
Every EditItem has an ID which is unique within the edit.
void restartPlayback()
Use this to tell the play engine to rebuild the audio graph if the toplogy has changed.
TransportControl & getTransport() const noexcept
Returns the TransportControl which is used to stop/stop/position playback and recording.
void pluginChanged(Plugin &) noexcept
Plugins should call this when one of their parameters or state changes to mark the edit as unsaved.
bool isLoading() const
Returns true if the Edit's not yet fully loaded.
virtual std::unique_ptr< juce::PluginDescription > findDescriptionForFileOrID(const juce::String &)
Gives an opportunity to load custom plugins for those that have been registered as custom formats but...
UIBehaviour & getUIBehaviour() const
Returns the UIBehaviour class.
EngineBehaviour & getEngineBehaviour() const
Returns the EngineBehaviour instance.
PluginManager & getPluginManager() const
Returns the PluginManager instance.
void setCurrentContext(const PluginRenderContext *rc)
juce::String getSelectableDescription() override
Subclasses must return a description of what they are.
bool setBusLayout(juce::AudioChannelSet, bool isInput, int busIndex)
Attempts to change the layout of the plugin.
void deleteFromParent() override
Attempts to delete this plugin, whether it's a master plugin, track plugin, etc.
bool hasNameForMidiNoteNumber(int note, int midiChannel, juce::String &name) override
If it's a synth that names its notes, this can return the name it uses for this note 0-127.
bool setBusesLayout(juce::AudioProcessor::BusesLayout)
Attempts to change the layout of the plugin.
void reset() override
Should reset synth voices, tails, clear delay buffers, etc.
void setEnabled(bool enabled) override
Enable/disable the plugin.
void trackPropertiesChanged() override
Track name or colour has changed.
void selectableAboutToBeDeleted() override
Called just before the selectable is about to be deleted so any subclasses should still be valid at t...
bool isDisabled() override
Plugins can be disabled to avoid them crashing Edits.
void applyToBuffer(const PluginRenderContext &) override
Process the next block of data.
juce::String getName() const override
The name of the type, e.g.
void initialiseFully() override
Gives the plugin a chance to do extra initialisation when it's been added to an edit.
int getNumOutputChannelsGivenInputs(int numInputs) override
This must return the number of output channels that the plugin will produce, given a number of input ...
bool hasNameForMidiProgram(int programNum, int bank, juce::String &name) override
Returns the name for a midi program, if there is one.
void deinitialise() override
Called after play stops to release resources.
bool isMissing() override
for things like VSTs where the DLL is missing.
void changed() override
method from Selectable, that's been overridden here to also tell the edit that it's changed.
virtual void setEnabled(bool)
Enable/disable the plugin.
void selectableAboutToBeDeleted() override
Called just before the selectable is about to be deleted so any subclasses should still be valid at t...
Track * getOwnerTrack() const
Returns the track if it's a track or clip plugin.
virtual void deleteFromParent()
Attempts to delete this plugin, whether it's a master plugin, track plugin, etc.
void stop(bool discardRecordings, bool clearDevices, bool canSendMMCStop=true)
Stops recording, creating clips of newyly recorded files/MIDI data.
TimeRange getLoopRange() const noexcept
Returns the loop range.
void triggerClearDevicesOnStop()
Triggers a graph rebuild when playback stops.
virtual void recreatePluginWindowContentAsync(Plugin &)
Should trigger an asynchronous refresh of any editor components showing for this plugin.
#define TRANS(stringLiteral)
#define JUCE_AUTORELEASEPOOL
#define JUCE_IMPLEMENT_SINGLETON(Classname)
#define JUCE_DECLARE_SINGLETON(Classname, doNotRecreateAfterDeletion)
Type jlimit(Type lowerLimit, Type upperLimit, Type valueToConstrain) noexcept
int roundToInt(const FloatType value) noexcept
tempo::Sequence::Position createPosition(const TempoSequence &s)
Creates a Position to iterate over the given TempoSequence.
SafeSelectable< SelectableType > makeSafeRef(SelectableType &selectable)
Creates a SafeSelectable for a given selectable object.
Passed into Plugins when they are being initialised, to give them useful contextual information that ...
Array< AudioChannelSet > outputBuses
Array< AudioChannelSet > inputBuses
Represents a position in real-life time.
double getPPQTimeOfBarStart() const noexcept
Returns the PPQ start time of the bar the position is in.
double getPPQTime() const noexcept
Returns the position as a PPQ time.
TimeSignature getTimeSignature() const
Returns the current TimeSignature of the Position.
void set(TimePosition)
Sets the Position to a new time.
double getTempo() const
Returns the current tempo of the Position.
The context passed to plugin render methods to provide it with buffers to fill.
int bufferNumSamples
The number of samples to write into the audio buffer.
MidiMessageArray * bufferForMidiMessages
A buffer of MIDI events to process.
juce::AudioBuffer< float > * destBuffer
The target audio buffer which needs to be filled.
int bufferStartSample
The index of the start point in the audio buffer from which data must be written.
double midiBufferOffset
A time offset to add to the timestamp of any events in the MIDI buffer.
bool allowBypassedProcessing
If this is true and the plugin supports it, this will call the bypassed processing method of the plug...
bool isPlaying
True if the the playhead is currently playing.
TimeRange editTime
The edit time range this context represents.
specialised AutomatableParameter for wet/dry.
Is an Edit is playing back, this resumes playback when destroyed.
#define CRASH_TRACER_PLUGIN(p)
This macro adds the current location and the name of a plugin to a stack which gets logged if a crash...
#define CRASH_TRACER
This macro adds the current location to a stack which gets logged if a crash happens.