diff --git a/Builds/MacOSX/Info.plist b/Builds/MacOSX/Info.plist
index 25959993283eb88d77a46324443c1cbc31b36903..e8a1d27140c165b8ba10b5f944eb2733ca0802cc 100644
--- a/Builds/MacOSX/Info.plist
+++ b/Builds/MacOSX/Info.plist
@@ -16,9 +16,9 @@
     <key>CFBundleSignature</key>
     <string>????</string>
     <key>CFBundleShortVersionString</key>
-    <string>0.2.0</string>
+    <string>0.2.1</string>
     <key>CFBundleVersion</key>
-    <string>0.2.0</string>
+    <string>0.2.1</string>
     <key>NSHumanReadableCopyright</key>
     <string>Open Ephys</string>
     <key>NSHighResolutionCapable</key>
diff --git a/Builds/VisualStudio2012/resources.rc b/Builds/VisualStudio2012/resources.rc
index bae929af05e4f9d9aeaab11977a4d57a46bad77c..94a64eb848ba3d9e2a42710def803813233b2c33 100644
--- a/Builds/VisualStudio2012/resources.rc
+++ b/Builds/VisualStudio2012/resources.rc
@@ -7,7 +7,7 @@
 #include <windows.h>
 
 VS_VERSION_INFO VERSIONINFO
-FILEVERSION  0,2,0,0
+FILEVERSION  0,2,1,0
 BEGIN
   BLOCK "StringFileInfo"
   BEGIN
@@ -15,9 +15,9 @@ BEGIN
     BEGIN
       VALUE "CompanyName",  "Open Ephys\0"
       VALUE "FileDescription",  "open-ephys\0"
-      VALUE "FileVersion",  "0.2.0\0"
+      VALUE "FileVersion",  "0.2.1\0"
       VALUE "ProductName",  "open-ephys\0"
-      VALUE "ProductVersion",  "0.2.0\0"
+      VALUE "ProductVersion",  "0.2.1\0"
     END
   END
 
diff --git a/JuceLibraryCode/JuceHeader.h b/JuceLibraryCode/JuceHeader.h
index 127ae06a183bc6db1e9b5679aff2d489eaf8c2b1..c740f3b377a8936d6c09a08fef1fd0a5c84fb9ff 100644
--- a/JuceLibraryCode/JuceHeader.h
+++ b/JuceLibraryCode/JuceHeader.h
@@ -39,8 +39,8 @@
 namespace ProjectInfo
 {
     const char* const  projectName    = "open-ephys";
-    const char* const  versionString  = "0.2.0";
-    const int          versionNumber  = 0x200;
+    const char* const  versionString  = "0.2.1";
+    const int          versionNumber  = 0x201;
 }
 
 #endif   // __APPHEADERFILE_YNSYIRR__
diff --git a/Source/Processors/Channel.cpp b/Source/Processors/Channel.cpp
index 3232d64137f6f62afa478fc46aaea783c91a5de6..d94ff8451c962947754bfa3fadcbd6d875af7b34 100644
--- a/Source/Processors/Channel.cpp
+++ b/Source/Processors/Channel.cpp
@@ -24,7 +24,7 @@
 #include "Channel.h"
 
 
