From fcd98020c76eb0730e3b4f1b3f663fc5f23f69c3 Mon Sep 17 00:00:00 2001
From: jsiegle <jsiegle@mit.edu>
Date: Sat, 10 Nov 2012 17:02:14 -0500
Subject: [PATCH] Switching to channel-based settings

---
 Source/Processors/AudioNode.cpp        | 84 ++++++++++++++++-------
 Source/Processors/AudioNode.h          | 20 ++++--
 Source/Processors/Channel.cpp          | 13 ++++
 Source/Processors/Channel.h            | 10 ++-
 Source/Processors/GenericProcessor.cpp | 44 ++++++------
 Source/Processors/GenericProcessor.h   | 28 ++------
 Source/Processors/ProcessorGraph.cpp   |  5 +-
 Source/Processors/RecordNode.cpp       | 95 ++++++++++----------------
 Source/Processors/RecordNode.h         | 30 ++++----
 9 files changed, 179 insertions(+), 150 deletions(-)

diff --git a/Source/Processors/AudioNode.cpp b/Source/Processors/AudioNode.cpp
index 6af939f90..5ac502891 100755
--- a/Source/Processors/AudioNode.cpp
+++ b/Source/Processors/AudioNode.cpp
@@ -31,11 +31,11 @@ AudioNode::AudioNode()
 	settings.numInputs = 128;
 	settings.numOutputs = 2;
 
-	// 64 inputs, 2 outputs (left and right channel)
+	// 128 inputs, 2 outputs (left and right channel)
 	setPlayConfigDetails(getNumInputs(),getNumOutputs(),44100.0,128);
 
-	leftChan.clear();
-	rightChan.clear();
+	//leftChan.clear();
+	//rightChan.clear();
 
 	nextAvailableChannel = 2; // keep first two channels empty
 
@@ -60,6 +60,16 @@ AudioProcessorEditor* AudioNode::createEditor()
 
 }
 
+void AudioNode::resetConnections()
+{
+
+	nextAvailableChannel = 2; // start connections at channel 2
+	wasConnected = false;
+
+	channelPointers.clear();
+
+}
+
 void AudioNode::setChannelStatus(int chan, bool status)
 {
 
@@ -87,29 +97,50 @@ void AudioNode::enableCurrentChannel(bool state)
 	}
 }
 
+
+void AudioNode::addInputChannel(GenericProcessor* sourceNode, int chan)
+{
+
+	if (chan != getProcessorGraph()->midiChannelIndex)
+	{
+        
+		int channelIndex = getNextChannel(false);
+
+        setPlayConfigDetails(channelIndex+1,0,44100.0,128);
+
+        channelPointers.add(sourceNode->channels[chan]);
+		
+	} else {
+
+		// Can't monitor events at the moment!
+	}
+
+}
+
 void AudioNode::setParameter (int parameterIndex, float newValue)
 {
 	// change left channel, right channel, or volume
 	if (parameterIndex == 1) 
 	{
-	// volume level
+		// volume level
 		volume = newValue*0.00001f;
+
 	} else if (parameterIndex == 100) 
 	{
 		// add current channel
-		if (!leftChan.contains(currentChannel))
-		{
-			leftChan.add(currentChannel);
-			rightChan.add(currentChannel);
-		} 
+		// if (!leftChan.contains(currentChannel))
+		// {
+		// 	leftChan.add(currentChannel);
+		// 	rightChan.add(currentChannel);
+		// } 
 	} else if (parameterIndex == -100)
 	{
 		// remove current channel
-		if (leftChan.contains(currentChannel))
-		{
-			leftChan.remove(leftChan.indexOf(currentChannel));
-			rightChan.remove(rightChan.indexOf(currentChannel));
-		}
+		// if (leftChan.contains(currentChannel))
+		// {
+		// 	leftChan.remove(leftChan.indexOf(currentChannel));
+		// 	rightChan.remove(rightChan.indexOf(currentChannel));
+		// }
 	}
 
 }
