AudioProcessorGraph rebuild() but AudioProcessor doesn't get expected channel count in buffer

I’m building a node based daw.
I noticed a changed in recent JUCE Version (7.0.3+) that makes my nodes not work when changing the number of in/out channels.

  • Changing in or out in my code triggers a graph rebuild(), and this node’s processor calls setPlayConfigDetails

This changes effectively the number of expected channels for this node (max between in and out), but the received buffer is still of the size before the channel count change.

  • Adding a new node / removing any other node / changing any connection between nodes, however, seems to trigger something that updates all the buffer unsynced channel count for all nodes.

Prior to 7.0.3, this behaviour was not happening, i.e. buffer count where always in sync with processor’s expectations, with the exact same code inside the nodes (I had to adapt the audioProcessorIOCallback calls in my AudioManager class but nothing more)

I tried checking the code to see where it’s done, and I would have expected that rebuild() and prepareToPlay() would have triggered the same things as a graph connection change but apparently not.

Is there a way in these new versions to force a graph update that would also change the buffer size for those changed nodes ?

The code is there : GitHub - benkuper/LeGrandMechantLoop: Node-based modular live performance oriented DAW

Please can you confirm that you’re seeing this behaviour on develop?

I can confirm it does happen on the latest develop commit at the time of this message.

I tracked down the problem to line 1913 of juce_AudioProcessorGraph.cpp

if (std::exchange (lastBuiltSequence, newSignature) != newSignature)

the signature doesn’t seem to take in account the number of expected channels exposed by each node, resulting in comparing seemingly sames signatures becauses the registered nodes and connections have not changed, although at least one of the nodes setup has changed.

Am i not doing something I should, or is there a way to force recreating the sequence ?

Thank you !

I can see the problem, and adding the current bus layouts to the RenderSequenceSignature seems to have the intended effect - the render sequence gets rebuilt if the bus layout of any node has changed.

It’s important to note that if just the bus layout has changed between rebuilds, then I think that implies that setBusesLayout and/or prepareToPlay have been called on an inner node while the graph is already prepared and potentially playing audio. Calling prepareToPlay and processBlock simultaneously is a violation of the AudioProcessor threading contract, and will cause problems.

In order to safely change the bus layout of a node that’s already been added to a graph, you’ll need to ensure that the graph is not playing audio when the bus layout is changed, to avoid the case that the setBusesLayout or prepareToPlay calls coincide with the graph calling processBlock on the processor. One option, used by the AudioPluginHost, is to take the graph’s callback lock before modifying the bus layout of any inner node. This ensures that the graph won’t call process while the bus layout is being updated.

In order to change the bus layout in a completely lock-free way, you’d need to remove the node from the graph and wait for it to be released by the audio thread before adjusting the bus layout and re-adding the node to the graph. We don’t currently have an API to “wait for removal” in that way, but maybe we can look at adding something like that.

1 Like

Interesting and reassuring that you find the same behaviour.
I already have a proper process to change the internal setup of the graph, just missing this :slight_smile:
Do you think it will be added to the develop branch at t some point ?

Thank you

That’s on develop now:

you’re the man :slight_smile: I’ll test that soon and report here

1 Like