diff --git a/Resources/DataFiles/data_stream_16ch_cortex b/Resources/DataFiles/data_stream_16ch_cortex
index 5a84489e3e31356737cf2f9e11ab0c5f72ca2fc1..7e1dd6831a396dc09ffd3c609a9cc7b307bf32f7 100644
Binary files a/Resources/DataFiles/data_stream_16ch_cortex and b/Resources/DataFiles/data_stream_16ch_cortex differ
diff --git a/Resources/DataFiles/data_stream_sine_wave b/Resources/DataFiles/data_stream_sine_wave
new file mode 100644
index 0000000000000000000000000000000000000000..26815b921e0ad1388c40d42de93005fcb31313eb
Binary files /dev/null and b/Resources/DataFiles/data_stream_sine_wave differ
diff --git a/Source/Processors/Channel.cpp b/Source/Processors/Channel.cpp
index 19bf8e2222b08e06384104f381e00e8442c1a768..210ca9ac3c84c3650019fc0aaaac53c14added1e 100644
--- a/Source/Processors/Channel.cpp
+++ b/Source/Processors/Channel.cpp
@@ -61,6 +61,11 @@ String Channel::getName()
 
 }
 
+void Channel::setName(String name_)
+{
+    name = name_;
+}
+
 void Channel::reset()
 {
     createDefaultName();
diff --git a/Source/Processors/Channel.h b/Source/Processors/Channel.h
index af30c38c8cd32e3fa0225e9218625422dd049b9a..a32c6cb93161372784abad3f99a69ef582c20fca 100644
--- a/Source/Processors/Channel.h
+++ b/Source/Processors/Channel.h
@@ -61,6 +61,9 @@ public:
     /** Returns the name of a given channel. */
     String getName();
 
+    /** Sets the name of a given channel. */
+    void setName(String);
+
     /** Restores the default settings for a given channel. */
     void reset();
 
diff --git a/Source/Processors/DataThreads/DataThread.h b/Source/Processors/DataThreads/DataThread.h
index 03a18aa30679b23f4b10f207d65d0926439a6f0e..72c4aa45cd463291169279c96526c0ca5b90a484 100755
--- a/Source/Processors/DataThreads/DataThread.h
+++ b/Source/Processors/DataThreads/DataThread.h
@@ -93,6 +93,9 @@ public:
         return 0;
     }
 
+    /** Changes the names of channels, if the thread needs custom names. */
+    virtual void updateChannelNames() { }
+
     SourceNode* sn;
 
     int16 eventCode;
diff --git a/Source/Processors/DataThreads/RHD2000Thread.cpp b/Source/Processors/DataThreads/RHD2000Thread.cpp
index e8fb5c1a9e8d41f2b81f02687ade3dc15f91968e..60231bd0b6796759c5fdeb5cd468c4830a20ec30 100644
--- a/Source/Processors/DataThreads/RHD2000Thread.cpp
+++ b/Source/Processors/DataThreads/RHD2000Thread.cpp
@@ -25,10 +25,15 @@
 #include "../SourceNode.h"
 
 RHD2000Thread::RHD2000Thread(SourceNode* sn) : DataThread(sn), isTransmitting(false),
