2222*/
2323
2424#include < stdio.h>
25+ #include < utility>
26+ #include < vector>
27+ #include < map>
2528
2629#include " ProcessorGraph.h"
2730#include " ../GenericProcessor/GenericProcessor.h"
3639#include " ../../UI/TimestampSourceSelection.h"
3740
3841#include " ../ProcessorManager/ProcessorManager.h"
39-
42+
4043ProcessorGraph::ProcessorGraph () : currentNodeId(100 )
4144{
4245
@@ -261,7 +264,37 @@ void ProcessorGraph::updateConnections(Array<SignalChainTabButton*, CriticalSect
261264 std::cout << std::endl;
262265
263266 Array<GenericProcessor*> splitters;
264- // GenericProcessor* activeSplitter = nullptr;
267+
268+ // keep track of which splitter is currently being explored, in case there's another
269+ // splitter between the one being explored and its source.
270+ GenericProcessor* activeSplitter = nullptr ;
271+
272+ // stores the pointer to a source leading into a particular dest node
273+ // along with a boolean vector indicating the position of this source
274+ // relative to other sources entering the dest via mergers
275+ // (when the mergerOrder vectors of all incoming nodes to a dest are
276+ // lexicographically sorted, the sources will be in the correct order)
277+ struct ConnectionInfo
278+ {
279+ GenericProcessor* source;
280+ std::vector<int > mergerOrder;
281+ bool connectContinuous;
282+ bool connectEvents;
283+
284+ // for SortedSet sorting:
285+ bool operator <(const ConnectionInfo& other) const
286+ {
287+ return mergerOrder < other.mergerOrder ;
288+ }
289+
290+ bool operator ==(const ConnectionInfo& other) const
291+ {
292+ return mergerOrder == other.mergerOrder ;
293+ }
294+ };
295+
296+ // each destination node gets a set of sources, sorted by their order as dictated by mergers
297+ std::unordered_map<GenericProcessor*, SortedSet<ConnectionInfo>> sourceMap;
265298
266299 for (int n = 0 ; n < tabs.size (); n++) // cycle through the tabs
267300 {
@@ -282,8 +315,8 @@ void ProcessorGraph::updateConnections(Array<SignalChainTabButton*, CriticalSect
282315 if (!(source->isSink () ||
283316 source->isSplitter () ||
284317 source->isMerger () ||
285- source->isUtility ())
286- && !( source->wasConnected ))
318+ source->isUtility () ||
319+ source->wasConnected ))
287320 {
288321 std::cout << " Connecting to audio and record nodes." << std::endl;
289322 connectProcessorToAudioAndRecordNodes (source);
@@ -293,58 +326,45 @@ void ProcessorGraph::updateConnections(Array<SignalChainTabButton*, CriticalSect
293326 std::cout << " NOT connecting to audio and record nodes." << std::endl;
294327 }
295328
296- if ( dest != nullptr )
297- {
329+ // find the next dest that's not a merger or splitter
330+ GenericProcessor* prev = source;
298331
299- while (dest->isMerger ()) // find the next dest that's not a merger
300- {
301- dest = dest->getDestNode ();
302-
303- if (dest == nullptr )
304- break ;
305- }
332+ ConnectionInfo conn;
333+ conn.source = source;
334+ conn.connectContinuous = true ;
335+ conn.connectEvents = true ;
306336
307- if (dest != nullptr )
337+ while (dest != nullptr && (dest->isMerger () || dest->isSplitter ()))
338+ {
339+ if (dest->isSplitter () && dest != activeSplitter && !splitters.contains (dest))
308340 {
309- while (dest->isSplitter ())
310- {
311- if (!dest->wasConnected )
312- {
313- if (!splitters.contains (dest))
314- {
315- splitters.add (dest);
316- dest->switchIO (0 ); // go down first path
317- }
318- else
319- {
320- int splitterIndex = splitters.indexOf (dest);
321- splitters.remove (splitterIndex);
322- dest->switchIO (1 ); // go down second path
323- dest->wasConnected = true ; // make sure we don't re-use this splitter
324- }
325- }
326-
327- dest = dest->getDestNode ();
328-
329- if (dest == nullptr )
330- break ;
331- }
332-
333- if (dest != nullptr )
334- {
335-
336- if (dest->isEnabledState ())
337- {
338- connectProcessors (source, dest);
339- }
340- }
341-
341+ // add to stack of splitters to explore
342+ splitters.add (dest);
343+ dest->switchIO (0 ); // go down first path
342344 }
343- else
345+ else if (dest-> isMerger ())
344346 {
345- std::cout << " No dest node." << std::endl;
347+ auto merger = static_cast <Merger*>(dest);
348+
349+ // keep the input aligned with the current path
350+ int path = merger->switchToSourceNode (prev);
351+ jassert (path != -1 ); // merger not connected to prev?
352+
353+ conn.mergerOrder .insert (conn.mergerOrder .begin (), path);
354+ conn.connectContinuous &= merger->sendContinuousForSource (prev);
355+ conn.connectEvents &= merger->sendEventsForSource (prev);
346356 }
347357
358+ prev = dest;
359+ dest = dest->getDestNode ();
360+ }
361+
362+ if (dest != nullptr )
363+ {
364+ if (dest->isEnabledState ())
365+ {
366+ sourceMap[dest].add (conn);
367+ }
348368 }
349369 else
350370 {
@@ -355,25 +375,58 @@ void ProcessorGraph::updateConnections(Array<SignalChainTabButton*, CriticalSect
355375 std::cout << std::endl;
356376
357377 source->wasConnected = true ;
358- source = dest; // switch source and dest
359378
360- if (source == nullptr && splitters. size () > 0 )
379+ if (dest != nullptr && dest-> wasConnected )
361380 {
381+ // don't bother retraversing downstream of a dest that has already been connected
382+ // (but if it leads to a splitter that is still in the stack, it may still be
383+ // used as a source for the unexplored branch.)
384+
385+ std::cout << dest->getName () << " " << dest->getNodeId () <<
386+ " has already been connected." << std::endl;
387+ std::cout << std::endl;
388+ dest = nullptr ;
389+ }
362390
363- source = splitters.getLast ();
364- GenericProcessor* newSource;// = source->getSourceNode();
391+ source = dest; // switch source and dest
365392
366- while (source->isSplitter () || source->isMerger ())
393+ if (source == nullptr )
394+ {
395+ if (splitters.size () > 0 )
367396 {
368- newSource = source->getSourceNode ();
369- newSource->setPathToProcessor (source);
370- source = newSource;
371- }
397+ activeSplitter = splitters.getLast ();
398+ splitters.removeLast ();
399+ activeSplitter->switchIO (1 );
372400
401+ source = activeSplitter;
402+ GenericProcessor* newSource;
403+ while (source->isSplitter () || source->isMerger ())
404+ {
405+ newSource = source->getSourceNode ();
406+ newSource->setPathToProcessor (source);
407+ source = newSource;
408+ }
409+ }
410+ else
411+ {
412+ activeSplitter = nullptr ;
413+ }
373414 }
374415
375416 } // end while source != 0
376417 } // end "tabs" for loop
418+
419+ // actually connect sources to each dest processor,
420+ // in correct order by merger topography
421+ for (const auto & destSources : sourceMap)
422+ {
423+ GenericProcessor* dest = destSources.first ;
424+
425+ for (const ConnectionInfo& conn : destSources.second )
426+ {
427+ connectProcessors (conn.source , dest, conn.connectContinuous , conn.connectEvents );
428+ }
429+ }
377430
378431 getAudioNode ()->updatePlaybackBuffer ();
379432 // Update RecordNode internal channel mappings
@@ -382,7 +435,8 @@ void ProcessorGraph::updateConnections(Array<SignalChainTabButton*, CriticalSect
382435 getRecordNode ()->addSpecialProcessorChannels (extraChannels);
383436} // end method
384437
385- void ProcessorGraph::connectProcessors (GenericProcessor* source, GenericProcessor* dest)
438+ void ProcessorGraph::connectProcessors (GenericProcessor* source, GenericProcessor* dest,
439+ bool connectContinuous, bool connectEvents)
386440{
387441
388442 if (source == nullptr || dest == nullptr )
@@ -391,19 +445,6 @@ void ProcessorGraph::connectProcessors(GenericProcessor* source, GenericProcesso
391445 std::cout << " Connecting " << source->getName () << " " << source->getNodeId (); // " channel ";
392446 std::cout << " to " << dest->getName () << " " << dest->getNodeId () << std::endl;
393447
394- bool connectContinuous = true ;
395- bool connectEvents = true ;
396-
397- if (source->getDestNode () != nullptr )
398- {
399- if (source->getDestNode ()->isMerger ())
400- {
401- Merger* merger = (Merger*) source->getDestNode ();
402- connectContinuous = merger->sendContinuousForSource (source);
403- connectEvents = merger->sendEventsForSource (source);
404- }
405- }
406-
407448 // 1. connect continuous channels
408449 if (connectContinuous)
409450 {
@@ -509,7 +550,7 @@ GenericProcessor* ProcessorGraph::createProcessorFromDescription(Array<var>& des
509550
510551 processor = ProcessorManager::createProcessorFromPluginInfo ((Plugin::PluginType)processorType, processorIndex, processorName, libName, libVersion, isSource, isSink);
511552 }
512-
553+
513554 String msg = " New " + processorName + " created" ;
514555 CoreServices::sendStatusMessage (msg);
515556
@@ -789,4 +830,4 @@ uint32 ProcessorGraph::getGlobalTimestampSourceFullId() const
789830void ProcessorGraph::setTimestampWindow (TimestampSourceSelectionWindow* window)
790831{
791832 m_timestampWindow = window;
792- }
833+ }
0 commit comments