I don't mind sharing it here. I've just been trying to figure out how to suggest making the change as my modified graph code is quite different.
Maybe I'll just outline the changes. Perhaps Jules would be interested in making changes to the stock graph in a way that is suitable and proper.
All I'm really doing is adding the connection to the Entry in the lookup table.
In buildRenderingSequence we have:
const GraphRenderingOps::ConnectionLookupTable table (connections);
We modify ConnectionLookupTable::Entry to include an Array of "source" connections
struct Entry
{
explicit Entry (const uint32 destNodeId_) noexcept : destNodeId (destNodeId_) {}
const uint32 destNodeId;
SortedSet<uint32> srcNodes;
//add this
Array<const Connection*> srcConnections;
JUCE_DECLARE_NON_COPYABLE (Entry);
};
In ConnectionLookupTable constructor we add a line to include the source connection
for (int i = 0; i < connections.size(); ++i)
{
const NamAudioProcessorGraph::Connection* const c = connections.getUnchecked(i);
int index;
Entry* entry = findEntry (c->destNodeId, index);
if (entry == nullptr)
{
entry = new Entry (c->destNodeId);
entries.insert (index, entry);
}
entry->srcNodes.add (c->sourceNodeId);
//add this line to include the connection in the entry
entry->srcConnections.add(c);
}
Then we add public getConnectionBetween to ConnectionLookupTable. (note I've made this version return bool. The usage in ops calculator only cares that it exists. Perhaps "isConnected" or something would be a better name)
bool getConnectionBetween (const uint32 sourceNodeId, const uint32 sourceChannelIndex, const uint32 destNodeId, const uint32 destChannelIndex) {
int index;
const Entry* const entry = findEntry (destNodeId, index);
if (entry != nullptr) {
for (int i = 0; i < entry->srcConnections.size(); ++i) {
const Connection * c = entry->srcConnections.getUnchecked(i);
if (c->sourceChannelIndex == sourceChannelIndex && c->destChannelIndex == destChannelIndex) {
return true;
}
}
}
return false;
}
Then we modify RenderingOpSequenceCalculator to include a const reference to the table and pass the table as a parameter to the calculator's constructor. (You'll need to move the ConnectionLookupTable class definition to be before the RenderingOpSequenceCalculator class definition.
//add private class member
const ConnectionLookupTable & connectionLookupTable;
//modify constructor to accept table reference
RenderingOpSequenceCalculator (AudioProcessorGraph& graph_,
const ConnectionLookupTable & connectionLookupTable_,
const Array<void*>& orderedNodes_,
Array<void*>& renderingOps)
: graph (graph_),
connectionLookupTable(connectionLookupTable_),
orderedNodes (orderedNodes_),
totalLatency (0)
{
//
Then in RenderingOpSequenceCalculator::isBufferNeededLater we replace graph.getConnectionBetween with connectionLookupTable.getConnectionBetween
bool isBufferNeededLater (int stepIndexToSearchFrom,
int inputChannelOfIndexToIgnore,
const uint32 nodeId,
const int outputChanIndex) const
{
while (stepIndexToSearchFrom < orderedNodes.size())
{
const NamAudioProcessorGraph::Node* const node = (const NamAudioProcessorGraph::Node*) orderedNodes.getUnchecked (stepIndexToSearchFrom);
if (outputChanIndex == NamAudioProcessorGraph::midiChannelIndex)
{
if (inputChannelOfIndexToIgnore != NamAudioProcessorGraph::midiChannelIndex
&&
//this is now using the connectionLookupTable
connectionLookupTable.getConnectionBetween (nodeId, NamAudioProcessorGraph::midiChannelIndex,
node->nodeId, NamAudioProcessorGraph::midiChannelIndex)
)
return true;
}
else
{
for (int i = 0; i < node->getProcessor()->getNumInputChannels(); ++i)
if (i != inputChannelOfIndexToIgnore
&&
//this is now using the connection lookup table
connectionLookupTable.getConnectionBetween (nodeId, outputChanIndex,
node->nodeId, i))
return true;
}
inputChannelOfIndexToIgnore = -1;
++stepIndexToSearchFrom;
}
return false;
}
Finally in buildRenderingSequence we move the table out of the local scope block and pass it to the calculator
//move outside of block
const GraphRenderingOps::ConnectionLookupTable table (connections);
{
for (int i = 0; i < nodes.size(); ++i)
{
Node* const node = nodes.getUnchecked(i);
node->prepare (getSampleRate(), getBlockSize(), this);
int j = 0;
for (; j < orderedNodes.size(); ++j)
if (table.isAnInputTo (node->nodeId, ((Node*) orderedNodes.getUnchecked(j))->nodeId))
break;
orderedNodes.insert (j, node);
}
}
//pass table to calculator
GraphRenderingOps::RenderingOpSequenceCalculator calculator (*this, table, orderedNodes, newRenderingOps);