-    fastSettleEnabled(false)
+    fastSettleEnabled(false), chipRegisters(30000.0f), dspEnabled(true), boardSampleRate(30000.0f),
+    desiredDspCutoffFreq(0.5f), desiredUpperBandwidth(7500.0f), desiredLowerBandwidth(1.0f),
+    savedSampleRateIndex(16), audioOutputL(-1), audioOutputR(-1), dacOutputShouldChange(false),
+    acquireAdcChannels(false), acquireAuxChannels(true),
+    cableLengthPortA(0.914f), cableLengthPortB(0.914f), cableLengthPortC(0.914f), cableLengthPortD(0.914f) // default is 3 feet (0.914 m)
 {
     evalBoard = new Rhd2000EvalBoard;
     dataBlock = new Rhd2000DataBlock(1);
+    dataBuffer = new DataBuffer(2, 10000); // start with 2 channels and automatically resize
 
     // Open Opal Kelly XEM6010 board.
     int return_code = evalBoard->open();
@@ -45,27 +50,11 @@ RHD2000Thread::RHD2000Thread(SourceNode* sn) : DataThread(sn), isTransmitting(fa
     if (deviceFound)
     {
 
-        numChannelsPerDataStream.insertMultiple(0,0,4);
-
-        // initialize data buffer for 32 channels + 3 aux.
-        dataBuffer = new DataBuffer(35, 10000);
-
+        // upload bitfile and restore default settings
         initializeBoard();
 
-		// manually set cable delay for now
-		//2 for one cable 
-		//3 for 2 cables daisy-chained
-		evalBoard->setCableDelay(Rhd2000EvalBoard::PortA, 3);
-        evalBoard->setCableDelay(Rhd2000EvalBoard::PortB, 3);
-
-        enableHeadstage(0,true); // start off with one headstage
-		enableHeadstage(1,true); // start off with one headstage
-
-
-
-        // automatically find connected headstages -- needs debugging
-       // scanPorts();
-
+        // automatically find connected headstages
+        scanPorts(); // do this after the editor has been created?
     }
 
 }
@@ -89,131 +78,108 @@ void RHD2000Thread::initializeBoard()
 {
     string bitfilename;
     bitfilename = "rhd2000.bit";
-    evalBoard->uploadFpgaBitfile(bitfilename);
+    if (!evalBoard->uploadFpgaBitfile(bitfilename))
+    {
+        // what to do if there's an error
+    }
 
-    // Initialize board.
+    // Initialize the board
+    std::cout << "Initializing acquisition board." << std::endl;
     evalBoard->initialize();
+    // This applies the following settings:
+    //  - sample rate to 30 kHz
+    //  - aux command banks to zero
+    //  - aux command lengths to zero
+    //  - continuous run mode to 'true'
+    //  - maxTimeStep to 2^32 - 1
+    //  - all cable lengths to 3 feet
+    //  - dspSettle to 'false'
+    //  - data source mapping as 0->PortA1, 1->PortB1, 2->PortC1, 3->PortD1, etc.
+    //  - enables all data streams
+    //  - clears the ttlOut
+    //  - disables all DACs and sets gain to 0
+
+    // Select RAM Bank 0 for AuxCmd3 initially, so the ADC is calibrated.
+    evalBoard->selectAuxCommandBank(Rhd2000EvalBoard::PortA, Rhd2000EvalBoard::AuxCmd3, 0);
+    evalBoard->selectAuxCommandBank(Rhd2000EvalBoard::PortB, Rhd2000EvalBoard::AuxCmd3, 0);
+    evalBoard->selectAuxCommandBank(Rhd2000EvalBoard::PortC, Rhd2000EvalBoard::AuxCmd3, 0);
+    evalBoard->selectAuxCommandBank(Rhd2000EvalBoard::PortD, Rhd2000EvalBoard::AuxCmd3, 0);
+
+    // Since our longest command sequence is 60 commands, run the SPI interface for
+    // 60 samples
+    evalBoard->setMaxTimeStep(60);
+    evalBoard->setContinuousRunMode(false);
 
-    // Select per-channel amplifier sampling rate.
-    evalBoard->setSampleRate(Rhd2000EvalBoard::SampleRate30000Hz);
-
-    // // Select RAM Bank 0 for AuxCmd3 initially, so the ADC is calibrated.
-    // evalBoard->selectAuxCommandBank(Rhd2000EvalBoard::PortA, Rhd2000EvalBoard::AuxCmd3, 0);
-    // evalBoard->selectAuxCommandBank(Rhd2000EvalBoard::PortB, Rhd2000EvalBoard::AuxCmd3, 0);
-    // evalBoard->selectAuxCommandBank(Rhd2000EvalBoard::PortC, Rhd2000EvalBoard::AuxCmd3, 0);
-    // evalBoard->selectAuxCommandBank(Rhd2000EvalBoard::PortD, Rhd2000EvalBoard::AuxCmd3, 0);
-    // evalBoard->flush(); // flush in case it crashed with data remaining
-
-    // // Since our longest command sequence is 60 commands, run the SPI interface for
-    // // 60 samples
-    // evalBoard->setMaxTimeStep(60);
-    // evalBoard->setContinuousRunMode(false);
-
-    // // Start SPI interface
-    // evalBoard->run();
-
-    // // Wait for the 60-sample run to complete
-    // while (evalBoard->isRunning())
-    // {
-    //     ;
-    // }
+    // Start SPI interface
+    evalBoard->run();
 
-    // // Read the resulting single data block from the USB interface. We don't
-    // // need to do anything with this, since it was only used for ADC calibration
-    // Rhd2000DataBlock* dataBlock = new Rhd2000DataBlock(evalBoard->getNumEnabledDataStreams());
-    // evalBoard->readDataBlock(dataBlock);
-
-    // // Now that ADC calibration has been performed, we switch to the command sequence
-    // // that does not execute ADC calibration.
-    // evalBoard->selectAuxCommandBank(Rhd2000EvalBoard::PortA, Rhd2000EvalBoard::AuxCmd3,
-    //                                 fastSettleEnabled ? 2 : 1);
-    // evalBoard->selectAuxCommandBank(Rhd2000EvalBoard::PortB, Rhd2000EvalBoard::AuxCmd3,
-    //                                 fastSettleEnabled ? 2 : 1);
-    // evalBoard->selectAuxCommandBank(Rhd2000EvalBoard::PortC, Rhd2000EvalBoard::AuxCmd3,
-    //                                 fastSettleEnabled ? 2 : 1);
-    // evalBoard->selectAuxCommandBank(Rhd2000EvalBoard::PortD, Rhd2000EvalBoard::AuxCmd3,
-    //                                 fastSettleEnabled ? 2 : 1);
-
-
-    // // Set default configuration for all eight DACs on interface board.
-    // evalBoard->enableDac(0, false);
-    // evalBoard->enableDac(1, false);
-    // evalBoard->enableDac(2, false);
-    // evalBoard->enableDac(3, false);
-    // evalBoard->enableDac(4, false);
-    // evalBoard->enableDac(5, false);
-    // evalBoard->enableDac(6, false);
-    // evalBoard->enableDac(7, false);
-    // evalBoard->selectDacDataStream(0, 0);
-    // evalBoard->selectDacDataStream(1, 0);
-    // evalBoard->selectDacDataStream(2, 0);
-    // evalBoard->selectDacDataStream(3, 0);
-    // evalBoard->selectDacDataStream(4, 0);
-    // evalBoard->selectDacDataStream(5, 0);
-    // evalBoard->selectDacDataStream(6, 0);
-    // evalBoard->selectDacDataStream(7, 0);
-    // evalBoard->selectDacDataChannel(0, 0);
-    // evalBoard->selectDacDataChannel(1, 1);
-    // evalBoard->selectDacDataChannel(2, 0);
-    // evalBoard->selectDacDataChannel(3, 0);
-    // evalBoard->selectDacDataChannel(4, 0);
-    // evalBoard->selectDacDataChannel(5, 0);
-    // evalBoard->selectDacDataChannel(6, 0);
-    // evalBoard->selectDacDataChannel(7, 0);
-    // evalBoard->setDacManual(Rhd2000EvalBoard::DacManual1, 32768);
-    // evalBoard->setDacManual(Rhd2000EvalBoard::DacManual2, 32768);
-    // evalBoard->setDacGain(0);
-    // evalBoard->setAudioNoiseSuppress(0);
-
-
-    // Set up an RHD2000 register object using this sample rate to optimize MUX-related
-    // register settings.
-    
-    std::cout << "Rhd sample rate : " << evalBoard->getSampleRate() << std::endl;
-	chipRegisters = new Rhd2000Registers(evalBoard->getSampleRate());
+    // Wait for the 60-sample run to complete
+    while (evalBoard->isRunning())
+    {
+        ;
+    }
 
+    // Read the resulting single data block from the USB interface. We don't
+    // need to do anything with this, since it was only used for ADC calibration
+    Rhd2000DataBlock* dataBlock = new Rhd2000DataBlock(evalBoard->getNumEnabledDataStreams());
 
 
-    // Before generating register configuration command sequences, set amplifier
-    // bandwidth paramters.
-    double dspCutoffFreq;
-    dspCutoffFreq = chipRegisters->setDspCutoffFreq(10.0);
-    cout << "Actual DSP cutoff frequency: " << dspCutoffFreq << " Hz" << endl;
+    evalBoard->readDataBlock(dataBlock);
 
-    chipRegisters->setLowerBandwidth(1.0);
-    chipRegisters->setUpperBandwidth(7500.0);
+    // Now that ADC calibration has been performed, we switch to the command sequence
+    // that does not execute ADC calibration.
+    evalBoard->selectAuxCommandBank(Rhd2000EvalBoard::PortA, Rhd2000EvalBoard::AuxCmd3,
+                                    fastSettleEnabled ? 2 : 1);
+    evalBoard->selectAuxCommandBank(Rhd2000EvalBoard::PortB, Rhd2000EvalBoard::AuxCmd3,
+                                    fastSettleEnabled ? 2 : 1);
+    evalBoard->selectAuxCommandBank(Rhd2000EvalBoard::PortC, Rhd2000EvalBoard::AuxCmd3,
+                                    fastSettleEnabled ? 2 : 1);
+    evalBoard->selectAuxCommandBank(Rhd2000EvalBoard::PortD, Rhd2000EvalBoard::AuxCmd3,
+                                    fastSettleEnabled ? 2 : 1);
 
 
-			// turn on aux inputs
-		chipRegisters->enableAux1(true);
-		chipRegisters->enableAux2(true);
-	   chipRegisters->enableAux3(true);
+    updateRegisters();
 
-    // Let's turn one LED on to indicate that the program is running.
+    // Let's turn one LED on to indicate that the board is now connected
     int ledArray[8] = {1, 0, 0, 0, 0, 0, 0, 0};
     evalBoard->setLedDisplay(ledArray);
 
-
 }
 
 void RHD2000Thread::scanPorts()
 {
     // Scan SPI ports
 
-    int delay, stream, id;
+    int delay, stream, id, i, channel, port;
+    int stream1, stream2;
+    int numChannelsOnPort[4] = {0, 0, 0, 0};
+    Array<int> chipId;
+    chipId.insertMultiple(0,-1,8);
+
+    setSampleRate(16, true); // set to 30 kHz temporarily
 
-    // assume we only have 32-channel headstages, for the sake of
-    // simplicity; this will have to be changed once 64-channel
-    // headstages are an option
+    // Enable all data streams, and set sources to cover one or two chips
+    // on Ports A-D.
     evalBoard->setDataSource(0, Rhd2000EvalBoard::PortA1);
-    evalBoard->setDataSource(1, Rhd2000EvalBoard::PortB1);
-    evalBoard->setDataSource(2, Rhd2000EvalBoard::PortC1);
-    evalBoard->setDataSource(3, Rhd2000EvalBoard::PortD1);
+    evalBoard->setDataSource(1, Rhd2000EvalBoard::PortA2);
+    evalBoard->setDataSource(2, Rhd2000EvalBoard::PortB1);
+    evalBoard->setDataSource(3, Rhd2000EvalBoard::PortB2);
+    evalBoard->setDataSource(4, Rhd2000EvalBoard::PortC1);
+    evalBoard->setDataSource(5, Rhd2000EvalBoard::PortC2);
+    evalBoard->setDataSource(6, Rhd2000EvalBoard::PortD1);
+    evalBoard->setDataSource(7, Rhd2000EvalBoard::PortD2);
 
     evalBoard->enableDataStream(0, true);
     evalBoard->enableDataStream(1, true);
     evalBoard->enableDataStream(2, true);
     evalBoard->enableDataStream(3, true);
+    evalBoard->enableDataStream(4, true);
+    evalBoard->enableDataStream(5, true);
+    evalBoard->enableDataStream(6, true);
+    evalBoard->enableDataStream(7, true);
+
+    std::cout << "Number of enabled data streams: " << evalBoard->getNumEnabledDataStreams() << std::endl;
+
 
     evalBoard->selectAuxCommandBank(Rhd2000EvalBoard::PortA,
                                     Rhd2000EvalBoard::AuxCmd3, 0);
@@ -233,23 +199,21 @@ void RHD2000Thread::scanPorts()
         new Rhd2000DataBlock(evalBoard->getNumEnabledDataStreams());
 
     Array<int> sumGoodDelays;
-    sumGoodDelays.insertMultiple(0,0,4);
+    sumGoodDelays.insertMultiple(0,0,8);
 
     Array<int> indexFirstGoodDelay;
-    indexFirstGoodDelay.insertMultiple(0,-1,4);
+    indexFirstGoodDelay.insertMultiple(0,-1,8);
 
     Array<int> indexSecondGoodDelay;
-    indexSecondGoodDelay.insertMultiple(0,-1,4);
-
-    Array<int> chipId;
-    chipId.insertMultiple(0,0,4);
+    indexSecondGoodDelay.insertMultiple(0,-1,8);
 
-    Array<int> optimumDelay;
-    optimumDelay.insertMultiple(0,0,4);
 
     // Run SPI command sequence at all 16 possible FPGA MISO delay settings
     // to find optimum delay for each SPI interface cable.
-    for (delay = 0; delay < 16; ++delay)
+
+    std::cout << "Checking for connected amplifier chips..." << std::endl;
+
+    for (delay = 0; delay < 16; delay++)//(delay = 0; delay < 16; ++delay)
     {
         evalBoard->setCableDelay(Rhd2000EvalBoard::PortA, delay);
         evalBoard->setCableDelay(Rhd2000EvalBoard::PortB, delay);
@@ -270,13 +234,18 @@ void RHD2000Thread::scanPorts()
 
         // Read the Intan chip ID number from each RHD2000 chip found.
         // Record delay settings that yield good communication with the chip.
-        for (stream = 0; stream < 4; ++stream)
+        for (stream = 0; stream < MAX_NUM_DATA_STREAMS; ++stream)//MAX_NUM_DATA_STREAMS; ++stream)
         {
+           // std::cout << "Stream number " << stream << ", delay = " << delay << std::endl;
+
             id = deviceId(dataBlock, stream);
-            std::cout << "Device ID found: " << id << std::endl;
-            if (id > 0)
+            
+            if (id > 0) // 1 = RHD2132, 2 = RHD2216
             {
+              //  std::cout << "Device ID found: " << id << std::endl;
+
                 sumGoodDelays.set(stream,sumGoodDelays[stream] + 1);
+
                 if (indexFirstGoodDelay[stream] == -1)
                 {
                     indexFirstGoodDelay.set(stream, delay);
@@ -291,11 +260,19 @@ void RHD2000Thread::scanPorts()
         }
     }
 
+    // std::cout << "Chip IDs found: ";
+    // for (int i = 0; i < MAX_NUM_DATA_STREAMS; ++i)
+    // {
+    //     std::cout << chipId[i] << " ";
+    // }
+    //std::cout << std::endl;
+
     // Now, disable data streams where we did not find chips present.
-    for (stream = 0; stream < 4; ++stream)
+    for (stream = 0; stream < MAX_NUM_DATA_STREAMS; ++stream)
     {
         if (chipId[stream] > 0)
         {
+            //std::cout << "Enabling headstage on stream " << stream << std::endl;
             enableHeadstage(stream, true);
         }
         else
@@ -304,9 +281,15 @@ void RHD2000Thread::scanPorts()
         }
     }
 
+    std::cout << "Number of enabled data streams: " << evalBoard->getNumEnabledDataStreams() << std::endl;
+
+
     // Set cable delay settings that yield good communication with each
     // RHD2000 chip.
-    for (stream = 0; stream < 4; ++stream)
+    Array<int> optimumDelay;
+    optimumDelay.insertMultiple(0,0,8);
+
+    for (stream = 0; stream < MAX_NUM_DATA_STREAMS; ++stream)
     {
         if (sumGoodDelays[stream] == 1 || sumGoodDelays[stream] == 2)
         {
@@ -336,7 +319,9 @@ void RHD2000Thread::scanPorts()
     cableLengthPortD =
         evalBoard->estimateCableLengthMeters(optimumDelay[3]);
 
+    setSampleRate(savedSampleRateIndex); // restore saved sample rate
 
+    updateRegisters();
 }
 
 int RHD2000Thread::deviceId(Rhd2000DataBlock* dataBlock, int stream)
@@ -346,11 +331,17 @@ int RHD2000Thread::deviceId(Rhd2000DataBlock* dataBlock, int stream)
     // First, check ROM registers 32-36 to verify that they hold 'INTAN'.
     // This is just used to verify that we are getting good data over the SPI
     // communication channel.
-    intanChipPresent = ((char) dataBlock->auxiliaryData[stream][2][32] == 'I' &&
-                        (char) dataBlock->auxiliaryData[stream][2][33] == 'N' &&
-                        (char) dataBlock->auxiliaryData[stream][2][34] == 'T' &&
-                        (char) dataBlock->auxiliaryData[stream][2][35] == 'A' &&
-                        (char) dataBlock->auxiliaryData[stream][2][36] == 'N');
+    // std::cout << dataBlock->auxiliaryData[stream][2][32] << " ";
+    // std::cout << dataBlock->auxiliaryData[stream][2][33] << " ";
+    // std::cout << dataBlock->auxiliaryData[stream][2][34] << " ";
+    // std::cout << dataBlock->auxiliaryData[stream][2][35] << " ";
+    // std::cout << dataBlock->auxiliaryData[stream][2][36] << std::endl;
+
+    intanChipPresent = (dataBlock->auxiliaryData[stream][2][32] == 73 && // I = 73
+                        dataBlock->auxiliaryData[stream][2][33] == 78 && // N = 78
+                        dataBlock->auxiliaryData[stream][2][34] == 84 && // T = 84
+                        dataBlock->auxiliaryData[stream][2][35] == 65 && // A = 65
+                        dataBlock->auxiliaryData[stream][2][36] == 78);  // N = 78
 
     // If the SPI communication is bad, return -1.  Otherwise, return the Intan
     // chip ID number stored in ROM regstier 63.
@@ -365,20 +356,31 @@ int RHD2000Thread::deviceId(Rhd2000DataBlock* dataBlock, int stream)
 }
 
 
+
 bool RHD2000Thread::isAcquisitionActive()
 {
     return isTransmitting;
 }
 
+void RHD2000Thread::setNumChannels(int hsNum, int numChannels)
+{
+    numChannelsPerDataStream.set(hsNum, numChannels);
+}
+
 int RHD2000Thread::getNumChannels()
 {
 
     numChannels = 0;
 
-    for (int i = 0; i < numChannelsPerDataStream.size(); i++)
+    for (int i = 0; i < MAX_NUM_DATA_STREAMS; i++)
     {
     
-		numChannels += numChannelsPerDataStream[i];
+        if (numChannelsPerDataStream[i] > 0)
+        {
+            numChannels += numChannelsPerDataStream[i];
+            numChannels += 3; // to account for aux inputs
+        }
+
 		
 		/*
 		if (chipRegisters->adcAux1En){ // no public function to read these? fix this in some way
@@ -392,7 +394,12 @@ int RHD2000Thread::getNumChannels()
 		}
 		*/
 	}
-	numChannels += 6;
+
+
+    if (acquireAdcChannels)
+    {
+        numChannels += 8; // add 8 channels for the ADCs
+    }        
 
     if (numChannels > 0)
         return numChannels;
@@ -400,6 +407,57 @@ int RHD2000Thread::getNumChannels()
         return 1; // to prevent crashing with 0 channels
 }
 
+void RHD2000Thread::updateChannelNames()
+{
+
+    int chNum = -1;
+
+    for (int i = 0; i < MAX_NUM_DATA_STREAMS; i++)
+    {
+    
+        for (int j = 0; j < numChannelsPerDataStream[i]; j++)
+        {
+            chNum++;
+
+            sn->channels[chNum]->setName(String(chNum));
+        }
+    }
+
+    if (acquireAuxChannels)
+    {
+        for (int i = 0; i < MAX_NUM_DATA_STREAMS; i++)
+        {
+        
+            for (int j = 0; j < 3; j++)
+            {
+                
+                chNum++;
+
+                String chName = "AUX";
+              //  chName += (j+1);
+
+              //  sn->channels[chNum]->setName(chName);
+            }
+        }
+    }
+
+
+    if (acquireAdcChannels)
+    {
+        for (int j = 0; j < 8; j++)
+        {
+            chNum++;
+
+            String chName = "ADC";
+           // chName += (j+1);
+
+          //  sn->channels[chNum]->setName(chName);
+        }
+    }        
+
+}
+
+
 int RHD2000Thread::getNumEventChannels()
 {
     return 16; // 8 inputs, 8 outputs
@@ -415,14 +473,23 @@ float RHD2000Thread::getBitVolts()
 	return 0.195f;
 }
 
-double RHD2000Thread::setUpperBandwidth(double desiredUpperBandwidth)
+double RHD2000Thread::setUpperBandwidth(double upper)
 {
-    return chipRegisters->setUpperBandwidth(desiredUpperBandwidth);
+
+    desiredUpperBandwidth = upper;
+
+    updateRegisters();
+
+    return actualUpperBandwidth;
 }
 
-double RHD2000Thread::setLowerBandwidth(double desiredLowerBandwidth)
+double RHD2000Thread::setLowerBandwidth(double lower)
 {
-    return chipRegisters->setLowerBandwidth(desiredLowerBandwidth);
+    desiredLowerBandwidth = lower;
+
+    updateRegisters();
+
+    return actualLowerBandwidth;
 }
 
 bool RHD2000Thread::foundInputSource()
@@ -446,12 +513,15 @@ bool RHD2000Thread::enableHeadstage(int hsNum, bool enabled)
         numChannelsPerDataStream.set(hsNum, 0);
     }
 
-    std::cout << "Enabled channels: " << numChannelsPerDataStream[0] <<
-              " " << numChannelsPerDataStream[1] <<
-              " " << numChannelsPerDataStream[2] <<
-              " " << numChannelsPerDataStream[3] << std::endl;
+    std::cout << "Enabled channels: ";
+
+    for (int i = 0; i < MAX_NUM_DATA_STREAMS; i++)
+    {
+        std::cout << numChannelsPerDataStream[i] << " ";
+    } 
+
+    std:: cout << std::endl;
 
-    std::cout << "Enabled data streams: " << evalBoard->getNumEnabledDataStreams() << std::endl;
 
     dataBuffer->resize(getNumChannels(), 10000);
 
@@ -470,89 +540,227 @@ bool RHD2000Thread::isHeadstageEnabled(int hsNum)
 
 }
 
-void RHD2000Thread::setSampleRate(int sampleRateIndex)
+void RHD2000Thread::assignAudioOut(int dacChannel, int dataChannel)
+{
+
+    if (dacChannel == 0)
+    {
+        audioOutputR = dataChannel;
+
+
+    } else if (dacChannel == 1)
+    {
+        audioOutputL = dataChannel;
+
+    }
+
+    dacOutputShouldChange = true; // set a flag and take care of setting wires
+                                  // during the updateBuffer() method
+                                  // to avoid problems
+
+}
+
+void RHD2000Thread::enableAdcs(bool t)
+{
+
+    acquireAdcChannels = t;
+
+    dataBuffer->resize(getNumChannels(), 10000);
+
+}
+
+void RHD2000Thread::setSampleRate(int sampleRateIndex, bool isTemporary)
 {
+
+    if (!isTemporary)
+    {
+        savedSampleRateIndex = sampleRateIndex;
+    }
  
+    int numUsbBlocksToRead = 0; // placeholder - make this change the number of blocks that are read in RHD2000Thread::updateBuffer()
 
-    int numUsbBlocksToRead=0; // placeholder - make this change the number of blocks that are read in  RHD2000Thread::updateBuffer()
     Rhd2000EvalBoard::AmplifierSampleRate sampleRate; // just for local use
 
-
     switch (sampleRateIndex) {
     case 0:
         sampleRate = Rhd2000EvalBoard::SampleRate1000Hz;
         numUsbBlocksToRead = 1;
+        boardSampleRate = 1000.0f;
         break;
     case 1:
         sampleRate = Rhd2000EvalBoard::SampleRate1250Hz;
         numUsbBlocksToRead = 1;
+        boardSampleRate = 1250.0f;
         break;
     case 2:
         sampleRate = Rhd2000EvalBoard::SampleRate1500Hz;
         numUsbBlocksToRead = 1;
+        boardSampleRate = 1500.0f;
         break;
     case 3:
         sampleRate = Rhd2000EvalBoard::SampleRate2000Hz;
         numUsbBlocksToRead = 1;
+        boardSampleRate = 2000.0f;
         break;
     case 4:
         sampleRate = Rhd2000EvalBoard::SampleRate2500Hz;
         numUsbBlocksToRead = 1;
+        boardSampleRate = 2500.0f;
         break;
     case 5:
         sampleRate = Rhd2000EvalBoard::SampleRate3000Hz;
         numUsbBlocksToRead = 2;
+        boardSampleRate = 3000.0f;
         break;
     case 6:
         sampleRate = Rhd2000EvalBoard::SampleRate3333Hz;
         numUsbBlocksToRead = 2;
+        boardSampleRate = 3333.0f;
         break;
     case 7:
         sampleRate = Rhd2000EvalBoard::SampleRate4000Hz;
         numUsbBlocksToRead = 2;
+        boardSampleRate = 4000.0f;
         break;
     case 8:
         sampleRate = Rhd2000EvalBoard::SampleRate5000Hz;
         numUsbBlocksToRead = 3;
+        boardSampleRate = 5000.0f;
         break;
     case 9:
         sampleRate = Rhd2000EvalBoard::SampleRate6250Hz;
         numUsbBlocksToRead = 3;
+        boardSampleRate = 6250.0f;
         break;
     case 10:
         sampleRate = Rhd2000EvalBoard::SampleRate8000Hz;
         numUsbBlocksToRead = 4;
+        boardSampleRate = 8000.0f;
         break;
     case 11:
         sampleRate = Rhd2000EvalBoard::SampleRate10000Hz;
         numUsbBlocksToRead = 6;
+        boardSampleRate = 10000.0f;
         break;
     case 12:
         sampleRate = Rhd2000EvalBoard::SampleRate12500Hz;
         numUsbBlocksToRead = 7;
+        boardSampleRate = 12500.0f;
         break;
     case 13:
         sampleRate = Rhd2000EvalBoard::SampleRate15000Hz;
         numUsbBlocksToRead = 8;
+        boardSampleRate = 15000.0f;
         break;
     case 14:
         sampleRate = Rhd2000EvalBoard::SampleRate20000Hz;
         numUsbBlocksToRead = 12;
+        boardSampleRate = 20000.0f;
         break;
     case 15:
         sampleRate = Rhd2000EvalBoard::SampleRate25000Hz;
         numUsbBlocksToRead = 14;
+        boardSampleRate = 25000.0f;
         break;
     case 16:
         sampleRate = Rhd2000EvalBoard::SampleRate30000Hz;
         numUsbBlocksToRead = 16;
+        boardSampleRate = 30000.0f;
         break;
+    default:
+        sampleRate = Rhd2000EvalBoard::SampleRate10000Hz;
+        numUsbBlocksToRead = 6;
+        boardSampleRate = 10000.0f;
     }
 
 
     // Select per-channel amplifier sampling rate.
     evalBoard->setSampleRate(sampleRate);
 
+    std::cout << "Sample rate set to " << evalBoard->getSampleRate() << std::endl;
+
+     // Now that we have set our sampling rate, we can set the MISO sampling delay
+    // which is dependent on the sample rate.
+    evalBoard->setCableLengthMeters(Rhd2000EvalBoard::PortA, cableLengthPortA);
+    evalBoard->setCableLengthMeters(Rhd2000EvalBoard::PortB, cableLengthPortB);
+    evalBoard->setCableLengthMeters(Rhd2000EvalBoard::PortC, cableLengthPortC);
+    evalBoard->setCableLengthMeters(Rhd2000EvalBoard::PortD, cableLengthPortD);
+
+}
+
+void RHD2000Thread::updateRegisters()
+{
+       // Set up an RHD2000 register object using this sample rate to
+    // optimize MUX-related register settings.
+    chipRegisters.defineSampleRate(boardSampleRate);
+
+
+    int commandSequenceLength;
+    vector<int> commandList;
+
+    // Create a command list for the AuxCmd1 slot.  This command sequence will create a 250 Hz,
+    // zero-amplitude sine wave (i.e., a flatline).  We will change this when we want to perform
+    // impedance testing.
+    commandSequenceLength = chipRegisters.createCommandListZcheckDac(commandList, 250.0, 0.0);
+    evalBoard->uploadCommandList(commandList, Rhd2000EvalBoard::AuxCmd1, 0);
+    evalBoard->selectAuxCommandLength(Rhd2000EvalBoard::AuxCmd1, 0, commandSequenceLength - 1);
+    evalBoard->selectAuxCommandBank(Rhd2000EvalBoard::PortA, Rhd2000EvalBoard::AuxCmd1, 0);
+    evalBoard->selectAuxCommandBank(Rhd2000EvalBoard::PortB, Rhd2000EvalBoard::AuxCmd1, 0);
+    evalBoard->selectAuxCommandBank(Rhd2000EvalBoard::PortC, Rhd2000EvalBoard::AuxCmd1, 0);
+    evalBoard->selectAuxCommandBank(Rhd2000EvalBoard::PortD, Rhd2000EvalBoard::AuxCmd1, 0);
+
+    // // Next, we'll create a command list for the AuxCmd2 slot.  This command sequence
+    // // will sample the temperature sensor and other auxiliary ADC inputs.
+    commandSequenceLength = chipRegisters.createCommandListTempSensor(commandList);
+    evalBoard->uploadCommandList(commandList, Rhd2000EvalBoard::AuxCmd2, 0);
+    evalBoard->selectAuxCommandLength(Rhd2000EvalBoard::AuxCmd2, 0, commandSequenceLength - 1);
+    evalBoard->selectAuxCommandBank(Rhd2000EvalBoard::PortA, Rhd2000EvalBoard::AuxCmd2, 0);
+    evalBoard->selectAuxCommandBank(Rhd2000EvalBoard::PortB, Rhd2000EvalBoard::AuxCmd2, 0);
+    evalBoard->selectAuxCommandBank(Rhd2000EvalBoard::PortC, Rhd2000EvalBoard::AuxCmd2, 0);
+    evalBoard->selectAuxCommandBank(Rhd2000EvalBoard::PortD, Rhd2000EvalBoard::AuxCmd2, 0);
+
+    // Before generating register configuration command sequences, set amplifier
+    // bandwidth paramters.
+     actualDspCutoffFreq = chipRegisters.setDspCutoffFreq(desiredDspCutoffFreq);
+     actualLowerBandwidth = chipRegisters.setLowerBandwidth(desiredLowerBandwidth);
+     actualUpperBandwidth = chipRegisters.setUpperBandwidth(desiredUpperBandwidth);
+     chipRegisters.enableDsp(dspEnabled);
+
+     // turn on aux inputs
+    chipRegisters.enableAux1(true);
+    chipRegisters.enableAux2(true);
+    chipRegisters.enableAux3(true);
+
+     chipRegisters.createCommandListRegisterConfig(commandList, true);
+        // Upload version with ADC calibration to AuxCmd3 RAM Bank 0.
+    evalBoard->uploadCommandList(commandList, Rhd2000EvalBoard::AuxCmd3, 0);
+    evalBoard->selectAuxCommandLength(Rhd2000EvalBoard::AuxCmd3, 0,
+                                      commandSequenceLength - 1);
+
+    commandSequenceLength = chipRegisters.createCommandListRegisterConfig(commandList, false);
+    // Upload version with no ADC calibration to AuxCmd3 RAM Bank 1.
+    evalBoard->uploadCommandList(commandList, Rhd2000EvalBoard::AuxCmd3, 1);
+    evalBoard->selectAuxCommandLength(Rhd2000EvalBoard::AuxCmd3, 0,
+                                      commandSequenceLength - 1);
+
+    chipRegisters.setFastSettle(true);
+    commandSequenceLength = chipRegisters.createCommandListRegisterConfig(commandList, false);
+    // Upload version with fast settle enabled to AuxCmd3 RAM Bank 2.
+    evalBoard->uploadCommandList(commandList, Rhd2000EvalBoard::AuxCmd3, 2);
+    evalBoard->selectAuxCommandLength(Rhd2000EvalBoard::AuxCmd3, 0,
+                                      commandSequenceLength - 1);
+    chipRegisters.setFastSettle(false);
+
+    
+
+    evalBoard->selectAuxCommandBank(Rhd2000EvalBoard::PortA, Rhd2000EvalBoard::AuxCmd3,
+                                    fastSettleEnabled ? 2 : 1);
+    evalBoard->selectAuxCommandBank(Rhd2000EvalBoard::PortB, Rhd2000EvalBoard::AuxCmd3,
+                                    fastSettleEnabled ? 2 : 1);
+    evalBoard->selectAuxCommandBank(Rhd2000EvalBoard::PortC, Rhd2000EvalBoard::AuxCmd3,
+                                    fastSettleEnabled ? 2 : 1);
+    evalBoard->selectAuxCommandBank(Rhd2000EvalBoard::PortD, Rhd2000EvalBoard::AuxCmd3,
+                                    fastSettleEnabled ? 2 : 1);
 }
 
 void RHD2000Thread::setCableLength(int hsNum, float length)
@@ -660,8 +868,6 @@ bool RHD2000Thread::updateBuffer()
     bool return_code;
 	
 
-    for (int n = 0; n < 10; n++)
-    {
         if (evalBoard->numWordsInFifo() >= blockSize)
         {
             return_code = evalBoard->readDataBlock(dataBlock);
@@ -671,7 +877,8 @@ bool RHD2000Thread::updateBuffer()
                 int streamNumber = -1;
                 int channel = -1;
 
-                for (int dataStream = 0; dataStream < numChannelsPerDataStream.size(); dataStream++)
+                // do the neural data channels first
+                for (int dataStream = 0; dataStream < MAX_NUM_DATA_STREAMS; dataStream++)
                 {
                     if (numChannelsPerDataStream[dataStream] > 0)
                     {
@@ -679,60 +886,105 @@ bool RHD2000Thread::updateBuffer()
 
                         for (int chan = 0; chan < numChannelsPerDataStream[dataStream]; chan++)
                         {
-                            //std::cout << "reading sample stream" << streamNumber << " chan " << chan << " sample "<< samp << std::endl;
+                         //   std::cout << "reading sample stream" << streamNumber << " chan " << chan << " sample "<< samp << std::endl;
 							channel++;
 
                             int value = dataBlock->amplifierData[streamNumber][chan][samp];
 
                             thisSample[channel] = float(value-32768)*0.195f;
                         }
-                    
 					
-						
-						if (samp % 4 == 1) { // every 4th sample should have auxiliary input data
-						
-							channel++;
-							thisSample[channel] = 0.0374 *
-							float(dataBlock->auxiliaryData[dataStream][1][samp+0]);
-							auxBuffer[channel]=thisSample[channel];
+					}
 
-							channel++;
-							thisSample[channel] = 0.0374 *
-							float(dataBlock->auxiliaryData[dataStream][1][samp+1]);
-							auxBuffer[channel]=thisSample[channel];
+				}
 
-						
-							channel++;
-							thisSample[channel] = 0.0374 *
-							float(dataBlock->auxiliaryData[dataStream][1][samp+2]);
-							auxBuffer[channel]=thisSample[channel];
+                streamNumber = -1;
 
-						} else{
-							channel++;
-							thisSample[channel] = auxBuffer[channel];
-							channel++;
-							thisSample[channel] = auxBuffer[channel];
-							channel++;
-							thisSample[channel] = auxBuffer[channel];
-						}
-						
-					}
+                // then do the ADC channels
+                for (int dataStream = 0; dataStream < MAX_NUM_DATA_STREAMS; dataStream++)
+                {
+                    if (numChannelsPerDataStream[dataStream] > 0)
+                    {
+                        streamNumber++;
+
+                        if (samp % 4 == 1) { // every 4th sample should have auxiliary input data
+                        
+                            channel++;
+                            thisSample[channel] = 0.0374 *
+                                 float(dataBlock->auxiliaryData[dataStream][1][samp+0]);
+
+                            auxBuffer[channel]=thisSample[channel];
+
+                            channel++;
+                            thisSample[channel] = 0.0374 *
+                                 float(dataBlock->auxiliaryData[dataStream][1][samp+1]);
+
+                            auxBuffer[channel]=thisSample[channel];
+
+                        
+                            channel++;
+                            thisSample[channel] = 0.0374 *
+                                 float(dataBlock->auxiliaryData[dataStream][1][samp+2]);
+
+                            auxBuffer[channel]=thisSample[channel];
+
+                        } else{ // repeat last values from buffer
+
+                            channel++;
+                            thisSample[channel] = auxBuffer[channel];
+                            channel++;
+                            thisSample[channel] = auxBuffer[channel];
+                            channel++;
+                            thisSample[channel] = auxBuffer[channel];
+                        }
+                    }
 
                 }
 
-                // std::cout << channel << std::endl;
+                // finally, loop through ADC channels if necessary
+                if (acquireAdcChannels)
+                {
+                    for (int adcChan = 0; adcChan < 8; ++adcChan) {
+                    
+                    channel++;
+                    // ADC waveform units = volts
+                     thisSample[channel] = 
+                       0.000050354 * float(dataBlock->boardAdcData[adcChan][samp]);
+                    }
+                }
+				// std::cout << channel << std::endl;
 
-                timestamp = dataBlock->timeStamp[samp];
-                timestamp = timestamp;
-                eventCode = dataBlock->ttlIn[samp];
+				timestamp = dataBlock->timeStamp[samp];
+				timestamp = timestamp;
+				eventCode = dataBlock->ttlIn[samp];
 
-                dataBuffer->addToBuffer(thisSample, &timestamp, &eventCode, 1);
+				dataBuffer->addToBuffer(thisSample, &timestamp, &eventCode, 1);
+				 
             }
 
         }