-Channel::Channel(GenericProcessor* p, int n) : num(n), eventType(0), processor(p), sampleRate(44100.0), bitVolts(1.0f), isEventChannel(false), isMonitored(false), isEnabled(true), isRecording(false)
+Channel::Channel(GenericProcessor* p, int n) : num(n), eventType(0), processor(p), sampleRate(44100.0), bitVolts(1.0f), isADCchannel(false),isEventChannel(false), isMonitored(false), isEnabled(true), isRecording(false)
     
 {
     nodeId = p->getNodeId();
@@ -38,6 +38,7 @@ Channel::Channel(const Channel& ch)
     isEventChannel = ch.isEventChannel;
     isEnabled = ch.isEnabled;
     isMonitored = false;
+	isADCchannel = ch.isADCchannel;
     sampleRate = ch.sampleRate;
     bitVolts = ch.bitVolts;
     name = ch.name;
diff --git a/Source/Processors/Channel.h b/Source/Processors/Channel.h
index 99925a80045ede2057b885276a08b499c588f65b..8ec61b722fdacea5381c6a5e0bf637920a23eca3 100644
--- a/Source/Processors/Channel.h
+++ b/Source/Processors/Channel.h
@@ -94,7 +94,7 @@ public:
     
     // boolean values:
     bool isEventChannel;
-    
+    bool isADCchannel;
     bool isMonitored;
     bool isEnabled;
 
diff --git a/Source/Processors/Editors/GenericEditor.cpp b/Source/Processors/Editors/GenericEditor.cpp
index ec60676fed01784edb3f8efb89b943f2146ab9ca..a06d7330e092510193b084879c8d1e4b7ca38431 100755
--- a/Source/Processors/Editors/GenericEditor.cpp
+++ b/Source/Processors/Editors/GenericEditor.cpp
@@ -33,11 +33,14 @@
 
 #include <math.h>
 
+#ifndef M_PI
+#define M_PI 3.14159265359
+#endif 
 GenericEditor::GenericEditor(GenericProcessor* owner, bool useDefaultParameterEditors=true)
     : AudioProcessorEditor(owner),
       desiredWidth(150), isFading(false), accumulator(0.0), acquisitionIsActive(false),
-      drawerButton(0), channelSelector(0),
-      isSelected(false),  isEnabled(true), tNum(-1)
+      drawerButton(0), channelSelector(0),drawerWidth(170),
+      isSelected(false),  isEnabled(true), isCollapsed(false), tNum(-1), drawerOpen(false)
 {
     constructorInitialize(owner, useDefaultParameterEditors);
 }
@@ -109,6 +112,12 @@ void GenericEditor::constructorInitialize(GenericProcessor* owner, bool useDefau
 
 }
 
+void GenericEditor::updateName()
+{
+    nodeId = getProcessor()->getNodeId();
+    repaint();
+}
+
 void GenericEditor::addParameterEditors(bool useDefaultParameterEditors=true)
 {
     if (useDefaultParameterEditors)
@@ -170,11 +179,14 @@ void GenericEditor::refreshColors()
 
 void GenericEditor::resized()
 {
-    if (drawerButton != 0)
-        drawerButton->setBounds(getWidth()-14, 40, 10, getHeight()-60);
+    if (!isCollapsed)
+    {
+        if (drawerButton != 0)
+            drawerButton->setBounds(getWidth()-14, 40, 10, getHeight()-60);
 
-    if (channelSelector != 0)
-        channelSelector->setBounds(desiredWidth - drawerWidth, 30, channelSelector->getDesiredWidth(), getHeight()-45);
+        if (channelSelector != 0)
+            channelSelector->setBounds(desiredWidth - drawerWidth, 30, channelSelector->getDesiredWidth(), getHeight()-45);
+    }
 }
 
 
@@ -256,7 +268,7 @@ void GenericEditor::setEnabledState(bool t)
 void GenericEditor::startAcquisition()
 {
 
-    std::cout << "GenericEditor received message to start acquisition." << std::endl;
+    //std::cout << "GenericEditor received message to start acquisition." << std::endl;
 
     if (channelSelector != 0)
         channelSelector->startAcquisition();
@@ -306,11 +318,17 @@ void GenericEditor::paint(Graphics& g)
         g.setColour(Colours::lightgrey);
 
     // draw colored background
-    g.fillRect(1,1,getWidth()-(2+offset),getHeight()-2);
-
-    // draw gray workspace
-    g.setGradientFill(backgroundGradient);
-    g.fillRect(1,22,getWidth()-2, getHeight()-29);
+    if (!isCollapsed)
+    {
+        g.fillRect(1,1,getWidth()-(2+offset),getHeight()-2);
+        // draw gray workspace
+        g.setGradientFill(backgroundGradient);
+        g.fillRect(1,22,getWidth()-2, getHeight()-29);
+    }
+    else
+    {
+        g.fillAll();
+    }
 
     g.setFont(titleFont);
     g.setFont(14);
@@ -325,8 +343,18 @@ void GenericEditor::paint(Graphics& g)
     }
 
     // draw title
-    g.drawText(name, 6, 5, 500, 15, Justification::left, false);
+    if (!isCollapsed)
+    {
+        if (!getProcessor()->isMerger() && !getProcessor()->isSplitter())
+            g.drawText(name+" ("+String(nodeId)+")", 6, 5, 500, 15, Justification::left, false);
+        else
+            g.drawText(name, 6, 5, 500, 15, Justification::left, false);
 
+    } else {
+        g.addTransform(AffineTransform::rotation(-M_PI/2.0));
+        g.drawText(name, -getHeight()+6, 5, 500, 15, Justification::left, false);
+        g.addTransform(AffineTransform::rotation(M_PI/2.0));
+    }
 
     if (isSelected)
     {
@@ -389,6 +417,7 @@ bool GenericEditor::checkDrawerButton(Button* button)
             drawerWidth = channelSelector->getDesiredWidth() + 20;
 
             desiredWidth += drawerWidth;
+            drawerOpen = true;
 
         }
         else
@@ -397,6 +426,7 @@ bool GenericEditor::checkDrawerButton(Button* button)
             channelSelector->setVisible(false);
 
             desiredWidth -= drawerWidth;
+            drawerOpen = false;
         }
 
         getEditorViewport()->makeEditorVisible(this);
@@ -532,17 +562,67 @@ void GenericEditor::setChannelSelectionState(int chan, bool p, bool r, bool a)
     }
 }
 
+bool GenericEditor::getCollapsedState()
+{
+    return isCollapsed;
+}
+
+void GenericEditor::switchCollapsedState()
+{
+
+    if (!getProcessor()->isMerger() && !getProcessor()->isSplitter())
+    {
+
+        if (isCollapsed)
+        {
+            // open it up
+            desiredWidth = originalWidth;
+            isCollapsed = false;
+
+        } else {
+            originalWidth = desiredWidth;
+            desiredWidth = 25;
+            isCollapsed = true;
+        }
+
+        for (int i = 0; i < getNumChildComponents(); i++)
+        {
+            Component* c = getChildComponent(i);
+            c->setVisible(!isCollapsed);
+        }
+
+        if (channelSelector != nullptr)
+        {
+            if (!drawerOpen)
+                channelSelector->setVisible(false);
+        }
+
+        collapsedStateChanged();
+
+        getEditorViewport()->refreshEditors();
+    }
+}
+
 void GenericEditor::saveEditorParameters(XmlElement* xml)
 {
 
-    //xml->setAttribute("Attribute", "WHAT");
+    xml->setAttribute("isCollapsed", isCollapsed);
+
+    saveCustomParameters(xml);
 
 }
 
 void GenericEditor::loadEditorParameters(XmlElement* xml)
 {
 
-    //xml->setAttribute("Attribute", "WHAT");
+    bool isCollapsed = xml->getBoolAttribute("isCollapsed", false);
+
+    if (isCollapsed)
+    {
+        switchCollapsedState();
+    }
+
+    loadCustomParameters(xml);
 
 }
 
@@ -796,6 +876,11 @@ void UtilityButton::resized()
 
 }
 
+String UtilityButton::getLabel()
+{
+	return label;
+}
+
 void UtilityButton::setLabel(String label_)
 {
     label = label_;
diff --git a/Source/Processors/Editors/GenericEditor.h b/Source/Processors/Editors/GenericEditor.h
index 105436eb89cf1974938881e2ae8a3011a5c28637..18a459a4b93b383ec5477220acfd24414526a840 100755
--- a/Source/Processors/Editors/GenericEditor.h
+++ b/Source/Processors/Editors/GenericEditor.h
@@ -120,6 +120,9 @@ public:
         return name;
     }
 
+    /** Updates name if processor ID changes. */
+    void updateName();
+
     /** Determines how wide the editor will be drawn. */
     int desiredWidth;
 
@@ -247,14 +250,29 @@ public:
     void setChannelSelectionState(int chan, bool p, bool r, bool a);
 
     /** Writes editor state to xml */
-    virtual void saveEditorParameters(XmlElement* xml);
+    void saveEditorParameters(XmlElement* xml);
+
+    /** Writes editor state to xml */
+    void loadEditorParameters(XmlElement* xml);
 
     /** Writes editor state to xml */