@@ -121,34 +152,35 @@ void AudioNode::process(AudioSampleBuffer &buffer,
 
 	//std::cout << "Audio node sample count: " << nSamples << std::endl; ///buffer.getNumSamples() << std::endl;
 
-
+	// clear the left and right channels
 	buffer.clear(0,0,buffer.getNumSamples());
 	buffer.clear(1,0,buffer.getNumSamples());
 
-	for (int n = 0; n < leftChan.size(); n++) 
+	for (int i = 2; i < buffer.getNumChannels(); i++)
 	{
 
-		buffer.addFrom(0,  // destination channel
-					   0,  // destination start sample
+		if (channelPointers[i-2]->isMonitored)
+		{
+			buffer.addFrom(0,  		// destination channel
+					   0,  			// destination start sample
 					   buffer,      // source
-					   leftChan[n], // source channel
+					   i, 			// source channel
 					   0,           // source start sample
 					   buffer.getNumSamples(), //  number of samples
 					   volume       // gain to apply
 					   );
-	}
-	
-	for (int n = 0; n < rightChan.size(); n++) 
-	{
 
-		buffer.addFrom(1,  // destination channel
-					   0,  // destination start sample
+			buffer.addFrom(1,  		// destination channel
+					   0,  			// destination start sample
 					   buffer,      // source
-					   rightChan[n], // source channel
+					   i, 			// source channel
 					   0,           // source start sample
 					   buffer.getNumSamples(), //  number of samples
 					   volume       // gain to apply
 					   );
+
+		}
+
 	}
 
 }
diff --git a/Source/Processors/AudioNode.h b/Source/Processors/AudioNode.h
index 94ce8f139..4495cf4a3 100755
--- a/Source/Processors/AudioNode.h
+++ b/Source/Processors/AudioNode.h
@@ -48,24 +48,32 @@ class AudioNode : public GenericProcessor
 {
 public:
 	
-	// real member functions:
 	AudioNode();
 	~AudioNode();
-	
+
+
+	/** Handle incoming data and decide which channels to monitor
+  */  
 	void process(AudioSampleBuffer &buffer, MidiBuffer &midiMessages, int& nSamples);
+
+  /** Overrides implementation in GenericProcessor; used to change audio monitoring
+      parameters on the fly.
+  */
 	void setParameter (int parameterIndex, float newValue);
 
 	AudioProcessorEditor* createEditor();
 
   void setChannelStatus(int, bool);
 
- // bool isAudioOrRecordNode() {return true;}
+  void resetConnections();
 
   void enableCurrentChannel(bool);
 
-   // AudioEditor* getEditor() {return audioEditor;}
+  void addInputChannel(GenericProcessor* source, int chan);
+
+  // AudioEditor* getEditor() {return audioEditor;}
 
-    ScopedPointer<AudioEditor> audioEditor;
+  ScopedPointer<AudioEditor> audioEditor;
 	
 private:
 
@@ -73,6 +81,8 @@ private:
 	Array<int> rightChan;
 	float volume;
 
+  Array<Channel*> audioChannels;
+
 	JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (AudioNode);
 
 };
diff --git a/Source/Processors/Channel.cpp b/Source/Processors/Channel.cpp
index 8455bebf0..13e144b4f 100644
--- a/Source/Processors/Channel.cpp
+++ b/Source/Processors/Channel.cpp
@@ -34,6 +34,19 @@ Channel::Channel(GenericProcessor* p, int n) :
 	createDefaultName();
 }
 
+Channel::Channel(const Channel& ch)
+{
+	processor = ch.processor;
+	isEventChannel = ch.isEventChannel;
+	isEnabled = ch.isEnabled;
+	isRecording = false;
+	isMonitored = false;
+	sampleRate = ch.sampleRate;
+	bitVolts = ch.bitVolts;
+	name = ch.name;
+
+}
+
 String Channel::getName()
 {
 	return name;
diff --git a/Source/Processors/Channel.h b/Source/Processors/Channel.h
index 93d160ee1..63aa82fa1 100644
--- a/Source/Processors/Channel.h
+++ b/Source/Processors/Channel.h
@@ -49,8 +49,12 @@ class Channel
 {
 public:
 
+	// Default constructor:
 	Channel(GenericProcessor* p, int n);
 
+	// Copy constructor:
+	Channel(const Channel& ch);
+
 	String getName();
 
 	void reset();
@@ -66,11 +70,15 @@ public:
 
 	// pointer to parent processor:
 	GenericProcessor* processor;
-
+	
 	// crucial information:
 	float sampleRate;
 	float bitVolts;
 
+	// file info (for disk writing):
+	String filename;
+	FILE* file;
+
 
 private:
 
diff --git a/Source/Processors/GenericProcessor.cpp b/Source/Processors/GenericProcessor.cpp
index ce711ee41..76f6093fd 100755
--- a/Source/Processors/GenericProcessor.cpp
+++ b/Source/Processors/GenericProcessor.cpp
@@ -127,10 +127,7 @@ int GenericProcessor::getNextChannel(bool increment)
 
 void GenericProcessor::resetConnections()
 {
-	//std::cout << "Resetting connections" << std::endl;
-	// if (isAudioOrRecordNode())
-	// 	nextAvailableChannel = 2;
-	// else
+
 	nextAvailableChannel = 0;
 
 	wasConnected = false;
@@ -206,8 +203,7 @@ void GenericProcessor::setSourceNode(GenericProcessor* sn)
 						sourceNode = sn;
 
 					sn->setDestNode(this);
-					//setNumInputs(sn->getNumOutputs());
-					//setSampleRate(sn->getSampleRate());
+
 				} else {
 		//			std::cout << "  The source node is not new." << std::endl;
 				}
@@ -258,8 +254,7 @@ void GenericProcessor::setDestNode(GenericProcessor* dn)
 						destNode = dn;
 
 					dn->setSourceNode(this);
-					//dn->setNumInputs(getNumOutputs());
-					//dn->setSampleRate(getSampleRate());
+
 				} else {
 			//		std::cout << "  The dest node is not new." << std::endl;
 				}
@@ -306,22 +301,31 @@ void GenericProcessor::update()
 		settings.numInputs = settings.numOutputs;
 		settings.numOutputs = settings.numInputs;
 
+		for (int i = 0; i < getNumInputs(); i++)
+		{
+			Channel* sourceChan = sourceNode->channels[i];
+			Channel* ch = new Channel(*sourceChan);
+			channels.add(ch);
+		}
+
 	} else {
 
-		settings.sampleRate = getDefaultSampleRate();
 		settings.numOutputs = getDefaultNumOutputs();
 
 		for (int i = 0; i < getNumOutputs(); i++)
-			settings.bitVolts.add(getDefaultBitVolts());
+		{
+			Channel* ch = new Channel(this, i);
+			ch->sampleRate = getDefaultSampleRate();
+			ch->bitVolts = getDefaultBitVolts();
 
-		generateDefaultChannelNames(settings.outputChannelNames);
+			channels.add(ch);
+		}
 
 	}
 
 	if (this->isSink())
 	{
 		settings.numOutputs = 0;
-		settings.outputChannelNames.clear();
 	}
 
 	updateSettings(); // custom settings code
@@ -337,21 +341,21 @@ void GenericProcessor::update()
 
 }
 