-    }
+    
 
+    if (dacOutputShouldChange)
+    {
+        if (audioOutputR >= 0)
+        {
+            evalBoard->enableDac(0, true);
+            evalBoard->selectDacDataChannel(0, audioOutputR);
+        } else {
+            evalBoard->enableDac(0, false);
+        }
+            
+        if (audioOutputL >= 0)
+        {
+            evalBoard->enableDac(1, true);
+            evalBoard->selectDacDataChannel(1, audioOutputR);
+        } else {
+            evalBoard->enableDac(1, false);
+        }
 
+        dacOutputShouldChange = false;
+    }
 
 
     return true;
diff --git a/Source/Processors/DataThreads/RHD2000Thread.h b/Source/Processors/DataThreads/RHD2000Thread.h
index 611d22d64b6271e20958f4c843972b11c45c6d24..47faa406f3c77257451d7080818bf473bade459b 100644
--- a/Source/Processors/DataThreads/RHD2000Thread.h
+++ b/Source/Processors/DataThreads/RHD2000Thread.h
@@ -38,6 +38,7 @@
 
 #include "DataThread.h"
 
+#define MAX_NUM_DATA_STREAMS 8
 
 class SourceNode;
 
@@ -67,22 +68,30 @@ public:
     void setCableLength(int hsNum, float length);
     void setNumChannels(int hsNum, int nChannels);
 
-    void setSampleRate(int sampleRateIndex);
+    void setSampleRate(int index, bool temporary = false);
 
-    double setUpperBandwidth(double desiredUpperBandwidth); // set desired BW, returns actual BW
-    double setLowerBandwidth(double desiredLowerBandwidth);
+    double setUpperBandwidth(double upper); // set desired BW, returns actual BW
+    double setLowerBandwidth(double lower);
 
+    void scanPorts();
 
     int getNumEventChannels();
 
+    void assignAudioOut(int dacChannel, int dataChannel);
+    void enableAdcs(bool);
+
     bool isAcquisitionActive();
 
+    void updateChannelNames();
+
 private:
 
     ScopedPointer<Rhd2000EvalBoard> evalBoard;
-    ScopedPointer<Rhd2000Registers> chipRegisters;
+    Rhd2000Registers chipRegisters;
     Rhd2000DataBlock* dataBlock;
 
+    int audioOutputL, audioOutputR;
+
     Array<int> numChannelsPerDataStream;
 
     int numChannels;
@@ -95,13 +104,26 @@ private:
 
     bool isTransmitting;
 
+    bool dacOutputShouldChange;
+    bool acquireAdcChannels;
+    bool acquireAuxChannels;
+
     bool fastSettleEnabled;
 
+    bool dspEnabled;
+    double actualDspCutoffFreq, desiredDspCutoffFreq;
+    double actualUpperBandwidth, desiredUpperBandwidth;
+    double actualLowerBandwidth, desiredLowerBandwidth;
+    double boardSampleRate;
+    int savedSampleRateIndex;
+
     bool startAcquisition();
     bool stopAcquisition();
 
     void initializeBoard();
-    void scanPorts();
+
+    void updateRegisters();
+    
     int deviceId(Rhd2000DataBlock* dataBlock, int stream);
 
     bool updateBuffer();