-    virtual void loadEditorParameters(XmlElement* xml);
+    virtual void saveCustomParameters(XmlElement* xml) { }
+
+    /** Writes editor state to xml */
+    virtual void loadCustomParameters(XmlElement* xml) { }
 
     /** Syncs parametereditor colors with parameter values */
     void updateParameterButtons(int parameterIndex = -1);
-    
+
+    /** Checks to see whether or not an editor is collapsed */
+    bool getCollapsedState();
+
+    /**  Collapses an editor if it's open, and opens it if it's collpased*/
+    void switchCollapsedState();
+
+     /**  Notifies the editor that the collapsed state changed, for non-standard function. */
+    virtual void collapsedStateChanged() {}
+
     /** Returns the editor of this processor's source */
     GenericEditor* getSourceEditor();
     
@@ -262,7 +280,7 @@ public:
     GenericEditor* getDestEditor();
 
     /** Returns the editors a splitter or merger is connected to */
-    virtual Array<GenericEditor*> getConnectedEditors() { }
+	virtual Array<GenericEditor*> getConnectedEditors(){ Array<GenericEditor*> a; return a;}
     
 protected:
 
@@ -272,6 +290,9 @@ protected:
     /** Determines the width of the ChannelSelector drawer when opened. */
     int drawerWidth;
 
+    /** Saves the open/closed state of the ChannelSelector drawer. */
+    bool drawerOpen;
+
 
     /** Can be overridden to customize the layout of ParameterEditors. */
     //Ideally this would be virtual, but since it's run in the construct and because virtual functions don't get overriden in the constructor, it's not.
@@ -299,11 +320,13 @@ private:
 
     bool isSelected;
     bool isEnabled;
+    bool isCollapsed;
 
     /**Used to determine if an editor is a splitter or Merger to avoid calling on CHannelSelector*/
     bool isSplitOrMerge;
 
     int tNum;
+    int originalWidth;
 
     /**initializing function Used to share constructor functions*/
     void constructorInitialize(GenericProcessor* owner, bool useDefaultParameterEditors);
@@ -382,6 +405,7 @@ public:
     }
 
     void setLabel(String label);
+	String getLabel();
 
 private:
     void paintButton(Graphics& g, bool isMouseOver, bool isButtonDown);
diff --git a/Source/Processors/Editors/MergerEditor.cpp b/Source/Processors/Editors/MergerEditor.cpp
index bcfcd905d7d1ecf7726a599c6d5f6d8e87ca9675..c56fbcbe5b0186acc20fe2d2163c2b2476ca97f1 100755
--- a/Source/Processors/Editors/MergerEditor.cpp
+++ b/Source/Processors/Editors/MergerEditor.cpp
@@ -57,7 +57,7 @@ MergerEditor::MergerEditor(GenericProcessor* parentNode, bool useDefaultParamete
     : GenericEditor(parentNode, useDefaultParameterEditors)
 
 {
-    desiredWidth = 90;
+    desiredWidth = 85;
 
     pipelineSelectorA = new ImageButton("Pipeline A");
 
@@ -114,6 +114,8 @@ void MergerEditor::buttonEvent(Button* button)
         processor->switchIO(1);
 
     }
+
+    getEditorViewport()->makeEditorVisible(this, false);
 }
 
 void MergerEditor::mouseDown(const MouseEvent& e)
@@ -158,6 +160,8 @@ void MergerEditor::mouseDown(const MouseEvent& e)
             processor->setMergerSourceNode(availableProcessors[result-2]);
             availableProcessors[result-2]->setDestNode(getProcessor());
 
+            getGraphViewer()->updateNodeLocations();
+
             getEditorViewport()->makeEditorVisible(this, false, true);
         }
     }
@@ -186,6 +190,27 @@ void MergerEditor::switchSource(int source)
     }
 }
 
+Array<GenericEditor*> MergerEditor::getConnectedEditors()
+{
+
+    Array<GenericEditor*> editors;
+
+    Merger* processor = (Merger*) getProcessor();
+    
+    for (int pathNum = 0; pathNum < 2; pathNum++)
+    {
+        processor->switchIO();
+
+        if (processor->getSourceNode() != nullptr)
+            editors.add(processor->getSourceNode()->getEditor());
+        else
+            editors.add(nullptr);
+    }
+    
+    return editors;
+
+}
+
 int MergerEditor::getPathForEditor(GenericEditor* editor)
 {
     Merger* processor = (Merger*) getProcessor();
diff --git a/Source/Processors/Editors/MergerEditor.h b/Source/Processors/Editors/MergerEditor.h
index edcf05efe7d9e25b5c90b88088e3d211b6eb84b6..654889677b2cde4e0a8293dff1a53ca115673035 100755
--- a/Source/Processors/Editors/MergerEditor.h
+++ b/Source/Processors/Editors/MergerEditor.h
@@ -54,6 +54,8 @@ public:
     
     int getPathForEditor(GenericEditor* editor);
 
+    Array<GenericEditor*> getConnectedEditors();
+
 private:
 
     ImageButton* pipelineSelectorA;
diff --git a/Source/Processors/Editors/SplitterEditor.cpp b/Source/Processors/Editors/SplitterEditor.cpp
index 1e360b7b8fcbb88c83ec158286ec5ad8ca3202a9..1d750f4f556291139a6c59ca2479c08f064c9648 100755
--- a/Source/Processors/Editors/SplitterEditor.cpp
+++ b/Source/Processors/Editors/SplitterEditor.cpp
@@ -23,6 +23,7 @@
 
 #include "SplitterEditor.h"
 #include "../Utilities/Splitter.h"
+#include "../../UI/EditorViewport.h"
 
 // PipelineSelectorButton::PipelineSelectorButton()
 // 	: DrawableButton ("Selector", DrawableButton::ImageFitted)
@@ -55,7 +56,7 @@ SplitterEditor::SplitterEditor(GenericProcessor* parentNode, bool useDefaultPara
     : GenericEditor(parentNode, useDefaultParameterEditors)
 
 {
-    desiredWidth = 90;
+    desiredWidth = 85;
 
     pipelineSelectorA = new ImageButton("Pipeline A");
 
@@ -103,6 +104,8 @@ void SplitterEditor::buttonEvent(Button* button)
         Splitter* processor = (Splitter*) getProcessor();
         processor->switchIO(0);
 
+        getEditorViewport()->makeEditorVisible(this, false);
+
     }
     else if (button == pipelineSelectorB)
     {
@@ -111,6 +114,8 @@ void SplitterEditor::buttonEvent(Button* button)
         Splitter* processor = (Splitter*) getProcessor();
         processor->switchIO(1);
 
+        getEditorViewport()->makeEditorVisible(this, false);
+
     }
 }
 
@@ -132,6 +137,8 @@ void SplitterEditor::switchDest(int dest)
         processor->switchIO(1);
 
     }