-bool GenericProcessor::recordStatus(int chan)
-{
+// bool GenericProcessor::recordStatus(int chan)
+// {
 
-	return getEditor()->getRecordStatus(chan);//recordChannels[chan];
+// 	return getEditor()->getRecordStatus(chan);//recordChannels[chan];
 
 
-}
+// }
 
-bool GenericProcessor::audioStatus(int chan)
-{
+// bool GenericProcessor::audioStatus(int chan)
+// {
 
-	return getEditor()->getAudioStatus(chan);//recordChannels[chan];
+// 	return getEditor()->getAudioStatus(chan);//recordChannels[chan];
 
 
-}
+// }
 
 // void GenericProcessor::generateDefaultChannelNames(StringArray& names)
 // {
diff --git a/Source/Processors/GenericProcessor.h b/Source/Processors/GenericProcessor.h
index 567dc2cee..ce875c80f 100755
--- a/Source/Processors/GenericProcessor.h
+++ b/Source/Processors/GenericProcessor.h
@@ -216,33 +216,19 @@ public:
 	virtual GenericEditor* getEditor() {return editor;}
 	ScopedPointer<GenericEditor> editor;
 
-	GenericProcessor* originalSource;
-
 	OwnedArray<Channel*> channels;
+	OwnedArray<Channel*> eventChannels;
 