diff --git a/Source/Processors/DataThreads/rhythm-api/rhd2000datablock.cpp b/Source/Processors/DataThreads/rhythm-api/rhd2000datablock.cpp
index d80dc6ebc2750f75400b64eda43cb145b2c1fdb8..449ca4731a291eaf8658a79b4015156aabade610 100755
--- a/Source/Processors/DataThreads/rhythm-api/rhd2000datablock.cpp
+++ b/Source/Processors/DataThreads/rhythm-api/rhd2000datablock.cpp
@@ -148,7 +148,7 @@ void Rhd2000DataBlock::fillFromUsbBuffer(unsigned char usbBuffer[], int blockInd
     {
         if (!checkUsbHeader(usbBuffer, index))
         {
-            cerr << "Error in Rhd2000EvalBoard::readDataBlock: Incorrect header." << endl;
+            //cerr << "Error in Rhd2000EvalBoard::readDataBlock: Incorrect header." << endl;
         }
         index += 8;
         timeStamp[t] = convertUsbTimeStamp(usbBuffer, index);
diff --git a/Source/Processors/Editors/ChannelMappingEditor.h b/Source/Processors/Editors/ChannelMappingEditor.h
index 3376fea761a5ea7ffcfd210f0d114a8b9b385254..0ddde7119fa9aea18d4446c3db8ae0f5964f6b0a 100644
--- a/Source/Processors/Editors/ChannelMappingEditor.h
+++ b/Source/Processors/Editors/ChannelMappingEditor.h
@@ -28,7 +28,7 @@
 #include "../../../JuceLibraryCode/JuceHeader.h"
 #include "GenericEditor.h"
 
-#include "SpikeDetectorEditor.h"
+#include "SpikeDetectorEditor.h" // for ElectrodeButton and ElectrodeEditorButton
 
 /**
 
diff --git a/Source/Processors/Editors/ChannelSelector.cpp b/Source/Processors/Editors/ChannelSelector.cpp
index 2cc01b7c55827310e74a5b2565d075e1b0a9747d..6e3b4bb3e3514414cdba77b1a0410d9b53b5f6e2 100755
--- a/Source/Processors/Editors/ChannelSelector.cpp
+++ b/Source/Processors/Editors/ChannelSelector.cpp
@@ -352,22 +352,29 @@ void ChannelSelector::stopAcquisition()
 void ChannelSelector::setRadioStatus(bool radioOn)
 {
 
-    radioStatus = radioOn;
-
-    for (int i = 0; i < parameterButtons.size(); i++)
+    if (radioStatus != radioOn)
     {
-        if (radioOn)
-        {
-            parameterButtons[i]->setToggleState(false, false);
-            parameterButtons[i]->setRadioGroupId(999);
-        }
-        else
+
+        radioStatus = radioOn;
+
+        for (int i = 0; i < parameterButtons.size(); i++)
         {
-            parameterButtons[i]->setToggleState(false, false);
-            parameterButtons[i]->setRadioGroupId(0);
+            if (radioOn)
+            {
+                parameterButtons[i]->setToggleState(false, false);
+                parameterButtons[i]->setRadioGroupId(999);
+            }
+            else
+            {
+                parameterButtons[i]->setToggleState(false, false);
+                parameterButtons[i]->setRadioGroupId(0);
+            }
         }
+
     }
 
+  
+
 }
 
 bool ChannelSelector::getParamStatus(int chan)
@@ -525,6 +532,13 @@ void ChannelSelector::buttonClicked(Button* button)
                 audioButtons[i]->setToggleState(false, true);
             }
         }
+
+        if (radioStatus) // if radio buttons are active
+            {
+                // send a message to parent
+                GenericEditor* editor = (GenericEditor*) getParentComponent();
+                editor->channelChanged(-1);
+            }
     }
     else
     {
diff --git a/Source/Processors/Editors/GenericEditor.cpp b/Source/Processors/Editors/GenericEditor.cpp
index 4738166c21f254c5f9556c07377a06735e200a76..6c41a3a48733dca79f49c9c72b521e4af3e6758f 100755
--- a/Source/Processors/Editors/GenericEditor.cpp
+++ b/Source/Processors/Editors/GenericEditor.cpp
@@ -555,7 +555,7 @@ void DrawerButton::paintButton(Graphics& g, bool isMouseOver, bool isButtonDown)
 
 }
 
-UtilityButton::UtilityButton(const String& label_, Font font_) :
+UtilityButton::UtilityButton(String label_, Font font_) :
     Button(label_), label(label_), font(font_)
 {
 
@@ -659,7 +659,7 @@ void UtilityButton::paintButton(Graphics& g, bool isMouseOver, bool isButtonDown
     g.setFont(font);
 
     g.setColour(fontColor);
-    g.drawText(getName(),0,0,getWidth(),getHeight(),Justification::centred,true);
+    g.drawText(label,0,0,getWidth(),getHeight(),Justification::centred,true);
 
     //g.drawSingleLineText(getName(), getWidth()/2 - stringWidth/2, 12);
 
@@ -753,6 +753,12 @@ void UtilityButton::resized()
 
 }
 
+void UtilityButton::setLabel(String label_)
+{
+    label = label_;
+    repaint();
+}
+
 void TriangleButton::paintButton(Graphics& g, bool isMouseOver, bool isButtonDown)
 {
 
@@ -803,10 +809,10 @@ void TriangleButton::paintButton(Graphics& g, bool isMouseOver, bool isButtonDow
 void GenericEditor::updateParameterButtons(int parameterIndex)
 {
 
-    if (parameterEditors.size()==0)
+    if (parameterEditors.size() == 0)
     {
         //Checks if there is a parameter editor, and stops a bug if there isn't.
-        std::cout << "No parameterEditors" << std::endl;
+        //std::cout << "No parameterEditors" << std::endl;
     }
     else
     {
@@ -821,6 +827,6 @@ void GenericEditor::updateParameterButtons(int parameterIndex)
         {
             parameterEditors[parameterIndex]->channelSelectionUI();
         }
-    std::cout << "updateParameterButtons" << std::endl;
+    //std::cout << "updateParameterButtons" << std::endl;
     }
 }
diff --git a/Source/Processors/Editors/GenericEditor.h b/Source/Processors/Editors/GenericEditor.h
index 762b9bc3f6593b28128c43f18c16d3516c1c609f..420af535b72a47e47e98512c511675443a19d1c0 100755
--- a/Source/Processors/Editors/GenericEditor.h
+++ b/Source/Processors/Editors/GenericEditor.h
@@ -106,10 +106,10 @@ public:
     void setEnabledState(bool);
 
     /** Called just prior to the start of acquisition, to allow the editor to prepare.*/
-    void startAcquisition();
+    virtual void startAcquisition();
 
     /** Called after the end of acquisition.*/
-    void stopAcquisition();
+    virtual void stopAcquisition();
 
     /** Returns the name of the editor.*/
     String getName()
@@ -344,7 +344,7 @@ private:
 class UtilityButton : public Button
 {
 public:
-    UtilityButton(const String& label_, Font font_);
+    UtilityButton(String label_, Font font_);
     ~UtilityButton() {}
 
     void setCorners(bool UL, bool UR, bool LL, bool LR);
@@ -356,10 +356,12 @@ public:
         return isEnabled;
     }
 
+    void setLabel(String label);
+
 private:
     void paintButton(Graphics& g, bool isMouseOver, bool isButtonDown);
 
-    const String label;
+    String label;
     Font font;
     bool roundUL, roundUR, roundLL, roundLR;
     float radius;
diff --git a/Source/Processors/Editors/RHD2000Editor.cpp b/Source/Processors/Editors/RHD2000Editor.cpp
index bea8a7d372c6cb7cfa3d767da10398f7458f1bbb..65a84dc7a54c6db3c54d9687b761edc4502ecc57 100644
--- a/Source/Processors/Editors/RHD2000Editor.cpp
+++ b/Source/Processors/Editors/RHD2000Editor.cpp
@@ -24,16 +24,17 @@
 #include "RHD2000Editor.h"
 #include "../../UI/EditorViewport.h"
 
+#include "ChannelSelector.h"
+
 #include "../DataThreads/RHD2000Thread.h"
 
 RHD2000Editor::RHD2000Editor(GenericProcessor* parentNode,
                              RHD2000Thread* board_,
-                             bool useDefaultParameterEditors=true
+                             bool useDefaultParameterEditors
                             )
     : GenericEditor(parentNode, useDefaultParameterEditors), board(board_)
 {
-    desiredWidth = 400;
-
+    desiredWidth = 260;
 
     // add headstage-specific controls (currently just an enable/disable button)
     for (int i = 0; i < 4; i++)
@@ -41,23 +42,128 @@ RHD2000Editor::RHD2000Editor(GenericProcessor* parentNode,
         HeadstageOptionsInterface* hsOptions = new HeadstageOptionsInterface(board, this, i);
         headstageOptionsInterfaces.add(hsOptions);
         addAndMakeVisible(hsOptions);
-        hsOptions->setBounds(80,25+i*23, 60, 22);
+        hsOptions->setBounds(3, 28+i*20, 70, 18);
     }
 
     // add sample rate selection
-    SampleRateInterface* rateOptions = new SampleRateInterface(board, this);
-    addAndMakeVisible(rateOptions);
-    rateOptions->setBounds(150,25,160, 50);
+    sampleRateInterface = new SampleRateInterface(board, this);
+    addAndMakeVisible(sampleRateInterface);
+    sampleRateInterface->setBounds(80, 25, 100, 50);
 
     // add Bandwidth selection
-    BandwidthInterface* bandwidthOptions = new BandwidthInterface(board, this);
-    addAndMakeVisible(bandwidthOptions);
-    bandwidthOptions->setBounds(150,65,160, 50);
+    bandwidthInterface = new BandwidthInterface(board, this);
+    addAndMakeVisible(bandwidthInterface);
+    bandwidthInterface->setBounds(80, 65, 100, 50);
+
+    // add rescan button
+    rescanButton = new UtilityButton("RESCAN", Font("Small Text", 13, Font::plain));
+    rescanButton->setRadius(3.0f);
+    rescanButton->setBounds(6, 108,65,18);
+    rescanButton->addListener(this);
+    addAndMakeVisible(rescanButton);
+
+    for (int i = 0; i < 2; i++)
+    {
+        ElectrodeButton* button = new ElectrodeButton(-1);
+        electrodeButtons.add(button);
+
+        button->setBounds(190+i*25, 40, 25, 15);
+        button->setChannelNum(-1);
+        button->setToggleState(false,false);
+        button->setRadioGroupId(999);
+
+        addAndMakeVisible(button);
+        button->addListener(this);
+    }
+
+    audioLabel = new Label("audio label", "Audio out");
+    audioLabel->setBounds(180,25,180,15);
+    audioLabel->setFont(Font("Small Text", 10, Font::plain));
+    audioLabel->setColour(Label::textColourId, Colours::darkgrey);
+    addAndMakeVisible(audioLabel);
+
+    adcButton = new UtilityButton("ADC 1-8", Font("Small Text", 13, Font::plain));
+    adcButton->setRadius(3.0f);
+    adcButton->setBounds(180, 70,65,18);
+    adcButton->addListener(this);
+    adcButton->setClickingTogglesState(true);
+    addAndMakeVisible(adcButton);
+    
 
 }
 
 RHD2000Editor::~RHD2000Editor()
 {
+
+}
+
+void RHD2000Editor::scanPorts()
+{
+    rescanButton->triggerClick();
+}
+
+void RHD2000Editor::buttonEvent(Button* button)
+{
+
+    if (button == rescanButton)
+    {
+        board->scanPorts();
+
+        for (int i = 0; i < 4; i++)
+        {
+            headstageOptionsInterfaces[i]->checkEnabledState();
+        }
+
+    } else if (button == electrodeButtons[0])
+    {
+        channelSelector->setRadioStatus(true);   
+    } else if (button == electrodeButtons[1])
+    {
+        channelSelector->setRadioStatus(true);   
+    } else if (button == adcButton)
+    {
+        board->enableAdcs(button->getToggleState());
+        getEditorViewport()->makeEditorVisible(this, false, true);
+    }
+
+}
+
+void RHD2000Editor::channelChanged(int chan)
+{
+    for (int i = 0; i < 2; i++)
+    {
+        if (electrodeButtons[i]->getToggleState())
+        {
+            electrodeButtons[i]->setChannelNum(chan);
+            electrodeButtons[i]->repaint();
+
+            board->assignAudioOut(i, chan);
+        }
+    }
+}
+
+void RHD2000Editor::startAcquisition()
+{
+
+    channelSelector->startAcquisition();
+
+    rescanButton->setEnabledState(false);
+    adcButton->setEnabledState(false);
+
+    acquisitionIsActive = true;
+
+}
+
+void RHD2000Editor::stopAcquisition()
+{
+
+    channelSelector->stopAcquisition();
+
+    rescanButton->setEnabledState(true);
+    adcButton->setEnabledState(true);
+
+    acquisitionIsActive = false;
+
 }
 
 // Bandwidth Options --------------------------------------------------------------------
@@ -67,20 +173,25 @@ BandwidthInterface::BandwidthInterface(RHD2000Thread* board_,
     board(board_), editor(editor_)
 {
 
-    name="Bandwidth";
+    name = "Bandwidth";
 
+    lastHighCutString = "7500";
+    lastLowCutString = "1";
 
-    UpperBandwidthSelection = new Label("UpperBandwidth","7500 Hz"); // this is currently set in RHD2000Thread, the cleaner would be to set it here again
+    UpperBandwidthSelection = new Label("UpperBandwidth",lastHighCutString); // this is currently set in RHD2000Thread, the cleaner would be to set it here again
     UpperBandwidthSelection->setEditable(true,false,false);
     UpperBandwidthSelection->addListener(this);
-    UpperBandwidthSelection->setBounds(0,10,300,30);
+    UpperBandwidthSelection->setBounds(30,30,60,20);
+    UpperBandwidthSelection->setColour(Label::textColourId, Colours::darkgrey);
     addAndMakeVisible(UpperBandwidthSelection);
 
 
-    LowerBandwidthSelection = new Label("LowerBandwidth","1 Hz");
+    LowerBandwidthSelection = new Label("LowerBandwidth",lastLowCutString);
     LowerBandwidthSelection->setEditable(true,false,false);
     LowerBandwidthSelection->addListener(this);
-    LowerBandwidthSelection->setBounds(0,30,300,30);
+    LowerBandwidthSelection->setBounds(25,10,60,20);
+    LowerBandwidthSelection->setColour(Label::textColourId, Colours::darkgrey);
+
     addAndMakeVisible(LowerBandwidthSelection);
 
 
@@ -93,29 +204,51 @@ BandwidthInterface::~BandwidthInterface()
 }
 
 
-void BandwidthInterface::labelTextChanged(Label* te)
+void BandwidthInterface::labelTextChanged(Label* label)
 {
     
     if (!(editor->acquisitionIsActive) && board->foundInputSource())
     {
-        if (te == UpperBandwidthSelection)
+        if (label == UpperBandwidthSelection)
         {
-            double actualUpperBandwidth = board->setUpperBandwidth(te->getText().getDoubleValue());
-           // cb->setText(cb->getItemText(te->getSelectedId()),true);
-            std::cout << "Setting Upper Bandwidth to " << te->getText().getDoubleValue() << std::endl;
-            std::cout << "Actual Upper Bandwidth:  " <<  actualUpperBandwidth  << std::endl;
-            te->setText(String(actualUpperBandwidth)+" Hz",false);
 
+            Value val = label->getTextValue();
+            double requestedValue = double(val.getValue());
+
+            if (requestedValue < 100.0 || requestedValue > 20000.0 || requestedValue < lastLowCutString.getFloatValue())
+            {
+                editor->sendActionMessage("Value out of range.");
+
+                label->setText(lastHighCutString, dontSendNotification);
+
+                return;
+            }
+
+            double actualUpperBandwidth = board->setUpperBandwidth(requestedValue);
+
+            std::cout << "Setting Upper Bandwidth to " << requestedValue << std::endl;
+            std::cout << "Actual Upper Bandwidth:  " <<  actualUpperBandwidth  << std::endl;
+            label->setText(String((roundFloatToInt)(actualUpperBandwidth)), false);
 
-            repaint();
         } else {
-            double actualLowerBandwidth = board->setLowerBandwidth(te->getText().getDoubleValue());
-           // cb->setText(cb->getItemText(te->getSelectedId()),true);
-            std::cout << "Setting Lower Bandwidth to " << te->getText().getDoubleValue() << std::endl;
-            std::cout << "Actual Lower Bandwidth:  " <<  actualLowerBandwidth  << std::endl;
-            te->setText(String(actualLowerBandwidth)+" Hz",false);
 
-            repaint(); 
+            Value val = label->getTextValue();
+            double requestedValue = double(val.getValue());
+
+            if (requestedValue < 0.1 || requestedValue > 500.0 || requestedValue > lastHighCutString.getFloatValue())
+            {
+                editor->sendActionMessage("Value out of range.");
+
+                 label->setText(lastLowCutString, dontSendNotification);
+
+                return;
+            }
+
+            double actualLowerBandwidth = board->setLowerBandwidth(requestedValue);
+
+            std::cout << "Setting Upper Bandwidth to " << requestedValue << std::endl;
+            std::cout << "Actual Upper Bandwidth:  " <<  actualLowerBandwidth  << std::endl;
+            label->setText(String(roundFloatToInt(actualLowerBandwidth)), false);
         }
     }
 }
@@ -125,16 +258,17 @@ void BandwidthInterface::labelTextChanged(Label* te)
 
 void BandwidthInterface::paint(Graphics& g)
 {
-    //g.setColour(Colours::lightgrey);
 
-    //g.fillRoundedRectangle(5,0,getWidth()-10,getHeight(),4.0f);
-  
-   // g.setColour(Colours::grey);
+     g.setColour(Colours::darkgrey);
 
-    g.setFont(Font("Small Text",15,Font::plain));
+    g.setFont(Font("Small Text",10,Font::plain));
 
     g.drawText(name, 0, 0, 200, 15, Justification::left, false);
 
+    g.drawText("Low: ", 0, 10, 200, 20, Justification::left, false);
+
+    g.drawText("High: ", 0, 30, 200, 20, Justification::left, false);
+
 }
 
 // Sample rate Options --------------------------------------------------------------------
@@ -144,7 +278,7 @@ SampleRateInterface::SampleRateInterface(RHD2000Thread* board_,
     board(board_), editor(editor_)
 {
 
-    name="SampleRate";
+    name="Sample Rate";
 
     sampleRateOptions.add("1.00 kS/s");
     sampleRateOptions.add("1.25 kS/s");
@@ -187,12 +321,11 @@ void SampleRateInterface::comboBoxChanged(ComboBox* cb)
     {
         if (cb == rateSelection)
         {
-            board->setSampleRate(cb->getSelectedId());
-            //cb->setText(cb->getItemText(cb->getSelectedId()),true);
-            std::cout << "Setting sample rate to index " << cb->getSelectedId() << std::endl;
+            board->setSampleRate(cb->getSelectedId()-1);
+
+            std::cout << "Setting sample rate to index " << cb->getSelectedId()-1 << std::endl;
 
             editor->getEditorViewport()->makeEditorVisible(editor, false, true);
-            //repaint();
         }
     }
 }
@@ -202,13 +335,10 @@ void SampleRateInterface::comboBoxChanged(ComboBox* cb)
 
 void SampleRateInterface::paint(Graphics& g)
 {
-    //g.setColour(Colours::lightgrey);
 
-    //g.fillRoundedRectangle(5,0,getWidth()-10,getHeight(),4.0f);
-  
-   // g.setColour(Colours::grey);
+     g.setColour(Colours::darkgrey);
 
-    g.setFont(Font("Small Text",15,Font::plain));
+    g.setFont(Font("Small Text",10,Font::plain));
 
     g.drawText(name, 0, 0, 200, 15, Justification::left, false);
 
@@ -220,10 +350,10 @@ void SampleRateInterface::paint(Graphics& g)
 HeadstageOptionsInterface::HeadstageOptionsInterface(RHD2000Thread* board_,
                                                      RHD2000Editor* editor_,
                                                      int hsNum) :
-    hsNumber(hsNum), isEnabled(false), board(board_), editor(editor_)
+    isEnabled(false), board(board_), editor(editor_)
 {
 
-    switch (hsNumber)
+    switch (hsNum)
     {
         case 0 :
             name = "A";
@@ -241,16 +371,31 @@ HeadstageOptionsInterface::HeadstageOptionsInterface(RHD2000Thread* board_,
             name = "X";
     }
 
-    isEnabled = board->isHeadstageEnabled(hsNumber);
-
-    enabledButton = new UtilityButton("on", Font("Small Text", 13, Font::plain));
-    enabledButton->addListener(this);
-    enabledButton->setRadius(3.0f);
-    enabledButton->setBounds(25,2,20,19);
-    addAndMakeVisible(enabledButton);
+    hsNumber1 = hsNum*2; // data stream 1
+    hsNumber2 = hsNumber1+1; // data stream 2
 
+    channelsOnHs1 = 0;
+    channelsOnHs2 = 0;
 
+    
 
+    hsButton1 = new UtilityButton(" ", Font("Small Text", 13, Font::plain));
+    hsButton1->setRadius(3.0f);
+    hsButton1->setBounds(23,1,20,17);
+    hsButton1->setEnabledState(false);
+    hsButton1->setCorners(true, false, true, false);
+    hsButton1->addListener(this);
+    addAndMakeVisible(hsButton1);
+
+    hsButton2 = new UtilityButton(" ", Font("Small Text", 13, Font::plain));
+    hsButton2->setRadius(3.0f);
+    hsButton2->setBounds(43,1,20,17);
+    hsButton2->setEnabledState(false);
+    hsButton2->setCorners(false, true, false, true);
+    hsButton2->addListener(this);
+    addAndMakeVisible(hsButton2);
+
+    checkEnabledState();
 }
 
 HeadstageOptionsInterface::~HeadstageOptionsInterface()
@@ -258,6 +403,37 @@ HeadstageOptionsInterface::~HeadstageOptionsInterface()
 
 }
 
+void HeadstageOptionsInterface::checkEnabledState()
+{
+    isEnabled = (board->isHeadstageEnabled(hsNumber1) || 
+                 board->isHeadstageEnabled(hsNumber2));
+
+    if (board->isHeadstageEnabled(hsNumber1))
+    {
+        channelsOnHs1 = 32;
+        hsButton1->setLabel(String(channelsOnHs1));
+        hsButton1->setEnabledState(true);
+    } else {
+        channelsOnHs1 = 0;
+        hsButton1->setLabel(" ");
+        hsButton1->setEnabledState(false);
+    }
+
+    if (board->isHeadstageEnabled(hsNumber2))
+    {
+        channelsOnHs2 = 32;
+        hsButton2->setLabel(String(channelsOnHs2));
+        hsButton2->setEnabledState(true);
+    } else {
+        channelsOnHs2 = 0;
+        hsButton2->setLabel(" ");
+        hsButton2->setEnabledState(false);
+    }
+
+    repaint();
+
+}
+
 void HeadstageOptionsInterface::buttonClicked(Button* button)
 {
 
@@ -265,35 +441,35 @@ void HeadstageOptionsInterface::buttonClicked(Button* button)
     {
 
         //std::cout << "Acquisition is not active" << std::endl;
-        if (isEnabled)
+        if (button == hsButton1)
         {
-            isEnabled = false;
-        }
-        else
+            if (channelsOnHs1 == 32)
+                channelsOnHs1 = 16;
+            else
+                channelsOnHs1 = 32;
+
+            //std::cout << "HS1 has " << channelsOnHs1 << " channels." << std::endl;
+
+            hsButton1->setLabel(String(channelsOnHs1));
+            board->setNumChannels(hsNumber1, channelsOnHs1);
+
+        } else if (button == hsButton2)
         {
-            isEnabled = true;
-        }
+            if (channelsOnHs2 == 32)
+                channelsOnHs2 = 16;
+            else
+                channelsOnHs2 = 32;
 
-        board->enableHeadstage(hsNumber, isEnabled);
+            hsButton2->setLabel(String(channelsOnHs2));
+            board->setNumChannels(hsNumber2, channelsOnHs2);
+        }
 
-        repaint();
 
         editor->getEditorViewport()->makeEditorVisible(editor, false, true);
     }
 
 }
 
-// void HeadstageOptionsInterface::mouseUp(const MouseEvent& event)
-// {
-// 	///>>>> ???? WHY ISN"T THIS WORKING?
-
-// 	if (event.eventComponent == this)
-// 	{
-
-
-// 	}
-
-// }
 
 void HeadstageOptionsInterface::paint(Graphics& g)
 {
@@ -306,8 +482,8 @@ void HeadstageOptionsInterface::paint(Graphics& g)
     else
         g.setColour(Colours::grey);
 
-    g.setFont(Font("Small Text",20,Font::plain));
+    g.setFont(Font("Small Text",15,Font::plain));
 
-    g.drawText(name, 8, 5, 200, 15, Justification::left, false);
+    g.drawText(name, 8, 2, 200, 15, Justification::left, false);
 
 }
\ No newline at end of file
diff --git a/Source/Processors/Editors/RHD2000Editor.h b/Source/Processors/Editors/RHD2000Editor.h
index 49aa01c799530da8e8d226695bcd41b0262c0d82..5ae7c7f3891a369aa392d28751572a1e31faaa28 100644
--- a/Source/Processors/Editors/RHD2000Editor.h
+++ b/Source/Processors/Editors/RHD2000Editor.h
@@ -27,6 +27,8 @@
 #include "../../../JuceLibraryCode/JuceHeader.h"
 #include "GenericEditor.h"
 
+#include "SpikeDetectorEditor.h" // for ElectrodeButton
+
 class HeadstageOptionsInterface;
 class SampleRateInterface;
 class BandwidthInterface;
@@ -50,10 +52,27 @@ public:
     RHD2000Editor(GenericProcessor* parentNode, RHD2000Thread*, bool useDefaultParameterEditors);
     ~RHD2000Editor();
 
+    void buttonEvent(Button* button);
+
+    void scanPorts();
+
+    void startAcquisition();
+    void stopAcquisition();
+
+    void channelChanged(int chan);
+
 private:
 
     OwnedArray<HeadstageOptionsInterface> headstageOptionsInterfaces;
-    ScopedPointer<SampleRateInterface> RateInterface;
+    OwnedArray<ElectrodeButton> electrodeButtons;
+
+    ScopedPointer<SampleRateInterface> sampleRateInterface;
+    ScopedPointer<BandwidthInterface> bandwidthInterface;
+
+    ScopedPointer<UtilityButton> rescanButton;
+    ScopedPointer<UtilityButton> adcButton;
+
+    ScopedPointer<Label> audioLabel;
 
     RHD2000Thread* board;
 
@@ -73,9 +92,12 @@ public:
 
     void buttonClicked(Button* button);
 
+    void checkEnabledState();
+
 private:
 
-    int hsNumber;
+    int hsNumber1, hsNumber2;
+    int channelsOnHs1, channelsOnHs2;
     String name;
 
     bool isEnabled;
@@ -83,7 +105,8 @@ private:
     RHD2000Thread* board;
     RHD2000Editor* editor;
 
-    ScopedPointer<UtilityButton> enabledButton;
+    ScopedPointer<UtilityButton> hsButton1;
+    ScopedPointer<UtilityButton> hsButton2;
 
 };
 
@@ -102,6 +125,8 @@ private:
 
     String name;
 
+    String lastLowCutString, lastHighCutString;
+
     RHD2000Thread* board;
     RHD2000Editor* editor;
 
diff --git a/Source/Processors/Editors/ResamplingNodeEditor.h b/Source/Processors/Editors/ResamplingNodeEditor.h
index 58878b2ec85843c495524dd16e95c3cd2e192d22..ee3fce9c7f280b7456dcd9934ae14dce92e58a23 100644
--- a/Source/Processors/Editors/ResamplingNodeEditor.h
+++ b/Source/Processors/Editors/ResamplingNodeEditor.h
@@ -42,8 +42,8 @@ public:
     ResamplingNodeEditor(GenericProcessor* parentNode, bool useDefaultParameterEditors);
     virtual ~ResamplingNodeEditor();
 
-    void startAcquisition();
-    void stopAcquisition();
+   // void startAcquisition();
+    //void stopAcquisition();
 
 private:
 
diff --git a/Source/Processors/Editors/SpikeDetectorEditor.cpp b/Source/Processors/Editors/SpikeDetectorEditor.cpp
index 19b31041c723bebad9550da6d171d1cb43f0c377..20bfdee9d222af90d6e318903483ca9535adf8a0 100755
--- a/Source/Processors/Editors/SpikeDetectorEditor.cpp
+++ b/Source/Processors/Editors/SpikeDetectorEditor.cpp
@@ -175,12 +175,11 @@ void SpikeDetectorEditor::sliderEvent(Slider* slider)
 void SpikeDetectorEditor::buttonEvent(Button* button)
 {
 
-    if (electrodeEditorButtons[0]->getToggleState()) // EDIT is active
-    {
 
-        std::cout << "Editing active." << std::endl;
+    if (electrodeButtons.contains((ElectrodeButton*) button))
+    {
 
-        if (electrodeButtons.contains((ElectrodeButton*) button))
+        if (electrodeEditorButtons[0]->getToggleState()) // EDIT is active
         {
             ElectrodeButton* eb = (ElectrodeButton*) button;
             int electrodeNum = eb->getChannelNum()-1;
@@ -195,9 +194,27 @@ void SpikeDetectorEditor::buttonEvent(Button* button)
             thresholdSlider->setActive(true);
             thresholdSlider->setValue(processor->getChannelThreshold(electrodeList->getSelectedItemIndex(),
                                                                      electrodeButtons.indexOf((ElectrodeButton*) button)));
+        } else {
+
+            SpikeDetector* processor = (SpikeDetector*) getProcessor();
+
+            ElectrodeButton* eb = (ElectrodeButton*) button;
+            int electrodeNum = electrodeList->getSelectedItemIndex();
+            int channelNum = electrodeButtons.indexOf(eb);
+
+            processor->setChannelActive(electrodeNum,
+                                        channelNum,
+                                        button->getToggleState());
+
+            std::cout << "Disabling channel " << channelNum <<
+                         " of electrode " << electrodeNum << std::endl;
+
         }
+    
+
     }
 
+
     int num = numElectrodes->getText().getIntValue();
 
     if (button == upButton)
@@ -530,7 +547,8 @@ void ElectrodeButton::paintButton(Graphics& g, bool isMouseOver, bool isButtonDo
 
     g.drawRect(0,0,getWidth(),getHeight(),1.0);
 
-    g.drawText(String(chan),0,0,getWidth(),getHeight(),Justification::centred,true);
+    if (chan >= 0)
+        g.drawText(String(chan),0,0,getWidth(),getHeight(),Justification::centred,true);
 }
 
 
diff --git a/Source/Processors/Editors/SpikeDisplayEditor.cpp b/Source/Processors/Editors/SpikeDisplayEditor.cpp
index 565967fa5b872b97228370d7918d68d384fa40eb..0f9fc3db2874aa5d0405f0a21b1ca8b5c913432c 100755
--- a/Source/Processors/Editors/SpikeDisplayEditor.cpp
+++ b/Source/Processors/Editors/SpikeDisplayEditor.cpp
@@ -143,7 +143,7 @@ void SpikeDisplayEditor::initializeButtons()
     allSubChansBtn->setToggleState(true, false);
     x += (w+xPad) * 2;
 
-    for (int i=0; i<nSubChannels; i++)
+    for (int i = 0; i < nSubChannels; i++)
     {
         String s = "";
         s += i;
diff --git a/Source/Processors/Editors/VisualizerEditor.cpp b/Source/Processors/Editors/VisualizerEditor.cpp
index 4ae16d93a285fad2ba61b2627773a74e8035eb6d..ff432a7bfd4031996702babf17eb177bf18be598 100755
--- a/Source/Processors/Editors/VisualizerEditor.cpp
+++ b/Source/Processors/Editors/VisualizerEditor.cpp
@@ -170,6 +170,7 @@ void VisualizerEditor::buttonEvent(Button* button)
         {
 
             canvas = createNewCanvas();
+            canvas->update();
 
             if (isPlaying)
                 canvas->beginAnimation();
diff --git a/Source/Processors/FileReader.cpp b/Source/Processors/FileReader.cpp
index 26dd11906045e6c03e1986d64d562c6233a6b07f..f8c2929e82a22ea433ce17ccfd16350d1c8d34c4 100644
--- a/Source/Processors/FileReader.cpp
+++ b/Source/Processors/FileReader.cpp
@@ -50,6 +50,17 @@ AudioProcessorEditor* FileReader::createEditor()
 
 }
 
+bool FileReader::isReady()
+{
+	if (input == 0)
+	{
+		sendActionMessage("No file selected in File Reader.");
+		return false;
+	} else {
+		return true;
+	}
+}
+
 
 float FileReader::getDefaultSampleRate()
 {
diff --git a/Source/Processors/FileReader.h b/Source/Processors/FileReader.h
index 38e5c697412298296cd82f05d88115f65c2f2d58..d688cba448837ae6d46f1504021a099d79e7f711 100644
--- a/Source/Processors/FileReader.h
+++ b/Source/Processors/FileReader.h
@@ -60,6 +60,8 @@ public:
 
     void updateSettings();
 
+    bool isReady();
+
     bool isSource()
     {
     	return true;
diff --git a/Source/Processors/FilterNode.cpp b/Source/Processors/FilterNode.cpp
index 7b7500f3597404978519241a036fb93ec3c890f2..ac453c109920bb17a2d5ac45afb565a44f1aa7a0 100755
--- a/Source/Processors/FilterNode.cpp
+++ b/Source/Processors/FilterNode.cpp
@@ -249,11 +249,11 @@ void FilterNode::process(AudioSampleBuffer& buffer,
 void FilterNode::saveCustomChannelParametersToXml(XmlElement* channelInfo, int channelNumber, bool isEventChannel)
 {
 
-    std::cout << "CHANNEL: " << channelNumber << std::endl;
+    //std::cout << "CHANNEL: " << channelNumber << std::endl;
 
     if (!isEventChannel && channelNumber > -1 && channelNumber < highCuts.size())
     {
-        std::cout << "Saving custom parameters for filter node." << std::endl;
+        //std::cout << "Saving custom parameters for filter node." << std::endl;
 
          XmlElement* channelParams = channelInfo->createNewChildElement("PARAMETERS");
          channelParams->setAttribute("highcut",highCuts[channelNumber]);
@@ -285,4 +285,4 @@ void FilterNode::loadCustomChannelParametersFromXml(XmlElement* channelInfo, boo
     }
 
 
-}
+}
diff --git a/Source/Processors/GenericProcessor.cpp b/Source/Processors/GenericProcessor.cpp
index 1c9306941f922b2a7e0b9b191eef3fa0078f3b26..e935833ecf9a1767d6df54f4665ca0194558520f 100755
--- a/Source/Processors/GenericProcessor.cpp
+++ b/Source/Processors/GenericProcessor.cpp
@@ -337,6 +337,8 @@ void GenericProcessor::update()
         {
             Channel* sourceChan = sourceNode->eventChannels[i];
             Channel* ch = new Channel(*sourceChan);
+            ch->sampleRate = getDefaultSampleRate();
+            ch->bitVolts = getDefaultBitVolts();
             eventChannels.add(ch);
         }
 
diff --git a/Source/Processors/RecordNode.cpp b/Source/Processors/RecordNode.cpp
index bfcc0e1eb80064d4409c0917cbb6c280eab37430..8115f6ac0d7d0c71f14cc7e7a9c012842a50edfa 100755
--- a/Source/Processors/RecordNode.cpp
+++ b/Source/Processors/RecordNode.cpp
@@ -472,15 +472,17 @@ String RecordNode::generateHeader(Channel* ch)
     {
 
         header += "header.channelType = 'Continuous';\n";
-
-        header += "header.sampleRate = ";
-        header += String(ch->sampleRate);
-        header += ";\n";
-        header += "header.blockLength = '";
-        header += BLOCK_LENGTH;
-        header += "';\n";
     }
 
+    header += "header.sampleRate = ";
+    header += String(channelPointers[0]->sampleRate); // all channels need to have the
+                                                      // same sample rate under the current
+                                                      // scheme
+    header += ";\n";
+    header += "header.blockLength = ";
+    header += BLOCK_LENGTH;
+    header += ";\n";
+
     header += "header.bitVolts = ";
     header += String(ch->bitVolts);
     header += ";\n";
diff --git a/Source/Processors/SourceNode.cpp b/Source/Processors/SourceNode.cpp
index c04d71b034df54e1db588595056161abf709345f..5a8b53ccc8cd2f88e386c5b6ec1b6465b62bbc46 100755
--- a/Source/Processors/SourceNode.cpp
+++ b/Source/Processors/SourceNode.cpp
@@ -114,6 +114,7 @@ void SourceNode::updateSettings()
     {
 
         inputBuffer = dataThread->getBufferAddress();
+        dataThread->updateChannelNames();
         std::cout << "Input buffer address is " << inputBuffer << std::endl;
     }
 
@@ -125,6 +126,7 @@ void SourceNode::updateSettings()
         eventChannels.add(ch);
     }
 
+
 }
 
 void SourceNode::actionListenerCallback(const String& msg)
@@ -209,6 +211,9 @@ AudioProcessorEditor* SourceNode::createEditor()
     if (getName().equalsIgnoreCase("Rhythm FPGA"))
     {
         editor = new RHD2000Editor(this, (RHD2000Thread*) dataThread.get(), true);
+
+      //  RHD2000Editor* r2e = (RHD2000Editor*) editor.get();
+      //  r2e->scanPorts();
     }
   //  else if (getName().equalsIgnoreCase("File Reader"))
   //  {
diff --git a/Source/Processors/SpikeDetector.cpp b/Source/Processors/SpikeDetector.cpp
index 46fcd17d411428e275ef8b72598eb3248d22c9d5..1a5025421829e486c36f58e726e6d71872a5ec39 100755
--- a/Source/Processors/SpikeDetector.cpp
+++ b/Source/Processors/SpikeDetector.cpp
@@ -165,7 +165,7 @@ bool SpikeDetector::addElectrode(int nChans)
 
 float SpikeDetector::getDefaultThreshold()
 {
-    return 200.0f;
+    return 75.0f;
 }
 
 StringArray SpikeDetector::getElectrodeNames()
@@ -222,9 +222,20 @@ int SpikeDetector::getChannel(int index, int i)
 }
 
 
-void SpikeDetector::setChannelActive(int electrodeIndex, int i, bool active)
+void SpikeDetector::setChannelActive(int electrodeIndex, int subChannel, bool active)
 {
-    *(electrodes[electrodeIndex]->isActive+i) = active;
+
+
+    currentElectrode = electrodeIndex;
+    currentChannelIndex = subChannel;
+
+    std::cout << "Setting parameter 98 to " << active << std::endl;
+
+    if (active)
+        setParameter(98, 1);
+    else
+        setParameter(98, 0);
+    
 }
 
 bool SpikeDetector::isChannelActive(int electrodeIndex, int i)
@@ -252,6 +263,12 @@ void SpikeDetector::setParameter(int parameterIndex, float newValue)
     if (parameterIndex == 99 && currentElectrode > -1)
     {
         *(electrodes[currentElectrode]->thresholds+currentChannelIndex) = newValue;
+    } else if (parameterIndex == 98 && currentElectrode > -1)
+    {
+        if (newValue == 0.0f)
+            *(electrodes[currentElectrode]->isActive+currentChannelIndex) = false;
+        else
+            *(electrodes[currentElectrode]->isActive+currentChannelIndex) = true;
     }
 }
 
@@ -343,17 +360,37 @@ void SpikeDetector::addWaveformToSpikeObject(SpikeObject* s,
     s->threshold[currentChannel] = (int) *(electrodes[electrodeNumber]->thresholds+currentChannel) / channels[chan]->bitVolts * 1000;
 
     // cycle through buffer
-    for (int sample = 0; sample < spikeLength; sample++)
+
+    if (isChannelActive(electrodeNumber, currentChannel))
     {
 
-        // warning -- be careful of bitvolts conversion
-        s->data[currentIndex] = uint16(getNextSample(*(electrodes[electrodeNumber]->channels+currentChannel)) / channels[chan]->bitVolts + 32768);
+        for (int sample = 0; sample < spikeLength; sample++)
+        {
+
+            // warning -- be careful of bitvolts conversion
+
 
-        currentIndex++;
-        sampleIndex++;
 
-        //std::cout << currentIndex << std::endl;
+            s->data[currentIndex] = uint16(getNextSample(*(electrodes[electrodeNumber]->channels+currentChannel)) / channels[chan]->bitVolts + 32768);
 
+            currentIndex++;
+            sampleIndex++;
+
+            //std::cout << currentIndex << std::endl;
+
+        }
+    } else {
+        for (int sample = 0; sample < spikeLength; sample++)
+        {
+
+            // insert a blank spike if the 
+            s->data[currentIndex] = 0; 
+            currentIndex++;
+            sampleIndex++;
+
+            //std::cout << currentIndex << std::endl;
+
+        }
     }
 
 
diff --git a/Source/Processors/SpikeDisplayNode.cpp b/Source/Processors/SpikeDisplayNode.cpp
index 008bb1c21b9c01b45b1a95979af30ce06bcf7a73..161aed18f00c95c9393e388042bb8a21f9a4ac9e 100755
--- a/Source/Processors/SpikeDisplayNode.cpp
+++ b/Source/Processors/SpikeDisplayNode.cpp
@@ -125,10 +125,10 @@ void SpikeDisplayNode::setParameter(int param, float val)
 
 
 
-void SpikeDisplayNode::process(AudioSampleBuffer& buffer, MidiBuffer& midiMessages, int& nSamples)
+void SpikeDisplayNode::process(AudioSampleBuffer& buffer, MidiBuffer& events, int& nSamples)
 {
 
-    checkForEvents(midiMessages); // automatically calls 'handleEvent
+    checkForEvents(events); // automatically calls 'handleEvent
 
 }
 
@@ -143,21 +143,3 @@ void SpikeDisplayNode::handleEvent(int eventType, MidiMessage& event, int sample
     }
 
 }
-
-bool SpikeDisplayNode::getNextSpike(SpikeObject* spike)
-{
-    std::cout<<"SpikeDisplayNode::getNextSpike()"<<std::endl;
-    /*
-    if (bufferSize<1 || spikebuffer.empty())
-    	return false;
-    else{
-    	SpikeObject s = spikebuffer.front();
-    	spikebuffer.pop();
-    	bufferSize--;
-    	*spike = s;
-    	return true;
-    }
-    */
-    return false;
-
-}
\ No newline at end of file
diff --git a/Source/Processors/SpikeDisplayNode.h b/Source/Processors/SpikeDisplayNode.h
index 54922440afe86becbe2164eed36ae1e62591c93c..66dcb85b44be709aece4b795320145063c9c961e 100755
--- a/Source/Processors/SpikeDisplayNode.h
+++ b/Source/Processors/SpikeDisplayNode.h
@@ -75,8 +75,6 @@ public:
     int getNumberOfChannelsForElectrode(int i);
     int getNumElectrodes();
 
-    bool getNextSpike(SpikeObject* spike);
-
 private:
 
     int numberOfSources;
diff --git a/Source/Processors/Visualization/LfpDisplayCanvas.cpp b/Source/Processors/Visualization/LfpDisplayCanvas.cpp
index 9cf1e5e94e27fd5efcfdd91e1e1c269c2e109de5..1235c8e1316e0a7fef9710368ee9c38b1b6d8b2d 100755
--- a/Source/Processors/Visualization/LfpDisplayCanvas.cpp
+++ b/Source/Processors/Visualization/LfpDisplayCanvas.cpp
@@ -40,6 +40,7 @@ LfpDisplayCanvas::LfpDisplayCanvas(LfpDisplayNode* processor_) :
     std::cout << "Setting displayBufferSize on LfpDisplayCanvas to " << displayBufferSize << std::endl;
 
     screenBuffer = new AudioSampleBuffer(MAX_N_CHAN, MAX_N_SAMP);
+    screenBuffer->clear();
 
     viewport = new Viewport();
     lfpDisplay = new LfpDisplay(this, viewport);
@@ -52,10 +53,15 @@ LfpDisplayCanvas::LfpDisplayCanvas(LfpDisplayNode* processor_) :
 
     scrollBarThickness = viewport->getScrollBarThickness();
 
+
+    //viewport->getVerticalScrollBar()->addListener(this->scrollBarMoved(viewport->getVerticalScrollBar(), 1.0));
+
+
+
     addAndMakeVisible(viewport);
     addAndMakeVisible(timescale);
 
-	voltageRanges.add("50");
+    voltageRanges.add("50");
     voltageRanges.add("100");
     voltageRanges.add("500");
     voltageRanges.add("1000");
@@ -112,7 +118,7 @@ LfpDisplayCanvas::~LfpDisplayCanvas()
 void LfpDisplayCanvas::resized()
 {
 
-    timescale->setBounds(0,0,getWidth()-scrollBarThickness,30);
+    timescale->setBounds(leftmargin,0,getWidth()-scrollBarThickness-leftmargin,30);
     viewport->setBounds(0,30,getWidth(),getHeight()-90);
 
     lfpDisplay->setBounds(0,0,getWidth()-scrollBarThickness, getChannelHeight()*nChans);
@@ -122,7 +128,7 @@ void LfpDisplayCanvas::resized()
     spreadSelection->setBounds(345,getHeight()-30,100,25);
 
    // std::cout << "Canvas thinks LfpDisplay should be this high: " 
-    //	<< lfpDisplay->getTotalHeight() << std::endl;
+    //  << lfpDisplay->getTotalHeight() << std::endl;
 
 }
 
@@ -146,7 +152,7 @@ void LfpDisplayCanvas::endAnimation()
 
 void LfpDisplayCanvas::update()
 {
-    nChans = processor->getNumInputs();
+    nChans = jmax(processor->getNumInputs(),1);
     sampleRate = processor->getSampleRate();
 
     std::cout << "Setting num inputs on LfpDisplayCanvas to " << nChans << std::endl;
@@ -154,10 +160,20 @@ void LfpDisplayCanvas::update()
     refreshScreenBuffer();
 
     lfpDisplay->setNumChannels(nChans);
-    lfpDisplay->setBounds(0,0,getWidth()-scrollBarThickness*2, lfpDisplay->getTotalHeight());
 
+    // update channel names
+	for (int i = 0; i < processor->getNumInputs(); i++)
+    {
 
-    repaint();
+    	String chName = processor->channels[i]->getName();
+
+    	//std::cout << chName << std::endl;
+
+    	lfpDisplay->channelInfo[i]->setName(chName);
+
+    }
+
+    lfpDisplay->setBounds(0,0,getWidth()-scrollBarThickness*2, lfpDisplay->getTotalHeight());
 
 }
 
@@ -185,9 +201,12 @@ void LfpDisplayCanvas::comboBoxChanged(ComboBox* cb)
     timescale->setTimebase(timebase);
 }
 
+
+
+
 int LfpDisplayCanvas::getChannelHeight()
 {
-	return spreads[spreadSelection->getSelectedId()-1].getIntValue();
+    return spreads[spreadSelection->getSelectedId()-1].getIntValue();
 
 }
 
@@ -227,46 +246,58 @@ void LfpDisplayCanvas::refreshScreenBuffer()
 
     // for (int i = 0; i < w; i++)
     // {
-    // 	float x = float(i);
+    //  float x = float(i);
 
-    // 	for (int n = 0; n < nChans; n++)
-    // 	{
-    // 		waves[n][i*2] = x;
-    // 		waves[n][i*2+1] = 0.5f; // line in center of display
-    // 	}
+    //  for (int n = 0; n < nChans; n++)
+    //  {
+    //      waves[n][i*2] = x;
+    //      waves[n][i*2+1] = 0.5f; // line in center of display
+    //  }
     // }
 
 }
 
 void LfpDisplayCanvas::updateScreenBuffer()
 {
+
+
     // copy new samples from the displayBuffer into the screenBuffer (waves)
+    int maxSamples = lfpDisplay->getWidth() - leftmargin;
 
-    lastScreenBufferIndex = screenBufferIndex;
+    if (screenBufferIndex >= maxSamples) // wrap around if we reached right edge before
+        screenBufferIndex = 0;
 
-    int maxSamples = lfpDisplay->getWidth();
+    lastScreenBufferIndex = screenBufferIndex;
 
     int index = processor->getDisplayBufferIndex();
 
-    int nSamples = index - displayBufferIndex;
+    int nSamples =  index - displayBufferIndex; // N new samples to be addeddisplayBufferIndex
 
     if (nSamples < 0) // buffer has reset to 0
     {
         nSamples = (displayBufferSize - displayBufferIndex) + index;
     }
 
-    float ratio = sampleRate * timebase / float(getWidth());
+    float ratio = sampleRate * timebase / float(getWidth() - leftmargin - scrollBarThickness);
 
-    // this number is crucial:
+    // this number is crucial: converting from samples to values (in px) for the screen buffer
     int valuesNeeded = (int) float(nSamples) / ratio;
 
+
+    if ( screenBufferIndex + valuesNeeded > maxSamples) // crop number of samples to fit cavas width
+    {
+            valuesNeeded = maxSamples - screenBufferIndex;
+    }
+
     float subSampleOffset = 0.0;
-    int nextPos = (displayBufferIndex + 1) % displayBufferSize;
+
+    displayBufferIndex = displayBufferIndex % displayBufferSize; // make sure we're not overshooting
+    int nextPos = (displayBufferIndex + 1) % displayBufferSize; //  position next to displayBufferIndex in display buffer to copy from
 
     if (valuesNeeded > 0 && valuesNeeded < 1000)
     {
 
-        for (int i = 0; i < valuesNeeded; i++)
+        for (int i = 0; i < valuesNeeded; i++) // also fill one extra sample for line drawing interpolation to match across draws
         {
             float gain = 1.0;
             float alpha = (float) subSampleOffset;
@@ -289,26 +320,14 @@ void LfpDisplayCanvas::updateScreenBuffer()
                                       1, // numSamples
                                       alpha*gain); // gain
 
-                //waves[channel][screenBufferIndex*2+1] =
-                //	*(displayBuffer->getSampleData(channel, displayBufferIndex))*invAlpha*gain*displayGain;
-
-                //waves[channel][screenBufferIndex*2+1] +=
-                //	*(displayBuffer->getSampleData(channel, nextPos))*alpha*gain*displayGain;
-
-                //waves[channel][screenBufferIndex*2+1] += 0.5f; // to center in viewport
 
             }
 
-            //// now do the event channel
-            ////	waves[nChans][screenBufferIndex*2+1] =
-            //		*(displayBuffer->getSampleData(nChans, displayBufferIndex));
-
-
             subSampleOffset += ratio;
 
             while (subSampleOffset >= 1.0)
             {
-                if (++displayBufferIndex >= displayBufferSize)
+                if (++displayBufferIndex > displayBufferSize)
                     displayBufferIndex = 0;
 
                 nextPos = (displayBufferIndex + 1) % displayBufferSize;
@@ -316,9 +335,9 @@ void LfpDisplayCanvas::updateScreenBuffer()
             }
 
             screenBufferIndex++;
-            screenBufferIndex %= maxSamples;
 
         }
+                
 
     }
     else
@@ -341,20 +360,29 @@ void LfpDisplayCanvas::paint(Graphics& g)
 {
 
     //std::cout << "Painting" << std::endl;
-    g.setColour(Colour(25,25,25));
-
+    g.setColour(Colour(0,18,43)); //background color
     g.fillRect(0, 0, getWidth(), getHeight());
 
-    g.setColour(Colour(40,40,40));
+    g.setGradientFill(ColourGradient(Colour(50,50,50),0,0,
+                                     Colour(25,25,25),0,30,
+                                     false));
 
-    int w = getWidth()-scrollBarThickness;
+    g.fillRect(0, 0, getWidth()-scrollBarThickness, 30);
 
-    for (int i = 1; i < 10; i++)
+    g.setColour(Colours::black);
+
+    g.drawLine(0,30,getWidth()-scrollBarThickness,30);
+
+    g.setColour(Colour(25,25,60)); // timing grid color
+
+    int w = getWidth()-scrollBarThickness-leftmargin;
+
+    for (int i = 0; i < 10; i++)
     {
-        if (i == 5)
-            g.drawLine(w/10*i,0,w/10*i,getHeight()-60,3.0f);
+        if (i == 5 || i == 0)
+            g.drawLine(w/10*i+leftmargin,0,w/10*i+leftmargin,getHeight()-60,3.0f);
         else
-            g.drawLine(w/10*i,0,w/10*i,getHeight()-60,1.0f);
+            g.drawLine(w/10*i+leftmargin,0,w/10*i+leftmargin,getHeight()-60,1.0f);
     }
 
     g.drawLine(0,getHeight()-60,getWidth(),getHeight()-60,3.0f);
@@ -364,17 +392,16 @@ void LfpDisplayCanvas::paint(Graphics& g)
     g.setColour(Colour(100,100,100));
 
     g.drawText("Voltage range (uV)",5,getHeight()-55,300,20,Justification::left, false);
-
     g.drawText("Timebase (s)",175,getHeight()-55,300,20,Justification::left, false);
     g.drawText("Spread (px)",345,getHeight()-55,300,20,Justification::left, false);
 
 }
 
-void LfpDisplayCanvas::refresh()
+void LfpDisplayCanvas::refresh() 
 {
     updateScreenBuffer();
 
-    lfpDisplay->refresh();
+    lfpDisplay->refresh(); // redraws only the new part of the screen buffer
 
     //getPeer()->performAnyPendingRepaintsNow();
 
@@ -429,15 +456,7 @@ LfpTimescale::~LfpTimescale()
 void LfpTimescale::paint(Graphics& g)
 {
 
-    g.setGradientFill(ColourGradient(Colour(50,50,50),0,0,
-                                     Colour(25,25,25),0,getHeight(),
-                                     false));
-
-    g.fillAll();
-
-    g.setColour(Colours::black);
-
-    g.drawLine(0,getHeight(),getWidth(),getHeight());
+    
 
     g.setFont(font);
 
@@ -485,15 +504,29 @@ LfpDisplay::LfpDisplay(LfpDisplayCanvas* c, Viewport* v) :
 
     addMouseListener(this, true);
 
-    for (int i = 0; i < 10; i++)
-    {
-        channelColours.add(Colour(200,200,255-i*25));
-    }
-
-    for (int i = 10; i > -1; i--)
-    {
-        channelColours.add(Colour(200,200,255-i*25));
-    }
+    // hue cycle
+    //for (int i = 0; i < 15; i++)
+    //{
+    //    channelColours.add(Colour(float(sin((3.14/2)*(float(i)/15))),float(1.0),float(1),float(1.0)));
+    //}
+
+    //hand-built palette
+    channelColours.add(Colour(224,185,36));
+    channelColours.add(Colour(214,210,182));
+    channelColours.add(Colour(243,119,33));
+    channelColours.add(Colour(186,157,168));
+    channelColours.add(Colour(237,37,36));
+    channelColours.add(Colour(179,122,79));
+    channelColours.add(Colour(217,46,171));
+    channelColours.add(Colour(217, 139,196));
+    channelColours.add(Colour(101,31,255));
+    channelColours.add(Colour(141,111,181));
+    channelColours.add(Colour(48,117,255));
+    channelColours.add(Colour(184,198,224));
+    channelColours.add(Colour(116,227,156));
+    channelColours.add(Colour(150,158,155));
+    channelColours.add(Colour(82,173,0));
+    channelColours.add(Colour(125,99,32));
 
 }
 
@@ -509,6 +542,7 @@ void LfpDisplay::setNumChannels(int numChannels)
     deleteAllChildren();
 
     channels.clear();
+    channelInfo.clear();
 
     totalHeight = 0;
 
@@ -527,6 +561,16 @@ void LfpDisplay::setNumChannels(int numChannels)
 
         channels.add(lfpChan);
 
+        LfpChannelDisplayInfo* lfpInfo = new LfpChannelDisplayInfo(canvas, i);
+
+        lfpInfo->setColour(channelColours[i % channelColours.size()]);
+        lfpInfo->setRange(range);
+        lfpInfo->setChannelHeight(canvas->getChannelHeight());
+
+        addAndMakeVisible(lfpInfo);
+
+        channelInfo.add(lfpInfo);
+
         totalHeight += lfpChan->getChannelHeight();
 
     }
@@ -535,7 +579,7 @@ void LfpDisplay::setNumChannels(int numChannels)
 
 int LfpDisplay::getTotalHeight()
 {
-	return totalHeight;
+    return totalHeight;
 }
 
 void LfpDisplay::resized()
@@ -543,20 +587,29 @@ void LfpDisplay::resized()
 
     int totalHeight = 0;
 
-    for (int i = 0; i < numChans; i++)
+    for (int i = 0; i < channels.size(); i++)
     {
 
         LfpChannelDisplay* disp = channels[i];
 
-        disp->setBounds(0,
+        disp->setBounds(canvas->leftmargin,
                 totalHeight-disp->getChannelOverlap()/2,
                 getWidth(),
                 disp->getChannelHeight()+disp->getChannelOverlap());
 
+        LfpChannelDisplayInfo* info = channelInfo[i];
+
+        info->setBounds(0,
+                totalHeight-disp->getChannelOverlap()/2,
+                canvas->leftmargin,
+                disp->getChannelHeight()+disp->getChannelOverlap());
+
         totalHeight += disp->getChannelHeight();
 
     }
 
+    canvas->fullredraw = true; //issue full redraw 
+
    // std::cout << "Total height: " << totalHeight << std::endl;
 
 }
@@ -577,73 +630,148 @@ void LfpDisplay::refresh()
     for (int i = 0; i < numChans; i++)
     {
 
-        int componentTop = getChildComponent(i)->getY();
-        int componentBottom = getChildComponent(i)->getHeight() + componentTop;
+        int componentTop = channels[i]->getY();
+        int componentBottom = channels[i]->getHeight() + componentTop;
 
         if ((topBorder <= componentBottom && bottomBorder >= componentTop))
         {
-            getChildComponent(i)->repaint();
-
+            if (canvas->fullredraw)
+            {    
+                channels[i]->fullredraw = true;
+                channels[i]->repaint();
+                channelInfo[i]->repaint();
+
+            } else {
+                channels[i]->repaint(canvas->lastScreenBufferIndex-2, 0, (canvas->screenBufferIndex-canvas->lastScreenBufferIndex)+3, getChildComponent(i)->getHeight() ); //repaint only the updated portion
+                // we redraw from -2 to +1 relative to the real redraw window, the -2 makes sure that the lines join nicely, and the +1 draws the vertical update line
+            }
             //std::cout << i << std::endl;
         }
 
     }
-
+        
+    canvas->fullredraw = false;
 }
 
 void LfpDisplay::setRange(float r)
 {
-
     range = r;
 
     for (int i = 0; i < numChans; i++)
     {
-
         channels[i]->setRange(range);
-
     }
+}
 
