Skip to content

Commit e2630b9

Browse files
authored
Merge pull request #286 from tne-lab/processorgraph-changes
Fix some issues with connecting processors before starting acquisition
2 parents a5b43f8 + 94e798f commit e2630b9

5 files changed

Lines changed: 137 additions & 75 deletions

File tree

Source/Processors/Merger/Merger.cpp

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,23 @@ void Merger::switchIO(int sourceNum)
9696

9797
}
9898

99+
int Merger::switchToSourceNode(GenericProcessor* sn)
100+
{
101+
if (sn == sourceNodeA)
102+
{
103+
switchIO(0);
104+
return 0;
105+
}
106+
107+
if (sn == sourceNodeB)
108+
{
109+
switchIO(1);
110+
return 1;
111+
}
112+
113+
return -1;
114+
}
115+
99116
bool Merger::sendContinuousForSource(GenericProcessor* sourceNode)
100117
{
101118
if (sourceNode == sourceNodeA)

Source/Processors/Merger/Merger.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ class Merger : public GenericProcessor
6161

6262
void switchIO(int) override;
6363
void switchIO() override;
64+
int switchToSourceNode(GenericProcessor* sn);
6465
void setMergerSourceNode(GenericProcessor* sn) override;
6566

6667
void updateSettings() override;

Source/Processors/Merger/MergerEditor.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -191,9 +191,11 @@ void MergerEditor::mouseDown(const MouseEvent& e)
191191
} else if (result == eventMerge)
192192
{
193193
*eventPtr = !(*eventPtr);
194+
CoreServices::updateSignalChain(this);
194195
} else if (result == continuousMerge)
195196
{
196197
*continuousPtr = !(*continuousPtr);
198+
CoreServices::updateSignalChain(this);
197199
}
198200
}
199201

Source/Processors/ProcessorGraph/ProcessorGraph.cpp

Lines changed: 115 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,9 @@
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"
@@ -36,7 +39,7 @@
3639
#include "../../UI/TimestampSourceSelection.h"
3740

3841
#include "../ProcessorManager/ProcessorManager.h"
39-
42+
4043
ProcessorGraph::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
789830
void ProcessorGraph::setTimestampWindow(TimestampSourceSelectionWindow* window)
790831
{
791832
m_timestampWindow = window;
792-
}
833+
}

Source/Processors/ProcessorGraph/ProcessorGraph.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,8 @@ class ProcessorGraph : public AudioProcessorGraph
114114

115115
void clearConnections();
116116

117-
void connectProcessors(GenericProcessor* source, GenericProcessor* dest);
117+
void connectProcessors(GenericProcessor* source, GenericProcessor* dest,
118+
bool connectContinuous, bool connectEvents);
118119
void connectProcessorToAudioAndRecordNodes(GenericProcessor* source);
119120

120121
int64 m_startSoftTimestamp{ 0 };

0 commit comments

Comments
 (0)