+
+    getEditorViewport()->makeEditorVisible(this, false);
 }
 
 void SplitterEditor::switchIO(int dest)
diff --git a/Source/Processors/GenericProcessor.cpp b/Source/Processors/GenericProcessor.cpp
index c4689864b2e1fef09009ae1e648dff9e04c5f847..ef13adae827d755952ce585bb32e6fd9d36ded7f 100755
--- a/Source/Processors/GenericProcessor.cpp
+++ b/Source/Processors/GenericProcessor.cpp
@@ -27,8 +27,9 @@
 GenericProcessor::GenericProcessor(const String& name_) : AccessClass(),
     sourceNode(0), destNode(0), isEnabled(true), wasConnected(false),
     nextAvailableChannel(0), saveOrder(-1), loadOrder(-1), currentChannel(-1),
-     parametersAsXml(nullptr),  name(name_), paramsWereLoaded(false)
+     parametersAsXml(nullptr),  name(name_), paramsWereLoaded(false), editor(0), sendSampleCount(true)
 {
+	  settings.numInputs = settings.numOutputs = settings.sampleRate = 0;
 }
 
 GenericProcessor::~GenericProcessor()
@@ -41,6 +42,17 @@ AudioProcessorEditor* GenericProcessor::createEditor()
     return editor;
 }
 