+int LfpDisplay::getRange()
+{
+    return channels[0]->getRange();
 }
 
+
 void LfpDisplay::setChannelHeight(int r)
 {
 
     for (int i = 0; i < numChans; i++)
     {
         channels[i]->setChannelHeight(r);
+        channelInfo[i]->setChannelHeight(r);
     }
 
     resized();
 
 }
 
-void LfpDisplay::mouseDown(const MouseEvent& event)
+int LfpDisplay::getChannelHeight()
 {
-    //int x = event.getMouseDownX();
-    //int y = event.getMouseDownY();
+    return channels[0]->getChannelHeight();
+}
+
+
+
+ void LfpDisplay::mouseWheelMove(const MouseEvent&  e, const MouseWheelDetails&   wheel )   {
+    
+    //std::cout << "Mouse wheel " <<  e.mods.isCommandDown() << "  " << wheel.deltaY << std::endl;
+    
+    if (e.mods.isCommandDown()){ // CTRL + scroll wheel -> change channel spacing 
+        // 
+        // this should also scroll to keep the selected channel at a constant y!
+        //
+        int h = getChannelHeight();
+        if (wheel.deltaY>0){
+            setChannelHeight(h+1);            
+        } else{
+            if (h>5)
+                setChannelHeight(h-1);
+        }
+    } else {
+        if(e.mods.isShiftDown())  {// SHIFT + scroll wheel -> change channel range
+            int h= getRange();
+            if (wheel.deltaY>0){
+                setRange(h+10);            
+            } else{
+                if (h>11)
+                    setRange(h-10);
+            }
+
+        } else{ // just scroll
+            //  passes the event up to the viewport so the screen scrolls
+            if (viewport != nullptr && e.eventComponent == this) // passes only if it's not a listening event
+                viewport->mouseWheelMove(e.getEventRelativeTo(canvas), wheel);
+
+        }
+    }
+
+    canvas->fullredraw = true;//issue full redraw 
+
+    refresh();
 
-    //std::cout << "Mouse down at " << x << ", " << y << std::endl;
+ }
 
 
-    for (int n = 0; n < numChans; n++)
+void LfpDisplay::mouseDown(const MouseEvent& event)
+{
+    //int y = event.getMouseDownY(); //relative to each channel pos
+    MouseEvent canvasevent = event.getEventRelativeTo(viewport);
+    int y = canvasevent.getMouseDownY() + viewport->getViewPositionY(); // need to account for scrolling
+
+    int dist=0; int mindist=10000; int closest=5;
+    for (int n = 0; n < numChans; n++) // select closest instead of relying ot eventComponent
     {
         channels[n]->deselect();
+        
+        int cpos=(channels[n]->getY() + (channels[n]->getHeight()/2));
+        dist=int(abs( y - cpos )); 
+    
+        //std::cout << "Mouse down at " << y << " pos is "<< cpos << "n:" << n << "  dist " << dist << std::endl;
+
+        if (dist<mindist) {
+            mindist=dist-1;
+            closest=n;
+        }
     }
 
-    LfpChannelDisplay* lcd = (LfpChannelDisplay*) event.eventComponent;
+    //LfpChannelDisplay* lcd = (LfpChannelDisplay*) event.eventComponent;
+    //lcd->select();
 
-    lcd->select();
+    channels[closest]->select();
 
-    repaint();
+    canvas->fullredraw = true;//issue full redraw 
+
+    refresh();
 
 }
 
 // ------------------------------------------------------------------
 
 LfpChannelDisplay::LfpChannelDisplay(LfpDisplayCanvas* c, int channelNumber) :
