From cf214b30d06b614c463359a128914cc5b3d58ef3 Mon Sep 17 00:00:00 2001
From: jsiegle <jsiegle@mit.edu>
Date: Sun, 4 Mar 2012 13:53:36 -0500
Subject: [PATCH] Building processor graph with splitters and mergers is now
 possible.

Although it has not been rigorously tested for all cases.
---
 Source/Processors/GenericProcessor.cpp   | 26 ++++++-
 Source/Processors/GenericProcessor.h     |  7 +-
 Source/Processors/ProcessorGraph.cpp     | 93 ++++++++++++++++--------
 Source/Processors/ProcessorGraph.h       |  8 +-
 Source/Processors/Utilities/Merger.h     | 10 ---
 Source/Processors/Utilities/Splitter.cpp |  6 ++
 Source/Processors/Utilities/Splitter.h   |  4 +-
 7 files changed, 107 insertions(+), 47 deletions(-)

diff --git a/Source/Processors/GenericProcessor.cpp b/Source/Processors/GenericProcessor.cpp
index 14bbca643..1fe7db01d 100644
--- a/Source/Processors/GenericProcessor.cpp
+++ b/Source/Processors/GenericProcessor.cpp
@@ -25,7 +25,8 @@
 #include "../UI/UIComponent.h"
 
 GenericProcessor::GenericProcessor(const String& name_) : name(name_),