+void GenericProcessor::setNodeId(int id)
+{
+    nodeId = id;
+
+    if (editor != 0)
+    {
+        editor->updateName();
+    }
+
+}
+
 Parameter& GenericProcessor::getParameterByName(String name_)
 {
     // doesn't work
@@ -277,6 +289,14 @@ void GenericProcessor::update()
 {
 
     std::cout << getName() << " updating settings." << std::endl;
+	// SO patched here to keep original channel names
+
+	int oldNumChannels = channels.size();
+	StringArray oldNames;
+	for (int k = 0; k < oldNumChannels; k++)
+	{
+		oldNames.add(channels[k]->getName());
+	}
 
     clearSettings();
 
@@ -314,15 +334,33 @@ void GenericProcessor::update()
     }
     else
     {
-
         settings.numOutputs = getDefaultNumOutputs();
         settings.sampleRate = getDefaultSampleRate();
-
-        for (int i = 0; i < getNumOutputs(); i++)
+		
+		int numChan = getNumOutputs();
+		int numADC_Chan = getDefaultADCoutputs();
+        for (int i = 0; i < numChan; i++)
         {
-            Channel* ch = new Channel(this, i);
+            Channel* ch = new Channel(this, i );
+
+			// if (i < oldNumChannels)
+			// 	ch->setName(oldNames[i]);
+			//else if (i >= numChan-numADC_Chan) 
+			//	ch->setName("ADC"+String(1+i-(numChan-numADC_Chan)));
+
+            if (i >= numChan-numADC_Chan) 
+              ch->setName("ADC"+String(1+i-(numChan-numADC_Chan)));
+
+            if (i >= numChan-numADC_Chan)
+              ch->isADCchannel = true;
+            
+
             ch->sampleRate = getDefaultSampleRate();
-            ch->bitVolts = getDefaultBitVolts();
+
+          //  if (ch->isADCchannel)
+                ch->bitVolts = getDefaultBitVolts();
+          //  else
+          //      ch->bitVolts = getDefaultAdcBitVolts(); // should implement this
 
              if (i < recordStatus.size())
             {
@@ -383,7 +421,9 @@ int GenericProcessor::getNumSamples(MidiBuffer& events)
     // the sample rate to change at different points in the signal chain.
     //
 
-    int numRead = 0;
+    int numRead = 0; 
+
+    //int numRead = 0;
 
     if (events.getNumEvents() > 0)
     {
@@ -396,17 +436,22 @@ int GenericProcessor::getNumSamples(MidiBuffer& events)
         const uint8* dataptr;
         int dataSize;
 
-        int samplePosition = -5;
+        int samplePosition = -1;
 
         while (i.getNextEvent(dataptr, dataSize, samplePosition))
         {
 
-            if (*dataptr == BUFFER_SIZE)
-            {
+             if (*dataptr == BUFFER_SIZE)
+             {
                 
-                numRead = samplePosition;
+                int16 nr;
+                memcpy(&nr, dataptr+2, 2);
 
-            } else if (*dataptr == TTL &&    // a TTL event
+                 numRead = nr;
+
+             } else 
+
+            if (*dataptr == TTL &&    // a TTL event
                         getNodeId() < 900 && // not handled by a specialized processor (e.g. AudioNode))
                         *(dataptr+1) > 0)    // that's flagged for saving
             {
@@ -435,14 +480,19 @@ void GenericProcessor::setNumSamples(MidiBuffer& events, int sampleIndex)
     // immediate source.
     //
 
-    uint8 data[2];
+    uint8 data[4];
+
+    int16 si = (int16) sampleIndex;
 
     data[0] = BUFFER_SIZE;  // most-significant byte
     data[1] = nodeId;       // least-significant byte
+    memcpy(data+2, &si, 2);
 
     events.addEvent(data,       // spike data
-                    2,          // total bytes
-                    sampleIndex); // sample index
+                    4,          // total bytes
+                    0); // sample index
+
+   // std::cout << "Processor " << getNodeId() << " adding a new sample count of " << sampleIndex << std::endl;
 
 }
 
@@ -517,7 +567,8 @@ void GenericProcessor::processBlock(AudioSampleBuffer& buffer, MidiBuffer& event
 
     process(buffer, eventBuffer, nSamples);
 
-    setNumSamples(eventBuffer, nSamples); // adds it back,
+    if (sendSampleCount)
+        setNumSamples(eventBuffer, nSamples); // adds it back,
     // even if it's unchanged
 
 }
@@ -631,6 +682,8 @@ void GenericProcessor::saveCustomChannelParametersToXml(XmlElement* channelInfo,
 void GenericProcessor::loadFromXml()
 {
 
+    update(); // make sure settings are updated
+
     std::cout << "Loading parameters for " << name << std::endl;
 
     if (!paramsWereLoaded)
@@ -641,6 +694,17 @@ void GenericProcessor::loadFromXml()
             // use parametersAsXml to restore state
             loadCustomParametersFromXml();
 
+            // load editor parameters
+            forEachXmlChildElement(*parametersAsXml, xmlNode)
+            {
+
+                if (xmlNode->hasTagName("EDITOR"))
+                {
+                    getEditor()->loadEditorParameters(xmlNode);
+                }
+
+            }
+
             forEachXmlChildElement(*parametersAsXml, xmlNode)
             {
                 if (xmlNode->hasTagName("CHANNEL"))
@@ -654,10 +718,6 @@ void GenericProcessor::loadFromXml()
                     loadChannelParametersFromXml(xmlNode, true);
 
                 }
-                else if (xmlNode->hasTagName("EDITOR"))
-                {
-                    getEditor()->loadEditorParameters(xmlNode);
-                }
 
             }
         }
diff --git a/Source/Processors/GenericProcessor.h b/Source/Processors/GenericProcessor.h
index edec0be3d2f9e9616134cf12947449c5d251ffcc..7db4f07c393923f724699aabd9c7527257c59027 100755
--- a/Source/Processors/GenericProcessor.h
+++ b/Source/Processors/GenericProcessor.h
@@ -277,6 +277,11 @@ public:
         return 2;
     }
 
+	  virtual int getDefaultADCoutputs()
+    {
+        return 0;
+    }
+
     /** Returns the default number of volts per bit, in case a processor is a source, of the processor gain otherwise. (assumes data comes from a 16bit source)*/
     virtual float getDefaultBitVolts()
     {
@@ -302,10 +307,7 @@ public:
     }
 
     /** Sets the unique integer ID for a processor. */
-    void setNodeId(int id)
-    {
-        nodeId = id;
-    }
+    void setNodeId(int id);
 
     /** Returns a pointer to the processor immediately preceding a given processor in the signal chain. */
     GenericProcessor* getSourceNode()
@@ -473,12 +475,14 @@ public:
         SPIKE = 4,
         EEG = 5,
         CONTINUOUS = 6,
-        SERIAL = 7
+		NETWORK = 7,
+		EYE_POSITION = 8,
+        SERIAL = 9
     };
 
     enum eventChannelTypes
     {
-        GENERIC_EVENT = 999,
+        GENERIC_EVENT = 100,
         SINGLE_ELECTRODE = 1,
         STEREOTRODE = 2,
         TETRODE = 4
@@ -577,9 +581,15 @@ public:
     /** Load custom parameters for each channel. */
     virtual void loadCustomChannelParametersFromXml(XmlElement* channelElement, bool isEventChannel=false);
 
+	/** handle messages from other processors */
+	virtual String interProcessorCommunication(String command) { return String("OK"); };
+
     /** Holds loaded parameters */
     XmlElement* parametersAsXml;
 
+    /** When set to false, this disables the sending of sample counts through the event buffer. */
+    bool sendSampleCount;
+
 private:
 
     /** Automatically extracts the number of samples in the buffer, then
@@ -605,6 +615,7 @@ private:
 
     bool paramsWereLoaded;
 
+
     JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(GenericProcessor);
 
 };
diff --git a/Source/Processors/Utilities/Merger.cpp b/Source/Processors/Utilities/Merger.cpp
index b51b8fb2d663c8773cb0923620a5c95de0887033..2bf958eceb2290a93ac323e13c8b8cab56a12a3f 100755
--- a/Source/Processors/Utilities/Merger.cpp
+++ b/Source/Processors/Utilities/Merger.cpp
@@ -32,7 +32,7 @@ Merger::Merger()
     : GenericProcessor("Merger"),
       sourceNodeA(0), sourceNodeB(0), activePath(0)//, tabA(-1), tabB(-1)
 {
-
+    sendSampleCount = false;
 }
 
 Merger::~Merger()
@@ -64,6 +64,11 @@ void Merger::setMergerSourceNode(GenericProcessor* sn)
         sourceNodeB = sn;
         std::cout << "Setting source node B." << std::endl;
     }
+
+    if (sn != nullptr)
+    {
+        sn->setDestNode(this);
+    }
 }
 
 void Merger::switchIO(int sourceNum)
@@ -84,7 +89,7 @@ void Merger::switchIO(int sourceNum)
         //std::cout << "Source node: " << getSourceNode() << std::endl;
     }
 
-    getEditorViewport()->makeEditorVisible((GenericEditor*) getEditor(), false);
+   // getEditorViewport()->makeEditorVisible((GenericEditor*) getEditor(), false);
 
 }
 
@@ -191,6 +196,60 @@ void Merger::updateSettings()
 
 }
 
+void Merger::saveCustomParametersToXml(XmlElement* parentElement)
+{
+    XmlElement* mainNode = parentElement->createNewChildElement("MERGER");
+	if (sourceNodeA!= nullptr)
+		mainNode->setAttribute("NodeA",	sourceNodeA->getNodeId());
+	else
+		mainNode->setAttribute("NodeA",	-1);
+
+	if (sourceNodeB != nullptr)
+		mainNode->setAttribute("NodeB",	sourceNodeB->getNodeId());
+	else
+		mainNode->setAttribute("NodeB",	-1);
+}
+
+
+void Merger::loadCustomParametersFromXml()
+{
+	if (1)
+	{
+	if (parametersAsXml != nullptr)
+	{
+		forEachXmlChildElement(*parametersAsXml, mainNode)
+		{
+			if (mainNode->hasTagName("MERGER"))
+			{
+				int NodeAid = mainNode->getIntAttribute("NodeA");
+				int NodeBid = mainNode->getIntAttribute("NodeB");
+
+				ProcessorGraph *gr = getProcessorGraph();
+				Array<GenericProcessor*> p = gr->getListOfProcessors();
+				
+                for (int k = 0; k < p.size(); k++)
+				{
+					if (p[k]->getNodeId() == NodeAid)
+                    {
+                        std::cout << "Setting Merger source A to " << NodeAid << std::endl;
+                        switchIO(0);
+						setMergerSourceNode(p[k]);
+					}
+                    if (p[k]->getNodeId() == NodeBid)
+                    {
+                        std::cout << "Setting Merger source B to " << NodeBid << std::endl;
+						switchIO(1);
+                        setMergerSourceNode(p[k]);
+				    }
+                }
+				
+                updateSettings();
+			}
+		}
+	}
+}
+}
+
 // void Merger::setNumOutputs(int /*outputs*/)
 // {
 // 	numOutputs = 0;
diff --git a/Source/Processors/Utilities/Merger.h b/Source/Processors/Utilities/Merger.h
index 069b2da50e79d9da174a76f87f29355c3cfcf02b..9f0ccd674aedea2782738b72122f243bc7d26c14 100755
--- a/Source/Processors/Utilities/Merger.h
+++ b/Source/Processors/Utilities/Merger.h
@@ -67,6 +67,9 @@ public:
     void addSettingsFromSourceNode(GenericProcessor* sn);
 
     bool stillHasSource();
+	
+	void saveCustomParametersToXml(XmlElement* parentElement);
+	void loadCustomParametersFromXml();
 
 private:
 
diff --git a/Source/Processors/Utilities/Splitter.cpp b/Source/Processors/Utilities/Splitter.cpp
index d1854748d8ed5717909bab07587f133058316626..1105d3251222d0f30cf5f0d5b0a92b9e40749321 100755
--- a/Source/Processors/Utilities/Splitter.cpp
+++ b/Source/Processors/Utilities/Splitter.cpp
@@ -30,7 +30,7 @@ Splitter::Splitter()
     : GenericProcessor("Splitter"),
       destNodeA(0), destNodeB(0), activePath(0)
 {
-
+    sendSampleCount = false;
 }
 
 Splitter::~Splitter()
@@ -83,22 +83,22 @@ void Splitter::setSplitterDestNode(GenericProcessor* dn)
 void Splitter::switchIO(int destNum)
 {
 
-    std::cout << "Switching to dest number " << destNum << std::endl;
+    //std::cout << "Switching to dest number " << destNum << std::endl;
 
     activePath = destNum;
 
     if (destNum == 0)
     {
         destNode = destNodeA;
-        std::cout << "Dest node: " << getDestNode() << std::endl;
+       // std::cout << "Dest node: " << getDestNode() << std::endl;
     }
     else
     {
         destNode = destNodeB;
-        std::cout << "Dest node: " << getDestNode() << std::endl;
+       // std::cout << "Dest node: " << getDestNode() << std::endl;
     }
 
-    getEditorViewport()->makeEditorVisible(getEditor(), false);
+   // getEditorViewport()->makeEditorVisible(getEditor(), false);
 
 }
 
diff --git a/Source/UI/ControlPanel.cpp b/Source/UI/ControlPanel.cpp
index d1bc5eac45a0b9fd8749829417958e8225c4a21d..e600b51a430b9944b7d8bd32845a67e2f7d98867 100755
--- a/Source/UI/ControlPanel.cpp
+++ b/Source/UI/ControlPanel.cpp
@@ -759,8 +759,7 @@ void ControlPanel::disableCallbacks()
 void ControlPanel::timerCallback()
 {
     //std::cout << "Message Received." << std::endl;
-
-    refreshMeters();
+   refreshMeters();
 
 }
 
@@ -869,4 +868,16 @@ void ControlPanel::loadStateFromXml(XmlElement* xml)
     
     getProcessorGraph()->getAudioNode()->updateBufferSize();
 
+}
+
+
+StringArray ControlPanel::getRecentlyUsedFilenames()
+{
+    return filenameComponent->getRecentlyUsedFilenames();
+}
+
+
+void ControlPanel::setRecentlyUsedFilenames(const StringArray& filenames)
+{
+    filenameComponent->setRecentlyUsedFilenames(filenames);
 }
\ No newline at end of file
diff --git a/Source/UI/ControlPanel.h b/Source/UI/ControlPanel.h
index 2b106f3f75c5e1cf17d2d080b31dad8d0cf820df..86f24bf221ac0e7a352970a33678cd68d01cb618 100755
--- a/Source/UI/ControlPanel.h
+++ b/Source/UI/ControlPanel.h
@@ -32,8 +32,7 @@
 #include "CustomLookAndFeel.h"
 #include "../AccessClass.h"
 #include "../Processors/Editors/GenericEditor.h" // for UtilityButton
-#include "../Processors/Visualization/OpenGLCanvas.h"
-
+#include <queue>
 
 /**
 
@@ -303,7 +302,6 @@ public:
 
     /** Used to manually turn recording on and off.*/
     void setRecordState(bool isRecording);
-
     /** Returns a boolean that indicates whether or not the FilenameComponet
         is visible. */
     bool isOpen()
@@ -328,10 +326,25 @@ public:
 
     /** Load settings. */
     void loadStateFromXml(XmlElement*);
+    
+	void handleIncomdingMessages();
+
+		/** Informs the Control Panel that recording has begun.*/
+    void startRecording();
+    
+    /** Informs the Control Panel that recording has stopped.*/
+    void stopRecording();
+
+    /** Returns a list of recently used directories for saving data. */
+    StringArray getRecentlyUsedFilenames();
 
+    /** Sets the list of recently used directories for saving data. */
+    void setRecentlyUsedFilenames(const StringArray& filenames);
+
+	ScopedPointer<RecordButton> recordButton;
 private:
     ScopedPointer<PlayButton> playButton;
-    ScopedPointer<RecordButton> recordButton;
+    
     ScopedPointer<Clock> masterClock;
     ScopedPointer<CPUMeter> cpuMeter;
     ScopedPointer<DiskSpaceMeter> diskMeter;
@@ -352,12 +365,6 @@ private:
     void resized();
 
     void buttonClicked(Button* button);
-    
-    /** Informs the Control Panel that recording has begun.*/
-    void startRecording();
-    
-    /** Informs the Control Panel that recording has stopped.*/
-    void stopRecording();
 
     bool initialize;
 
@@ -372,6 +379,7 @@ private:
 
     bool keyPressed(const KeyPress& key);
 
+
     Font font;
 
     bool open;
diff --git a/Source/UI/GraphViewer.cpp b/Source/UI/GraphViewer.cpp
index ca7e52b115c556412e5167a89a68595030d6b1c1..fc3da28cd64776e3134a254e2f4f9fef5b65f447 100644
--- a/Source/UI/GraphViewer.cpp
+++ b/Source/UI/GraphViewer.cpp
@@ -27,7 +27,7 @@ GraphViewer::GraphViewer()
 {
     
     labelFont = Font("Paragraph", 50, Font::plain);
-    
+    rootNum = 0;
 }
 
 GraphViewer::~GraphViewer()
@@ -41,7 +41,7 @@ void GraphViewer::addNode(GenericEditor* editor)
     GraphNode* gn = new GraphNode(editor, this);
     addAndMakeVisible(gn);
     availableNodes.add(gn);
-    
+    gn->setBounds(20, 20, 150, 50);
     updateNodeLocations();
     
 }
@@ -69,40 +69,98 @@ void GraphViewer::updateNodeLocations()
     // set the initial locations
     for (int i = 0; i < availableNodes.size(); i++)
     {
-        availableNodes[i]->updateBoundaries();
+
     }
-    
-    // perform checks
-    //checkLayout(); // not helpful...yet
-    
+
+    rootNum = 0;
+
+    // do initial layout
+    for (int i = 0; i < availableNodes.size(); i++)
+    {
+        checkLayout(availableNodes[i]);
+    }
+
+    // check for overlap
+    for (int i = 0; i < availableNodes.size(); i++)
+    {
+        for (int j = 0; j < availableNodes.size(); j++)
+        {
+            if (j != i)
+            {
+                if (availableNodes[j]->getLevel() == availableNodes[i]->getLevel() &&
+                    availableNodes[j]->getHorzShift() == availableNodes[i]->getHorzShift())
+                {
+                    availableNodes[j]->setHorzShift(availableNodes[j]->getHorzShift()+1);
+                }
+            }
+        }
+    }
+
     repaint();
 }
 
-void GraphViewer::checkLayout()
+void GraphViewer::checkLayout(GraphNode* gn)
 {
-    
-    for (int i = 0; i < availableNodes.size(); i++)
+ 
+    if (gn != nullptr)
     {
-        int sourceIndex = indexOfEditor(availableNodes[i]->getSource());
-        
-        if (sourceIndex > -1)
+
+        GraphNode* sourceNode;
+
+        if (gn->isMerger())
         {
-            if (availableNodes[i]->getHorzShift() < availableNodes[sourceIndex]->getHorzShift())
+            Array<GenericEditor*> editors = gn->getConnectedEditors();
+
+            int level1 = 0;
+            int level2 = 0;
+
+            if (editors[0] != nullptr)
+            {
+                level1 = getNodeForEditor(editors[0])->getLevel();
+            }
+
+            if (editors[1] != nullptr)
             {
-                availableNodes[i]->setHorzShift(availableNodes[sourceIndex]->getHorzShift());
+                level2 = getNodeForEditor(editors[1])->getLevel();
             }
+
+           // std::cout << "LEVEL1 = " << level1 << " LEVEL2 = " << level2 << std::endl;
+
+            sourceNode = level1 > level2 ? getNodeForEditor(editors[0]) : 
+                                           getNodeForEditor(editors[1]); // choose the higher source
+
+        } else {
+            sourceNode = getNodeForEditor(gn->getSource());
         }
-        
-        int destIndex = indexOfEditor(availableNodes[i]->getDest());
-        
-        if (destIndex > -1)
+
+        if (sourceNode == nullptr)
         {
-            if (availableNodes[i]->getLevel() > availableNodes[destIndex]->getLevel())
+            gn->setLevel(0);
+            gn->setHorzShift(rootNum);
+            rootNum++;
+        } else if (sourceNode->isSplitter()) 
+        {
+            Array<GenericEditor*> editors = sourceNode->getConnectedEditors();
+
+            if (gn->hasEditor(editors[1]))
             {
-                availableNodes[destIndex]->setLevel(availableNodes[i]->getLevel()+1);
+                gn->setLevel(sourceNode->getLevel()+1); // increase level
+                gn->setHorzShift(sourceNode->getHorzShift()+1); // increase horz shift
+            } else {
+                 gn->setLevel(sourceNode->getLevel()+1); // increase level
+                gn->setHorzShift(sourceNode->getHorzShift()); // same horz shift
             }
+
+        } else {
+
+            gn->setLevel(sourceNode->getLevel()+1); // increase level
+            gn->setHorzShift(sourceNode->getHorzShift()); // same horz shift
         }
+
+        checkLayout(getNodeForEditor(gn->getDest()));
+
     }
+
 }
 
 int GraphViewer::indexOfEditor(GenericEditor* editor)
@@ -120,6 +178,16 @@ int GraphViewer::indexOfEditor(GenericEditor* editor)
     return index;
 }
 