-    canvas(c), isSelected(false), chan(channelNumber), channelHeight(40), channelOverlap(60), range(1000.0f)
+    canvas(c), isSelected(false), chan(channelNumber), channelHeight(40), channelOverlap(300), range(1000.0f)
 {
 
+
+	name = String(channelNumber+1); // default is to make the channelNumber the name
+
+
     channelHeightFloat = (float) channelHeight;
 
     channelFont = Font("Default", channelHeight*0.6, Font::plain);
@@ -662,14 +790,17 @@ void LfpChannelDisplay::paint(Graphics& g)
 
     //g.fillAll(Colours::grey);
 
-    g.setColour(Colours::yellow);
+    g.setColour(Colours::yellow);   // draw most recent drawn sample position
+    g.drawLine(canvas->screenBufferIndex+1, 0, canvas->screenBufferIndex+1, getHeight());
 
-    g.drawLine(canvas->screenBufferIndex, 0, canvas->screenBufferIndex, getHeight()-channelOverlap);
+    //g.setColour(Colours::red); // draw oldest drawn sample position 
+    //g.drawLine(canvas->lastScreenBufferIndex, 0, canvas->lastScreenBufferIndex, getHeight()-channelOverlap);
 
     int center = getHeight()/2;
 
     if (isSelected)
     {
+
         g.setColour(Colours::lightgrey);
         g.fillRect(0,center-channelHeight/2,10,channelHeight);
         g.drawLine(0,center+channelHeight/2,getWidth(),center+channelHeight/2);
@@ -686,56 +817,73 @@ void LfpChannelDisplay::paint(Graphics& g)
     g.drawLine(0, getHeight()/2, getWidth(), getHeight()/2);
 
     int stepSize = 1;
-	int from = 0;
-	int to = 0;
+    int from = 0; // for vertical line drawing in the LFP data 
+    int to = 0;
     g.setColour(lineColour);
 
-    for (int i = 0; i < getWidth()-stepSize; i += stepSize)
+    //for (int i = 0; i < getWidth()-stepSize; i += stepSize) // redraw entire display
+    int ifrom = canvas->lastScreenBufferIndex - 3; // need to start drawing a bit before the actual redraw windowfor the interpolated line to join correctly
+    
+    if (ifrom < 0) 
+        ifrom = 0;
+
+    int ito = canvas->screenBufferIndex - 1;
+
+    if (fullredraw)
+    {
+        ifrom = 0; //canvas->leftmargin;
+        ito = getWidth()-stepSize;
+        fullredraw = false;
+    }
+
+    for (int i = ifrom; i < ito ; i += stepSize) // redraw only changed portion
     {
 
-	   // drawLine makes for nice anti-aliased plots, but is pretty slow
-       // g.drawLine(i,
-       //           (canvas->getYCoord(chan, i)/range*channelHeightFloat)+getHeight()/2,
-       //            i+stepSize,
-       //             (canvas->getYCoord(chan, i+stepSize)/range*channelHeightFloat)+getHeight()/2);
-
-
-		// // pixel wise line plot has no anti-aliasing, but runs much faster
-		double a = (canvas->getYCoord(chan, i)/range*channelHeightFloat)+getHeight()/2;
-		double b = (canvas->getYCoord(chan, i+stepSize)/range*channelHeightFloat)+getHeight()/2;
-
-		if (a<b){
-			 from = (a);
-			 to = (b);
-		} else {
-			 from = (b);
-			 to = (a);
-		}
-		
-		if ((to-from) < 40){ // if there is too much vertical range in one pixel, don't draw the full line for speed reasons 
-			for (int j = from; j <= to; j += 1)
-			{
-				g.setPixel(i,j);
-			}
-		} else if ((to-from) < 100){
-			for (int j = from; j <= to; j += 2)
-			{
-				g.setPixel(i,j);
-			}
-		} else {
-			g.setPixel(i,to);
-			g.setPixel(i,from);
-		}
-
-
-		
+       // drawLine makes for ok anti-aliased plots, but is pretty slow
+        g.drawLine(i,
+                  (canvas->getYCoord(chan, i)/range*channelHeightFloat)+getHeight()/2,
+                   i+stepSize,
+                    (canvas->getYCoord(chan, i+stepSize)/range*channelHeightFloat)+getHeight()/2);
+
+        if (false) // switched back to line drawing now that we only draw partial updates
+        {
+
+            // // pixel wise line plot has no anti-aliasing, but runs much faster
+            double a = (canvas->getYCoord(chan, i)/range*channelHeightFloat)+getHeight()/2;
+            double b = (canvas->getYCoord(chan, i+stepSize)/range*channelHeightFloat)+getHeight()/2;
+
+            if (a<b){
+                 from = (a);
+                 to = (b);
+            } else {
+                 from = (b);
+                 to = (a);
+            }
+            
+            if ((to-from) < 40){ // if there is too much vertical range in one pixel, don't draw the full line for speed reasons 
+                for (int j = from; j <= to; j += 1)
+                {
+                    g.setPixel(i,j);
+                }
+            } else if ((to-from) < 100){
+                for (int j = from; j <= to; j += 2)
+                {
+                    g.setPixel(i,j);
+                }
+            } else {
+                g.setPixel(i,to);
+                g.setPixel(i,from);
+            }
+
+        }
+        
     }
 
  // g.setColour(lineColour.withAlpha(0.7f)); // alpha on seems to decrease draw speed
-    g.setFont(channelFont);
-    g.setFont(channelHeightFloat);
+   // g.setFont(channelFont);
+  //  g.setFont(channelHeightFloat*0.6);
 
-    g.drawText(String(chan+1), 15, center-channelHeight/2, 200, channelHeight, Justification::left, false);
+   // g.drawText(String(chan+1), 10, center-channelHeight/2, 200, channelHeight, Justification::left, false);
 
 
 }
@@ -748,6 +896,12 @@ void LfpChannelDisplay::setRange(float r)
     //std::cout << "Range: " << r << std::endl;
 }
 