-	int numInputs;
-	int numOutputs;
-
-	// OBSOLETE PROCESSOR SETTINGS:
-	// struct ProcessorSettings {
-
-	// 	GenericProcessor* originalSource;
-
-	// 	int numInputs;
-	// 	int numOutputs;
-	// 	StringArray inputChannelNames;
-	// 	StringArray outputChannelNames;
+	struct ProcessorSettings {
 
-	// 	float sampleRate;
-	// 	Array<float> bitVolts;
+	 	GenericProcessor* originalSource;
 
-	// 	Array<int> eventChannelIds;
-	// 	StringArray eventChannelNames;
-	// 	Array<int> eventChannelTypes;
+		int numInputs;
+	 	int numOutputs;
 
-	// };
+	};
 
-	//ProcessorSettings settings;
+	ProcessorSettings settings;
 
 	//virtual bool isAudioOrRecordNode() {return false;}
 
diff --git a/Source/Processors/ProcessorGraph.cpp b/Source/Processors/ProcessorGraph.cpp
index b2aa8bd60..69f7a217c 100644
--- a/Source/Processors/ProcessorGraph.cpp
+++ b/Source/Processors/ProcessorGraph.cpp
@@ -257,8 +257,7 @@ void ProcessorGraph::updateConnections(Array<SignalChainTabButton*, CriticalSect
 				{
 					std::cout << "   Connecting to audio and record nodes." << std::endl;
 
-
-					source->setStartChannel(getAudioNode()->getNextChannel(false));
+					//source->setStartChannel(getAudioNode()->getNextChannel(false));
 
 
 					for (int chan = 0; chan < source->getNumOutputs(); chan++) {
@@ -273,7 +272,7 @@ void ProcessorGraph::updateConnections(Array<SignalChainTabButton*, CriticalSect
 						addConnection(source->getNodeId(), 		   // sourceNodeID
 						  	chan, 						           // sourceNodeChannelIndex
 						   	AUDIO_NODE_ID, 					       // destNodeID
-						  	getAudioNode()->getNextChannel(true) + 2); // destNodeChannelIndex
+						  	getAudioNode()->getNextChannel(true)); // destNodeChannelIndex
 									// add 2 to account for 2 output channels
 
 						
diff --git a/Source/Processors/RecordNode.cpp b/Source/Processors/RecordNode.cpp
index b7e8483a6..483957568 100755
--- a/Source/Processors/RecordNode.cpp
+++ b/Source/Processors/RecordNode.cpp
@@ -90,8 +90,8 @@ void RecordNode::resetConnections()
 	nextAvailableChannel = 0;
 	wasConnected = false;
 
-	continuousChannels.clear();
-	eventChannels.clear();
+	channelPointers.clear();
+	eventChannelPointers.clear();
 }
 
 void RecordNode::filenameComponentChanged(FilenameComponent* fnc)
@@ -116,68 +116,45 @@ void RecordNode::addInputChannel(GenericProcessor* sourceNode, int chan)
 	if (chan != getProcessorGraph()->midiChannelIndex)
 	{
         
-        setPlayConfigDetails(getNextChannel(false)+1,0,44100.0,128);
-        
-		Channel newChannel;
+		int channelIndex = getNextChannel(false);
 
-		std::cout << "Record node adding channel." << std::endl;
+        setPlayConfigDetails(channelIndex+1,0,44100.0,128);
 
-		newChannel.nodeId = sourceNode->getNodeId();
-		newChannel.chan = chan;
-		newChannel.name = sourceNode->getOutputChannelName(chan);
-		newChannel.isRecording = sourceNode->recordStatus(chan);
+        channelPointers.add(sourceNode->channelPointers[chan]);
 
-		String filename = rootFolder.getFullPathName();
+        String filename = rootFolder.getFullPathName();
 		filename += "/";
-		filename += newChannel.nodeId;
+		filename += sourceNode->getNodeId();
 		filename += "_";
-		filename += newChannel.name;
+		filename += channelPointers[channelIndex]->name;
 		filename += ".continuous";
 
-		newChannel.filename = filename;
-		newChannel.file = 0; 
+        channelPointers[channelIndex]->filename = filename;
+        channelPointers[channelIndex]->file = 0;
 
-		if (newChannel.isRecording)
+		if (channelPointers[channelIndex]->isRecording)
 			std::cout << "  This channel will be recorded." << std::endl;
 		else 
 			std::cout << "  This channel will NOT be recorded." << std::endl;
 	
 		std::cout << "adding channel " << getNextChannel(false) << std::endl;
 
-		std::pair<int, Channel> newPair (getNextChannel(false), newChannel);
+		//std::pair<int, Channel> newPair (getNextChannel(false), newChannel);
 
 		//std::cout << "adding channel " << getNextChannel(false) << std::endl;
 
-		continuousChannels.insert(newPair);
+		//continuouschannelPointers.insert(newPair);
 
 		
 	} else {
 
-		std::map<int, Channel> eventChans;
-
-		int ID = sourceNode->getNodeId();
-
-		for (int n = 0; n < sourceNode->settings.eventChannelIds.size(); n++)
+		for (int n = 0; n < sourceNode->eventChannels.size(); n++)
 		{
 
-			Channel newChannel;
-
-			newChannel.nodeId = ID;
-			newChannel.chan = sourceNode->settings.eventChannelIds[n];
-			newChannel.name = sourceNode->settings.eventChannelNames[n];
-			newChannel.isRecording = true;
-			newChannel.file = 0;
-
-			std::pair<int, Channel> newPair (newChannel.chan, newChannel);
-
-			eventChans.insert(newPair);
+			eventChannelPointers.add(sourceNode->eventChannels[n]);
 
 		}
 
-		std::pair<int, std::map<int, Channel> > newPair (ID, eventChans);
-
-		eventChannels.insert(newPair);
-
 	}
 
 }
@@ -232,21 +209,21 @@ void RecordNode::setParameter (int parameterIndex, float newValue)
  			rootFolder.createDirectory();
 
 		// create / open necessary files
-		for (int i = 0; i < continuousChannels.size(); i++)
+		for (int i = 0; i < channelPointers.size(); i++)
 		{
-			if (continuousChannels[i].isRecording)
+			if (channelPointers[i]->isRecording)
 			{
-				std::cout << "OPENING FILE: " << continuousChannels[i].filename << std::endl;
+				std::cout << "OPENING FILE: " << channelPointers[i]->filename << std::endl;
 
-				File f = File(continuousChannels[i].filename);
+				File f = File(channelPointers[i]->filename);
 
-				continuousChannels[i].file = fopen(continuousChannels[i].filename.toUTF8(), "a+b");
+				channelPointers[i]->file = fopen(channelPointers[i]->filename.toUTF8(), "a+b");
 
 				if (!f.exists())
 				{
 					// create header (needs more details, obviously)
 					String header = "THIS IS A HEADER.";
-					fwrite(header.toUTF8(), 1, header.getNumBytesAsUTF8(), continuousChannels[i].file);
+					fwrite(header.toUTF8(), 1, header.getNumBytesAsUTF8(), channelPointers[i]->file);
 				}
 
 			}
@@ -275,21 +252,21 @@ void RecordNode::setParameter (int parameterIndex, float newValue)
 			std::cout << "Toggling channel " << currentChannel << std::endl;
 
 	 		if (newValue == 0.0f) {
-	 			continuousChannels[currentChannel].isRecording = false;
+	 			channelPointers[currentChannel]->isRecording = false;
 
 	 			if (isRecording) {
-	 				std::cout << "CLOSING FILE: " << continuousChannels[currentChannel].filename << std::endl;
-	 				fclose(continuousChannels[currentChannel].file);
+	 				std::cout << "CLOSING FILE: " << channelPointers[currentChannel]->filename << std::endl;
+	 				fclose(channelPointers[currentChannel]->file);
 	 			}
 
 	 		}
 	 		else {
-	 			continuousChannels[currentChannel].isRecording = true;
+	 			channelPointers[currentChannel]->isRecording = true;
 
 	 			if (isRecording) {
-	 				std::cout << "OPENING FILE: " << continuousChannels[currentChannel].filename << std::endl;
-	 				continuousChannels[currentChannel].file = 
-	 					fopen(continuousChannels[currentChannel].filename.toUTF8(), "a+b");
+	 				std::cout << "OPENING FILE: " << channelPointers[currentChannel]->filename << std::endl;
+	 				channelPointers[currentChannel]->file = 
+	 					fopen(channelPointers[currentChannel]->filename.toUTF8(), "a+b");
 	 			}
 	 		}
 		}
@@ -299,12 +276,12 @@ void RecordNode::setParameter (int parameterIndex, float newValue)
 void RecordNode::closeAllFiles()
 {
 
-	for (int i = 0; i < continuousChannels.size(); i++)
+	for (int i = 0; i < channelPointers.size(); i++)
 	{
-		if (continuousChannels[i].isRecording)
+		if (channelPointers[i]->isRecording)
 		{
-			std::cout << "CLOSING FILE: " << continuousChannels[i].filename << std::endl;
-			fclose(continuousChannels[i].file);
+			std::cout << "CLOSING FILE: " << channelPointers[i]->filename << std::endl;
+			fclose(channelPointers[i]->file);
 		}
 	}
 }
@@ -350,17 +327,17 @@ void RecordNode::writeContinuousBuffer(float* data, int nSamples, int channel)
 	fwrite(&timestamp,							// ptr
 			   8,   							// size of each element
 			   1, 		  						// count 
-			   continuousChannels[channel].file);   // ptr to FILE object
+			   channelPointers[channel]->file);   // ptr to FILE object
 
 	fwrite(&nSamples,								// ptr
 			   sizeof(nSamples),   				// size of each element
 			   1, 		  						// count 
-			   continuousChannels[channel].file);   // ptr to FILE object
+			   channelPointers[channel]->file);   // ptr to FILE object
 
 	int n = fwrite(continuousDataIntegerBuffer,		// ptr
 			   2,			     					// size of each element
 			   nSamples, 		  					// count 
-			   continuousChannels[channel].file);   // ptr to FILE object
+			   channelPointers[channel]->file);   // ptr to FILE object
 	// n must equal "count", otherwise there was an error
 }
  