+GraphNode* GraphViewer::getNodeForEditor(GenericEditor* editor)
+{
+    int index = indexOfEditor(editor);
+
+    if (index > -1)
+        return availableNodes[index];
+    else
+        return nullptr;
+}
+
 int GraphViewer::nodesAtLevel(int level)
 {
 
@@ -240,33 +308,35 @@ GraphNode::~GraphNode()
 
 int GraphNode::getLevel()
 {
-    int level = -1;
+    // int level = -1;
 
-    GenericEditor* ed = editor;
+    // GenericEditor* ed = editor;
 
-    while (ed != nullptr)
-    {
-        level += 1;
-        ed = ed->getSourceEditor();
-    }
+    // while (ed != nullptr)
+    // {
+    //     level += 1;
+    //     ed = ed->getSourceEditor();
+    // }
 
-    return level;
+    return vertShift;
 }
 
 void GraphNode::setLevel(int level)
 {
-    setBounds(getX(), 20+getLevel()*40, getWidth(), getHeight());
+    setBounds(getX(), 20+level*40, getWidth(), getHeight());
     
+    vertShift = level;
 }
 
 int GraphNode::getHorzShift()
 {
-    return gv->getHorizontalShift(this);
+    return horzShift; //gv->getHorizontalShift(this);
 }
 
 void GraphNode::setHorzShift(int shift)
 {
     setBounds(20+shift*140, getY(), getWidth(), getHeight());
+    horzShift = shift;
 }
     
 void GraphNode::mouseEnter(const MouseEvent& m)
diff --git a/Source/UI/GraphViewer.h b/Source/UI/GraphViewer.h
index 1454631b6ee09239622e96ebe599afcdde4a811f..65017ee9068f1406480a0ac6cfdc6976aab88da2 100644
--- a/Source/UI/GraphViewer.h
+++ b/Source/UI/GraphViewer.h
@@ -71,12 +71,16 @@ public:
     void setLevel(int);
     int getHorzShift();
     void setHorzShift(int);
+
+    int horzShift;
+    int vertShift;
     
 private:
 
     GenericEditor* editor;
     
     Font labelFont;
+
     
     bool mouseOver;
 
@@ -97,19 +101,23 @@ public:
     void addNode(GenericEditor* editor);
     void removeNode(GenericEditor* editor);
     void removeAllNodes();
+    void updateNodeLocations();;
 
     int nodesAtLevel(int lvl);
     int getHorizontalShift(GraphNode*);
+    GraphNode* getNodeForEditor(GenericEditor* editor);
 
 private:
 
     void connectNodes(int, int, Graphics&);
-    void checkLayout();
+    void checkLayout(GraphNode*);
+    
     
-    void updateNodeLocations();
     int indexOfEditor(GenericEditor* editor);
     
     Font labelFont;
+
+    int rootNum;
     
     OwnedArray<GraphNode> availableNodes;
     
diff --git a/Source/UI/UIComponent.cpp b/Source/UI/UIComponent.cpp
index abe50fb1ea1ce0cf6caf755434700acbbc186d4f..5811e06494fcc14a2bd1a4aa45a1cddb53498eb2 100755
--- a/Source/UI/UIComponent.cpp
+++ b/Source/UI/UIComponent.cpp
@@ -32,12 +32,11 @@ UIComponent::UIComponent(MainWindow* mainWindow_, ProcessorGraph* pgraph, AudioC
     processorGraph->setUIComponent(this);
 
     infoLabel = new InfoLabel();
+    graphViewer = new GraphViewer();
 
     dataViewport = new DataViewport();
     addChildComponent(dataViewport);
     dataViewport->addTabToDataViewport("Info", infoLabel,0);
-    
-    graphViewer = new GraphViewer();
     dataViewport->addTabToDataViewport("Graph", graphViewer,0);
 
     std::cout << "Created data viewport." << std::endl;
@@ -124,7 +123,7 @@ void UIComponent::resized()
         top = 40;
 
         if (processorList->isOpen())
-            left = 207;
+            left = 202;
         else
             left = 6;
 
@@ -170,9 +169,9 @@ void UIComponent::resized()
     {
         if (processorList->isOpen())
             if (editorViewportButton->isOpen())
-                processorList->setBounds(5,5,200,h-200);
+                processorList->setBounds(5,5,195,h-200);
             else
-                processorList->setBounds(5,5,200,h-50);
+                processorList->setBounds(5,5,195,h-50);
         else
             processorList->setBounds(5,5,195,34);
     }
@@ -504,6 +503,16 @@ void UIComponent::loadStateFromXml(XmlElement* xml)
     }
 }
 