+int LfpChannelDisplay::getRange()
+{
+    return range;
+}
+
+
 void LfpChannelDisplay::select()
 {
     isSelected = true;
@@ -768,7 +922,8 @@ void LfpChannelDisplay::setChannelHeight(int c)
 {
     channelHeight = c;
     channelHeightFloat = (float) channelHeight;
-    channelOverlap = channelHeight / 2;
+    //channelOverlap = channelHeight / 2; //clips data too early, 
+    channelOverlap = channelHeight *5;   
 }
 
 int LfpChannelDisplay::getChannelHeight()
@@ -786,4 +941,35 @@ void LfpChannelDisplay::setChannelOverlap(int overlap)
 int LfpChannelDisplay::getChannelOverlap()
 {
     return channelOverlap;
-}
\ No newline at end of file
+}
+
+void LfpChannelDisplay::setName(String name_)
+{
+	name = name_;
+}
+
+// -------------------------------
+
+LfpChannelDisplayInfo::LfpChannelDisplayInfo(LfpDisplayCanvas* canvas_, int ch)
+    : LfpChannelDisplay(canvas_, ch)
+{
+
+}
+
+void LfpChannelDisplayInfo::paint(Graphics& g)
+{
+
+
+
+    int center = getHeight()/2;
+
+    g.setColour(lineColour);
+
+    g.setFont(channelFont);
+    g.setFont(channelHeightFloat*0.3);
+
+    g.drawText(name, 10, center-channelHeight/2, 200, channelHeight, Justification::left, false);
+
+}
+
+ 
\ No newline at end of file
diff --git a/Source/Processors/Visualization/LfpDisplayCanvas.h b/Source/Processors/Visualization/LfpDisplayCanvas.h
index ebe5250480859a471bdd013048050ded9b39afd9..298473735b79c8210fe9536b1017e5c5e3eaa40c 100755
--- a/Source/Processors/Visualization/LfpDisplayCanvas.h
+++ b/Source/Processors/Visualization/LfpDisplayCanvas.h
@@ -32,6 +32,7 @@ class LfpDisplayNode;
 class LfpTimescale;
 class LfpDisplay;
 class LfpChannelDisplay;
+class LfpChannelDisplayInfo;
 
 /**
 
@@ -43,7 +44,7 @@ class LfpChannelDisplay;
 
 class LfpDisplayCanvas : public Visualizer,
     public ComboBox::Listener
-
+    
 {
 public:
     LfpDisplayCanvas(LfpDisplayNode* n);
@@ -79,7 +80,10 @@ public:
 
     void loadVisualizerParameters(XmlElement* xml);
 
+    //void scrollBarMoved(ScrollBar *scrollBarThatHasMoved, double newRangeStart);
 
+    bool fullredraw; // used to indicate that a full redraw is required. is set false after each full redraw, there is a similar switch for ach ch display;
+    static const int leftmargin=50; // left margin for lfp plots (so the ch number text doesnt overlap)
 
 private:
 
@@ -93,6 +97,9 @@ private:
     static const int MAX_N_SAMP = 5000; // maximum display size in pixels
     //float waves[MAX_N_CHAN][MAX_N_SAMP*2]; // we need an x and y point for each sample
 
+    
+
+
     LfpDisplayNode* processor;
     AudioSampleBuffer* displayBuffer;
     AudioSampleBuffer* screenBuffer;
@@ -120,6 +127,7 @@ private:
 
     int nChans;
 
+
     JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(LfpDisplayCanvas);
 
 };
@@ -163,9 +171,17 @@ public:
     void resized();
 
     void mouseDown(const MouseEvent& event);
+    void mouseWheelMove(const MouseEvent&  event, const MouseWheelDetails&   wheel ) ;
 
+    
     void setRange(float range);
+    int getRange();
+
     void setChannelHeight(int r);
+    int getChannelHeight();
+
+    Array<LfpChannelDisplay*> channels;
+    Array<LfpChannelDisplayInfo*> channelInfo;
 
 private:
     int numChans;
@@ -175,7 +191,6 @@ private:
     LfpDisplayCanvas* canvas;
     Viewport* viewport;
 
-    Array<LfpChannelDisplay*> channels;
     Array<Colour> channelColours;
 
     float range;
@@ -193,6 +208,8 @@ public:
     void select();
     void deselect();
 
+    void setName(String);
+
     void setColour(Colour c);
 
     void setChannelHeight(int);
@@ -202,8 +219,11 @@ public:
     int getChannelOverlap();
 
     void setRange(float range);
+    int getRange();
 
-private:
+    bool fullredraw; // used to indicate that a full redraw is required. is set false after each full redraw
+
+protected:
 
     LfpDisplayCanvas* canvas;
 
@@ -211,6 +231,8 @@ private:
 
     int chan;
 
+    String name;
+
     Font channelFont;
 
     Colour lineColour;
@@ -223,5 +245,13 @@ private:
 
 };
 
+class LfpChannelDisplayInfo : public LfpChannelDisplay
+{
+public:
+    LfpChannelDisplayInfo(LfpDisplayCanvas*, int channelNumber);
+
+    void paint(Graphics& g);
+
+};
 
 #endif  // __LFPDISPLAYCANVAS_H_B711873A__
diff --git a/Source/Processors/Visualization/SpikeDisplayCanvas.cpp b/Source/Processors/Visualization/SpikeDisplayCanvas.cpp
index b36307fc645d395003a7dfbe2fea9ec35c51cc61..fe16ddafc0a1c36265b1b66d4345aad9fbdd701a 100755
--- a/Source/Processors/Visualization/SpikeDisplayCanvas.cpp
+++ b/Source/Processors/Visualization/SpikeDisplayCanvas.cpp
@@ -37,6 +37,11 @@ SpikeDisplayCanvas::SpikeDisplayCanvas(SpikeDisplayNode* n) :
 
     scrollBarThickness = viewport->getScrollBarThickness();
 
+    clearButton = new UtilityButton("Clear plots", Font("Small Text", 13, Font::plain));
+    clearButton->setRadius(3.0f);
+    clearButton->addListener(this);
+    addAndMakeVisible(clearButton);
+
     addAndMakeVisible(viewport);
 
     setWantsKeyboardFocus(true);
@@ -52,14 +57,14 @@ SpikeDisplayCanvas::~SpikeDisplayCanvas()
 
 void SpikeDisplayCanvas::beginAnimation()
 {
-    std::cout << "Beginning animation." << std::endl;
+    std::cout << "SpikeDisplayCanvas beginning animation." << std::endl;
 
     startCallbacks();
 }
 
 void SpikeDisplayCanvas::endAnimation()
 {
-    std::cout << "Ending animation." << std::endl;
+    std::cout << "SpikeDisplayCanvas ending animation." << std::endl;
 
     stopCallbacks();
 }
@@ -67,17 +72,16 @@ void SpikeDisplayCanvas::endAnimation()
 void SpikeDisplayCanvas::update()
 {
 
-    std::cout << "UPDATING SpikeDisplayCanvas" << std::endl;
+    std::cout << "Updating SpikeDisplayCanvas" << std::endl;
 
     int nPlots = processor->getNumElectrodes();
-    spikeDisplay->clear();
+    spikeDisplay->removePlots();
 
     for (int i = 0; i < nPlots; i++)
     {
         spikeDisplay->addSpikePlot(processor->getNumberOfChannelsForElectrode(i), i);
     }
 
-    //initializeSpikePlots();
     spikeDisplay->resized();
     spikeDisplay->repaint();
 }
@@ -86,8 +90,6 @@ void SpikeDisplayCanvas::update()
 void SpikeDisplayCanvas::refreshState()
 {
     // called when the component's tab becomes visible again
-    // displayBufferIndex = processor->getDisplayBufferIndex();
-    // screenBufferIndex = 0;
     resized();
 }
 
@@ -96,6 +98,9 @@ void SpikeDisplayCanvas::resized()
     viewport->setBounds(0,0,getWidth(),getHeight()-90);
 
     spikeDisplay->setBounds(0,0,getWidth()-scrollBarThickness, spikeDisplay->getTotalHeight());
+
+    clearButton->setBounds(10, getHeight()-40, 100,20);
+
 }
 
 void SpikeDisplayCanvas::paint(Graphics& g)
@@ -130,25 +135,15 @@ void SpikeDisplayCanvas::processSpikeEvents()
 
             const uint8_t* dataptr = message.getRawData();
             int bufferSize = message.getRawDataSize();
-            //int nSamples = (bufferSize-4)/2;
 
             SpikeObject newSpike;
-            //SpikeObject simSpike;
 
-            unpackSpike(&newSpike, dataptr, bufferSize);
+            bool isValid = unpackSpike(&newSpike, dataptr, bufferSize);
 
             int electrodeNum = newSpike.source;
 
-            // generateSimulatedSpike(&simSpike, 0, 0);
-
-            // for (int i = 0; i < newSpike.nChannels * newSpike.nSamples; i++)
-            // {
-            //     simSpike.data[i] = newSpike.data[i%80] + 5000;// * 3 - 10000;
-            // }
-
-            // simSpike.nSamples = 40;
-
-            spikeDisplay->plotSpike(newSpike, electrodeNum);
+            if (isValid)
+                spikeDisplay->plotSpike(newSpike, electrodeNum);
 
         }
 
@@ -160,7 +155,10 @@ void SpikeDisplayCanvas::processSpikeEvents()
 
 bool SpikeDisplayCanvas::keyPressed(const KeyPress& key)
 {
-    if (key.getKeyCode() == 67) // C
+
+    KeyPress c = KeyPress::createFromDescription("c");
+
+    if (key.isKeyCode(c.getKeyCode())) // C
     {
         spikeDisplay->clear();
         
@@ -172,6 +170,17 @@ bool SpikeDisplayCanvas::keyPressed(const KeyPress& key)
 
 }
 
+void SpikeDisplayCanvas::buttonClicked(Button* button)
+{
+
+    if (button == clearButton)
+    {
+        spikeDisplay->clear();
+    }
+}
+
+
+
 // ----------------------------------------------------------------
 
 SpikeDisplay::SpikeDisplay(SpikeDisplayCanvas* sdc, Viewport* v) :
@@ -199,6 +208,12 @@ void SpikeDisplay::clear()
         
 }
 
+void SpikeDisplay::removePlots()
+{
+   spikePlots.clear();
+        
+}
+
 void SpikeDisplay::addSpikePlot(int numChannels, int electrodeNum)
 {
 
@@ -238,6 +253,9 @@ void SpikeDisplay::resized()
 
         float width, height;
 
+
+        float maxHeight = 0;
+
         for (int i = 0; i < spikePlots.size(); i++)
         {
 
@@ -271,6 +289,8 @@ void SpikeDisplay::resized()
 
             spikePlots[i]->setBounds(width*column, row*height, width, height);
 
+            maxHeight = jmax(maxHeight, row*height + height);
+
             if (spikePlots[i]->nChannels == 1)
             {
                 stereotrodeStart = (int)(height*(float(row)+1));
@@ -282,6 +302,7 @@ void SpikeDisplay::resized()
 
         }
 
+
         for (int i = 0; i < spikePlots.size(); i++)
         {
 
@@ -293,21 +314,23 @@ void SpikeDisplay::resized()
             if (spikePlots[i]->nChannels == 2)
             {
                 spikePlots[i]->setBounds(x, y+stereotrodeStart, w2, h2);
+                maxHeight = jmax(maxHeight, (float) y+stereotrodeStart+h2);
 
             }
             else if (spikePlots[i]->nChannels == 4)
             {
                 spikePlots[i]->setBounds(x, y+stereotrodeStart+tetrodeStart, w2, h2);
+                maxHeight = jmax(maxHeight, (float) y+stereotrodeStart+tetrodeStart+h2);
             }
 
+
         }
 
-        totalHeight = 5000; // don't even deal with making the display the correct height
+        totalHeight = (int) maxHeight + 50; 
 
-        if (totalHeight < getHeight())
-        {
-            canvas->resized();
-        }
+       // std::cout << "New height = " << totalHeight << std::endl;
+
+        setBounds(0, 0, getWidth(), totalHeight);
     }
 
 }
@@ -365,7 +388,7 @@ SpikePlot::SpikePlot(SpikeDisplayCanvas* sdc, int elecNum, int p) :
             //            nHistAx = 1;
             //            break;
         default: // unsupported number of axes provided
-            std::cout<<"SpikePlot as UNKNOWN, defaulting to SINGLE_PLOT"<<std::endl;
+            std::cout << "SpikePlot as UNKNOWN, defaulting to SINGLE_PLOT" << std::endl;
             nWaveAx = 1;
             nProjAx = 0;
             plotType = SINGLE_PLOT;
@@ -374,6 +397,15 @@ SpikePlot::SpikePlot(SpikeDisplayCanvas* sdc, int elecNum, int p) :
 
     initAxes();
 
+    for (int i = 0; i < nChannels; i++)
+    {
+        UtilityButton* rangeButton = new UtilityButton("250", Font("Small Text", 10, Font::plain));
+        rangeButton->setRadius(3.0f);
+        rangeButton->addListener(this);
+        addAndMakeVisible(rangeButton);
+
+        rangeButtons.add(rangeButton);
+    }
 
 }
 
@@ -424,6 +456,7 @@ void SpikePlot::initAxes()
         WaveAxes* wAx = new WaveAxes(WAVE1 + i);
         wAxes.add(wAx);
         addAndMakeVisible(wAx);
+        ranges.add(250.0f); // default range is 250 microvolts
     }
 
     for (int i = 0; i < nProjAx; i++)
@@ -433,14 +466,14 @@ void SpikePlot::initAxes()
         addAndMakeVisible(pAx);
     }
 
-    setLimitsOnAxes(); // initialize thel limits on the axes
+    setLimitsOnAxes(); // initialize the ranges
 }
 
 void SpikePlot::resized()
 {
 
     float width = getWidth()-10;
-    float height = getHeight()-20;
+    float height = getHeight()-25;
 
     float axesWidth, axesHeight;
 
@@ -472,10 +505,43 @@ void SpikePlot::resized()
     }
 
     for (int i = 0; i < nWaveAx; i++)
-        wAxes[i]->setBounds(5 + (i % nWaveCols) * axesWidth/nWaveCols, 15 + (i/nWaveCols) * axesHeight, axesWidth/nWaveCols, axesHeight);
+    {
+        wAxes[i]->setBounds(5 + (i % nWaveCols) * axesWidth/nWaveCols, 20 + (i/nWaveCols) * axesHeight, axesWidth/nWaveCols, axesHeight);
+        rangeButtons[i]->setBounds(8 + (i % nWaveCols) * axesWidth/nWaveCols, 
+                                   20 + (i/nWaveCols) * axesHeight + axesHeight - 18, 
+                                   25, 15);
+    }
 
     for (int i = 0; i < nProjAx; i++)
-        pAxes[i]->setBounds(5 + (1 + i%nProjCols) * axesWidth, 15 + (i/nProjCols) * axesHeight, axesWidth, axesHeight);
+        pAxes[i]->setBounds(5 + (1 + i%nProjCols) * axesWidth, 20 + (i/nProjCols) * axesHeight, axesWidth, axesHeight);
+
+
+}
+
+void SpikePlot::buttonClicked(Button* button)
+{
+    UtilityButton* buttonThatWasClicked = (UtilityButton*) button;
+
+    int index = rangeButtons.indexOf(buttonThatWasClicked);
+    String label;
+
+    if (ranges[index] == 250.0f)
+    {
+        ranges.set(index, 500.0f);
+        label = "500";
+    } else if (ranges[index] == 500.0f)
+    {
+        ranges.set(index, 100.0f);
+        label = "100";
+    } else if  (ranges[index] == 100.0f)
+    {
+        ranges.set(index, 250.0f);
+        label = "250";
+    } 
+
+    buttonThatWasClicked->setLabel(label);
+
+    setLimitsOnAxes();
 
 }
 
@@ -483,18 +549,17 @@ void SpikePlot::setLimitsOnAxes()
 {
     //std::cout<<"SpikePlot::setLimitsOnAxes()"<<std::endl;
 
-    // for (int i = 0; i < nWaveAx; i++)
-    //     wAxes[i]->setYLims(limits[i][0], limits[i][1]);
+    for (int i = 0; i < nWaveAx; i++)
+         wAxes[i]->setRange(ranges[i]);
 
-    // // Each Projection sets its limits using the limits of the two waveform dims it represents.
-    // // Convert projection number to indecies, and then set the limits using those indices
-    // int j1, j2;
-    // for (int i = 0; i < nProjAx; i++)
-    // {
-    //     n2ProjIdx(pAxes[i]->getType(), &j1, &j2);
-    //     pAxes[i]->setYLims(limits[j1][0], limits[j1][1]);
-    //     pAxes[i]->setXLims(limits[j2][0], limits[j2][1]);
-    // }
+    // Each projection sets its limits using the limits of the two waveform dims it represents.
+    // Convert projection number to indices, and then set the limits using those indices
+    int j1, j2;
+    for (int i = 0; i < nProjAx; i++)
+    {
+        pAxes[i]->n2ProjIdx(pAxes[i]->getType(), &j1, &j2);
+        pAxes[i]->setRange(ranges[j1], ranges[j2]);
+    }
 }
 
 void SpikePlot::initLimits()
@@ -540,51 +605,13 @@ void SpikePlot::clear()
         pAxes[i]->clear();
 }
 
-void SpikePlot::pan(int dim, bool up)
-{
-
-    std::cout << "SpikePlot::pan() dim:" << dim << std::endl;
-
-    int mean = (limits[dim][0] + limits[dim][1])/2;
-    int dLim = limits[dim][1] - mean;
-
-    if (up)
-        mean = mean + dLim/20;
-    else
-        mean = mean - dLim/20;
-
-    limits[dim][0] = mean-dLim;
-    limits[dim][1] = mean+dLim;
-
-    setLimitsOnAxes();
-}
-
-void SpikePlot::zoom(int dim, bool in)
-{
-    std::cout << "SpikePlot::zoom()" << std::endl;
-
-    int mean = (limits[dim][0] + limits[dim][1])/2;
-    int dLim = limits[dim][1] - mean;
-
-    if (in)
-        dLim = dLim * .90;
-    else
-        dLim = dLim / .90;
-
-    limits[dim][0] = mean-dLim;
-    limits[dim][1] = mean+dLim;
-
-    setLimitsOnAxes();
-}
-
-
 
 
 // --------------------------------------------------
 
 
 WaveAxes::WaveAxes(int channel) : GenericAxes(channel), drawGrid(true), 
-    bufferSize(10), spikeIndex(0), thresholdLevel(0.5f),
+    bufferSize(10), spikeIndex(0), thresholdLevel(0.5f), range(250.0f),
     isOverThresholdSlider(false), isDraggingThresholdSlider(false)
 {
 
@@ -603,17 +630,27 @@ WaveAxes::WaveAxes(int channel) : GenericAxes(channel), drawGrid(true),
     }
 }
 
+void WaveAxes::setRange(float r)
+{
+
+    //std::cout << "Setting range to " << r << std::endl;
+
+    range = r;
+
+    repaint();
+}
+
 void WaveAxes::paint(Graphics& g)
 {
     g.setColour(Colours::black);
-    g.fillRect(5,5,getWidth()-10, getHeight()-10);
+    g.fillRect(0,0,getWidth(), getHeight());
 
     int chan = 0;
 
     // draw the grid lines for the waveforms
 
     if (drawGrid)
-        drawWaveformGrid(s.threshold[chan], s.gain[chan], g);
+        drawWaveformGrid(g);
 
     // draw the threshold line and labels
     drawThresholdSlider(g);
@@ -650,7 +687,7 @@ void WaveAxes::plotSpike(const SpikeObject& s, Graphics& g)
     float h = getHeight();
 
     //compute the spatial width for each waveform sample
-    float dx = (getWidth()-10)/float(spikeBuffer[0].nSamples);
+    float dx = getWidth()/float(spikeBuffer[0].nSamples);
     
     // type corresponds to channel so we need to calculate the starting
     // sample based upon which channel is getting plotted
@@ -658,16 +695,25 @@ void WaveAxes::plotSpike(const SpikeObject& s, Graphics& g)
 
     int dSamples = 1;
 
-
-    float x = 5.0f;
+    float x = 0.0f;
 
      for (int i = 0; i < s.nSamples-1; i++)
     {
         //std::cout << s.data[sampIdx] << std::endl;
-        g.drawLine(x, 
-            h/2 + (s.data[sampIdx]-32768)/100, 
-            x+dx, 
-            h/2 + (s.data[sampIdx+1]-32768)/100);
+
+        if (*s.gain != 0)
+        {
+            float s1 = h/2 + float(s.data[sampIdx]-32768)/float(*s.gain)*1000.0f / range * h;
+            float s2 =  h/2 + float(s.data[sampIdx+1]-32768)/float(*s.gain)*1000.0f / range * h; 
+
+             g.drawLine(x, 
+                 s1, 
+                 x+dx, 
+                 s2);
+        }
+
+        
+
         sampIdx += dSamples;
         x += dx;
     }
@@ -680,89 +726,23 @@ void WaveAxes::drawThresholdSlider(Graphics& g)
     float h = getHeight()*thresholdLevel;
 
     g.setColour(thresholdColour);
-    g.drawLine(5.0f, h, getWidth()-5.0f, h);
+    g.drawLine(0, h, getWidth(), h);
 
 }
 
-void WaveAxes::drawWaveformGrid(int threshold, int gain, Graphics& g)
+void WaveAxes::drawWaveformGrid(Graphics& g)
 {
 
     float h = getHeight();
     float w = getWidth();
 
-    for (int i = 1; i < 10; i++)
-    {
-        g.setColour(Colours::darkgrey);
-
-        g.drawLine(5.0,h/10*i,w-5.0f,h/10*i);
+    g.setColour(Colours::darkgrey);
 
+    for (float y = -range/2; y < range/2; y += 25.0f)
+    {
+        g.drawLine(0,h/2 + y/range*h, w, h/2+ y/range*h);
     }
-
-    // double voltRange = ylims[1] - ylims[0];
-    // double pixelRange = getHeight();
-    // //This is a totally arbitrary value that seemed to lok the best for me
-    // int minPixelsPerTick = 25;
-    // int MAX_N_TICKS = 10;
-
-    // int nTicks = pixelRange / minPixelsPerTick;
-    // while (nTicks > MAX_N_TICKS)
-    // {
-    //     minPixelsPerTick += 5;
-    //     nTicks = pixelRange / minPixelsPerTick;
-    // }
-
-    // int voltPerTick = (voltRange / nTicks);
-
-    // g.setColour(Colours::red);
-    // char cstr[200] = {0};
-    // String str;
-
-    // double tickVoltage = (double) threshold;
-
-    // // If the limits are bad we don't want to hang the program trying to draw too many ticks
-    // // so count the number of ticks drawn and kill the routine after 100 draws
-    // int tickCount=0;
-    // while (tickVoltage < ylims[1] - voltPerTick*1.5) // Draw the ticks above the thold line
-    // {
-    //     tickVoltage = (double) roundUp(tickVoltage + voltPerTick, 100);
-
-    //     g.drawLine(0, tickVoltage, s.nSamples, tickVoltage);
-
-    //     // glBegin(GL_LINE_STRIP);
-    //     // glVertex2i(0, tickVoltage);
-    //     // glVertex2i(s.nSamples, tickVoltage);
-    //     // glEnd();
-
-    //     makeLabel(tickVoltage, gain, true, cstr);
-    //     str = String(cstr);
-    //     g.setFont(font);
-    //     g.drawText(str, 1, tickVoltage+voltPerTick/10, 100, 15, Justification::left, false);
-
-    //     if (tickCount++>100)
-    //         return;
-    // }
-
-    // tickVoltage = threshold;
-    // tickCount = 0;
-
-    // while (tickVoltage > ylims[0] + voltPerTick) // draw the ticks below the thold line
-    // {
-    //     tickVoltage = (double) roundUp(tickVoltage - voltPerTick, 100);
-
-    //     g.drawLine(0, tickVoltage, s.nSamples, tickVoltage);
-
-    //     // glBegin(GL_LINE_STRIP);
-    //     // glVertex2i(0, tickVoltage);
-    //     // glVertex2i(s.nSamples, tickVoltage);
-    //     // glEnd();
-
-    //     makeLabel(tickVoltage, gain, true, cstr);
-    //     str = String(cstr);
-    //     g.drawText(str, 1, tickVoltage+voltPerTick/10, 100, 15, Justification::left, false);
-
-    //     if (tickCount++>100)
-    //         return;
-    // }
+   
 }
 
 void WaveAxes::updateSpikeData(const SpikeObject& s)
@@ -774,15 +754,21 @@ void WaveAxes::updateSpikeData(const SpikeObject& s)
 
     SpikeObject newSpike = s;
 
-    spikeBuffer.set(spikeIndex, newSpike);
-
     spikeIndex++;
     spikeIndex %= bufferSize;
 
+    spikeBuffer.set(spikeIndex, newSpike);
+
+    
+
 }
 
 void WaveAxes::clear()
 {
+
+    spikeBuffer.clear();
+    spikeIndex = 0;
+
     for (int n = 0; n < bufferSize; n++)
     {
         SpikeObject so;
@@ -865,7 +851,8 @@ void WaveAxes::mouseExit(const MouseEvent& event)
 
 // --------------------------------------------------
 
-ProjectionAxes::ProjectionAxes(int projectionNum) : GenericAxes(projectionNum), imageDim(500)
+ProjectionAxes::ProjectionAxes(int projectionNum) : GenericAxes(projectionNum), imageDim(500),
+                                                    rangeX(250), rangeY(250)
 {
     projectionImage = Image(Image::RGB, imageDim, imageDim, true);
 
@@ -879,13 +866,24 @@ ProjectionAxes::ProjectionAxes(int projectionNum) : GenericAxes(projectionNum),
 
 }
 
+void ProjectionAxes::setRange(float x, float y)
+{
+    rangeX = (int) x;
+    rangeY = (int) y;
+
+    //std::cout << "Setting range to " << x << " " << y << std::endl;
+
+    repaint();
+}
+
 void ProjectionAxes::paint(Graphics& g)
 {
     //g.setColour(Colours::orange);
     //g.fillRect(5,5,getWidth()-5, getHeight()-5);
+
     g.drawImage(projectionImage,
-                5, 5, getWidth()-10, getHeight()-10,
-                0, 250, 250, 250);
+                0, 0, getWidth(), getHeight(),
+                0, imageDim-rangeY, rangeX, rangeY);
 }
 
 void ProjectionAxes::updateSpikeData(const SpikeObject& s)
@@ -899,19 +897,25 @@ void ProjectionAxes::updateSpikeData(const SpikeObject& s)
     calcWaveformPeakIdx(s, ampDim1, ampDim2, &idx1, &idx2);
 
     // add peaks to image
-    updateProjectionImage(s.data[idx1], s.data[idx2]);
+
+    updateProjectionImage(s.data[idx1], s.data[idx2], *s.gain);
 
 }
 
-void ProjectionAxes::updateProjectionImage(uint16_t x, uint16_t y)
+void ProjectionAxes::updateProjectionImage(uint16_t x, uint16_t y, uint16_t gain)
 {
     Graphics g(projectionImage);
 
-    float xf = float(x-32768)*(float(imageDim)/32768.0);
-    float yf = float(imageDim) - float(y-32768)*(float(imageDim)/32768.0);
+   // h/2 + float(s.data[sampIdx]-32768)/float(*s.gain)*1000.0f / range * h;
 
-    g.setColour(Colours::white);
-    g.fillEllipse(xf,yf,2.0f,2.0f);
+    if (gain != 0)
+    {
+        float xf = float(x-32768)/float(gain)*1000.0f; // in microvolts
+        float yf = float(imageDim) - float(y-32768)/float(gain)*1000.0f; // in microvolts
+
+        g.setColour(Colours::white);
+        g.fillEllipse(xf,yf,2.0f,2.0f); 
+    }
 
 }
 
diff --git a/Source/Processors/Visualization/SpikeDisplayCanvas.h b/Source/Processors/Visualization/SpikeDisplayCanvas.h
index 8edb6ecf2dba2788406250814f54582eb58cb143..02ba77143ab868b2840866023d47934bbe1cdad6 100755
--- a/Source/Processors/Visualization/SpikeDisplayCanvas.h
+++ b/Source/Processors/Visualization/SpikeDisplayCanvas.h
@@ -66,7 +66,7 @@ class SpikePlot;
 
 */
 
