11namespace tracktion {
inline namespace engine
14static constexpr int maxRackAudioChans = 64;
18 if (i == 0)
return TRANS(
"Left input");
19 if (i == 1)
return TRANS(
"Right input");
26 if (i == 0)
return TRANS(
"Left output");
27 if (i == 1)
return TRANS(
"Right output");
36 sourceID.referTo (state, IDs::src, um);
37 destID.referTo (state, IDs::dst, um);
38 sourcePin.referTo (state, IDs::srcPin, um);
39 destPin.referTo (state, IDs::dstPin, um);
49 callBlocking ([
this] { this->rebuildObjects(); });
59 return v.hasType (IDs::PLUGININSTANCE);
65 auto* i =
new PluginInfo();
66 i->plugin = type.edit.getPluginCache().getOrCreatePluginFor (v.getChild(0));
71 void deleteObject (PluginInfo* p)
override
81 if (tree.
hasType (IDs::PLUGIN) && p.hasType (IDs::PLUGININSTANCE))
82 for (
auto info : objects)
83 if (info->plugin ==
nullptr && info->state == p)
84 info->plugin = type.edit.getPluginCache().getOrCreatePluginFor (tree);
87 void objectRemoved (PluginInfo*)
override
89 removeBrokenConnections (type.state, type.getUndoManager());
92 void newObjectAdded (PluginInfo*)
override {}
93 void objectOrderChanged()
override {}
117 return v.hasType (IDs::CONNECTION);
122 if (! type.edit.isLoading())
123 TRACKTION_ASSERT_MESSAGE_THREAD
130 if (! type.edit.isLoading())
131 TRACKTION_ASSERT_MESSAGE_THREAD
139 void objectOrderChanged()
override {}
154 callBlocking ([
this] { this->rebuildObjects(); });
164 return v.hasType (IDs::WINDOWSTATE);
181 void objectOrderChanged()
override {}
192 edit (owner), state (v),
193 rackID (
EditItemID::readOrCreateNewID (edit, state))
197 auto windowState = state.getChildWithName (IDs::WINDOWSTATE);
199 if (! windowState.isValid())
201 auto ws = createValueTree (IDs::WINDOWSTATE,
202 IDs::windowPos, state[IDs::windowPos]);
204 if (state.hasProperty (IDs::windowLocked))
205 ws.setProperty (IDs::windowLocked, state[IDs::windowLocked],
nullptr);
207 state.addChild (ws, -1,
nullptr);
212 rackName.referTo (state, IDs::name, getUndoManager());
214 if (rackName.get().isEmpty())
215 rackName =
TRANS(
"New Rack");
220 if (getOutputNames().isEmpty())
223 if (getInputNames().isEmpty())
226 loadWindowPosition();
231 state.addListener (
this);
237 notifyListenersOfDeletion();
238 hideWindowForShutdown();
240 windowStateList.reset();
245 return createValueTree (type,
249void RackType::removeAllInputsAndOutputs()
255 if (v.hasType (IDs::OUTPUT) || v.hasType (IDs::INPUT))
260void RackType::addDefaultInputs()
262 state.
addChild (createInOrOut (IDs::INPUT,
"midi input"), -1,
nullptr);
263 state.
addChild (createInOrOut (IDs::INPUT,
"input 1 (left)"), -1,
nullptr);
264 state.
addChild (createInOrOut (IDs::INPUT,
"input 2 (right)"), -1,
nullptr);
267void RackType::addDefaultOutputs()
269 state.
addChild (createInOrOut (IDs::OUTPUT,
"midi output"), -1,
nullptr);
270 state.
addChild (createInOrOut (IDs::OUTPUT,
"output 1 (left)"), -1,
nullptr);
271 state.
addChild (createInOrOut (IDs::OUTPUT,
"output 2 (right)"), -1,
nullptr);
282 if (hasAnyModifierAssignmentsRecursive (v))
292 if (hasAnyModifierAssignmentsRecursive (vt))
293 return juce::Result::fail (
TRANS(
"Unable to apply preset due to Macro or Modifier connections, please create a new Rack from the preset"));
297 if (v.hasType (IDs::PRESET))
298 v = v.getChildWithName (IDs::RACK);
300 if (! v.hasType (IDs::RACK))
303 rackID.writeID (v,
nullptr);
306 auto um = getUndoManager();
314 if (! (c.hasType (IDs::WINDOWSTATE) || c.hasType (IDs::MACROPARAMETERS) || c.hasType (IDs::MODIFIERS)))
319 for (
int i = v.getNumChildren(); --i >= 0;)
321 auto c = v.getChild (i);
322 v.removeChild (i,
nullptr);
324 if (! (c.hasType (IDs::WINDOWSTATE) || c.hasType (IDs::MACROPARAMETERS) || c.hasType (IDs::MODIFIERS)))
330 for (
auto rf : activeRackInstances)
342 saveWindowPosition();
344 for (
auto p : getPlugins())
345 p->flushPluginStateToValueTree();
349 if (! includeAutomation)
350 AutomationCurve::removeAllAutomationCurvesRecursively (v);
357 return windowStateList->objects;
360void RackType::loadWindowPosition()
362 for (
auto* ws : getWindowStates())
364 if (
ws->state.hasProperty (IDs::windowPos))
367 if (
ws->state.hasProperty (IDs::windowLocked))
368 ws->windowLocked =
ws->state[IDs::windowLocked];
372void RackType::saveWindowPosition()
374 for (
auto* ws : getWindowStates())
376 auto windowState =
ws->lastWindowBounds.toString();
377 ws->state.setProperty (IDs::windowPos, windowState.isEmpty() ?
juce::var() :
juce::var (windowState), nullptr);
378 ws->state.setProperty (IDs::windowLocked,
ws->windowLocked,
nullptr);
382RackType::Ptr RackType::createTypeToWrapPlugins (
const Plugin::Array& plugins, Edit& sourceEdit)
384 auto rack = sourceEdit.getRackList().addNewRack();
386 if (plugins.size() == 1)
387 rack->rackName = plugins.getFirst()->getName() +
" " +
TRANS(
"Wrapper");
388 else if (plugins.getFirst()->getOwnerTrack() ==
nullptr)
389 rack->rackName =
TRANS(
"Master Wrapper");
391 rack->rackName = plugins.getFirst()->getOwnerTrack()->getName() +
" " +
TRANS(
"Wrapper");
393 rack->removeInput (2);
394 rack->removeInput (1);
395 rack->removeOutput (2);
396 rack->removeOutput (1);
398 for (
int i = 0; i < plugins.size(); ++i)
399 if (
auto f = plugins[i])
400 rack->addPlugin (f,
juce::Point<float> (1.0f / (plugins.size() + 1) * (i + 1), 0.5f),
false);
403 plugins.getFirst()->getChannelNames (&ins,
nullptr);
404 plugins.getLast()->getChannelNames (
nullptr, &outs);
407 for (
int i = 0; i <
std::min (maxRackAudioChans, ins.
size()); ++i)
411 if (name.isEmpty() || name.equalsIgnoreCase (
TRANS(
"Unnamed")))
412 name = getDefaultInputName (i);
414 rack->addInput (-1, name);
415 rack->addConnection ({}, i + 1, plugins.getFirst()->itemID, i + 1);
419 for (
int i = 0; i <
std::min (maxRackAudioChans, outs.
size()); ++i)
423 if (name.isEmpty() || name.equalsIgnoreCase (
TRANS(
"Unnamed")))
424 name = getDefaultOutputName (i);
426 rack->addOutput (-1, name);
427 rack->addConnection (plugins.getLast()->itemID, i + 1, {}, i + 1);
431 rack->addConnection ({}, 0, plugins.getFirst()->itemID, 0);
432 rack->addConnection (plugins.getLast()->itemID, 0, {}, 0);
434 for (
int i = 0; i < plugins.size() - 1; ++i)
436 auto fsrc = plugins[i];
437 auto fdst = plugins[i + 1];
440 fsrc->getChannelNames (
nullptr, &srcOuts);
441 fdst->getChannelNames (&dstIns,
nullptr);
443 rack->addConnection (fsrc->itemID, 0, fdst->itemID, 0);
446 rack->addConnection (fsrc->itemID, j + 1, fdst->itemID, j + 1);
456 for (
const auto& v : state)
457 if (v.hasType (IDs::INPUT))
458 s.add (v.getProperty (IDs::name));
467 for (
const auto& v : state)
468 if (v.hasType (IDs::OUTPUT))
469 s.add (v.getProperty (IDs::name));
478 for (
auto i : pluginList->objects)
479 if (i->plugin != nullptr)
480 list.add (i->plugin.get());
485bool RackType::isPluginAllowed (
const Plugin::Ptr& p)
487 return p !=
nullptr && p->canBeAddedToRack();
492 if (! isPluginAllowed (p))
495 if (! getPlugins().contains (p.get()))
499 bool autoConnect = canAutoConnect && pluginList->objects.isEmpty();
501 p->removeFromParent();
503 auto v = createValueTree (IDs::PLUGININSTANCE,
506 v.addChild (p->state, -1, getUndoManager());
508 state.
addChild (v, -1, getUndoManager());
513 p->getChannelNames (&ins, &outs);
515 while (outs.
size() > getOutputNames().size() - 1)
516 if (addOutput (getOutputNames().size(),
TRANS(
"Output") +
" " +
juce::String (getOutputNames().size())) == -1)
519 for (
int i = 0; i < ins.
size(); ++i) addConnection ({}, i + 1, p->itemID, i + 1);
520 for (
int i = 0; i < outs.
size(); ++i) addConnection (p->itemID, i + 1, {}, i + 1);
523 addConnection ({}, 0, p->itemID, 0);
524 addConnection (p->itemID, 0, {}, 0);
535 for (
auto info : pluginList->objects)
536 if (info->plugin == p)
537 return { info->state[IDs::x],
538 info->state[IDs::y] };
545 if (
auto info = pluginList->objects[index])
546 return { info->state[IDs::x],
547 info->state[IDs::y] };
554 if (
auto info = pluginList->objects[index])
556 info->state.setProperty (IDs::x,
juce::jlimit (0.0f, 1.0f, pos.
x), getUndoManager());
557 info->state.setProperty (IDs::y,
juce::jlimit (0.0f, 1.0f, pos.
y), getUndoManager());
566 if (sourceId.isValid())
567 for (
auto rc : connectionList->objects)
568 if (rc->sourceID == sourceId && rc->destID.get().isValid())
569 results.addIfNotAlreadyThere (rc->destID);
574bool RackType::arePluginsConnectedIndirectly (EditItemID src, EditItemID dest,
int depth)
const
578 auto dests = getPluginsWhichTakeInputFrom (src);
580 for (
auto& d : dests)
584 for (
auto& d : dests)
585 if (arePluginsConnectedIndirectly (d, dest, depth + 1))
592bool RackType::isConnectionLegal (EditItemID source,
int sourcePin,
593 EditItemID dest,
int destPin)
const
597 if (sourcePin >= getInputNames().
size())
605 p->getChannelNames (&ins, &outs);
607 if (sourcePin > outs.
size())
611 if (! dest.isValid())
613 if (destPin >= getOutputNames().
size())
621 p->getChannelNames (&ins, &outs);
623 ins = m->getAudioInputNames();
625 if (destPin > ins.
size())
629 if (! (source.
isValid() || dest.isValid()))
635 return ! arePluginsConnectedIndirectly (dest, source);
638bool RackType::addConnection (EditItemID srcId,
int sourcePin,
639 EditItemID dstId,
int destPin)
641 if (! isConnectionLegal (srcId, sourcePin, dstId, destPin))
644 for (
auto rc : connectionList->objects)
645 if (rc->destID == dstId && rc->destPin == destPin
646 && rc->sourceID == srcId && rc->sourcePin == sourcePin)
649 auto v = createValueTree (IDs::CONNECTION,
652 IDs::srcPin, sourcePin,
653 IDs::dstPin, destPin);
655 state.
addChild (v, -1, getUndoManager());
659bool RackType::removeConnection (EditItemID srcId,
int sourcePin,
660 EditItemID dstId,
int destPin)
662 TRACKTION_ASSERT_MESSAGE_THREAD
664 for (
int i = connectionList->objects.size(); --i >= 0;)
666 if (
auto rc = connectionList->objects[i])
668 if (rc->destID == dstId && rc->sourceID == srcId
669 && rc->destPin == destPin && rc->sourcePin == sourcePin)
680void RackType::checkConnections()
683 TRACKTION_ASSERT_MESSAGE_THREAD
685 for (
int i = connectionList->objects.size(); --i >= 0;)
687 if (
auto rc = connectionList->objects[i])
690 if (((rc->sourcePin < 0 || rc->sourcePin >= getInputNames().
size()) && rc->sourceID->isInvalid())
691 || ((rc->destPin < 0 || rc->destPin >= getOutputNames().
size()) && rc->destID->isInvalid()))
702 if (
auto ep =
dynamic_cast<ExternalPlugin*
> (getPluginForID (rc->sourceID)))
704 if (ep->getAudioPluginInstance() !=
nullptr)
706 if (rc->sourcePin < 0 || rc->sourcePin > ep->getNumOutputs())
714 if (
auto ep =
dynamic_cast<ExternalPlugin*
> (getPluginForID (rc->destID)))
716 if (ep->getAudioPluginInstance() !=
nullptr)
718 if (rc->destPin < 0 || rc->destPin > ep->getNumInputs())
733 for (
auto rc : connectionList->objects)
740static bool findModifierWithID (
juce::ValueTree& modifiers, EditItemID itemID)
742 for (
auto m : modifiers)
743 if (EditItemID::fromID (m) == itemID)
749static bool findPluginOrModifierWithID (
juce::ValueTree& rack, EditItemID itemID)
751 for (
int i = rack.getNumChildren(); --i >= 0;)
753 auto c = rack.getChild (i);
755 if (c.hasType (IDs::PLUGININSTANCE))
756 if (EditItemID::fromID (c.getChildWithName (IDs::PLUGIN)) == itemID)
759 if (c.hasType (IDs::MODIFIERS))
760 if (findModifierWithID (c, itemID))
771 for (
int i = rack.getNumChildren(); --i >= 0;)
772 if (rack.getChild (i).hasType (type))
779 int srcPin, EditItemID dstID,
int dstPin)
781 if (srcID.isInvalid())
783 if (srcPin < 0 || srcPin >= countNumConnections (rack, IDs::INPUT))
786 else if (! findPluginOrModifierWithID (rack, srcID))
791 if (dstID.isInvalid())
793 if (dstPin < 0 || dstPin >= countNumConnections (rack, IDs::OUTPUT))
796 else if (! findPluginOrModifierWithID (rack, dstID))
806 for (
int i = rack.getNumChildren(); --i >= 0;)
808 auto c = rack.getChild (i);
810 if (c.hasType (IDs::CONNECTION)
811 && ! connectionIsValid (rack,
812 EditItemID::fromProperty (c, IDs::src), c[IDs::srcPin],
813 EditItemID::fromProperty (c, IDs::dst), c[IDs::dstPin]))
814 rack.removeChild (i, um);
818void RackType::createInstanceForSideChain (Track& at,
const juce::BigInteger& channelMask,
819 EditItemID pluginID,
int pinIndex)
821 const bool connectLeft = channelMask[0];
822 const bool connectRight = channelMask[1];
823 auto& pl = at.pluginList;
824 RackInstance* rack =
nullptr;
827 if (auto rf = dynamic_cast<RackInstance*> (p))
828 if (rf->type.get() == this)
833 if (
auto p = edit.
getPluginCache().getOrCreatePluginFor (RackInstance::create (*
this)))
835 pl.insertPlugin (p, 0,
nullptr);
836 rack =
dynamic_cast<RackInstance*
> (p.get());
842 auto inputs = getInputNames();
844 const juce::String rightName (
"sidechain input (right)");
845 auto noneName = rack->getNoPinName();
849 int srcPinIndex = inputs.indexOf (leftName);
851 if (srcPinIndex == -1)
852 srcPinIndex = addInput (-1, leftName);
854 rack->setInputName (RackInstance::left, leftName);
855 rack->setOutputName (RackInstance::left, noneName);
859 rack->setInputName (RackInstance::right, noneName);
860 rack->setOutputName (RackInstance::right, noneName);
863 if (srcPinIndex >= 0)
864 addConnection ({}, srcPinIndex, pluginID, pinIndex);
869 int srcPinIndex = inputs.indexOf (rightName);
871 if (srcPinIndex == -1)
872 srcPinIndex = addInput (-1, rightName);
874 rack->setInputName (RackInstance::right, rightName);
875 rack->setOutputName (RackInstance::right, noneName);
879 rack->setInputName (RackInstance::left, noneName);
880 rack->setOutputName (RackInstance::left, noneName);
883 if (srcPinIndex != -1)
884 addConnection ({}, srcPinIndex, pluginID,
885 connectLeft ? pinIndex + 1 : pinIndex);
891 SelectionManager::refreshAllPropertyPanelsShowing (*rack);
896 TRANS(
"Unable to create rack on source track"));
903 return TRANS(
"Plugin Rack");
915 if (v.hasType (type))
916 if (count++ == index)
923int RackType::addInput (
int index,
const juce::String& name)
925 int numNames = getInputNames().
size();
927 if (numNames <= maxRackAudioChans)
931 for (
auto conn : connectionList->objects)
932 if (conn->sourceID->isInvalid() && conn->sourcePin >= index)
933 conn->sourcePin = conn->sourcePin + 1;
936 state.
addChild (createInOrOut (IDs::INPUT, name),
937 index < 0 ? findIndexOfNthInstanceOf (state, IDs::INPUT, numNames - 1) + 1
938 : findIndexOfNthInstanceOf (state, IDs::INPUT, index),
944 jassert (getInputNames()[index] == name);
951int RackType::addOutput (
int index,
const juce::String& name)
953 int numNames = getOutputNames().
size();
955 if (numNames <= maxRackAudioChans)
959 for (
auto conn : connectionList->objects)
960 if (conn->destID->isInvalid() && conn->destPin >= index)
961 conn->destPin = conn->destPin + 1;
964 state.
addChild (createInOrOut (IDs::OUTPUT, name),
965 index < 0 ? findIndexOfNthInstanceOf (state, IDs::OUTPUT, numNames - 1) + 1
966 : findIndexOfNthInstanceOf (state, IDs::OUTPUT, index),
972 jassert (getOutputNames()[index] == name);
979void RackType::removeInput (
int index)
981 TRACKTION_ASSERT_MESSAGE_THREAD
982 int toRemove = findIndexOfNthInstanceOf (state, IDs::INPUT, index);
986 for (
auto conn : connectionList->objects)
987 if (conn->sourceID->isInvalid() && conn->sourcePin > index)
988 conn->sourcePin = conn->sourcePin - 1;
995void RackType::removeOutput (
int index)
997 TRACKTION_ASSERT_MESSAGE_THREAD
998 int toRemove = findIndexOfNthInstanceOf (state, IDs::OUTPUT, index);
1002 for (
auto conn : connectionList->objects)
1003 if (conn->destID->isInvalid() && conn->destPin > index)
1004 conn->destPin = conn->destPin - 1;
1013 return name.trim().isEmpty() ?
TRANS(
"Unnamed") : name;
1016void RackType::renameInput (
int index,
const juce::String& name)
1018 int toRename = findIndexOfNthInstanceOf (state, IDs::INPUT, index);
1021 state.
getChild (toRename).
setProperty (IDs::name, checkChannelName (name), getUndoManager());
1024void RackType::renameOutput (
int index,
const juce::String& name)
1026 int toRename = findIndexOfNthInstanceOf (state, IDs::OUTPUT, index);
1029 state.
getChild (toRename).
setProperty (IDs::name, checkChannelName (name), getUndoManager());
1038void RackType::countInstancesInEdit()
1041 TRACKTION_ASSERT_MESSAGE_THREAD
1043 numberOfInstancesInEdit = 0;
1046 if (auto rf = dynamic_cast<RackInstance*> (p))
1047 if (rf->type.get() == this)
1048 ++numberOfInstancesInEdit;
1052void RackType::registerInstance (RackInstance* instance,
const PluginInitialisationInfo&)
1055 activeRackInstances.addIfNotAlreadyThere (instance);
1056 numActiveInstances.
store (activeRackInstances.size());
1058 countInstancesInEdit();
1061void RackType::deregisterInstance (RackInstance* instance)
1063 activeRackInstances.removeAllInstancesOf (instance);
1064 numActiveInstances.
store (activeRackInstances.size());
1066 countInstancesInEdit();
1069void RackType::updateAutomatableParamPositions (TimePosition time)
1071 for (
auto f : getPlugins())
1072 f->updateAutomatableParamPosition (
time);
1074 for (
auto m : getModifierList().getModifiers())
1075 m->updateAutomatableParamPosition (
time);
1079RackType::Ptr RackType::findRackTypeContaining (
const Plugin& plugin)
1082 if (auto rack = dynamic_cast<RackInstance*> (p))
1083 if (rack->type != nullptr)
1084 if (rack->type->getPluginForID (plugin.itemID))
1096 for (
auto&& n : names)
1097 n =
juce::String (++i) +
". " + n;
1104 return stripAndPrependChannels (getInputNames());
1109 return stripAndPrependChannels (getOutputNames());
1113Plugin* RackType::getPluginForID (EditItemID pluginID)
1115 if (pluginID.isInvalid())
1118 for (
auto p : pluginList->objects)
1119 if (p->plugin != nullptr && p->plugin->itemID == pluginID)
1120 return p->plugin.get();
1125void RackType::hideWindowForShutdown()
1127 for (
auto af : getPlugins())
1128 if (auto ep = dynamic_cast<ExternalPlugin*> (af))
1129 ep->hideWindowForShutdown();
1131 for (
auto ws : getWindowStates())
1132 ws->hideWindowForShutdown();
1135bool RackType::pasteClipboard()
1142 SelectableList pastedItems;
1144 if (
auto plugins = Clipboard::getInstance()->getContentWithType<Clipboard::Plugins>())
1146 for (
auto& pluginState : plugins->plugins)
1148 auto stateCopy = pluginState.createCopy();
1149 EditItemID::remapIDs (stateCopy,
nullptr, edit);
1151 if (
auto newPlugin = edit.
getPluginCache().getOrCreatePluginFor (stateCopy))
1153 auto selectedPlugin = sm->getFirstItemOfType<Plugin>();
1154 RackType::Ptr selectedRack (sm->getFirstItemOfType<RackType>());
1156 if (selectedPlugin !=
nullptr || selectedRack !=
nullptr)
1158 if (selectedRack ==
nullptr)
1159 selectedRack = edit.
getRackList().findRackContaining (*selectedPlugin);
1161 if (selectedRack !=
nullptr)
1165 if (selectedPlugin !=
nullptr && selectedRack.get() ==
this)
1166 pos = getPluginPosition (*selectedPlugin).
translated (0.1f, 0.1f);
1168 for (
auto af : getPlugins())
1169 if (pos == getPluginPosition (*af))
1170 pos = pos.translated (0.1f, 0.1f);
1172 selectedRack->addPlugin (newPlugin, pos,
false);
1173 pastedItems.add (newPlugin.get());
1180 sm->select (pastedItems);
1182 return pastedItems.isNotEmpty();
1186ModifierList& RackType::getModifierList() const noexcept
1188 return *modifierList;
1208 return v.hasType (IDs::RACK);
1213 auto t =
new RackType (v, list.edit);
1214 t->incReferenceCount();
1218 void deleteObject (
RackType* t)
override
1221 t->decReferenceCount();
1224 void newObjectAdded (
RackType*)
override { sendChange(); }
1225 void objectRemoved (
RackType*)
override { sendChange(); }
1226 void objectOrderChanged()
override { sendChange(); }
1240RackTypeList::RackTypeList (
Edit& ed) : edit (ed)
1249 jassert (state.hasType (IDs::RACKS));
1252 list->rebuildObjects();
1255RackTypeList::~RackTypeList()
1257 for (
auto t : list->objects)
1258 t->hideWindowForShutdown();
1265 return list->objects;
1268int RackTypeList::size()
const
1270 return list->objects.
size();
1273RackType::Ptr RackTypeList::getRackType (
int index)
const
1275 return list->objects[index];
1278RackType::Ptr RackTypeList::getRackTypeForID (EditItemID rackID)
const
1280 for (
auto r : list->objects)
1281 if (r->rackID == rackID)
1287RackType::Ptr RackTypeList::findRackContaining (Plugin& p)
const
1289 for (
auto r : list->objects)
1290 if (r->getPlugins().contains (&p))
1296void RackTypeList::removeRackType (
const RackType::Ptr& type)
1298 if (list->objects.
contains (type.get()))
1303 if (auto rf = dynamic_cast<RackInstance*> (f))
1304 if (rf->type == type)
1305 rf->deleteFromParent();
1308 if (
auto mpl = type->getMacroParameterList())
1309 mpl->hideMacroParametersFromTracks();
1311 for (
auto macro : type->getMacroParameters())
1313 param->removeModifier (*macro);
1315 for (
auto modifier : type->getModifierList().getModifiers())
1317 for (
auto t : allTracks)
1318 t->hideAutomatableParametersForSource (modifier->itemID);
1321 param->removeModifier (*modifier);
1324 type->hideWindowForShutdown();
1329RackType::Ptr RackTypeList::addNewRack()
1334 newID.writeID (v,
nullptr);
1337 auto type = getRackTypeForID (newID);
1341 type->getMacroParameterListForWriting().remapOnTempoChange =
true;
1346RackType::Ptr RackTypeList::addRackTypeFrom (
const juce::ValueTree& rackType)
1348 if (! rackType.hasType (IDs::RACK))
1351 auto typeID = EditItemID::fromID (rackType);
1353 if (typeID.isInvalid())
1356 auto type = getRackTypeForID (typeID);
1358 if (type ==
nullptr)
1362 state.addChild (rackType.createCopy(), -1, &edit.
getUndoManager());
1364 type = getRackTypeForID (typeID);
1368 type->getMacroParameterListForWriting().remapOnTempoChange =
true;
1377 int oldNumRacks = size();
1379 for (
auto& f : files)
1381 addRackTypeFrom (
juce::ValueTree::fromXml (*xml));
1383 if (oldNumRacks < size())
1388void RackType::triggerUpdate()
1395 countInstancesInEdit();
1400void RackType::updateRenderContext()
1403 TRACKTION_ASSERT_MESSAGE_THREAD
1417void RackType::valueTreeChildOrderChanged (
juce::ValueTree&,
int,
int) {}
1418void RackType::valueTreeRedirected (
juce::ValueTree&) { triggerUpdate(); }
1422 if (! state.getParent().
isValid())
1423 hideWindowForShutdown();
1430 if (v.hasType (IDs::PLUGININSTANCE) || v.hasType (IDs::CONNECTION))
1431 if (ident != IDs::x && ident != IDs::y && ident != IDs::windowLocked && ident != IDs::windowPos)
1434 if (v == state && ident == IDs::name)
1436 rackName.forceUpdateOfCachedValue();
1439 if (auto rf = dynamic_cast<RackInstance*> (af))
1440 if (rf->type.get() == this)
1446 if (v == state && ident == IDs::id)
1451RackType::WindowState::WindowState (RackType& r,
juce::ValueTree windowStateTree)
1452 : PluginWindowState (r.edit), rack (r), state (
std::
move (windowStateTree))
int size() const noexcept
bool contains(ParameterType elementToLookFor) const
bool isValid() const noexcept
constexpr Point translated(ValueType deltaX, ValueType deltaY) const noexcept
static Rectangle fromString(StringRef stringVersion)
static Result fail(const String &errorMessage) noexcept
static Result ok() noexcept
int size() const noexcept
bool hasType(const Identifier &typeName) const noexcept
void removeChild(const ValueTree &child, UndoManager *undoManager)
ValueTree getChild(int index) const
int getNumChildren() const noexcept
void copyPropertiesFrom(const ValueTree &source, UndoManager *undoManager)
ValueTree & setProperty(const Identifier &name, const var &newValue, UndoManager *undoManager)
void addChild(const ValueTree &child, int index, UndoManager *undoManager)
ValueTree createCopy() const
void removeListener(Listener *listener)
The Tracktion Edit class!
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.
PluginCache & getPluginCache() noexcept
Returns the PluginCache which manages all active Plugin[s] for this Edit.
bool isLoading() const
Returns true if the Edit's not yet fully loaded.
juce::UndoManager & getUndoManager() noexcept
Returns the juce::UndoManager used for this Edit.
EditItemID createNewItemID() const
Returns a new EditItemID to use for a new EditItem.
bool shouldLoadPlugins() const noexcept
Returns true if this Edit can load Plugin[s].
RackTypeList & getRackList() const noexcept
Returns the RackTypeList which contains all the RackTypes for the Edit.
Engine & engine
A reference to the Engine.
UIBehaviour & getUIBehaviour() const
Returns the UIBehaviour class.
EngineBehaviour & getEngineBehaviour() const
Returns the EngineBehaviour instance.
Base class for elements which can contain macro parameters.
juce::String getSelectableDescription() override
Subclasses must return a description of what they are.
bool addPlugin(const Plugin::Ptr &, juce::Point< float > pos, bool canAutoConnect)
Adds a plugin to the Rack optionally connecting it to the input and outputs.
virtual void changed()
This should be called to send a change notification to any SelectableListeners that are registered wi...
void stopIfRecording()
Stops playback only if recording is currently in progress.
virtual void showWarningAlert(const juce::String &title, const juce::String &message)
Should display a dismissable alert window.
virtual void showWarningMessage(const juce::String &message)
Should display a temporary warning message.
#define TRANS(stringLiteral)
Type jlimit(Type lowerLimit, Type upperLimit, Type valueToConstrain) noexcept
std::unique_ptr< XmlElement > parseXML(const String &textToParse)
juce::ReferenceCountedArray< AutomatableParameter > getAllParametersBeingModifiedBy(Edit &edit, AutomatableParameter::ModifierSource &m)
Iterates an Edit looking for all parameters that are being modified by the given ModifierSource.
juce::Array< Track * > getAllTracks(const Edit &edit)
Returns all the tracks in an Edit.
Modifier::Ptr findModifierForID(ModifierList &ml, EditItemID modifierID)
Returns a Modifier if it can be found in the list.
Plugin::Array getAllPlugins(const Edit &edit, bool includeMasterVolume)
Returns all the plugins in a given Edit.
ID for objects of type EditElement - e.g.
#define CRASH_TRACER
This macro adds the current location to a stack which gets logged if a crash happens.