Rebuilding an AudioProcessorGraph when a node changes it's I/O


#1

I have an AudioProcessorGraph that contains custom AudioProcessors that can dynamically change their IO count. When the IO count changes i need to get the graph to rebuild.

I've been trying to work out how to do that but I keep coming up against issues, normally private methods that i can't call outside of the graph.

Can anyone recommend how to do this without modifying JUCE? I need to "unprepare" the nodes and rebuild the graph and graphical representation.

currently i hacked in a method, guess i could subclass, but i'm wondering if i've missed something.

 

void AudioProcessorGraph::rebuild()
{
  for (int i = 0; i < nodes.size(); ++i)
    nodes.getUnchecked(i)->unprepare();

  clearRenderingSequence();
  buildRenderingSequence();
}

 

 


#2

Hi,

I made almost the same thing, for the same needs, I added a public method like yours. Which means that I modified JUCE, thus that i'm not answering to your question :-/

But as I'm trying now to have a multi threaded AudioProcessorGraph to replace the original Juce's one, I'll always have to bypass entirely the juce_AudioProcessorGraph.h and .cpp files, and i won't have to modify anything inside of them each time i'll update the sources. If you want to take a look, i posted a first draft of it recently (here: http://www.juce.com/forum/topic/multithreaded-audio-processor-graph) , based on another user's code (chkn) which made debate but works very well for me till now. And it manages node's IO changes. but i guess i'm still not answering to your question :-)


#3

thanks, i will check out your version.

perhaps I should be totally removing the filter from the graph and re-adding it with new channel i/o. looks like i might be able to do that without hacking the AudioProcessorGraph source.

oli


#4


Hi Oli. I'm working on something similar myself right now. I've tried it a different way, with mixed results. Instead of deleting and adding the filter again I'm simply updating the node whilst it's still in place. When the user updates the number of channels for one of my custom processors I call setPlayConfigDetails() with the new config settings. Internally my processors can handle a change in IO. After calling the setConfig method  getNumOutputChannels() correctly returns the updated channel count in my processor, but there is a problem. The AudioSampleBuffer passed to my processBlock() still returns the original channel setup. 

Perhaps I've hit a dead end with this approach, but I've a few other things to try before I give up on it. I'll let you know if I make any headway with it.

 

[edit] Now that i've thought about for a bit, I can't see this approach ever working :( Time for a change of tack. Deleting and readding the filter will be my next port of call.
 


#5

I can confirm simply removing and adding the filter after a change to IO works fine. No need to do any messing with the graph. In case you are interested here is how I make sure it goes back in the same place, with the same connections.

void GraphEditorPanel::updateNode (const int nodeID, const int inChannels, const int outChannels)
{
    
    ScopedPointer<XmlElement> temp(graph.createXml());
    const XmlElement tempXml (*temp);
    
    graph.removeFilter(nodeID);
    
    forEachXmlChildElementWithTagName (tempXml, e, "FILTER")
    {            
        if(nodeID==e->getIntAttribute("uid"))
        {
            double origX = e->getDoubleAttribute("x");
            double origY = e->getDoubleAttribute("y");
            e->setAttribute("x", origX);
            e->setAttribute("y", origY);
            e->setAttribute("numInputs", inChannels);
            e->setAttribute("numOutputs", outChannels);
            graph.createNodeFromXml(*e);
            graph.changed();
        }
    }    

    forEachXmlChildElementWithTagName (tempXml, e, "CONNECTION")
    {
        if(e->getIntAttribute ("srcFilter")==nodeID || e->getIntAttribute ("dstFilter")==nodeID)
        {
            graph.addConnection((uint32) e->getIntAttribute ("srcFilter"),
                                e->getIntAttribute ("srcChannel"),
                                (uint32) e->getIntAttribute ("dstFilter"),
                                e->getIntAttribute ("dstChannel"));
        }
    }    
    
}

#6

thanks rory, got something working a bit like that

oli