-class SpikeDisplayCanvas : public Visualizer
+class SpikeDisplayCanvas : public Visualizer, public Button::Listener
 
 {
 public:
@@ -93,6 +93,8 @@ public:
 
     bool keyPressed(const KeyPress& key);
 
+    void buttonClicked(Button* button);
+
 private:
 
     SpikeDisplayNode* processor;
@@ -101,7 +103,7 @@ private:
     ScopedPointer<SpikeDisplay> spikeDisplay;
     ScopedPointer<Viewport> viewport;
 
-
+    ScopedPointer<UtilityButton> clearButton;
 
     bool newSpike;
     SpikeObject spike;
@@ -118,6 +120,7 @@ public:
     SpikeDisplay(SpikeDisplayCanvas*, Viewport*);
     ~SpikeDisplay();
 
+    void removePlots();
     void clear();
     void addSpikePlot(int numChannels, int electrodeNum);
 
@@ -160,7 +163,7 @@ private:
 
 */
 
-class SpikePlot : public Component
+class SpikePlot : public Component, Button::Listener
 {
 public:
     SpikePlot(SpikeDisplayCanvas*, int elecNum, int plotType);
@@ -186,12 +189,12 @@ public:
     void getBestDimensions(int*, int*);
 
     void clear();
-    void zoom(int, bool);
-    void pan(int, bool);
 
     float minWidth;
     float aspectRatio;
 
+    void buttonClicked(Button* button);
+
 private:
 
 
@@ -205,6 +208,8 @@ private:
 
     OwnedArray<ProjectionAxes> pAxes;
     OwnedArray<WaveAxes> wAxes;
+    OwnedArray<UtilityButton> rangeButtons;
+    Array<float> ranges;
 
     void initLimits();
     void setLimitsOnAxes();
@@ -288,6 +293,9 @@ public:
     void mouseDown(const MouseEvent& event);
     void mouseDrag(const MouseEvent& event);
 
+    void setRange(float);
+    float getRange() {return range;}
+
     //MouseCursor getMouseCursor();
 
 private:
@@ -300,7 +308,7 @@ private:
 
     float thresholdLevel;
 
-    void drawWaveformGrid(int threshold, int gain, Graphics& g);
+    void drawWaveformGrid(Graphics& g);
 
     void drawThresholdSlider(Graphics& g);
 
@@ -311,6 +319,8 @@ private:
     int spikeIndex;
     int bufferSize;
 
+    float range;
+
     bool isOverThresholdSlider;
     bool isDraggingThresholdSlider;
 
@@ -340,14 +350,15 @@ public:
 
     void clear();
 
-private:
+    void setRange(float, float);
 
-    void updateProjectionImage(uint16_t, uint16_t);
+    static void n2ProjIdx(int i, int* p1, int* p2);
 
-    void calcWaveformPeakIdx(const SpikeObject&, int, int, int*, int*);
+private:
 
+    void updateProjectionImage(uint16_t, uint16_t, uint16_t);
 
-    void n2ProjIdx(int i, int* p1, int* p2);
+    void calcWaveformPeakIdx(const SpikeObject&, int, int, int*, int*);
 
     int ampDim1, ampDim2;
 
@@ -358,6 +369,10 @@ private:
 
     int imageDim;
 
+    int rangeX;
+    int rangeY;
+
+
 };
 
 
diff --git a/Source/Processors/Visualization/SpikeObject.cpp b/Source/Processors/Visualization/SpikeObject.cpp
index 7522d0b08182a45d7500010a0d4a5d7ab262c80f..c2665d123aca88f6505a8b9432228b22d30d8be2 100755
--- a/Source/Processors/Visualization/SpikeObject.cpp
+++ b/Source/Processors/Visualization/SpikeObject.cpp
@@ -61,14 +61,14 @@ int packSpike(SpikeObject* s, uint8_t* buffer, int bufferSize)
     memcpy(buffer+idx, &(s->threshold), s->nChannels * 2);
     idx += s->nChannels * 2;
 
-
-
     if (idx >= MAX_SPIKE_BUFFER_LEN)
     {
-        std::cout<<"Spike is larger than it should be. Size was:"<<idx<<" Max Size is:"<<MAX_SPIKE_BUFFER_LEN<<std::endl;
+        std::cout << "Spike is larger than it should be. Size was: " << idx 
+                  << " Max Size is: " << MAX_SPIKE_BUFFER_LEN << std::endl;
 
     }
-    // makeBufferValid(buffer, bufferSize);
+    
+    makeBufferValid(buffer, bufferSize);
 
     return idx;
 
@@ -77,8 +77,8 @@ int packSpike(SpikeObject* s, uint8_t* buffer, int bufferSize)
 // Simple method for deserializing a string of bytes into a Spike object
 bool unpackSpike(SpikeObject* s, const uint8_t* buffer, int bufferSize)
 {
-    // if (!isBufferValid(buffer, bufferSize))
-   //  	return false;
+   // if (!isBufferValid(buffer, bufferSize))
+    // 	return false;
 
     int idx = 0;
 
@@ -115,7 +115,7 @@ bool unpackSpike(SpikeObject* s, const uint8_t* buffer, int bufferSize)
 }
 
 // Checks the validity of the buffer, this should be run before unpacking and after packing the buffer
-bool isBufferValid(uint8_t* buffer, int bufferSize)
+bool isBufferValid(const uint8_t* buffer, int bufferSize)
 {
 
     if (! CHECK_BUFFER_VALIDITY)
@@ -126,14 +126,14 @@ bool isBufferValid(uint8_t* buffer, int bufferSize)
 
     int idx;
 
-    for (idx = 0; idx < bufferSize-2; idx += 2)
+    for (idx = 0; idx < bufferSize - 2; idx += 2)
     {
-        memcpy(buffer + idx, &value, 2);
+        memcpy(&value, buffer + idx, 2);
         runningSum += value;
     }
 
     uint16_t integrityCheck = 0;
-    memcpy(buffer + idx, &integrityCheck, 2);
+    memcpy(&integrityCheck, buffer + idx + 2, 2);
 
     std::cout << integrityCheck<< " == " << runningSum <<std::endl;
 
@@ -150,13 +150,13 @@ void makeBufferValid(uint8_t* buffer, int bufferSize)
 
     int idx;
 
-    for (idx = 0; idx < bufferSize-2; idx += 2)
+    for (idx = 0; idx < bufferSize - 2; idx += 2)
     {
-        memcpy(buffer + idx, &value, 2);
+        memcpy(&value, buffer + idx, 2);
         runningSum += value;
     }
 
-    memcpy(&runningSum, buffer + idx, 2);
+    memcpy(buffer + idx + 2, &runningSum, 2);
 
 }
 
diff --git a/Source/Processors/Visualization/SpikeObject.h b/Source/Processors/Visualization/SpikeObject.h
index b32f3aaa8f04b3abf1b9e1b65efeb4683cb9963a..1bd73f2ec990f3f2293f7808e7163191f97ff46e 100755
--- a/Source/Processors/Visualization/SpikeObject.h
+++ b/Source/Processors/Visualization/SpikeObject.h
@@ -74,7 +74,7 @@ int packSpike(SpikeObject* s, uint8_t* buffer, int bufferLength);
 bool unpackSpike(SpikeObject* s, const uint8_t* buffer, int bufferLength);
 
 /** Checks the validity of the buffer, this should be run before unpacking the buffer */
-bool isBufferValid(uint8_t* buffer, int bufferLength);
+bool isBufferValid(const uint8_t* buffer, int bufferLength);
 
 /** Computes the validity value for the buffer, this should be called after packing the buffer */
 void makeBufferValid(uint8_t* buffer, int bufferLength);
diff --git a/Source/Processors/Visualization/Visualizer.h b/Source/Processors/Visualization/Visualizer.h
index bcf3b1d7f9e15cb4ac1cda2babee02d27ceebbb1..3825800a64294b488ba5f5d289bc5bf99ad8130d 100755
--- a/Source/Processors/Visualization/Visualizer.h
+++ b/Source/Processors/Visualization/Visualizer.h
@@ -69,7 +69,7 @@ public:
     /** Starts the timer callbacks. */
     void startCallbacks()
     {
-        startTimer(50);
+        startTimer(20);
     }
 
     /** Stops the timer callbacks. */
diff --git a/Source/UI/EditorViewport.cpp b/Source/UI/EditorViewport.cpp
index 747f4df9d0cb1b092e8eae7341aae288a3469429..b36413d395ba3900aab94dab21eb61a647b105c0 100755
--- a/Source/UI/EditorViewport.cpp
+++ b/Source/UI/EditorViewport.cpp
@@ -1413,7 +1413,7 @@ void EditorViewport::setParametersByXML(GenericProcessor* targetProcessor, XmlEl
     forEachXmlChildElementWithTagName(*processorXML, channelXML, "CHANNEL"){
         currentChannel=channelXML->getIntAttribute("name");
         
-        std::cout <<"currentChannel:"<< currentChannel  << std::endl;
+       // std::cout <<"currentChannel:"<< currentChannel  << std::endl;
         // Sets channel to change parameter on
         targetProcessor->setCurrentChannel(currentChannel-1);
 
diff --git a/Source/UI/UIComponent.cpp b/Source/UI/UIComponent.cpp
index 34747cb8248b924195079093dcd8ad199231c08f..7d94fb6b2ea432e14860752e4831db6a34401eb8 100755
--- a/Source/UI/UIComponent.cpp
+++ b/Source/UI/UIComponent.cpp
@@ -92,7 +92,7 @@ UIComponent::UIComponent(MainWindow* mainWindow_, ProcessorGraph* pgraph, AudioC
     mainWindow->setMenuBar(this);
 #endif
 
-  //  getEditorViewport()->loadState(File("/home/jsiegle/Programming/GUI/Builds/Linux/build/spike_display.xml"));
+   // getEditorViewport()->loadState(File("/home/jsiegle/Programming/GUI/Builds/Linux/build/rhythm_config.xml"));
 
 }