+StringArray UIComponent::getRecentlyUsedFilenames()
+{
+    return controlPanel->getRecentlyUsedFilenames();
+}
+
+void UIComponent::setRecentlyUsedFilenames(const StringArray& filenames)
+{
+    controlPanel->setRecentlyUsedFilenames(filenames);
+}
+
 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 
 EditorViewportButton::EditorViewportButton(UIComponent* ui) : UI(ui)
diff --git a/Source/UI/UIComponent.h b/Source/UI/UIComponent.h
index d0b8cc1a662bfcc3005ebd35c50430754b57fdea..a8e5e5637ce85bd3bf3bee1547234d7240cb04a0 100755
--- a/Source/UI/UIComponent.h
+++ b/Source/UI/UIComponent.h
@@ -35,9 +35,6 @@
 #include "../Processors/ProcessorGraph.h"
 #include "../Audio/AudioComponent.h"
 #include "../MainWindow.h"
-#include "../Processors/Visualization/OpenGLCanvas.h"
-
-//#include "../OpenGL.h"
 
 class MainWindow;
 class ProcessorList;
@@ -163,6 +160,10 @@ public:
     /** Load settings. */
     void loadStateFromXml(XmlElement*);
 
+    StringArray getRecentlyUsedFilenames();
+
+    void setRecentlyUsedFilenames(const StringArray& filenames);
+
 private:
 
     ScopedPointer<DataViewport> dataViewport;
@@ -173,7 +174,7 @@ private:
     ScopedPointer<MessageCenter> messageCenter;
     ScopedPointer<InfoLabel> infoLabel;
     ScopedPointer<GraphViewer> graphViewer;
-
+	
     /** Pointer to the GUI's MainWindow, which owns the UIComponent. */
     MainWindow* mainWindow;
 
diff --git a/open-ephys.jucer b/open-ephys.jucer
index 9ab19fe825badf802ea944bc20c5c2d420e5efcb..ba5c1efba08c87882fb75c11c32852d8169009bc 100644
--- a/open-ephys.jucer
+++ b/open-ephys.jucer
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 
-<JUCERPROJECT id="ynSYIrr" name="open-ephys" projectType="guiapp" version="0.2.0"
+<JUCERPROJECT id="ynSYIrr" name="open-ephys" projectType="guiapp" version="0.2.1"
               juceLinkage="amalg_multi" buildVST="1" buildRTAS="0" buildAU="1"
               pluginName="Juce Project" pluginDesc="Juce Project" pluginManufacturer="yourcompany"
               pluginManufacturerCode="Manu" pluginCode="Plug" pluginChannelConfigs="{1, 1}, {2, 2}"