1
0
Fork 0
mirror of https://github.com/juce-framework/JUCE.git synced 2026-01-10 23:44:24 +00:00

Added support saving/restoring plugin bus layouts in the audio host demo

This commit is contained in:
hogliux 2017-01-10 12:50:45 +00:00
parent 101a59ad2a
commit 83a4f74b1f
3 changed files with 140 additions and 0 deletions

View file

@ -288,6 +288,67 @@ void FilterGraph::setLastDocumentOpened (const File& file)
}
//==============================================================================
static void readBusLayoutFromXml (AudioProcessor::BusesLayout& busesLayout, AudioProcessor* plugin, const XmlElement& xml, const bool isInput)
{
Array<AudioChannelSet>& targetBuses = (isInput ? busesLayout.inputBuses : busesLayout.outputBuses);
int maxNumBuses = 0;
if (auto* buses = xml.getChildByName (isInput ? "INPUTS" : "OUTPUTS"))
{
forEachXmlChildElementWithTagName (*buses, e, "BUS")
{
const int busIdx = e->getIntAttribute ("index");
maxNumBuses = jmax (maxNumBuses, busIdx + 1);
// the number of buses on busesLayout may not be in sync with the plugin after adding buses
// because adding an input bus could also add an output bus
for (int actualIdx = plugin->getBusCount (isInput) - 1; actualIdx < busIdx; ++actualIdx)
if (! plugin->addBus (isInput)) return;
for (int actualIdx = targetBuses.size() - 1; actualIdx < busIdx; ++actualIdx)
targetBuses.add (plugin->getChannelLayoutOfBus (isInput, busIdx));
const String& layout = e->getStringAttribute("layout");
if (layout.isNotEmpty())
targetBuses.getReference (busIdx) = AudioChannelSet::fromAbbreviatedString (layout);
}
}
// if the plugin has more buses than specified in the xml, then try to remove them!
while (maxNumBuses < targetBuses.size())
{
if (! plugin->removeBus (isInput))
return;
targetBuses.removeLast();
}
}
//==============================================================================
static XmlElement* createBusLayoutXml (const AudioProcessor::BusesLayout& layout, const bool isInput)
{
const Array<AudioChannelSet>& buses = (isInput ? layout.inputBuses : layout.outputBuses);
XmlElement* xml = new XmlElement (isInput ? "INPUTS" : "OUTPUTS");
const int n = buses.size();
for (int busIdx = 0; busIdx < n; ++busIdx)
{
XmlElement* bus = new XmlElement ("BUS");
bus->setAttribute ("index", busIdx);
const AudioChannelSet& set = buses.getReference (busIdx);
const String layoutName = set.isDisabled() ? "disabled" : set.getSpeakerArrangementAsString();
bus->setAttribute ("layout", layoutName);
xml->addChildElement (bus);
}
return xml;
}
static XmlElement* createNodeXml (AudioProcessorGraph::Node* const node) noexcept
{
AudioPluginInstance* plugin = dynamic_cast<AudioPluginInstance*> (node->getProcessor());
@ -327,6 +388,14 @@ static XmlElement* createNodeXml (AudioProcessorGraph::Node* const node) noexcep
state->addTextElement (m.toBase64Encoding());
e->addChildElement (state);
XmlElement* layouts = new XmlElement ("LAYOUT");
const AudioProcessor::BusesLayout layout = plugin->getBusesLayout();
for (bool isInput : { true, false })
layouts->addChildElement (createBusLayoutXml (layout, isInput));
e->addChildElement (layouts);
return e;
}
@ -347,6 +416,16 @@ void FilterGraph::createNodeFromXml (const XmlElement& xml)
if (instance == nullptr)
return;
if (const XmlElement* const layoutEntity = xml.getChildByName ("LAYOUT"))
{
AudioProcessor::BusesLayout layout = instance->getBusesLayout();
for (bool isInput : { true, false })
readBusLayoutFromXml (layout, instance, *layoutEntity, isInput);
instance->setBusesLayout (layout);
}
AudioProcessorGraph::Node::Ptr node (graph.addNode (instance, (uint32) xml.getIntAttribute ("uid")));
if (const XmlElement* const state = xml.getChildByName ("STATE"))

View file

@ -114,6 +114,43 @@ String AudioChannelSet::getAbbreviatedChannelTypeName (AudioChannelSet::ChannelT
return "";
}
AudioChannelSet::ChannelType AudioChannelSet::getChannelTypeFromAbbreviation (const String& abbr)
{
if (abbr.length() > 0 && (abbr[0] >= '0' && abbr[0] <= '9'))
return static_cast<AudioChannelSet::ChannelType> (static_cast<int> (discreteChannel0)
+ abbr.getIntValue() + 1);
if (abbr == "L") return left;
else if (abbr == "R") return right;
else if (abbr == "C") return centre;
else if (abbr == "Lfe") return LFE;
else if (abbr == "Ls") return leftSurround;
else if (abbr == "Rs") return rightSurround;
else if (abbr == "Lc") return leftCentre;
else if (abbr == "Rc") return rightCentre;
else if (abbr == "Cs") return centreSurround;
else if (abbr == "Lrs") return leftSurroundRear;
else if (abbr == "Rrs") return rightSurroundRear;
else if (abbr == "Tm") return topMiddle;
else if (abbr == "Tfl") return topFrontLeft;
else if (abbr == "Tfc") return topFrontCentre;
else if (abbr == "Tfr") return topFrontRight;
else if (abbr == "Trl") return topRearLeft;
else if (abbr == "Trc") return topRearCentre;
else if (abbr == "Trr") return topRearRight;
else if (abbr == "Wl") return wideLeft;
else if (abbr == "Wr") return wideRight;
else if (abbr == "Lfe2") return LFE2;
else if (abbr == "Lss") return leftSurroundSide;
else if (abbr == "Rss") return rightSurroundSide;
else if (abbr == "W") return ambisonicW;
else if (abbr == "X") return ambisonicX;
else if (abbr == "Y") return ambisonicY;
else if (abbr == "Z") return ambisonicZ;
return unknown;
}
String AudioChannelSet::getSpeakerArrangementAsString() const
{
StringArray speakerTypes;
@ -130,6 +167,22 @@ String AudioChannelSet::getSpeakerArrangementAsString() const
return speakerTypes.joinIntoString (" ");
}
AudioChannelSet AudioChannelSet::fromAbbreviatedString (const String& str)
{
StringArray abbr = StringArray::fromTokens(str, true);
AudioChannelSet set;
for (int i = 0; i < abbr.size(); ++i)
{
AudioChannelSet::ChannelType type = getChannelTypeFromAbbreviation (abbr[i]);
if (type != unknown)
set.addChannel (type);
}
return set;
}
String AudioChannelSet::getDescription() const
{
if (isDiscreteLayout()) return String ("Discrete #") + String (size());

View file

@ -308,6 +308,9 @@ public:
/** Returns the abbreviated name of a channel type. For example, this method may return "Ls". */
static String getAbbreviatedChannelTypeName (ChannelType);
/** Returns the channel type from an abbreviated name. */
static ChannelType getChannelTypeFromAbbreviation (const String& abbreviation);
//==============================================================================
enum
{
@ -342,6 +345,11 @@ public:
the returned string will be empty.*/
String getSpeakerArrangementAsString() const;
/** Returns an AudioChannelSet from a string returned by getSpeakerArrangementAsString
@see getSpeakerArrangementAsString */
static AudioChannelSet fromAbbreviatedString (const String& set);
/** Returns the description of the current layout. For example, this method may return
"Quadraphonic". Note that the returned string may not be unique. */
String getDescription() const;