-	sourceNode(0), destNode(0), editor(0), isEnabled(true), saveOrder(-1), loadOrder(-1)
+	sourceNode(0), destNode(0), editor(0), isEnabled(true), saveOrder(-1), loadOrder(-1),
+	nextAvailableChannel(0), wasConnected(false)
 	
 {
 
@@ -110,6 +111,29 @@ void GenericProcessor::releaseResources()
 // }
 
 
+int GenericProcessor::getNextChannel(bool increment)
+{
+	int chan = nextAvailableChannel;
+
+	//std::cout << chan << std::endl;
+
+	if (increment)
+		nextAvailableChannel++;
+	
+	if (chan < getNumInputs())
+		return chan;
+	else
+		return -1;
+
+}
+
+void GenericProcessor::resetConnections()
+{
+	//std::cout << "Resetting connections" << std::endl;
+	nextAvailableChannel = 0;
+	wasConnected = false;
+}
+
 void GenericProcessor::setNumSamples(MidiBuffer& midiMessages, int numberToAdd) {
 
 	uint8 data[2];
diff --git a/Source/Processors/GenericProcessor.h b/Source/Processors/GenericProcessor.h
index 6d99155b1..9c159be66 100644
--- a/Source/Processors/GenericProcessor.h
+++ b/Source/Processors/GenericProcessor.h
@@ -133,6 +133,9 @@ public:
 	virtual void setNumOutputs(int);
 	virtual void setNumOutputs();
 	virtual int getDefaultNumOutputs();
+
+	virtual int getNextChannel(bool);
+	virtual void resetConnections();
 	
 	virtual void updateSettings();
 
@@ -173,13 +176,15 @@ public:
 	virtual AudioSampleBuffer* getContinuousBuffer() {return 0;}
 	virtual MidiBuffer* getEventBuffer() {return 0;}
 
-
+	int nextAvailableChannel;
 
 	int checkForMidiEvents(MidiBuffer& mb);
 	void addMidiEvent(MidiBuffer& mb, int a, int b);
 
 	bool isEnabled;
 
+	bool wasConnected;
+
 	int saveOrder;
 	int loadOrder;
 
diff --git a/Source/Processors/ProcessorGraph.cpp b/Source/Processors/ProcessorGraph.cpp
index 0b3192124..ce3c7717a 100644
--- a/Source/Processors/ProcessorGraph.cpp
+++ b/Source/Processors/ProcessorGraph.cpp
@@ -48,9 +48,9 @@ ProcessorGraph::ProcessorGraph() :
 	RECORD_NODE_ID(199), 
 	AUDIO_NODE_ID(200), 
 	OUTPUT_NODE_ID(201), 
-	RESAMPLING_NODE_ID(202),
-	totalAudioConnections(0),
-	totalRecordConnections(0)
+	RESAMPLING_NODE_ID(202)
+	//totalAudioConnections(0),
+	//totalRecordConnections(0)
 	
 	{
 
@@ -59,7 +59,7 @@ ProcessorGraph::ProcessorGraph() :
 	setPlayConfigDetails(0, // number of inputs
 				         2, // number of outputs
 				         44100.0, // sampleRate
-				         128);    // blockSize
+				         1024);    // blockSize
 
 	createDefaultNodes();
 
@@ -121,13 +121,9 @@ void* ProcessorGraph::createNewProcessor(String& description)//,
 	if (processor != 0) {
 
 		processor->setNodeId(id); // identifier within processor graph
-
 		std::cout << "  Adding node to graph with ID number " << id << std::endl;
 		
-		//processor->setFilterViewport(filterViewport);
-		//processor->setConfiguration(config);
-		//processor->addActionListener(messageCenter);
-		processor->setUIComponent(getUIComponent());
+		processor->setUIComponent(getUIComponent()); // give access to important pointers
 
 		addNode(processor,id); // have to add it so it can be deleted by the graph
 
@@ -154,6 +150,17 @@ void ProcessorGraph::clearConnections()
 		 {
 		 	; // leave it   	
 		 } else {
+
+		 	Node* node = getNodeForId(connection->sourceNodeId);
+		 	GenericProcessor* p =(GenericProcessor*) node->getProcessor();
+		 	//if (p->getNextChannel(false) > 0)
+		 		p->resetConnections();
+
+		 	node = getNodeForId(connection->destNodeId);
+		 	p =(GenericProcessor*) node->getProcessor();
+		 	//if (p->getNextChannel(false) > 0)
+		 		p->resetConnections();
+
 		 	removeConnection(i);
 		 }
 	}
@@ -165,6 +172,8 @@ void ProcessorGraph::updateConnections(Array<SignalChainTabButton*, CriticalSect
 
 	std::cout << "Updating connections:" << std::endl;
 
+	Array<GenericProcessor*> splitters;
+
  	for (int n = 0; n < tabs.size(); n++)
 	{
 		std::cout << "Signal chain " << n << std::endl;
@@ -176,9 +185,21 @@ void ProcessorGraph::updateConnections(Array<SignalChainTabButton*, CriticalSect
 		{
 			std::cout << "Source node: " << source->getName() << ", ";
 			GenericProcessor* dest = (GenericProcessor*) source->getDestNode();
+
 			if (dest != 0)
 			{
 				std::cout << "Dest node: " << dest->getName() << std::endl;
+				if (dest->isMerger()) // move it forward by one
+				{
+					dest = dest->getDestNode();
+				} else if (dest->isSplitter())
+				{
+					if (!dest->wasConnected)
+						splitters.add(dest);
+
+					dest = dest->getDestNode();
+				}
+
 			} else {
 				std::cout << "no dest node." << std::endl;
 			}
@@ -187,8 +208,10 @@ void ProcessorGraph::updateConnections(Array<SignalChainTabButton*, CriticalSect
 			{
 
 				// add the connections to audio and record nodes if necessary
-				if (!(source->isSink() || source->isSource() ||
-				      source->isSplitter() || source->isMerger()))
+
+
+				if (!(source->isSink() ||
+				      source->isSplitter() || source->isMerger()) && !(source->wasConnected))
 				{
 					std::cout << "   Connecting to audio and record nodes." << std::endl;
 
@@ -197,39 +220,40 @@ void ProcessorGraph::updateConnections(Array<SignalChainTabButton*, CriticalSect
 						addConnection(source->getNodeId(), // sourceNodeID
 						  	chan, // sourceNodeChannelIndex
 						   	AUDIO_NODE_ID, // destNodeID
-						  	getNextFreeAudioChannel()); // destNodeChannelIndex
+						  	getAudioNode()->getNextChannel(true)); // destNodeChannelIndex
 
 						addConnection(source->getNodeId(), // sourceNodeID
 						  	chan, // sourceNodeChannelIndex
 						   	RECORD_NODE_ID, // destNodeID
-						  	getNextFreeRecordChannel()); // destNodeChannelIndex
+						  	getRecordNode()->getNextChannel(true)); // destNodeChannelIndex
 					}
 				}
 
 				if (dest != 0) {
 
 					if (dest->enabledState())
-						std::cout << "OK." << std::endl;
-					else
-						std::cout << "Not OK." << std::endl;
+						std::cout << "     OK." << std::endl;
+					else 
+						std::cout << "     Not OK." << std::endl;
 
 					if (dest->enabledState())
 					{
 
 						std::cout << "     Connecting " << source->getName() << " channel ";
 
+						//int nextChan;
+						//int chan = 0;
+
 						for (int chan = 0; chan < source->getNumOutputs(); chan++) 
+						
+						//ile ((nextChan = dest->getNextChannel(true)) != -1)
 						{
-
-							// eventually need to account for splitter and mergers
-							
 							std::cout << chan << " ";
 							           
-
 							addConnection(source->getNodeId(), // sourceNodeID
 							  	chan, // sourceNodeChannelIndex
 							   	dest->getNodeId(), // destNodeID
-							  	chan); // destNodeChannelIndex
+							  	dest->getNextChannel(true)); // destNodeChannelIndex
 						}
 
 						std::cout << " to " << dest->getName() << std::endl;
@@ -248,20 +272,31 @@ void ProcessorGraph::updateConnections(Array<SignalChainTabButton*, CriticalSect
 				}
 			}	
 			
+			source->wasConnected = true;
 			source = dest; // switch source and dest
+
+			if (source == 0 && splitters.size() > 0)
+			{
+				dest = splitters.getFirst(); // dest is now the splitter
+				splitters.remove(0); // take it out of the 
+				dest->switchDest(); // switch to the other destination
+				dest->wasConnected = true; // don't want to re-add splitter
+				source = dest->getSourceNode(); // splitter is now source
+			}
+
 		} // end while source != 0
 	} // end "tabs" for loop
 } // end method
 
-int ProcessorGraph::getNextFreeAudioChannel()
-{
-	return totalAudioConnections++;
-}
+// int ProcessorGraph::getNextFreeAudioChannel()
+// {
+// 	return totalAudioConnections++;
+// }
 
-int ProcessorGraph::getNextFreeRecordChannel()
-{
-	return totalRecordConnections++;
-}
+// int ProcessorGraph::getNextFreeRecordChannel()
+// {
+// 	return totalRecordConnections++;
+// }
 
 GenericProcessor* ProcessorGraph::createProcessorFromDescription(String& description)
 {
diff --git a/Source/Processors/ProcessorGraph.h b/Source/Processors/ProcessorGraph.h
index f4c145391..279ae7406 100644
--- a/Source/Processors/ProcessorGraph.h
+++ b/Source/Processors/ProcessorGraph.h
@@ -83,8 +83,8 @@ public:
 	void saveState();
 	void loadState();
 
-	int getNextFreeAudioChannel();
-	int getNextFreeRecordChannel();
+	//int getNextFreeAudioChannel();
+	//int getNextFreeRecordChannel();
 
 private:	
 
@@ -105,8 +105,8 @@ private:
 	///Configuration* config;
 	//MessageCenter* messageCenter;
 
-	int totalAudioConnections;
-	int totalRecordConnections;
+	//int totalAudioConnections;
+	//int totalRecordConnections;
 
 };
 
diff --git a/Source/Processors/Utilities/Merger.h b/Source/Processors/Utilities/Merger.h
index 4f5f6ee86..66d4459bc 100644
--- a/Source/Processors/Utilities/Merger.h
+++ b/Source/Processors/Utilities/Merger.h
@@ -32,8 +32,6 @@
 
 /**
 
-  --UNDER CONSTRUCTION--
-  
   Allows the user to merge two signal chains.
 
   @see GenericProcessor, ProcessorGraph
@@ -50,30 +48,22 @@ public:
 	AudioProcessorEditor* createEditor();
 
 	void process(AudioSampleBuffer &buffer, MidiBuffer &midiMessages, int& nSamples) {}
-//	void setParameter (int parameterIndex, float newValue) {}
 
 	bool isMerger() {return true;}
 
-	//void tabNumber(int);
-
 	void switchSource(int);
 	void switchSource();
 	void setMergerSourceNode(GenericProcessor* sn);
 
-	//void setNumOutputs(int);
 	void setNumInputs(int);
 
 	bool stillHasSource();
 
-	//int tabA, tabB;
-
 private:
 
 	GenericProcessor* sourceNodeA;
 	GenericProcessor* sourceNodeB;
 
-
-
 	int activePath;
 
 	JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Merger);
diff --git a/Source/Processors/Utilities/Splitter.cpp b/Source/Processors/Utilities/Splitter.cpp
index f134d3035..f259291f9 100644
--- a/Source/Processors/Utilities/Splitter.cpp
+++ b/Source/Processors/Utilities/Splitter.cpp
@@ -96,4 +96,10 @@ void Splitter::switchDest()
 	    destNode = destNodeA;
 	}
 
+}
+
+void Splitter::setNumInputs(int n)
+{
+	numInputs = n;
+	setNumOutputs(getNumInputs());
 }
\ No newline at end of file
diff --git a/Source/Processors/Utilities/Splitter.h b/Source/Processors/Utilities/Splitter.h
index 0c03499db..69581ba62 100644
--- a/Source/Processors/Utilities/Splitter.h
+++ b/Source/Processors/Utilities/Splitter.h
@@ -32,8 +32,6 @@
 
 /**
 
-  --UNDER CONSTRUCTION--
-  
   Allows the user to split the signal chain.
 
   @see GenericProcessor, ProcessorGraph
@@ -59,6 +57,8 @@ public:
     void switchDest();
 	void setSplitterDestNode(GenericProcessor* dn);
 
+    void setNumInputs(int);
+
 private:
 
 	GenericProcessor* destNodeA;
-- 
GitLab