@@ -393,7 +370,7 @@ void RecordNode::process(AudioSampleBuffer &buffer,
 		for (int i = 0; i < buffer.getNumChannels(); i++)
 		{
 
-			if (continuousChannels[i].isRecording)
+			if (channelPointers[i]->isRecording)
 			{
 				// write buffer to disk!
 				writeContinuousBuffer(buffer.getSampleData(i),
diff --git a/Source/Processors/RecordNode.h b/Source/Processors/RecordNode.h
index b7be99757..46c789e88 100755
--- a/Source/Processors/RecordNode.h
+++ b/Source/Processors/RecordNode.h
@@ -92,10 +92,6 @@ public:
   */
   void resetConnections();
 
-  /** Overrides implementation by GenericProcessor.
-  */
- // bool isAudioOrRecordNode() {return true;}
-
   /** Callback to indicate when user has chosen a new data directory.
   */
   void filenameComponentChanged(FilenameComponent*);
@@ -140,27 +136,31 @@ private:
   /** Holds information for a given channel to be recorded to 
       its own file.
   */ 
-  struct Channel
-  {
-    int nodeId;
-    int chan;
-    String name;
-    bool isRecording;
-    String filename;
-    FILE* file;
-  };
+  // struct Channel
+  // {
+  //   int nodeId;
+  //   int chan;
+  //   String name;
+  //   bool isRecording;
+  //   String filename;
+  //   FILE* file;
+  // };
 
   /** Closes all open files after recording has finished.
   */ 
   void closeAllFiles();
 
+
+  Array<Channel*> channelPointers;
+  Array<Channel*> eventChannelPointers;
+
   /** Map of continuous channels. 
   */ 
-  std::map<int, Channel> continuousChannels;
+  //std::map<int, Channel> continuousChannels;
 
   /** Map of event channels. 
   */ 
-  std::map<int, std::map<int,Channel> > eventChannels;
+  //std::map<int, std::map<int,Channel> > eventChannels;
 
   /** Method for writing continuous buffers to disk. 
   */ 
-- 
GitLab