diff --git a/Source/Plugins/LfpDisplayNode/LfpDisplayCanvas.cpp b/Source/Plugins/LfpDisplayNode/LfpDisplayCanvas.cpp
index fa33dde3adbb069ce918bb94df47e05d0293e10f..f644bba5122000a7c26713952945853bbc408501 100644
--- a/Source/Plugins/LfpDisplayNode/LfpDisplayCanvas.cpp
+++ b/Source/Plugins/LfpDisplayNode/LfpDisplayCanvas.cpp
@@ -942,7 +942,8 @@ void LfpDisplayCanvas::updateScreenBuffer()
 
         if (nSamples < 0) // buffer has reset to 0
         {
-            nSamples = (displayBufferSize - dbi) + index;
+            nSamples = (displayBufferSize - dbi) + index +1;
+             std::cout << "nsamples 0 " ;
         }
 
         //if (channel == 15 || channel == 16)
@@ -1007,12 +1008,12 @@ void LfpDisplayCanvas::updateScreenBuffer()
                     float sample_min   =  10000000;
                     float sample_max   = -10000000;
                     
-                    int nextpix = (dbi +(int)ratio +1) % displayBufferSize; //  position to next pixels index
+                    int nextpix = (dbi +(int)ratio +1) % (displayBufferSize+1); //  position to next pixels index
                     
-                    if (nextpix <= dbi) { // at the end of the displaybuffer, this can occur and it causes the display to miss one pixel woth of sample - this circumvents that
-                        //std::cout << "np " ;
-                        nextpix=dbi;
-                    }
+                    //if (nextpix <= dbi) { // at the end of the displaybuffer, this can occur and it causes the display to miss one pixel woth of sample - this circumvents that
+                    //    std::cout << "np " ;
+                        //nextpix=dbi;
+                    //}
                    
                     for (int j = dbi; j <= nextpix; j++)
                     {
diff --git a/Source/Plugins/LfpDisplayNodeBeta/LfpDisplayCanvas.cpp b/Source/Plugins/LfpDisplayNodeBeta/LfpDisplayCanvas.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..f644bba5122000a7c26713952945853bbc408501
--- /dev/null
+++ b/Source/Plugins/LfpDisplayNodeBeta/LfpDisplayCanvas.cpp
@@ -0,0 +1,2670 @@
+/*
+------------------------------------------------------------------
+
+This file is part of the Open Ephys GUI
+Copyright (C) 2013 Open Ephys
+
+------------------------------------------------------------------
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#include "LfpDisplayCanvas.h"
+
+#include <math.h>
+
+LfpDisplayCanvas::LfpDisplayCanvas(LfpDisplayNode* processor_) :
+     timebase(1.0f), displayGain(1.0f),   timeOffset(0.0f),
+    processor(processor_), selectedChannelType(HEADSTAGE_CHANNEL)
+{
+
+    nChans = processor->getNumInputs();
+    std::cout << "Setting num inputs on LfpDisplayCanvas to " << nChans << std::endl;
+
+    displayBuffer = processor->getDisplayBufferAddress();
+    displayBufferSize = displayBuffer->getNumSamples();
+    std::cout << "Setting displayBufferSize on LfpDisplayCanvas to " << displayBufferSize << std::endl;
+
+    screenBuffer = new AudioSampleBuffer(MAX_N_CHAN, MAX_N_SAMP);
+    screenBuffer->clear();
+
+    screenBufferMin = new AudioSampleBuffer(MAX_N_CHAN, MAX_N_SAMP);
+    screenBufferMin->clear();
+    screenBufferMean = new AudioSampleBuffer(MAX_N_CHAN, MAX_N_SAMP);
+    screenBufferMean->clear();
+    screenBufferMax = new AudioSampleBuffer(MAX_N_CHAN, MAX_N_SAMP);
+    screenBufferMax->clear();
+
+    viewport = new LfpViewport(this);
+    lfpDisplay = new LfpDisplay(this, viewport);
+    timescale = new LfpTimescale(this);
+
+    timescale->setTimebase(timebase);
+
+    viewport->setViewedComponent(lfpDisplay, false);
+    viewport->setScrollBarsShown(true, false);
+
+    scrollBarThickness = viewport->getScrollBarThickness();
+
+    isChannelEnabled.insertMultiple(0,true,10000); // max 10k channels
+
+    //viewport->getVerticalScrollBar()->addListener(this->scrollBarMoved(viewport->getVerticalScrollBar(), 1.0));
+
+    UtilityButton* tbut;
+
+    addAndMakeVisible(viewport);
+    addAndMakeVisible(timescale);
+
+    //Ranges for neural data
+     voltageRanges[HEADSTAGE_CHANNEL].add("25");
+    voltageRanges[HEADSTAGE_CHANNEL].add("50");
+    voltageRanges[HEADSTAGE_CHANNEL].add("100");
+    voltageRanges[HEADSTAGE_CHANNEL].add("250");
+    voltageRanges[HEADSTAGE_CHANNEL].add("400");
+    voltageRanges[HEADSTAGE_CHANNEL].add("500");
+    voltageRanges[HEADSTAGE_CHANNEL].add("750");
+    voltageRanges[HEADSTAGE_CHANNEL].add("1000");
+    voltageRanges[HEADSTAGE_CHANNEL].add("2000");
+    voltageRanges[HEADSTAGE_CHANNEL].add("5000");
+    voltageRanges[HEADSTAGE_CHANNEL].add("10000");
+    voltageRanges[HEADSTAGE_CHANNEL].add("15000");
+    selectedVoltageRange[HEADSTAGE_CHANNEL] = 8;
+    rangeGain[HEADSTAGE_CHANNEL] = 1; //uV
+    rangeSteps[HEADSTAGE_CHANNEL] = 10;
+    rangeUnits.add("uV");
+    typeNames.add("DATA");
+
+    tbut = new UtilityButton("DATA",Font("Small Text", 9, Font::plain));
+    tbut->setEnabledState(true);
+    tbut->setCorners(false,false,false,false);
+    tbut->addListener(this);
+    tbut->setClickingTogglesState(true);
+    tbut->setRadioGroupId(100,dontSendNotification);
+    tbut->setToggleState(true,dontSendNotification);
+    addAndMakeVisible(tbut);
+    typeButtons.add(tbut);
+    
+    //Ranges for AUX/accelerometer data
+    voltageRanges[AUX_CHANNEL].add("25");
+    voltageRanges[AUX_CHANNEL].add("50");
+    voltageRanges[AUX_CHANNEL].add("100");
+    voltageRanges[AUX_CHANNEL].add("250");
+    voltageRanges[AUX_CHANNEL].add("400");
+    voltageRanges[AUX_CHANNEL].add("500");
+    voltageRanges[AUX_CHANNEL].add("750");
+    voltageRanges[AUX_CHANNEL].add("1000");
+    voltageRanges[AUX_CHANNEL].add("2000");
+    //voltageRanges[AUX_CHANNEL].add("5000");
+    selectedVoltageRange[AUX_CHANNEL] = 9;
+    rangeGain[AUX_CHANNEL] = 0.001; //mV
+    rangeSteps[AUX_CHANNEL] = 10;
+    rangeUnits.add("mV");
+    typeNames.add("AUX");
+    
+    
+
+    tbut = new UtilityButton("AUX",Font("Small Text", 9, Font::plain));
+    tbut->setEnabledState(true);
+    tbut->setCorners(false,false,false,false);
+    tbut->addListener(this);
+    tbut->setClickingTogglesState(true);
+    tbut->setRadioGroupId(100,dontSendNotification);
+    tbut->setToggleState(false,dontSendNotification);
+    addAndMakeVisible(tbut);
+    typeButtons.add(tbut);
+
+    //Ranges for ADC data
+     voltageRanges[ADC_CHANNEL].add("0.01");
+    voltageRanges[ADC_CHANNEL].add("0.05");
+    voltageRanges[ADC_CHANNEL].add("0.1");
+    voltageRanges[ADC_CHANNEL].add("0.5");
+    voltageRanges[ADC_CHANNEL].add("1.0");
+    voltageRanges[ADC_CHANNEL].add("2.0");
+    voltageRanges[ADC_CHANNEL].add("5.0");
+    voltageRanges[ADC_CHANNEL].add("10.0");
+    selectedVoltageRange[ADC_CHANNEL] = 8;
+    rangeGain[ADC_CHANNEL] = 1; //V
+    rangeSteps[ADC_CHANNEL] = 0.1; //in V
+    rangeUnits.add("V");
+    typeNames.add("ADC");
+
+    tbut = new UtilityButton("ADC",Font("Small Text", 9, Font::plain));
+    tbut->setEnabledState(true);
+    tbut->setCorners(false,false,false,false);
+    tbut->addListener(this);
+    tbut->setClickingTogglesState(true);
+    tbut->setRadioGroupId(100,dontSendNotification);
+    tbut->setToggleState(false,dontSendNotification);
+    addAndMakeVisible(tbut);
+    typeButtons.add(tbut);
+
+    selectedVoltageRangeValues[HEADSTAGE_CHANNEL] = voltageRanges[HEADSTAGE_CHANNEL][selectedVoltageRange[HEADSTAGE_CHANNEL]-1];
+    selectedVoltageRangeValues[AUX_CHANNEL] = voltageRanges[AUX_CHANNEL][selectedVoltageRange[AUX_CHANNEL]-1];
+    selectedVoltageRangeValues[ADC_CHANNEL] = voltageRanges[ADC_CHANNEL][selectedVoltageRange[ADC_CHANNEL]-1];
+
+    timebases.add("0.25");
+    timebases.add("0.5");
+    timebases.add("1.0");
+    timebases.add("2.0");
+    timebases.add("3.0");
+    timebases.add("4.0");
+    timebases.add("5.0");
+    timebases.add("10.0");
+    timebases.add("20.0");
+    selectedTimebase = 4;
+    selectedTimebaseValue = timebases[selectedTimebase-1];
+
+    spreads.add("10");
+    spreads.add("20");
+    spreads.add("30");
+    spreads.add("40");
+    spreads.add("50");
+    spreads.add("60");
+    spreads.add("70");
+    spreads.add("80");
+    spreads.add("90");
+    spreads.add("100");
+    selectedSpread = 5;
+    selectedSpreadValue = spreads[selectedSpread-1];
+
+
+    overlaps.add("0.5");
+    overlaps.add("0.75");
+    overlaps.add("1");
+    overlaps.add("2");
+    overlaps.add("3");
+    overlaps.add("4");
+    overlaps.add("5");
+    selectedOverlap = 4;
+    selectedOverlapValue = overlaps[selectedOverlap-1];
+
+    saturationThresholds.add("0.5");
+    saturationThresholds.add("100");
+    saturationThresholds.add("1000");
+    saturationThresholds.add("5000");
+    saturationThresholds.add("6389");
+    
+    selectedSaturation = 5;
+    selectedSaturationValue = saturationThresholds[selectedSaturation-1];
+    
+    
+    colorGroupings.add("1");
+    colorGroupings.add("2");
+    colorGroupings.add("4");
+    colorGroupings.add("8");
+    colorGroupings.add("16");
+
+
+    rangeSelection = new ComboBox("Voltage range");
+    rangeSelection->addItemList(voltageRanges[HEADSTAGE_CHANNEL], 1);
+    rangeSelection->setSelectedId(selectedVoltageRange[HEADSTAGE_CHANNEL], sendNotification);
+    rangeSelection->setEditableText(true);
+    rangeSelection->addListener(this);
+    addAndMakeVisible(rangeSelection);
+
+
+    timebaseSelection = new ComboBox("Timebase");
+    timebaseSelection->addItemList(timebases, 1);
+    timebaseSelection->setSelectedId(selectedTimebase, sendNotification);
+    timebaseSelection->setEditableText(true);
+    timebaseSelection->addListener(this);
+    addAndMakeVisible(timebaseSelection);
+
+
+    spreadSelection = new ComboBox("Spread");
+    spreadSelection->addItemList(spreads, 1);
+    spreadSelection->setSelectedId(selectedSpread,sendNotification);
+    spreadSelection->addListener(this);
+    spreadSelection->setEditableText(true);
+    addAndMakeVisible(spreadSelection);
+
+    overlapSelection = new ComboBox("Overlap");
+    overlapSelection->addItemList(overlaps, 1);
+    overlapSelection->setSelectedId(selectedOverlap,sendNotification);
+    overlapSelection->addListener(this);
+    overlapSelection->setEditableText(true);
+    addAndMakeVisible(overlapSelection);
+    
+    saturationWarningSelection = new ComboBox("Sat.Warn");
+    saturationWarningSelection->addItemList(saturationThresholds, 1);
+    saturationWarningSelection->setSelectedId(selectedSaturation,sendNotification);
+    saturationWarningSelection->addListener(this);
+    saturationWarningSelection->setEditableText(true);
+    addAndMakeVisible(saturationWarningSelection);
+    
+    
+    colorGroupingSelection = new ComboBox("Color Grouping");
+    colorGroupingSelection->addItemList(colorGroupings, 1);
+    colorGroupingSelection->setSelectedId(1,sendNotification);
+    colorGroupingSelection->addListener(this);
+    addAndMakeVisible(colorGroupingSelection);
+
+    invertInputButton = new UtilityButton("Invert", Font("Small Text", 13, Font::plain));
+    invertInputButton->setRadius(5.0f);
+    invertInputButton->setEnabledState(true);
+    invertInputButton->setCorners(true, true, true, true);
+    invertInputButton->addListener(this);
+    invertInputButton->setClickingTogglesState(true);
+    invertInputButton->setToggleState(false, sendNotification);
+    addAndMakeVisible(invertInputButton);
+
+    //button for controlling drawing algorithm - old line-style or new per-pixel style
+    drawMethodButton = new UtilityButton("DrawMethod", Font("Small Text", 13, Font::plain));
+    drawMethodButton->setRadius(5.0f);
+    drawMethodButton->setEnabledState(true);
+    drawMethodButton->setCorners(true, true, true, true);
+    drawMethodButton->addListener(this);
+    drawMethodButton->setClickingTogglesState(true);
+    drawMethodButton->setToggleState(false, sendNotification);
+    addAndMakeVisible(drawMethodButton);
+    
+    // two sliders for the two histogram components of the supersampled plotting mode
+    // todo: rename these
+    brightnessSliderA = new Slider;
+    brightnessSliderA->setRange (0, 1);
+    brightnessSliderA->setTextBoxStyle(Slider::NoTextBox, false, 50,30);
+    brightnessSliderA->addListener(this);
+    addAndMakeVisible (brightnessSliderA);
+    
+    brightnessSliderB = new Slider;
+    brightnessSliderB->setRange (0, 1);
+    brightnessSliderB->setTextBoxStyle(Slider::NoTextBox, false, 50,30);
+    brightnessSliderB->addListener(this);
+    addAndMakeVisible (brightnessSliderB);
+    
+    sliderALabel = new Label("Brightness","Brightness");
+    sliderALabel->setFont(Font("Small Text", 13, Font::plain));
+    sliderALabel->setColour(Label::textColourId,Colour(150,150,150));
+    addAndMakeVisible(sliderALabel);
+    
+    sliderBLabel = new Label("Min. brightness","Min. brightness");
+    sliderBLabel->setFont(Font("Small Text", 13, Font::plain));
+    sliderBLabel->setColour(Label::textColourId,Colour(150,150,150));
+    addAndMakeVisible(sliderBLabel);
+    
+    
+    //ScopedPointer<UtilityButton> drawClipWarningButton; // optinally draw (subtle) warning if data is clipped in display
+    drawClipWarningButton = new UtilityButton("0", Font("Small Text", 13, Font::plain));
+    drawClipWarningButton->setRadius(5.0f);
+    drawClipWarningButton->setEnabledState(true);
+    drawClipWarningButton->setCorners(true, true, true, true);
+    drawClipWarningButton->addListener(this);
+    drawClipWarningButton->setClickingTogglesState(true);
+    drawClipWarningButton->setToggleState(false, sendNotification);
+    addAndMakeVisible(drawClipWarningButton);
+    
+    
+    //ScopedPointer<UtilityButton> drawSaturateWarningButton; // optionally raise hell if the actual data is saturating
+    drawSaturateWarningButton = new UtilityButton("0", Font("Small Text", 13, Font::plain));
+    drawSaturateWarningButton->setRadius(5.0f);
+    drawSaturateWarningButton->setEnabledState(true);
+    drawSaturateWarningButton->setCorners(true, true, true, true);
+    drawSaturateWarningButton->addListener(this);
+    drawSaturateWarningButton->setClickingTogglesState(true);
+    drawSaturateWarningButton->setToggleState(false, sendNotification);
+    addAndMakeVisible(drawSaturateWarningButton);
+    
+
+    //button for pausing the display - works by skipping buffer updates. This way scrolling etc still works
+    pauseButton = new UtilityButton("Pause", Font("Small Text", 13, Font::plain));
+    pauseButton->setRadius(5.0f);
+    pauseButton->setEnabledState(true);
+    pauseButton->setCorners(true, true, true, true);
+    pauseButton->addListener(this);
+    pauseButton->setClickingTogglesState(true);
+    pauseButton->setToggleState(false, sendNotification);
+    addAndMakeVisible(pauseButton);
+
+
+    lfpDisplay->setNumChannels(nChans);
+    lfpDisplay->setRange(voltageRanges[HEADSTAGE_CHANNEL][selectedVoltageRange[HEADSTAGE_CHANNEL]-1].getFloatValue()*rangeGain[HEADSTAGE_CHANNEL]
+        ,HEADSTAGE_CHANNEL);
+	lfpDisplay->setRange(voltageRanges[ADC_CHANNEL][selectedVoltageRange[ADC_CHANNEL] - 1].getFloatValue()*rangeGain[ADC_CHANNEL]
+		, ADC_CHANNEL);
+	lfpDisplay->setRange(voltageRanges[AUX_CHANNEL][selectedVoltageRange[AUX_CHANNEL] - 1].getFloatValue()*rangeGain[AUX_CHANNEL]
+		, AUX_CHANNEL);
+
+    // add event display-specific controls (currently just an enable/disable button)
+    for (int i = 0; i < 8; i++)
+    {
+
+        EventDisplayInterface* eventOptions = new EventDisplayInterface(lfpDisplay, this, i);
+        eventDisplayInterfaces.add(eventOptions);
+        addAndMakeVisible(eventOptions);
+        eventOptions->setBounds(500+(floor(i/2)*20), getHeight()-20-(i%2)*20, 40, 20);
+
+        lfpDisplay->setEventDisplayState(i,true);
+
+    }
+    
+    // allocate samplesPerPixel, behaves like float samplesPerPixel[nChans][MAX_N_SAMP][MAX_N_SAMP_PER_PIXEL]
+    samplesPerPixel = (float***)malloc(nChans * sizeof(float **));
+    for(int i=0;i<nChans;i++)
+    {
+        samplesPerPixel[i] = (float**)malloc(MAX_N_SAMP * sizeof(float*));
+        for(int j=0;j<MAX_N_SAMP;j++)
+        {
+            samplesPerPixel[i][j] = (float*)malloc(MAX_N_SAMP_PER_PIXEL*sizeof(float));
+        }
+    }
+
+    TopLevelWindow::getTopLevelWindow(0)->addKeyListener(this);
+}
+
+LfpDisplayCanvas::~LfpDisplayCanvas()
+{
+
+    deleteAndZero(screenBuffer);
+    deleteAndZero(screenBufferMin);
+    deleteAndZero(screenBufferMean);
+    deleteAndZero(screenBufferMax);
+
+    // de-allocate 3d-array samplesPerPixel [nChans][MAX_N_SAMP][MAX_N_SAMP_PER_PIXEL];
+
+    for(int i=0;i<nChans;i++)
+    {
+        for(int j=0;j<MAX_N_SAMP;j++)
+        {
+            free(samplesPerPixel[i][j]);
+        }
+        free(samplesPerPixel[i]);
+    }
+    free(samplesPerPixel);
+    
+    
+    TopLevelWindow::getTopLevelWindow(0)->removeKeyListener(this);
+}
+
+void LfpDisplayCanvas::resized()
+{
+
+    timescale->setBounds(leftmargin,0,getWidth()-scrollBarThickness-leftmargin,30);
+    viewport->setBounds(0,30,getWidth(),getHeight()-90);
+
+    if (lfpDisplay->getSingleChannelState())
+        lfpDisplay->setChannelHeight(viewport->getHeight(),false);
+
+    lfpDisplay->setBounds(0,0,getWidth()-scrollBarThickness, lfpDisplay->getChannelHeight()*nChans);
+
+    rangeSelection->setBounds(5,getHeight()-30,80,25);
+    timebaseSelection->setBounds(175,getHeight()-30,60,25);
+    
+    spreadSelection->setBounds(245,getHeight()-30,60,25);
+    
+    overlapSelection->setBounds(315,getHeight()-30,60,25);
+    drawClipWarningButton->setBounds(410-30,getHeight()-29,20,20);
+    
+    colorGroupingSelection->setBounds(620,getHeight()-30,60,25);
+
+    invertInputButton->setBounds(750,getHeight()-50,100,22);
+    drawMethodButton->setBounds(750,getHeight()-25,100,22);
+    pauseButton->setBounds(860,getHeight()-50,50,44);
+
+    saturationWarningSelection->setBounds(315+90,getHeight()-30,60,25);
+    drawSaturateWarningButton->setBounds(410-30+90,getHeight()-29,20,20);
+    
+    for (int i = 0; i < 8; i++)
+    {
+        eventDisplayInterfaces[i]->setBounds(500+(floor(i/2)*20), getHeight()-40+(i%2)*20, 40, 20); // arrange event channel buttons in two rows
+        eventDisplayInterfaces[i]->repaint();
+    }
+    
+    brightnessSliderA->setBounds(920,getHeight()-50,100,22);
+    sliderALabel->setBounds(1020, getHeight()-50, 180, 22);
+    brightnessSliderA->setValue(0.9); //set default value
+    
+    brightnessSliderB->setBounds(920,getHeight()-25,100,22);
+    sliderBLabel->setBounds(1020, getHeight()-25, 180, 22);
+    brightnessSliderB->setValue(0.1); //set default value
+    
+    int bh = 25/typeButtons.size();
+    for (int i = 0; i < typeButtons.size(); i++)
+    {
+        typeButtons[i]->setBounds(110,getHeight()-30+i*bh,50,bh);
+    }
+    // std::cout << "Canvas thinks LfpDisplay should be this high: "
+    //  << lfpDisplay->getTotalHeight() << std::endl;
+
+}
+
+void LfpDisplayCanvas::beginAnimation()
+{
+    std::cout << "Beginning animation." << std::endl;
+
+    displayBufferSize = displayBuffer->getNumSamples();
+
+    for (int i = 0; i < screenBufferIndex.size(); i++)
+    {
+        screenBufferIndex.set(i,0);
+    }
+
+    startCallbacks();
+}
+
+void LfpDisplayCanvas::endAnimation()
+{
+    std::cout << "Ending animation." << std::endl;
+
+    stopCallbacks();
+}
+
+void LfpDisplayCanvas::update()
+{
+    nChans = jmax(processor->getNumInputs(),1);
+
+    sampleRate.clear();
+    screenBufferIndex.clear();
+    lastScreenBufferIndex.clear();
+    displayBufferIndex.clear();
+
+    for (int i = 0; i <= nChans; i++) // extra channel for events
+    {
+		if (processor->getNumInputs() > 0)
+		{
+			if (i < nChans)
+				sampleRate.add(processor->channels[i]->sampleRate);
+			else
+				sampleRate.add(processor->channels[i - 1]->sampleRate); // for event channel (IT'S A HACK -- BE CAREFUL!)
+		}
+		else
+			sampleRate.add(30000);
+        
+       // std::cout << "Sample rate for ch " << i << " = " << sampleRate[i] << std::endl; 
+        displayBufferIndex.add(0);
+        screenBufferIndex.add(0);
+        lastScreenBufferIndex.add(0);
+    }
+
+
+
+    if (nChans != lfpDisplay->getNumChannels())
+    {
+        //std::cout << "Setting num inputs on LfpDisplayCanvas to " << nChans << std::endl;
+
+        refreshScreenBuffer();
+
+        lfpDisplay->setNumChannels(nChans); // add an extra channel for events
+
+        // update channel names
+        for (int i = 0; i < processor->getNumInputs(); i++)
+        {
+
+            String chName = processor->channels[i]->getName();
+
+            //std::cout << chName << std::endl;
+
+            lfpDisplay->channelInfo[i]->setName(chName);
+            lfpDisplay->enableChannel(isChannelEnabled[i], i);
+
+        }
+
+        lfpDisplay->setBounds(0,0,getWidth()-scrollBarThickness*2, lfpDisplay->getTotalHeight());
+
+        resized();
+    }
+    else
+    {
+        for (int i = 0; i < processor->getNumInputs(); i++)
+        {
+            lfpDisplay->channels[i]->updateType();
+            lfpDisplay->channelInfo[i]->updateType();
+        }
+        
+    }
+
+}
+
+void LfpDisplayCanvas::buttonClicked(Button* b)
+{
+    if (b == invertInputButton)
+    {
+        lfpDisplay->setInputInverted(b->getToggleState());
+        return;
+    }
+    if (b == drawMethodButton)
+    {
+        lfpDisplay->setDrawMethod(b->getToggleState()); // this should be done the same way as drawClipWarning - or the other way around.
+        return;
+    }
+    if (b == drawClipWarningButton)
+    {
+        drawClipWarning = b->getToggleState();
+        
+        fullredraw=true;
+        repaint();
+        refresh();
+        return;
+    }
+    if (b == drawSaturateWarningButton)
+    {
+        drawSaturationWarning = b->getToggleState();
+        
+        fullredraw=true;
+        repaint();
+        refresh();
+        return;
+    }
+    
+    if (b == pauseButton)
+    {
+        lfpDisplay->isPaused = b->getToggleState();
+        return;
+    }
+
+    int idx = typeButtons.indexOf((UtilityButton*)b);
+    if ((idx >= 0) && (b->getToggleState()))
+    {
+        for (int i = 0; i < processor->getNumInputs(); i++)
+        {
+            if (lfpDisplay->channels[i]->getSelected())
+            {
+                lfpDisplay->channels[i]->deselect();
+                lfpDisplay->channels[i]->repaint();
+            }
+        }  
+        setSelectedType((ChannelType) idx, false);
+    }
+
+}
+
+
+void LfpDisplayCanvas::comboBoxChanged(ComboBox* cb)
+{
+
+    if (cb == timebaseSelection)
+    {
+        if (cb->getSelectedId())
+        {
+            timebase = timebases[cb->getSelectedId()-1].getFloatValue();
+        }
+        else
+        {
+            timebase = cb->getText().getFloatValue();
+            if (timebase)
+            {
+                if (timebase < timebases[0].getFloatValue())
+                {
+                    cb->setSelectedId(1,dontSendNotification);
+                    timebase = timebases[0].getFloatValue();
+                }
+                else if (timebase > timebases[timebases.size()-1].getFloatValue())
+                {
+                    cb->setSelectedId(timebases.size(),dontSendNotification);
+                    timebase = timebases[timebases.size()-1].getFloatValue();
+                }
+                else
+                    cb->setText(String(timebase,1),dontSendNotification);
+            }
+            else
+            {
+                if (selectedSpread == 0)
+                {
+                    cb->setText(selectedTimebaseValue,dontSendNotification);
+                    timebase = selectedTimebaseValue.getFloatValue();
+                }
+                else
+                {
+                    cb->setSelectedId(selectedTimebase,dontSendNotification);
+                    timebase = timebases[selectedTimebase-1].getFloatValue();
+                }
+
+            }
+        }
+    }
+    else if (cb == rangeSelection)
+    {
+        if (cb->getSelectedId())
+        {
+        lfpDisplay->setRange(voltageRanges[selectedChannelType][cb->getSelectedId()-1].getFloatValue()*rangeGain[selectedChannelType]
+            ,selectedChannelType);
+        }
+        else
+        {
+            float vRange = cb->getText().getFloatValue();
+            if (vRange)
+            {
+                if (vRange < voltageRanges[selectedChannelType][0].getFloatValue())
+                {
+                    cb->setSelectedId(1,dontSendNotification);
+                    vRange = voltageRanges[selectedChannelType][0].getFloatValue();
+                }
+                else if (vRange > voltageRanges[selectedChannelType][voltageRanges[selectedChannelType].size()-1].getFloatValue())
+                {
+                   // cb->setSelectedId(voltageRanges[selectedChannelType].size(),dontSendNotification);
+                   // vRange = voltageRanges[selectedChannelType][voltageRanges[selectedChannelType].size()-1].getFloatValue();
+                }
+                else
+                {
+                    if (rangeGain[selectedChannelType] > 1)
+                        cb->setText(String(vRange,1),dontSendNotification);
+                    else
+                        cb->setText(String(vRange),dontSendNotification);
+                }
+                lfpDisplay->setRange(vRange*rangeGain[selectedChannelType],selectedChannelType);
+            }
+            else
+            {
+                if (selectedVoltageRange[selectedChannelType])
+                    cb->setText(selectedVoltageRangeValues[selectedChannelType],dontSendNotification);
+                else
+                    cb->setSelectedId(selectedVoltageRange[selectedChannelType],dontSendNotification);
+            }
+        }
+        selectedVoltageRange[selectedChannelType] = cb->getSelectedId();
+        selectedVoltageRangeValues[selectedChannelType] = cb->getText();
+        //std::cout << "Setting range to " << voltageRanges[cb->getSelectedId()-1].getFloatValue() << std::endl;
+        fullredraw = true; //issue full redraw
+        repaint();
+        refresh();
+    }
+    else if (cb == spreadSelection)
+    {
+        if (cb->getSelectedId())
+        {
+            lfpDisplay->setChannelHeight(spreads[cb->getSelectedId()-1].getIntValue());
+            resized();
+        }
+        else
+        {
+            int spread = cb->getText().getIntValue();
+            if (spread)
+            {
+                if (spread < spreads[0].getFloatValue())
+                {
+                    cb->setSelectedId(1,dontSendNotification);
+                    spread = spreads[0].getFloatValue();
+                }
+                else if (spread > spreads[spreads.size()-1].getFloatValue())
+                {
+                    cb->setSelectedId(spreads.size(),dontSendNotification);
+                    spread = spreads[spreads.size()-1].getFloatValue();
+                }
+                else
+                {
+                    cb->setText(String(spread),dontSendNotification);
+                }
+                lfpDisplay->setChannelHeight(spread);
+                resized();
+            }
+            else
+            {
+                if (selectedSpread == 0)
+                    cb->setText(selectedSpreadValue,dontSendNotification);
+                else
+                    cb->setSelectedId(selectedSpread,dontSendNotification);
+            }
+        }
+        selectedSpread = cb->getSelectedId();
+        selectedSpreadValue = cb->getText();
+        fullredraw = true; //issue full redraw
+        repaint();
+        refresh();
+        //std::cout << "Setting spread to " << spreads[cb->getSelectedId()-1].getFloatValue() << std::endl;
+    }
+    else if (cb == saturationWarningSelection)
+    {
+        if (cb->getSelectedId())
+        {
+            selectedSaturationValueFloat=(saturationThresholds[cb->getSelectedId()-1].getFloatValue());
+        }
+        else
+        {
+            selectedSaturationValueFloat = cb->getText().getFloatValue();
+            if (selectedSaturationValueFloat)
+            {
+                 std::cout << "Setting saturation warning to to " << selectedSaturationValueFloat << std::endl;
+                if (selectedSaturationValueFloat < 0)
+                {
+                    cb->setSelectedId(1,dontSendNotification);
+                    selectedSaturationValueFloat = saturationThresholds[0].getFloatValue();
+                }
+                else
+                {
+                  //  cb->setText(String(selectedSaturationValueFloat),dontSendNotification);
+                }
+            }
+            else
+            {
+               // cb->setSelectedId(1,dontSendNotification);
+                //selectedSaturationValueFloat = saturationThresholds[0].getFloatValue();
+
+            }
+        }
+       // selectedSpread = cb->getSelectedId();
+       // selectedSpreadValue = cb->getText();
+       // lfpDisplay->setChannelHeight( lfpDisplay->getChannelHeight());
+        fullredraw = true; //issue full redraw
+        repaint();
+        refresh();
+        std::cout << "Setting saturation warning to to " << selectedSaturationValueFloat << std::endl;
+    }
+    else if (cb == overlapSelection)
+    {
+        if (cb->getSelectedId())
+        {
+            channelOverlapFactor=(overlaps[cb->getSelectedId()-1].getFloatValue());
+            resized();
+        }
+        else
+        {
+            float overlap = cb->getText().getFloatValue();
+            if (overlap)
+            {
+                if (overlap < overlaps[0].getFloatValue())
+                {
+                    cb->setSelectedId(1,dontSendNotification);
+                    overlap = overlaps[0].getFloatValue();
+                }
+                else if (overlap > overlaps[overlaps.size()-1].getFloatValue())
+                {
+                    cb->setSelectedId(overlaps.size(),dontSendNotification);
+                    overlap = overlaps[overlaps.size()-1].getFloatValue();
+                }
+                else
+                {
+                    cb->setText(String(overlap),dontSendNotification);
+                }
+                channelOverlapFactor= overlap;
+                resized();
+            }
+            else
+            {
+                if (selectedSpread == 0)
+                    cb->setText(selectedSpreadValue,dontSendNotification);
+                else
+                    cb->setSelectedId(selectedSpread,dontSendNotification);
+            }
+        }
+        selectedSpread = cb->getSelectedId();
+        selectedSpreadValue = cb->getText();
+        lfpDisplay->setChannelHeight( lfpDisplay->getChannelHeight());
+        fullredraw = true; //issue full redraw
+        repaint();
+        refresh();
+        //std::cout << "Setting spread to " << spreads[cb->getSelectedId()-1].getFloatValue() << std::endl;
+    }
+
+    else if (cb == colorGroupingSelection)
+    {
+        // set color grouping hre
+
+        lfpDisplay->setColorGrouping(colorGroupings[cb->getSelectedId()-1].getIntValue());// so that channel colors get re-assigned
+        fullredraw = true; //issue full redraw
+        repaint();
+        refresh();
+    }
+
+    timescale->setTimebase(timebase);
+}
+
+
+void LfpDisplayCanvas::sliderValueChanged(Slider* sl)
+{
+    if (sl == brightnessSliderA)
+    histogramParameterA = sl->getValue();
+
+    if (sl == brightnessSliderB)
+    histogramParameterB = sl->getValue();
+    
+    fullredraw=true;
+    //repaint();
+    refresh();
+
+}
+
+
+void LfpDisplayCanvas::sliderEvent(Slider* sl) {}
+
+int LfpDisplayCanvas::getChannelHeight()
+{
+    //return spreads[spreadSelection->getSelectedId()-1].getIntValue();
+    return (int)spreadSelection->getText().getIntValue();
+    
+}
+
+
+void LfpDisplayCanvas::setParameter(int param, float val)
+{
+    // not used for anything, since LfpDisplayCanvas is not a processor
+}
+
+void LfpDisplayCanvas:: setRangeSelection(float range, bool canvasMustUpdate)
+{
+    if (canvasMustUpdate)
+    {
+        rangeSelection->setText(String(range/rangeGain[selectedChannelType]), sendNotification); 
+    }
+    else
+    {
+        rangeSelection->setText(String(range/rangeGain[selectedChannelType]),dontSendNotification);
+        selectedVoltageRange[selectedChannelType]=rangeSelection->getSelectedId();
+        selectedVoltageRangeValues[selectedChannelType]=rangeSelection->getText();
+
+        repaint();
+        refresh();
+    }
+
+}
+
+void LfpDisplayCanvas:: setSpreadSelection(int spread, bool canvasMustUpdate)
+{
+    if (canvasMustUpdate)
+    {
+        spreadSelection->setText(String(spread),sendNotification);
+    }
+    else
+    {
+        spreadSelection->setText(String(spread),dontSendNotification);
+        selectedSpread=spreadSelection->getSelectedId();
+        selectedSpreadValue=spreadSelection->getText();
+
+        repaint();
+        refresh();
+    }
+}
+
+void LfpDisplayCanvas::refreshState()
+{
+    // called when the component's tab becomes visible again
+
+    for (int i = 0; i <= displayBufferIndex.size(); i++) // include event channel
+    {
+
+        displayBufferIndex.set(i, processor->getDisplayBufferIndex(i));
+        screenBufferIndex.set(i,0);
+    }
+
+}
+
+void LfpDisplayCanvas::refreshScreenBuffer()
+{
+
+    for (int i = 0; i < screenBufferIndex.size(); i++)
+        screenBufferIndex.set(i,0);
+
+    screenBuffer->clear();
+    screenBufferMin->clear();
+    screenBufferMean->clear();
+    screenBufferMax->clear();
+
+
+    // int w = lfpDisplay->getWidth();
+    // //std::cout << "Refreshing buffer size to " << w << "pixels." << std::endl;
+
+    // for (int i = 0; i < w; 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
+    //  }
+    // }
+
+}
+
+void LfpDisplayCanvas::updateScreenBuffer()
+{
+
+    // copy new samples from the displayBuffer into the screenBuffer
+    int maxSamples = lfpDisplay->getWidth() - leftmargin;
+
+	ScopedLock displayLock(*processor->getMutex());
+
+    for (int channel = 0; channel <= nChans; channel++) // pull one extra channel for event display
+    {
+
+        if (screenBufferIndex[channel] >= maxSamples) // wrap around if we reached right edge before
+            screenBufferIndex.set(channel, 0);
+
+         // hold these values locally for each channel - is this a good idea?
+        int sbi = screenBufferIndex[channel];
+        int dbi = displayBufferIndex[channel];
+        
+        lastScreenBufferIndex.set(channel,sbi);
+
+        int index = processor->getDisplayBufferIndex(channel);
+
+        int nSamples =  index - dbi; // N new samples (not pixels) to be added to displayBufferIndex
+
+        if (nSamples < 0) // buffer has reset to 0
+        {
+            nSamples = (displayBufferSize - dbi) + index +1;
+             std::cout << "nsamples 0 " ;
+        }
+
+        //if (channel == 15 || channel == 16)
+        //     std::cout << channel << " " << sbi << " " << dbi << " " << nSamples << std::endl;
+
+
+        float ratio = sampleRate[channel] * timebase / float(getWidth() - leftmargin - scrollBarThickness); // samples / pixel
+        // this number is crucial: converting from samples to values (in px) for the screen buffer
+        int valuesNeeded = (int) float(nSamples) / ratio; // N pixels needed for this update
+
+        if (sbi + valuesNeeded > maxSamples)  // crop number of samples to fit canvas width
+        {
+            valuesNeeded = maxSamples - sbi;
+        }
+        float subSampleOffset = 0.0;
+
+        dbi %= displayBufferSize; // make sure we're not overshooting
+        int nextPos = (dbi + 1) % displayBufferSize; //  position next to displayBufferIndex in display buffer to copy from
+
+        // if (channel == 0)
+        //     std::cout << "Channel " 
+        //               << channel << " : " 
+        //               << sbi << " : " 
+        //               << index << " : " 
+        //               << dbi << " : " 
+        //               << valuesNeeded << " : " 
+        //               << ratio 
+        //                             << std::endl;
+        
+        if (valuesNeeded > 0 && valuesNeeded < 1000000)
+        {
+            for (int i = 0; i < valuesNeeded; i++) // also fill one extra sample for line drawing interpolation to match across draws
+            {
+                //If paused don't update screen buffers, but update all indexes as needed
+                if (!lfpDisplay->isPaused)
+                {
+                    float gain = 1.0;
+                    float alpha = (float) subSampleOffset;
+                    float invAlpha = 1.0f - alpha;
+
+                    screenBuffer->clear(channel, sbi, 1);
+                    screenBufferMin->clear(channel, sbi, 1);
+                    screenBufferMax->clear(channel, sbi, 1);
+
+                     dbi %= displayBufferSize; // just to be sure
+
+                    // interpolate between two samples with invAlpha and alpha
+                    screenBuffer->addFrom(channel, // destChannel
+                                          sbi, // destStartSample
+                                          displayBuffer->getReadPointer(channel, dbi), // source
+                                          1, // numSamples
+                                          invAlpha*gain); // gain
+
+
+                    screenBuffer->addFrom(channel, // destChannel
+                                          sbi, // destStartSample
+                                          displayBuffer->getReadPointer(channel, nextPos), // source
+                                          1, // numSamples
+                                          alpha*gain); // gain
+
+                    // same thing again, but this time add the min,mean, and max of all samples in current pixel
+                    float sample_min   =  10000000;
+                    float sample_max   = -10000000;
+                    
+                    int nextpix = (dbi +(int)ratio +1) % (displayBufferSize+1); //  position to next pixels index
+                    
+                    //if (nextpix <= dbi) { // at the end of the displaybuffer, this can occur and it causes the display to miss one pixel woth of sample - this circumvents that
+                    //    std::cout << "np " ;
+                        //nextpix=dbi;
+                    //}
+                   
+                    for (int j = dbi; j <= nextpix; j++)
+                    {
+                         float sample_current = displayBuffer->getSample(channel, j);
+                        //sample_mean = sample_mean + sample_current;
+
+                        if (sample_min>sample_current)
+                        {
+                            sample_min=sample_current;
+                        }
+
+                        if (sample_max<sample_current)
+                        {
+                            sample_max=sample_current;
+                        }
+                       
+                    }
+                    
+                    // similarly, for each pixel on the screen, we want a list of all values so we can draw a histogram later
+                    // for simplicity, we'll just do this as 2d array, samplesPerPixel[px][samples]
+                    // with an additional array sampleCountPerPixel[px] that holds the N samples per pixel
+                    if (channel < nChans) // we're looping over one 'extra' channel for events above, so make sure not to loop over that one here
+                        {
+                            int c = 0;
+                            for (int j = dbi; j <= nextpix & c < MAX_N_SAMP_PER_PIXEL; j++)
+                            {
+                                float sample_current = displayBuffer->getSample(channel, j);
+                                samplesPerPixel[channel][sbi][c]=sample_current;
+                                c++;
+                            }
+                            if (c>0){
+                                sampleCountPerPixel[sbi]=c-1; // save count of samples for this pixel
+                            }else{
+                                sampleCountPerPixel[sbi]=0;
+                            }
+                            //sample_mean = sample_mean/c;
+                            //screenBufferMean->addSample(channel, sbi, sample_mean*gain);
+                            
+                            screenBufferMin->addSample(channel, sbi, sample_min*gain);
+                            screenBufferMax->addSample(channel, sbi, sample_max*gain);
+                    }
+                sbi++;
+                }
+            
+            subSampleOffset += ratio;
+
+            while (subSampleOffset >= 1.0)
+            {
+                if (++dbi > displayBufferSize)
+                    dbi = 0;
+
+                nextPos = (dbi + 1) % displayBufferSize;
+                subSampleOffset -= 1.0;
+            }
+
+        }
+
+        // update values after we're done
+        screenBufferIndex.set(channel, sbi);
+        displayBufferIndex.set(channel, dbi);
+        }
+
+    }
+
+}
+
+const float LfpDisplayCanvas::getXCoord(int chan, int samp)
+{
+    return samp;
+}
+
+int LfpDisplayCanvas::getNumChannels()
+{
+    return nChans;
+}
+
+const float LfpDisplayCanvas::getYCoord(int chan, int samp)
+{
+    return *screenBuffer->getReadPointer(chan, samp);
+}
+
+const float LfpDisplayCanvas::getYCoordMean(int chan, int samp)
+{
+    return *screenBufferMean->getReadPointer(chan, samp);
+}
+const float LfpDisplayCanvas::getYCoordMin(int chan, int samp)
+{
+    return *screenBufferMin->getReadPointer(chan, samp);
+}
+const float LfpDisplayCanvas::getYCoordMax(int chan, int samp)
+{
+    return *screenBufferMax->getReadPointer(chan, samp);
+}
+
+const float* LfpDisplayCanvas::getSamplesPerPixel(int chan, int px)
+{
+    return samplesPerPixel[chan][px];
+}
+const int LfpDisplayCanvas::getSampleCountPerPixel(int px)
+{
+    return sampleCountPerPixel[px];
+}
+
+
+
+bool LfpDisplayCanvas::getInputInvertedState()
+{
+    return invertInputButton->getToggleState();
+}
+
+bool LfpDisplayCanvas::getDrawMethodState()
+{
+    return drawMethodButton->getToggleState();
+}
+
+void LfpDisplayCanvas::paint(Graphics& g)
+{
+    
+    //std::cout << "Painting" << std::endl;
+
+    //g.setColour(Colour(0,0,0)); // for high-precision per-pixel density display, make background black for better visibility
+    g.setColour(lfpDisplay->backgroundColour); //background color
+    g.fillRect(0, 0, getWidth(), getHeight());
+
+    g.setGradientFill(ColourGradient(Colour(50,50,50),0,0,
+                                     Colour(25,25,25),0,30,
+                                     false));
+
+    g.fillRect(0, 0, getWidth()-scrollBarThickness, 30);
+
+    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 || i == 0)
+            g.drawLine(w/10*i+leftmargin,0,w/10*i+leftmargin,getHeight()-60,3.0f);
+        else
+            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);
+
+    g.setFont(Font("Default", 16, Font::plain));
+
+    g.setColour(Colour(100,100,100));
+
+    g.drawText("Range("+ rangeUnits[selectedChannelType] +")",5,getHeight()-55,300,20,Justification::left, false);
+    g.drawText("Timebase(s)",140,getHeight()-55,300,20,Justification::left, false);
+    g.drawText("Size(px)",240,getHeight()-55,300,20,Justification::left, false);
+    g.drawText("Clip",315,getHeight()-55,300,20,Justification::left, false);
+    g.drawText("Warn",373,getHeight()-55,300,20,Justification::left, false);
+    
+    g.drawText("Sat.Warn.",315+105,getHeight()-55,300,20,Justification::left, false);
+    //g.drawText("Warn",375+90,getHeight()-55,300,20,Justification::left, false);
+    
+    g.drawText("Color grouping",620,getHeight()-55,300,20,Justification::left, false);
+
+    
+    //g.drawText(typeNames[selectedChannelType],110,getHeight()-30,50,20,Justification::centredLeft,false);
+
+    g.drawText("Event disp.",500,getHeight()-55,300,20,Justification::left, false);
+
+    if(drawClipWarning)
+    {
+        g.setColour(Colours::white);
+        g.fillRoundedRectangle(408-30,getHeight()-30-1,24,24,6.0f);
+    }
+    
+    if(drawSaturationWarning)
+    {
+        g.setColour(Colours::red);
+        g.fillRoundedRectangle(408-30+90,getHeight()-30-1,24,24,6.0f);
+    }
+    
+
+}
+
+void LfpDisplayCanvas::refresh()
+{
+
+    updateScreenBuffer();
+
+    lfpDisplay->refresh(); // redraws only the new part of the screen buffer
+
+    //getPeer()->performAnyPendingRepaintsNow();
+
+}
+
+bool LfpDisplayCanvas::keyPressed(const KeyPress& key)
+{
+    if (key.getKeyCode() == key.spaceKey)
+    {
+        pauseButton->setToggleState(!pauseButton->getToggleState(), sendNotification);
+        return true;
+    }
+
+    return false;
+}
+
+bool LfpDisplayCanvas::keyPressed(const KeyPress& key, Component* orig)
+{
+    if (getTopLevelComponent() == orig && isVisible())
+    {
+        return keyPressed(key);
+    }
+    return false;
+}
+
+void LfpDisplayCanvas::saveVisualizerParameters(XmlElement* xml)
+{
+
+    XmlElement* xmlNode = xml->createNewChildElement("LFPDISPLAY");
+
+
+    xmlNode->setAttribute("Range",selectedVoltageRangeValues[0]+","+selectedVoltageRangeValues[1]+
+        ","+selectedVoltageRangeValues[2]);
+    xmlNode->setAttribute("Timebase",timebaseSelection->getText());
+    xmlNode->setAttribute("Spread",spreadSelection->getText());
+    xmlNode->setAttribute("colorGrouping",colorGroupingSelection->getSelectedId());
+    xmlNode->setAttribute("isInverted",invertInputButton->getToggleState());
+    xmlNode->setAttribute("drawMethod",drawMethodButton->getToggleState());
+
+    int eventButtonState = 0;
+
+    for (int i = 0; i < 8; i++)
+    {
+        if (lfpDisplay->eventDisplayEnabled[i])
+        {
+            eventButtonState += (1 << i);
+        }
+    }
+
+    xmlNode->setAttribute("EventButtonState", eventButtonState);
+
+    String channelDisplayState = "";
+
+    for (int i = 0; i < nChans; i++)
+    {
+        if (lfpDisplay->getEnabledState(i))
+        {
+            channelDisplayState += "1";
+        }
+        else
+        {
+            channelDisplayState += "0";
+        }
+    }
+
+    xmlNode->setAttribute("ChannelDisplayState", channelDisplayState);
+
+    xmlNode->setAttribute("ScrollX",viewport->getViewPositionX());
+    xmlNode->setAttribute("ScrollY",viewport->getViewPositionY());
+}
+
+
+void LfpDisplayCanvas::loadVisualizerParameters(XmlElement* xml)
+{
+    forEachXmlChildElement(*xml, xmlNode)
+    {
+        if (xmlNode->hasTagName("LFPDISPLAY"))
+        {
+            StringArray ranges;
+            ranges.addTokens(xmlNode->getStringAttribute("Range"),",",String::empty);
+            selectedVoltageRangeValues[0] = ranges[0];
+            selectedVoltageRangeValues[1] = ranges[1];
+            selectedVoltageRangeValues[2] = ranges[2];
+            selectedVoltageRange[0] = voltageRanges[0].indexOf(ranges[0])+1;
+            selectedVoltageRange[1] = voltageRanges[1].indexOf(ranges[1])+1;
+            selectedVoltageRange[2] = voltageRanges[2].indexOf(ranges[2])+1;
+            rangeSelection->setText(ranges[0]);
+
+            timebaseSelection->setText(xmlNode->getStringAttribute("Timebase"));
+            spreadSelection->setText(xmlNode->getStringAttribute("Spread"));
+            if (xmlNode->hasAttribute("colorGrouping"))
+            {
+                colorGroupingSelection->setSelectedId(xmlNode->getIntAttribute("colorGrouping"));
+            }
+            else
+            {
+                colorGroupingSelection->setSelectedId(1);
+            }
+
+            invertInputButton->setToggleState(xmlNode->getBoolAttribute("isInverted", true), sendNotification);
+
+            drawMethodButton->setToggleState(xmlNode->getBoolAttribute("drawMethod", true), sendNotification);
+
+            viewport->setViewPosition(xmlNode->getIntAttribute("ScrollX"),
+                                      xmlNode->getIntAttribute("ScrollY"));
+
+            int eventButtonState = xmlNode->getIntAttribute("EventButtonState");
+
+            for (int i = 0; i < 8; i++)
+            {
+                lfpDisplay->eventDisplayEnabled[i] = (eventButtonState >> i) & 1;
+
+                eventDisplayInterfaces[i]->checkEnabledState();
+            }
+
+            String channelDisplayState = xmlNode->getStringAttribute("ChannelDisplayState");
+
+            for (int i = 0; i < channelDisplayState.length(); i++)
+            {
+
+                if (channelDisplayState.substring(i,i+1).equalsIgnoreCase("1"))
+                {
+                    //std::cout << "LfpDisplayCanvas enabling channel " << i << std::endl;
+                    lfpDisplay->enableChannel(true, i);
+                    isChannelEnabled.set(i,true); //lfpDisplay->enableChannel(true, i);
+                }
+                else
+                {
+                    //std::cout << "LfpDisplayCanvas disabling channel " << i << std::endl;
+                    lfpDisplay->enableChannel(false, i);
+                    isChannelEnabled.set(i,false);
+                }
+
+
+            }
+        }
+    }
+
+}
+
+ChannelType LfpDisplayCanvas::getChannelType(int n)
+{
+	if (n < processor->getNumInputs())
+		return processor->channels[n]->getType();
+	else
+		return HEADSTAGE_CHANNEL;
+}
+
+ChannelType LfpDisplayCanvas::getSelectedType()
+{
+    return selectedChannelType;
+}
+
+void LfpDisplayCanvas::setSelectedType(ChannelType type, bool toggleButton)
+{
+    if (selectedChannelType == type)
+        return; //Nothing to do here
+    selectedChannelType = type;
+    rangeSelection->clear(dontSendNotification);
+    rangeSelection->addItemList(voltageRanges[type],1);
+    int id = selectedVoltageRange[type];
+    if (id)
+        rangeSelection->setSelectedId(id,sendNotification);
+    else
+        rangeSelection->setText(selectedVoltageRangeValues[selectedChannelType],dontSendNotification);
+    repaint(5,getHeight()-55,300,100);
+
+    if (toggleButton)
+        typeButtons[type]->setToggleState(true,dontSendNotification);
+}
+
+String LfpDisplayCanvas::getTypeName(ChannelType type)
+{
+    return typeNames[type];
+}
+
+int LfpDisplayCanvas::getRangeStep(ChannelType type)
+{
+    return rangeSteps[type];
+}
+
+//void LfpDisplayCanvas::sliderValueChanged(Slider* s)
+//{    
+//    sliderEvent(slider);
+//}
+
+
+// -------------------------------------------------------------
+
+LfpTimescale::LfpTimescale(LfpDisplayCanvas* c) : canvas(c)
+{
+
+    font = Font("Default", 16, Font::plain);
+}
+
+LfpTimescale::~LfpTimescale()
+{
+
+}
+
+void LfpTimescale::paint(Graphics& g)
+{
+
+    g.setFont(font);
+
+    g.setColour(Colour(100,100,100));
+
+    g.drawText("ms:",5,0,100,getHeight(),Justification::left, false);
+
+    for (int i = 1; i < 10; i++)
+    {
+        if (i == 5)
+            g.drawLine(getWidth()/10*i,0,getWidth()/10*i,getHeight(),3.0f);
+        else
+            g.drawLine(getWidth()/10*i,0,getWidth()/10*i,getHeight(),1.0f);
+
+        g.drawText(labels[i-1],getWidth()/10*i+3,0,100,getHeight(),Justification::left, false);
+    }
+
+}
+
+void LfpTimescale::setTimebase(float t)
+{
+    timebase = t;
+
+    labels.clear();
+
+    for (float i = 1.0f; i < 10.0; i++)
+    {
+        String labelString = String(timebase/10.0f*1000.0f*i);
+
+        labels.add(labelString.substring(0,6));
+    }
+
+    repaint();
+
+}
+
+
+// ---------------------------------------------------------------
+
+LfpDisplay::LfpDisplay(LfpDisplayCanvas* c, Viewport* v) :
+    singleChan(-1), canvas(c), viewport(v)
+{
+    totalHeight = 0;
+    colorGrouping=1;
+
+    range[0] = 1000;
+    range[1] = 500;
+    range[2] = 500000;
+
+    addMouseListener(this, true);
+
+    // 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)));
+    //}
+
+    backgroundColour = Colour(0,18,43);
+    
+    //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));
+
+    isPaused=false;
+
+}
+
+LfpDisplay::~LfpDisplay()
+{
+    deleteAllChildren();
+}
+
+
+
+int LfpDisplay::getNumChannels()
+{
+    return numChans;
+}
+
+
+
+int LfpDisplay::getColorGrouping()
+{
+    return colorGrouping;
+}
+
+void LfpDisplay::setColorGrouping(int i)
+{
+    colorGrouping=i;
+    setColors(); // so that channel colors get re-assigned
+
+}
+
+
+void LfpDisplay::setNumChannels(int numChannels)
+{
+    numChans = numChannels;
+
+    deleteAllChildren();
+
+    channels.clear();
+    channelInfo.clear();
+
+    totalHeight = 0;
+
+    for (int i = 0; i < numChans; i++)
+    {
+
+        //std::cout << "Adding new display for channel " << i << std::endl;
+
+        LfpChannelDisplay* lfpChan = new LfpChannelDisplay(canvas, this, i);
+
+        //lfpChan->setColour(channelColours[i % channelColours.size()]);
+        lfpChan->setRange(range[canvas->getChannelType(i)]);
+        lfpChan->setChannelHeight(canvas->getChannelHeight());
+        
+        addAndMakeVisible(lfpChan);
+
+        channels.add(lfpChan);
+
+        LfpChannelDisplayInfo* lfpInfo = new LfpChannelDisplayInfo(canvas, this, i);
+
+        //lfpInfo->setColour(channelColours[i % channelColours.size()]);
+        lfpInfo->setRange(range[canvas->getChannelType(i)]);
+        lfpInfo->setChannelHeight(canvas->getChannelHeight());
+
+        addAndMakeVisible(lfpInfo);
+
+        channelInfo.add(lfpInfo);
+
+		savedChannelState.add(true);
+
+        totalHeight += lfpChan->getChannelHeight();
+
+    }
+
+    setColors();
+    
+
+    //std::cout << "TOTAL HEIGHT = " << totalHeight << std::endl;
+
+}
+
+void LfpDisplay::setColors()
+{
+    for (int i = 0; i < numChans; i++)
+    {
+
+        channels[i]->setColour(channelColours[(int(i/colorGrouping)+1) % channelColours.size()]);
+        channelInfo[i]->setColour(channelColours[(int(i/colorGrouping)+1)  % channelColours.size()]);
+    }
+
+}
+
+
+int LfpDisplay::getTotalHeight()
+{
+    return totalHeight;
+}
+
+void LfpDisplay::resized()
+{
+    
+    //canvas->channelOverlapFactor
+
+    int totalHeight = 0;
+
+    for (int i = 0; i < channels.size(); i++)
+    {
+
+        LfpChannelDisplay* disp = channels[i];
+
+        disp->setBounds(canvas->leftmargin,
+                        totalHeight-(disp->getChannelOverlap()*canvas->channelOverlapFactor)/2,
+                        getWidth(),
+                        disp->getChannelHeight()+(disp->getChannelOverlap()*canvas->channelOverlapFactor));
+
+        disp-> resized();
+        
+        LfpChannelDisplayInfo* info = channelInfo[i];
+
+        info->setBounds(0,
+                        totalHeight-disp->getChannelHeight()/4,
+                        canvas->leftmargin,
+                        disp->getChannelHeight());
+
+        totalHeight += disp->getChannelHeight();
+
+    }
+
+    canvas->fullredraw = true; //issue full redraw
+    if (singleChan != -1)
+        viewport->setViewPosition(Point<int>(0,singleChan*getChannelHeight()));
+
+  
+
+    lfpChannelBitmap = Image(Image::ARGB, getWidth(), getHeight(), false);
+    
+    //inititalize black background
+    Graphics gLfpChannelBitmap(lfpChannelBitmap);
+    gLfpChannelBitmap.setColour(Colour(0,0,0)); //background color
+    gLfpChannelBitmap.fillRect(0,0, getWidth(), getHeight());
+
+    
+    canvas->fullredraw = true;
+    
+    refresh();
+    // std::cout << "Total height: " << totalHeight << std::endl;
+
+}
+
+void LfpDisplay::paint(Graphics& g)
+{
+
+    g.drawImageAt(lfpChannelBitmap, canvas->leftmargin,0);
+    
+}
+
+
+void LfpDisplay::refresh()
+{
+    // X-bounds of this update
+    int fillfrom = canvas->lastScreenBufferIndex[0];
+    int fillto = (canvas->screenBufferIndex[0]);
+    
+    if (fillfrom<0){fillfrom=0;};
+    if (fillto>lfpChannelBitmap.getWidth()){fillto=lfpChannelBitmap.getWidth();};
+    
+    int topBorder = viewport->getViewPositionY();
+    int bottomBorder = viewport->getViewHeight() + topBorder;
+
+    // clear appropriate section of the bitmap --
+    // we need to do this before each channel draws its new section of data into lfpChannelBitmap
+    Graphics gLfpChannelBitmap(lfpChannelBitmap);
+    gLfpChannelBitmap.setColour(backgroundColour); //background color
+
+    if (canvas->fullredraw)
+    {
+        gLfpChannelBitmap.fillRect(0,0, getWidth(), getHeight());
+    } else {
+        gLfpChannelBitmap.setColour(backgroundColour); //background color
+
+        gLfpChannelBitmap.fillRect(fillfrom,0, (fillto-fillfrom)+1, getHeight());
+    };
+    
+    
+    for (int i = 0; i < numChans; i++)
+    {
+
+        int componentTop = channels[i]->getY();
+        int componentBottom = channels[i]->getHeight() + componentTop;
+
+        if ((topBorder <= componentBottom && bottomBorder >= componentTop)) // only draw things that are visible
+        {
+            if (canvas->fullredraw)
+            {
+                channels[i]->fullredraw = true;
+                
+                channels[i]->pxPaint();
+                channelInfo[i]->repaint();
+                
+            }
+            else
+            {
+                 channels[i]->pxPaint(); // draws to lfpChannelBitmap
+                
+                 // it's not clear why, but apparently because the pxPaint() in a child component of LfpDisplay, we also need to issue repaint() calls for each channel, even though there's nothin to repaint there. Otherwise, the repaint call in LfpDisplay::refresh(), a few lines down, lags behind the update line by ~60 px. This could ahev something to do with teh reopaint message passing in juce. In any case, this seemingly redundant repaint here seems to fix the issue.
+                
+                 // we redraw from 0 to +2 (px) relative to the real redraw window, the +1 draws the vertical update line
+                 channels[i]->repaint(fillfrom, 0, (fillto-fillfrom)+2, channels[i]->getHeight());
+                
+                
+            }
+            //std::cout << i << std::endl;
+        }
+
+    }
+    
+    
+    if (canvas->fullredraw)
+    {
+        repaint(0,topBorder,getWidth(),bottomBorder-topBorder);
+    }else{
+        //repaint(fillfrom, topBorder, (fillto-fillfrom)+1, bottomBorder-topBorder); // doesntb seem to be needed and results in duplicate repaint calls
+    }
+    
+    canvas->fullredraw = false;
+    
+}
+
+
+
+void LfpDisplay::setRange(float r, ChannelType type)
+{
+    range[type] = r;
+
+    for (int i = 0; i < numChans; i++)
+    {
+        if (channels[i]->getType() == type)
+            channels[i]->setRange(range[type]);
+    }
+    canvas->fullredraw = true; //issue full redraw
+}
+
+int LfpDisplay::getRange()
+{
+    return getRange(canvas->getSelectedType());
+}
+
+int LfpDisplay::getRange(ChannelType type)
+{
+    for (int i=0; i < numChans; i++)
+    {
+        if (channels[i]->getType() == type)
+            return channels[i]->getRange();
+    }
+    return 0;
+}
+
+
+void LfpDisplay::setChannelHeight(int r, bool resetSingle)
+{
+
+    for (int i = 0; i < numChans; i++)
+    {
+        channels[i]->setChannelHeight(r);
+        channelInfo[i]->setChannelHeight(r);
+    }
+    if (resetSingle && singleChan != -1)
+    {
+        std::cout << "width " <<  getWidth() << " numchans  " << numChans << " height " << getChannelHeight() << std::endl;
+        setSize(getWidth(),numChans*getChannelHeight());
+        viewport->setScrollBarsShown(true,false);
+        viewport->setViewPosition(Point<int>(0,singleChan*r));
+        singleChan = -1;
+        for (int n = 0; n < numChans; n++)
+        {
+			channelInfo[n]->setEnabledState(savedChannelState[n]);
+        }
+    }
+
+    resized();
+
+}
+
+void LfpDisplay::setInputInverted(bool isInverted)
+{
+
+    for (int i = 0; i < numChans; i++)
+    {
+        channels[i]->setInputInverted(isInverted);
+    }
+
+    resized();
+
+}
+
+void LfpDisplay::setDrawMethod(bool isDrawMethod)
+{
+    for (int i = 0; i < numChans; i++)
+    {
+        channels[i]->setDrawMethod(isDrawMethod);
+    }
+    resized();
+
+}
+
+
+int LfpDisplay::getChannelHeight()
+{
+    return channels[0]->getChannelHeight();
+}
+
+
+
+void LfpDisplay::mouseWheelMove(const MouseEvent&  e, const MouseWheelDetails&   wheel)
+{
+
+    //std::cout << "Mouse wheel " <<  e.mods.isCommandDown() << "  " << wheel.deltaY << std::endl;
+    //TODO Changing ranges with the wheel is currently broken. With multiple ranges, most
+    //of the wheel range code needs updating
+    
+    
+    if (e.mods.isCommandDown())  // CTRL + scroll wheel -> change channel spacing
+    {
+        int h = getChannelHeight();
+        int hdiff=0;
+        
+        // std::cout << wheel.deltaY << std::endl;
+        
+        if (wheel.deltaY > 0)
+        {
+            hdiff = 2;
+        }
+        else
+        {
+            if (h > 5)
+                hdiff = -2;
+        }
+
+        if (abs(h) > 100) // accelerate scrolling for large ranges
+            hdiff *= 3;
+
+        setChannelHeight(h+hdiff);
+        int oldX=viewport->getViewPositionX();
+        int oldY=viewport->getViewPositionY();
+
+        setBounds(0,0,getWidth()-0, getChannelHeight()*canvas->nChans); // update height so that the scrollbar is correct
+
+        int mouseY=e.getMouseDownY(); // should be y pos relative to inner viewport (0,0)
+        int scrollBy = (mouseY/h)*hdiff*2;// compensate for motion of point under current mouse position
+        viewport->setViewPosition(oldX,oldY+scrollBy); // set back to previous position plus offset
+
+        canvas->setSpreadSelection(h+hdiff); // update combobox
+        
+        canvas->fullredraw = true;//issue full redraw - scrolling without modifier doesnt require a full redraw
+    }
+    else
+    {
+        if (e.mods.isAltDown())  // ALT + scroll wheel -> change channel range (was SHIFT but that clamps wheel.deltaY to 0 on OSX for some reason..)
+        {
+            int h = getRange();
+            
+            
+            int step = canvas->getRangeStep(canvas->getSelectedType());
+                       
+            // std::cout << wheel.deltaY << std::endl;
+            
+            if (wheel.deltaY > 0)
+            {
+                setRange(h+step,canvas->getSelectedType());
+            }
+            else
+            {
+                if (h > step+1)
+                    setRange(h-step,canvas->getSelectedType());
+            }
+
+            canvas->setRangeSelection(h); // update combobox
+            canvas->fullredraw = true; //issue full redraw - scrolling without modifier doesnt require a full redraw
+            
+        }
+        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);
+
+        }
+      
+
+    }
+       //refresh(); // doesn't seem to be needed now that channels daraw to bitmap
+
+}
+
+void LfpDisplay::toggleSingleChannel(int chan)
+{
+    //std::cout << "Toggle channel " << chan << std::endl;
+
+    if (chan != singleChan)
+    {
+        singleChan = chan;
+        int newHeight = viewport->getHeight();
+		channelInfo[chan]->setEnabledState(true);
+        setChannelHeight(newHeight, false);
+        setSize(getWidth(), numChans*getChannelHeight());
+        viewport->setScrollBarsShown(false,false);
+        viewport->setViewPosition(Point<int>(0,chan*newHeight));
+        for (int n = 0; n < numChans; n++)
+        {
+			savedChannelState.set(n, channels[n]->getEnabledState());
+            if (n != chan) channelInfo[n]->setEnabledState(false);
+        }
+
+    }
+    else
+    {
+        setChannelHeight(canvas->getChannelHeight());
+    }
+}
+
+bool LfpDisplay::getSingleChannelState()
+{
+    if (singleChan < 0) return false;
+    else return true;
+}
+
+
+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 on 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;
+        }
+    }
+
+    channels[closest]->select();
+    canvas->setSelectedType(channels[closest]->getType());
+
+    if (event.getNumberOfClicks() == 2)
+        toggleSingleChannel(closest);
+
+    if (event.mods.isRightButtonDown())
+    {
+        PopupMenu channelMenu = channels[closest]->getOptions();
+        const int result = channelMenu.show();
+        channels[closest]->changeParameter(result);
+    }
+
+    canvas->fullredraw = true;//issue full redraw
+
+    refresh();
+
+}
+
+
+bool LfpDisplay::setEventDisplayState(int ch, bool state)
+{
+    eventDisplayEnabled[ch] = state;
+    return eventDisplayEnabled[ch];
+}
+
+
+bool LfpDisplay::getEventDisplayState(int ch)
+{
+    return eventDisplayEnabled[ch];
+}
+
+void LfpDisplay::enableChannel(bool state, int chan)
+{
+
+    if (chan < numChans)
+    {
+        channelInfo[chan]->setEnabledState(state);
+        canvas->isChannelEnabled.set(chan, state);
+    }
+}
+
+void LfpDisplay::setEnabledState(bool state, int chan)
+{
+
+    if (chan < numChans)
+    {
+        channels[chan]->setEnabledState(state);
+        canvas->isChannelEnabled.set(chan, state);
+    }
+}
+
+bool LfpDisplay::getEnabledState(int chan)
+{
+    if (chan < numChans)
+    {
+        return channels[chan]->getEnabledState();
+    }
+
+    return false;
+}
+
+
+// ------------------------------------------------------------------
+
+LfpChannelDisplay::LfpChannelDisplay(LfpDisplayCanvas* c, LfpDisplay* d, int channelNumber) :
+    canvas(c), display(d), isSelected(false), chan(channelNumber),
+    channelOverlap(300), channelHeight(40), range(1000.0f),
+    isEnabled(true), inputInverted(false), canBeInverted(true), drawMethod(false)
+{
+
+
+    name = String(channelNumber+1); // default is to make the channelNumber the name
+
+
+    channelHeightFloat = (float) channelHeight;
+
+    channelFont = Font("Default", channelHeight*0.6, Font::plain);
+
+    lineColour = Colour(255,255,255);
+
+    type = c->getChannelType(channelNumber);
+    typeStr = c->getTypeName(type);
+    
+    
+
+}
+
+LfpChannelDisplay::~LfpChannelDisplay()
+{
+
+}
+
+void LfpChannelDisplay::resized()
+{
+    // all of this will likely need to be moved into the sharedLfpDisplay image in the lfpDisplay, not here
+    // now that the complete height is know, the sharedLfpDisplay image that we'll draw the pixel-wise lfp plot to needs to be resized
+    //lfpChannelBitmap = Image(Image::ARGB, getWidth(), getHeight(), false);
+}
+
+
+void LfpChannelDisplay::updateType()
+{
+    type = canvas->getChannelType(chan);
+    typeStr = canvas->getTypeName(type);
+}
+
+void LfpChannelDisplay::setEnabledState(bool state)
+{
+
+    //if (state)
+    //std::cout << "Setting channel " << name << " to true." << std::endl;
+    //else
+    //std::cout << "Setting channel " << name << " to false." << std::endl;
+
+    isEnabled = state;
+
+}
+
+void LfpChannelDisplay::pxPaint()
+{
+    if (isEnabled)
+    {
+        Image::BitmapData bdLfpChannelBitmap(display->lfpChannelBitmap, 0,0, display->lfpChannelBitmap.getWidth(), display->lfpChannelBitmap.getHeight());
+
+        int center = getHeight()/2;
+        
+        // max and min of channel in absolute px coords for event displays etc - actual data might be drawn outside of this range
+        int jfrom_wholechannel= (int) (getY()+center-channelHeight/2)+1 +0 ;
+        int jto_wholechannel= (int) (getY()+center+channelHeight/2) -0;
+    
+        int jfrom_wholechannel_almost= (int) (getY()+center-channelHeight/3)+1 +0 ; // a bit less tall, for saturation warnings
+        int jto_wholechannel_almost= (int) (getY()+center+channelHeight/3) -0;
+        
+        
+        // max and min of channel, this is the range where actual data is drawn
+        int jfrom_wholechannel_clip= (int) (getY()+center-(channelHeight)*canvas->channelOverlapFactor)+1  ;
+        int jto_wholechannel_clip  = (int) (getY()+center+(channelHeight)*canvas->channelOverlapFactor) -0;
+    
+        
+
+        if (jfrom_wholechannel<0) {jfrom_wholechannel=0;};
+        if (jto_wholechannel >= display->lfpChannelBitmap.getHeight()) {jto_wholechannel=display->lfpChannelBitmap.getHeight()-1;};
+    
+        // draw most recent drawn sample position
+        if (canvas->screenBufferIndex[chan]+1 <= display->lfpChannelBitmap.getWidth())
+        for (int k=jfrom_wholechannel; k<=jto_wholechannel; k+=2) // draw line
+            bdLfpChannelBitmap.setPixelColour(canvas->screenBufferIndex[chan]+1,k, Colours::yellow);
+        
+        
+        bool clipWarningHi =false; // keep track if something clipped in the display, so we can draw warnings after the data pixels are done
+        bool clipWarningLo =false;
+
+        bool saturateWarningHi =false; // similar, but for saturating the amplifier, not just the display - make this warning very visible
+        bool saturateWarningLo =false;
+        
+        // pre compute some colors for later so we dont do it once per pixel.
+        Colour lineColourBright = lineColour.withMultipliedBrightness(2.0f);
+        //Colour lineColourDark = lineColour.withMultipliedSaturation(0.5f).withMultipliedBrightness(0.3f);
+        Colour lineColourDark = lineColour.withMultipliedSaturation(0.5f*canvas->histogramParameterB).withMultipliedBrightness(canvas->histogramParameterB);
+        
+    
+        int stepSize = 1;
+        int from = 0; // for vertical line drawing in the LFP data
+        int to = 0;
+        
+        int ifrom = canvas->lastScreenBufferIndex[chan] - 1; // need to start drawing a bit before the actual redraw window for the interpolated line to join correctly
+        
+        if (ifrom < 0)
+            ifrom = 0;
+        
+        int ito = canvas->screenBufferIndex[chan] +0;
+        
+        if (fullredraw)
+        {
+            ifrom = 0; //canvas->leftmargin;
+            ito = getWidth()-stepSize;
+            fullredraw = false;
+        }
+        
+        
+        for (int i = ifrom; i < ito ; i += stepSize) // redraw only changed portion
+        {
+            
+            //draw zero line
+            int m = getY()+center;
+            if(m>0 & m<display->lfpChannelBitmap.getHeight()){
+                if ( bdLfpChannelBitmap.getPixelColour(i,m) == display->backgroundColour ) { // make sure we're not drawing over an existing plot from another channel
+                    bdLfpChannelBitmap.setPixelColour(i,m,Colour(50,50,50));
+                }
+            }
+            
+            //draw range markers
+            if (isSelected)
+            {
+                m = getY()+center+channelHeight/2;
+                if(m>0 & m<display->lfpChannelBitmap.getHeight()){
+                    if ( bdLfpChannelBitmap.getPixelColour(i,m) == display->backgroundColour ) { // make sure we're not drawing over an existing plot from another channel
+                        bdLfpChannelBitmap.setPixelColour(i,m,Colour(80,80,80));
+                    }
+                }
+                m = getY()+center-channelHeight/2;
+                if(m>0 & m<display->lfpChannelBitmap.getHeight()){
+                    if ( bdLfpChannelBitmap.getPixelColour(i,m) == display->backgroundColour ) { // make sure we're not drawing over an existing plot from another channel
+                        bdLfpChannelBitmap.setPixelColour(i,m,Colour(80,80,80));
+                    }
+                }
+            }
+            
+            // draw event markers
+            int rawEventState = canvas->getYCoord(canvas->getNumChannels(), i);// get last channel+1 in buffer (represents events)
+            
+            //if (i == ifrom)
+            //    std::cout << rawEventState << std::endl;
+            
+            for (int ev_ch = 0; ev_ch < 8 ; ev_ch++) // for all event channels
+            {
+                if (display->getEventDisplayState(ev_ch))  // check if plotting for this channel is enabled
+                {
+                    if (rawEventState & (1 << ev_ch))    // events are  representet by a bit code, so we have to extract the individual bits with a mask
+                    {
+                        //std::cout << "Drawing event." << std::endl;
+                        Colour currentcolor=display->channelColours[ev_ch*2];
+                        
+                        for (int k=jfrom_wholechannel; k<=jto_wholechannel; k++) // draw line
+                            bdLfpChannelBitmap.setPixelColour(i,k,bdLfpChannelBitmap.getPixelColour(i,k).interpolatedWith(currentcolor,0.3f));
+                        
+                    }
+                }
+            }
+            
+            //std::cout << "e " << canvas->getYCoord(canvas->getNumChannels()-1, i) << std::endl;
+            
+            
+            // set max-min range for plotting, used in all methods
+            double a = (canvas->getYCoordMax(chan, i)/range*channelHeightFloat);
+            double b = (canvas->getYCoordMin(chan, i)/range*channelHeightFloat);
+            
+            double a_raw = canvas->getYCoordMax(chan, i);
+            double b_raw = canvas->getYCoordMin(chan, i);
+            double from_raw=0; double to_raw=0;
+            
+            //double m = (canvas->getYCoordMean(chan, i)/range*channelHeightFloat)+getHeight()/2;
+            if (a<b)
+            {
+                from = (a); to = (b);
+                from_raw = (a_raw); to_raw = (b_raw);
+
+            }
+            else
+            {
+                from = (b); to = (a);
+                from_raw = (b_raw); to_raw = (a_raw);
+            }
+            
+            // start by clipping so that we're not populating pixels that we dont want to plot
+            int lm= channelHeightFloat*canvas->channelOverlapFactor;
+            if (lm>0)
+                lm=-lm;
+        
+            if (from > -lm) {from = -lm; clipWarningHi=true;};
+            if (to > -lm) {to = -lm; clipWarningHi=true;};
+            if (from < lm) {from = lm; clipWarningLo=true;};
+            if (to < lm) {to = lm; clipWarningLo=true;};
+            
+            
+            // test if raw data is clipped for displaying saturation warning
+            if (from_raw > canvas->selectedSaturationValueFloat) { saturateWarningHi=true;};
+            if (to_raw > canvas->selectedSaturationValueFloat) { saturateWarningHi=true;};
+            if (from_raw < -canvas->selectedSaturationValueFloat) { saturateWarningLo=true;};
+            if (to_raw < -canvas->selectedSaturationValueFloat) { saturateWarningLo=true;};
+            
+            
+            from=from+getHeight()/2;       // so the plot is centered in the channeldisplay
+            to=to+getHeight()/2;
+            
+            int samplerange=to-from;
+            
+            
+            
+            if (drawMethod) // switched between 'supersampled' drawing and simple pixel wise drawing
+            { // histogram based supersampling method
+                
+                const float *samplesThisPixel = canvas->getSamplesPerPixel(chan, i);
+                int sampleCountThisPixel = canvas->getSampleCountPerPixel(i);
+                
+                if (samplerange>0 & sampleCountThisPixel>0)
+                {
+                    
+                    //float localHist[samplerange]; // simple histogram
+                    float rangeHist[samplerange]; // paired range histogram, same as plotting at higher res. and subsampling
+                    
+                    for (int k=0; k<=samplerange; k++)
+                        rangeHist[k]=0;
+
+                    
+                
+                    
+                    
+                    for (int k=0; k<=sampleCountThisPixel; k++) // add up paired-range histogram per pixel - for each pair fill intermediate with uniform distr.
+                    {
+                        int cs_this = (((samplesThisPixel[k]/range*channelHeightFloat)+getHeight()/2)-from); // sample values -> pixel coordinates relative to from
+                        int cs_next = (((samplesThisPixel[k+1]/range*channelHeightFloat)+getHeight()/2)-from);
+                        
+                        
+                        if (cs_this<0) {cs_this=0;};                        //here we could clip the diaplay to the max/min, or ignore out of bound values, not sure which one is better
+                        if (cs_this>samplerange) {cs_this=samplerange;};
+                        if (cs_next<0) {cs_next=0;};
+                        if (cs_next>samplerange) {cs_next=samplerange;};
+                        
+                        int hfrom=0;
+                        int hto=0;
+                        
+                        if (cs_this<cs_next)
+                        {
+                            hfrom = (cs_this);  hto = (cs_next);
+                        }
+                        else
+                        {
+                            hfrom = (cs_next);  hto = (cs_this);
+                        }
+                        float hrange=hto-hfrom;
+                        float ha=1;
+                        for (int l=hfrom; l<hto; l++)
+                        {
+                            rangeHist[l]+=ha; //this emphasizes fast Y components
+                            
+                            //rangeHist[l]+=1/hrange; // this is like an oscilloscope, same energy depositetd per dx, not dy
+                        }
+                    }
+                    
+                    
+                    for (int s = 0; s <= samplerange; s ++)  // plot histogram one pixel per bin
+                    {
+                        float a=15*((rangeHist[s])/(sampleCountThisPixel)) *(2*(0.2+canvas->histogramParameterA));
+                        if (a>1.0f) {a=1.0f;};
+                        if (a<0.0f) {a=0.0f;};
+                        
+                        
+                        //Colour gradedColor = lineColour.withMultipliedBrightness(2.0f).interpolatedWith(lineColour.withMultipliedSaturation(0.6f).withMultipliedBrightness(0.3f),1-a) ;
+                        Colour gradedColor =  lineColourBright.interpolatedWith(lineColourDark,1-a);
+                        //Colour gradedColor =  Colour(0,255,0);
+                        
+                        int ploty = from+s+getY();
+                        if(ploty>0 & ploty < display->lfpChannelBitmap.getHeight()) {
+                            bdLfpChannelBitmap.setPixelColour(i,from+s+getY(),gradedColor);
+                        }
+                    }
+                    
+                } else {
+                    
+                    int ploty = from+getY();
+                    if(ploty>0 & ploty < display->lfpChannelBitmap.getHeight()) {
+                        bdLfpChannelBitmap.setPixelColour(i,ploty,lineColour);
+                    }
+                }
+                
+                
+                
+            }
+            else //drawmethod
+            { // simple per-pixel min-max drawing, has no anti-aliasing, but runs faster
+                
+                int jfrom=from+getY();
+                int jto=to+getY();
+                
+                //if (yofs<0) {yofs=0;};
+                
+                if (i<0) {i=0;};
+                if (i >= display->lfpChannelBitmap.getWidth()) {i = display->lfpChannelBitmap.getWidth()-1;}; // this shouldnt happen, there must be some bug above - to replicate, run at max refresh rate where draws overlap the right margin by a lot
+                
+                if (jfrom<0) {jfrom=0;};
+                if (jto >= display->lfpChannelBitmap.getHeight()) {jto=display->lfpChannelBitmap.getHeight()-1;};
+                
+                
+                for (int j = jfrom; j <= jto; j += 1)
+                {
+                    
+                    //uint8* const pu8Pixel = bdSharedLfpDisplay.getPixelPointer(	(int)(i),(int)(j));
+                    //*(pu8Pixel)		= 200;
+                    //*(pu8Pixel+1)	= 200;
+                    //*(pu8Pixel+2)	= 200;
+                    
+                    bdLfpChannelBitmap.setPixelColour(i,j,lineColour);
+                    
+                }
+                
+            }
+            
+            // now draw warnings, if needed
+            if (canvas->drawClipWarning) // draw simple warning if display cuts off data
+            {
+                
+                if(clipWarningHi) {
+                    for (int j=0; j<=3; j++)
+                    {
+                        int clipmarker = jto_wholechannel_clip;
+                    
+                        if(clipmarker>0 & clipmarker<display->lfpChannelBitmap.getHeight()){
+                                                  bdLfpChannelBitmap.setPixelColour(i,clipmarker-j,Colour(255,255,255));
+                        }
+                    }
+                }
+                 
+                if(clipWarningLo) {
+                        for (int j=0; j<=3; j++)
+                        {
+                           int clipmarker = jfrom_wholechannel_clip;
+                            
+                            if(clipmarker>0 & clipmarker<display->lfpChannelBitmap.getHeight()){
+                                bdLfpChannelBitmap.setPixelColour(i,clipmarker+j,Colour(255,255,255));
+                            }
+                        }
+                }
+
+            clipWarningHi=false;
+            clipWarningLo=false;
+            }
+            
+            
+            if (canvas->drawSaturationWarning) // draw bigger warning if actual data gets cuts off
+            {
+                
+                if(saturateWarningHi || saturateWarningLo) {
+                    
+                    
+                    for (int k=jfrom_wholechannel; k<=jto_wholechannel; k++){ // draw line
+                        Colour thiscolour=Colour(255,0,0);
+                        if (fmod((i+k),50)>25){
+                            thiscolour=Colour(255,255,255);
+                        }
+                        if(k>0 & k<display->lfpChannelBitmap.getHeight()){
+                            bdLfpChannelBitmap.setPixelColour(i,k,thiscolour);
+                        }
+                    };
+                }
+                
+                saturateWarningHi=false; // we likely just need one of this because for this warning we dont care if its saturating on the positive or negative side
+                saturateWarningLo=false;
+            }
+
+            
+        } // for i (x pixels)
+        
+    } // isenabled
+    
+
+}
+
+void LfpChannelDisplay::paint(Graphics& g) {}
+
+
+
+PopupMenu LfpChannelDisplay::getOptions()
+{
+
+    PopupMenu menu;
+    menu.addItem(1, "Invert signal", true, inputInverted);
+
+    return menu;
+}
+
+void LfpChannelDisplay::changeParameter(int id)
+{
+    switch (id)
+    {
+        case 1:
+            setInputInverted(!inputInverted);
+        default:
+            break;
+    }
+}
+
+void LfpChannelDisplay::setRange(float r)
+{
+    
+    range = r;
+
+    //std::cout << "Range: " << r << std::endl;
+}
+
+int LfpChannelDisplay::getRange()
+{
+    return range;
+}
+
+
+void LfpChannelDisplay::select()
+{
+    isSelected = true;
+}
+
+void LfpChannelDisplay::deselect()
+{
+    isSelected = false;
+}
+
+bool LfpChannelDisplay::getSelected()
+{
+   return isSelected;
+}
+
+void LfpChannelDisplay::setColour(Colour c)
+{
+    lineColour = c;
+}
+
+
+void LfpChannelDisplay::setChannelHeight(int c)
+{
+    channelHeight = c;
+
+    channelHeightFloat = (float) channelHeight;
+
+    if (!inputInverted)
+        channelHeightFloat = -channelHeightFloat;
+
+    channelOverlap = channelHeight*2;
+}
+
+int LfpChannelDisplay::getChannelHeight()
+{
+
+    return channelHeight;
+}
+
+void LfpChannelDisplay::setChannelOverlap(int overlap)
+{
+    channelOverlap = overlap;
+}
+
+
+int LfpChannelDisplay::getChannelOverlap()
+{
+    return channelOverlap;
+}
+
+void LfpChannelDisplay::setCanBeInverted(bool _canBeInverted)
+{
+    canBeInverted = _canBeInverted;
+}
+
+void LfpChannelDisplay::setInputInverted(bool isInverted)
+{
+    if (canBeInverted)
+    {
+        inputInverted = isInverted;
+        setChannelHeight(channelHeight);
+    }
+}
+
+void LfpChannelDisplay::setDrawMethod(bool isDrawMethod)
+{
+
+    drawMethod = isDrawMethod;
+
+}
+
+
+void LfpChannelDisplay::setName(String name_)
+{
+    name = name_;
+}
+
+ChannelType LfpChannelDisplay::getType()
+{
+    return type;
+}
+
+// -------------------------------
+
+LfpChannelDisplayInfo::LfpChannelDisplayInfo(LfpDisplayCanvas* canvas_, LfpDisplay* display_, int ch)
+    : LfpChannelDisplay(canvas_, display_, ch)
+{
+
+    chan = ch;
+
+    enableButton = new UtilityButton(String(ch+1), Font("Small Text", 13, Font::plain));
+    enableButton->setRadius(5.0f);
+
+    enableButton->setEnabledState(true);
+    enableButton->setCorners(true, true, true, true);
+    enableButton->addListener(this);
+    enableButton->setClickingTogglesState(true);
+    enableButton->setToggleState(true, dontSendNotification);
+
+    addAndMakeVisible(enableButton);
+
+}
+
+void LfpChannelDisplayInfo::updateType()
+{
+    type = canvas->getChannelType(chan);
+    typeStr = canvas->getTypeName(type);
+    repaint();
+}
+
+void LfpChannelDisplayInfo::buttonClicked(Button* button)
+{
+
+    bool state = button->getToggleState();
+
+    display->setEnabledState(state, chan);
+
+    //UtilityButton* b = (UtilityButton*) button;
+
+    // if (state)
+    // {
+    //  b->setLabel("ON");
+    // } else {
+    //  b->setLabel("OFF");
+    // }
+
+    //std::cout << "Turn channel " << chan << " to " << button->getToggleState() << std::endl;
+
+}
+
+void LfpChannelDisplayInfo::setEnabledState(bool state)
+{
+    enableButton->setToggleState(state, sendNotification);
+}
+
+void LfpChannelDisplayInfo::paint(Graphics& g)
+{
+
+    int center = getHeight()/2;
+
+    g.setColour(lineColour);
+
+    //if (chan > 98)
+    //  g.fillRoundedRectangle(5,center-8,51,22,8.0f);
+    //else
+    g.fillRoundedRectangle(5,center-8,41,22,8.0f);
+
+      g.setFont(Font("Small Text", 13, Font::plain));
+      g.drawText(typeStr,5,center+16,41,10,Justification::centred,false);
+    // g.setFont(channelHeightFloat*0.3);
+
+    //  g.drawText(name, 10, center-channelHeight/2, 200, channelHeight, Justification::left, false);
+
+}
+
+void LfpChannelDisplayInfo::resized()
+{
+
+    int center = getHeight()/2;
+
+    //if (chan > 98)
+    //  enableButton->setBounds(8,center-5,45,16);
+    //else
+    enableButton->setBounds(8,center-5,35,16);
+}
+
+
+
+// Event display Options --------------------------------------------------------------------
+
+EventDisplayInterface::EventDisplayInterface(LfpDisplay* display_, LfpDisplayCanvas* canvas_, int chNum):
+    isEnabled(true), display(display_), canvas(canvas_)
+{
+
+    channelNumber = chNum;
+
+    chButton = new UtilityButton(String(channelNumber+1), Font("Small Text", 13, Font::plain));
+    chButton->setRadius(5.0f);
+    chButton->setBounds(4,4,14,14);
+    chButton->setEnabledState(true);
+    chButton->setCorners(true, false, true, false);
+    //chButton.color = display->channelColours[channelNumber*2];
+    chButton->addListener(this);
+    addAndMakeVisible(chButton);
+
+
+    checkEnabledState();
+
+}
+
+EventDisplayInterface::~EventDisplayInterface()
+{
+
+}
+
+void EventDisplayInterface::checkEnabledState()
+{
+    isEnabled = display->getEventDisplayState(channelNumber);
+
+    //repaint();
+}
+
+void EventDisplayInterface::buttonClicked(Button* button)
+{
+    checkEnabledState();
+    if (isEnabled)
+    {
+        display->setEventDisplayState(channelNumber, false);
+    }
+    else
+    {
+        display->setEventDisplayState(channelNumber, true);
+    }
+
+    repaint();
+
+}
+
+
+void EventDisplayInterface::paint(Graphics& g)
+{
+
+    checkEnabledState();
+
+    if (isEnabled)
+    {
+        g.setColour(display->channelColours[channelNumber*2]);
+        g.fillRoundedRectangle(2,2,18,18,6.0f);
+    }
+
+
+    //g.drawText(String(channelNumber), 8, 2, 200, 15, Justification::left, false);
+
+}
+
+// Lfp Viewport -------------------------------------------
+
+LfpViewport::LfpViewport(LfpDisplayCanvas *canvas)
+    : Viewport()
+{
+    this->canvas = canvas;
+}
+
+void LfpViewport::visibleAreaChanged(const Rectangle<int>& newVisibleArea)
+{
+    canvas->fullredraw = true;
+    canvas->refresh();
+}
diff --git a/Source/Plugins/LfpDisplayNodeBeta/LfpDisplayCanvas.h b/Source/Plugins/LfpDisplayNodeBeta/LfpDisplayCanvas.h
new file mode 100644
index 0000000000000000000000000000000000000000..2a27c8e6f57149c62f80390b441a9b7337da902d
--- /dev/null
+++ b/Source/Plugins/LfpDisplayNodeBeta/LfpDisplayCanvas.h
@@ -0,0 +1,485 @@
+/*
+    ------------------------------------------------------------------
+
+    This file is part of the Open Ephys GUI
+    Copyright (C) 2013 Open Ephys
+
+    ------------------------------------------------------------------
+
+    This program is free software: you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+*/
+#ifndef __LFPDISPLAYCANVAS_H_B711873A__
+#define __LFPDISPLAYCANVAS_H_B711873A__
+
+#include "../../../JuceLibraryCode/JuceHeader.h"
+#include "LfpDisplayNode.h"
+#include "../../Processors/Visualization/Visualizer.h"
+#define CHANNEL_TYPES 3
+
+class LfpDisplayNode;
+
+class LfpTimescale;
+class LfpDisplay;
+class LfpChannelDisplay;
+class LfpChannelDisplayInfo;
+class EventDisplayInterface;
+class LfpViewport;
+
+/**
+
+  Displays multiple channels of continuous data.
+
+  @see LfpDisplayNode, LfpDisplayEditor
+
+*/
+
+class LfpDisplayCanvas : public Visualizer,
+    public Slider::Listener,
+    public ComboBox::Listener,
+    public Button::Listener,
+    public KeyListener
+{
+public:
+    LfpDisplayCanvas(LfpDisplayNode* n);
+    ~LfpDisplayCanvas();
+
+    void beginAnimation();
+    void endAnimation();
+
+    void refreshState();
+    void update();
+
+    void setParameter(int, float);
+    void setParameter(int, int, int, float) {}
+
+    void setRangeSelection(float range, bool canvasMustUpdate = false); // set range selection combo box to correct value if it has been changed by scolling etc.
+    void setSpreadSelection(int spread, bool canvasMustUpdate = false); // set spread selection combo box to correct value if it has been changed by scolling etc.
+
+    void paint(Graphics& g);
+
+    void refresh();
+
+    void resized();
+
+    int getChannelHeight();
+    
+    float channelOverlapFactor;
+
+    float histogramParameterA;
+    float histogramParameterB;
+
+    int getNumChannels();
+    bool getInputInvertedState();
+    bool getDrawMethodState();
+
+    const float getXCoord(int chan, int samp);
+    const float getYCoord(int chan, int samp);
+    
+    const float *getSamplesPerPixel(int chan, int px);
+    const int getSampleCountPerPixel(int px);
+    
+    const float getYCoordMin(int chan, int samp);
+    const float getYCoordMean(int chan, int samp);
+    const float getYCoordMax(int chan, int samp);
+
+    Array<int> screenBufferIndex;
+    Array<int> lastScreenBufferIndex;
+
+    void comboBoxChanged(ComboBox* cb);
+    void buttonClicked(Button* button);
+    
+    /** Handles slider events for all editors. */
+    void sliderValueChanged(Slider* sl);
+    
+    /** Called by sliderValueChanged(). Deals with clicks on custom sliders. Subclasses
+     of GenericEditor should modify this method only.*/
+    void sliderEvent(Slider* sl);
+    
+    void saveVisualizerParameters(XmlElement* xml);
+    void loadVisualizerParameters(XmlElement* xml);
+
+    bool keyPressed(const KeyPress& key);
+    bool keyPressed(const KeyPress& key, Component* orig);
+
+    ChannelType getChannelType(int n);
+    ChannelType getSelectedType();
+    String getTypeName(ChannelType type);
+    int getRangeStep(ChannelType type);
+
+    void setSelectedType(ChannelType type, bool toggleButton = true);
+
+    //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 each display;
+    static const int leftmargin=50; // left margin for lfp plots (so the ch number text doesnt overlap)
+
+    Array<bool> isChannelEnabled;
+    
+    bool  drawClipWarning; // optinally draw (subtle) warning if data is clipped in display
+    bool  drawSaturationWarning; // optionally raise hell if the actual data is saturating
+    
+    float selectedSaturationValueFloat; // TODO: this is way ugly - we should refactor all these parameters soon and get them into a nicer format- probably when we do the genreal plugin parameter overhaul.
+
+    
+    int nChans;
+
+private:
+    
+    Array<float> sampleRate;
+    float timebase;
+    float displayGain;
+    float timeOffset;
+    //int spread ; // vertical spacing between channels
+
+
+    static const int MAX_N_CHAN = 2048;  // maximum number of channels
+    static const int MAX_N_SAMP = 5000; // maximum display size in pixels
+    static const int MAX_N_SAMP_PER_PIXEL = 1000; // maximum samples considered for drawing each pixel
+    //float waves[MAX_N_CHAN][MAX_N_SAMP*2]; // we need an x and y point for each sample
+
+    LfpDisplayNode* processor;
+    AudioSampleBuffer* displayBuffer; // sample wise data buffer for display
+    AudioSampleBuffer* screenBuffer; // subsampled buffer- one int per pixel
+
+    //'define 3 buffers for min mean and max for better plotting of spikes
+    // not pretty, but 'AudioSampleBuffer works only for channels X samples
+    AudioSampleBuffer* screenBufferMin; // like screenBuffer but holds min/mean/max values per pixel
+    AudioSampleBuffer* screenBufferMean; // like screenBuffer but holds min/mean/max values per pixel
+    AudioSampleBuffer* screenBufferMax; // like screenBuffer but holds min/mean/max values per pixel
+
+    MidiBuffer* eventBuffer;
+
+    ScopedPointer<LfpTimescale> timescale;
+    ScopedPointer<LfpDisplay> lfpDisplay;
+    ScopedPointer<LfpViewport> viewport;
+
+    ScopedPointer<ComboBox> timebaseSelection;
+    ScopedPointer<ComboBox> rangeSelection;
+    ScopedPointer<ComboBox> spreadSelection;
+    
+    ScopedPointer<ComboBox> overlapSelection;
+    ScopedPointer<UtilityButton> drawClipWarningButton; // optinally draw (subtle) warning if data is clipped in display
+    
+    ScopedPointer<ComboBox> saturationWarningSelection;
+    ScopedPointer<UtilityButton> drawSaturateWarningButton; // optionally raise hell if the actual data is saturating
+    
+    ScopedPointer<ComboBox> colorGroupingSelection;
+    ScopedPointer<UtilityButton> invertInputButton;
+    ScopedPointer<UtilityButton> drawMethodButton;
+    ScopedPointer<UtilityButton> pauseButton;
+    OwnedArray<UtilityButton> typeButtons;
+    
+    
+    ScopedPointer<Slider> brightnessSliderA;
+    ScopedPointer<Slider> brightnessSliderB;
+    
+    ScopedPointer<Label> sliderALabel;
+    ScopedPointer<Label> sliderBLabel;
+
+    StringArray voltageRanges[CHANNEL_TYPES];
+    StringArray timebases;
+    StringArray spreads; // option for vertical spacing between channels
+    StringArray colorGroupings; // option for coloring every N channels the same
+    StringArray overlaps; //
+    StringArray saturationThresholds; //default values for when different amplifiers saturate
+
+    
+    ChannelType selectedChannelType;
+    int selectedVoltageRange[CHANNEL_TYPES];
+    String selectedVoltageRangeValues[CHANNEL_TYPES];
+    float rangeGain[CHANNEL_TYPES];
+    StringArray rangeUnits;
+    StringArray typeNames;
+    int rangeSteps[CHANNEL_TYPES];
+
+    int selectedSpread;
+    String selectedSpreadValue;
+
+    int selectedTimebase;
+    String selectedTimebaseValue;
+
+    int selectedOverlap;
+    String selectedOverlapValue;
+    
+    int selectedSaturation; // for saturation warning
+    String selectedSaturationValue;
+
+    
+    OwnedArray<EventDisplayInterface> eventDisplayInterfaces;
+
+    void refreshScreenBuffer();
+    void updateScreenBuffer();
+
+    Array<int> displayBufferIndex;
+    int displayBufferSize;
+
+    int scrollBarThickness;
+    
+    //float samplesPerPixel[MAX_N_SAMP][MAX_N_SAMP_PER_PIXEL];
+    float*** samplesPerPixel;
+    int sampleCountPerPixel[MAX_N_SAMP];
+
+    JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(LfpDisplayCanvas);
+
+};
+
+class LfpTimescale : public Component
+{
+public:
+    LfpTimescale(LfpDisplayCanvas*);
+    ~LfpTimescale();
+
+    void paint(Graphics& g);
+
+    void setTimebase(float t);
+
+private:
+
+    LfpDisplayCanvas* canvas;
+
+    float timebase;
+
+    Font font;
+
+    StringArray labels;
+
+};
+
+class LfpDisplay : public Component
+{
+public:
+    LfpDisplay(LfpDisplayCanvas*, Viewport*);
+    ~LfpDisplay();
+    
+    Image lfpChannelBitmap; // plot as bitmap instead of separately setting pixels
+    // this is done purely for the preformance improvement
+
+    void setNumChannels(int numChannels);
+    int getNumChannels();
+
+    int getTotalHeight();
+
+    void paint(Graphics& g);
+
+    void refresh();
+
+    void resized();
+
+    void mouseDown(const MouseEvent& event);
+    void mouseWheelMove(const MouseEvent&  event, const MouseWheelDetails&   wheel) ;
+
+
+    void setRange(float range, ChannelType type);
+    
+    //Withouth parameters returns selected type
+    int getRange();
+    int getRange(ChannelType type);
+
+    void setChannelHeight(int r, bool resetSingle = true);
+    int getChannelHeight();
+    void setInputInverted(bool);
+    void setDrawMethod(bool);
+
+    void setColors();
+
+    bool setEventDisplayState(int ch, bool state);
+    bool getEventDisplayState(int ch);
+
+    int getColorGrouping();
+    void setColorGrouping(int i);
+
+    void setEnabledState(bool, int);
+    bool getEnabledState(int);
+    void enableChannel(bool, int);
+
+    bool getSingleChannelState();
+
+    Colour backgroundColour;
+    
+    Array<Colour> channelColours;
+
+    Array<LfpChannelDisplay*> channels;
+    Array<LfpChannelDisplayInfo*> channelInfo;
+
+    bool eventDisplayEnabled[8];
+    bool isPaused; // simple pause function, skips screen bufer updates
+
+    
+private:
+    
+    
+    void toggleSingleChannel(int chan);
+    int singleChan;
+	Array<bool> savedChannelState;
+
+    int numChans;
+
+    int totalHeight;
+
+    int colorGrouping;
+
+    LfpDisplayCanvas* canvas;
+    Viewport* viewport;
+
+    float range[3];
+
+
+};
+
+class LfpChannelDisplay : public Component
+{
+public:
+    LfpChannelDisplay(LfpDisplayCanvas*, LfpDisplay*, int channelNumber);
+    ~LfpChannelDisplay();
+
+    void resized();
+    
+    void paint(Graphics& g);
+    
+    void pxPaint(); // like paint, but just populate lfpChannelBitmap
+                    // needs to avoid a paint(Graphics& g) mechanism here becauswe we need to clear the screen in the lfpDisplay repaint(),
+                    // because otherwise we cant deal with the channel overlap (need to clear a vertical section first, _then_ all channels are dawn, so cant do it per channel)
+                
+
+    void select();
+    void deselect();
+
+    bool getSelected();
+
+    void setName(String);
+
+    void setColour(Colour c);
+
+    void setChannelHeight(int);
+    int getChannelHeight();
+
+    void setChannelOverlap(int);
+    int getChannelOverlap();
+
+    void setRange(float range);
+    int getRange();
+
+    void setInputInverted(bool);
+    void setCanBeInverted(bool);
+
+    void setDrawMethod(bool);
+
+    PopupMenu getOptions();
+    void changeParameter(const int id);
+
+    void setEnabledState(bool);
+    bool getEnabledState()
+    {
+        return isEnabled;
+    }
+
+    ChannelType getType();
+    void updateType();
+
+    bool fullredraw; // used to indicate that a full redraw is required. is set false after each full redraw
+
+protected:
+
+    
+    LfpDisplayCanvas* canvas;
+    LfpDisplay* display;
+
+    bool isSelected;
+
+    int chan;
+
+    String name;
+
+    Font channelFont;
+
+    Colour lineColour;
+
+    int channelOverlap;
+    int channelHeight;
+    float channelHeightFloat;
+
+    float range;
+
+    bool isEnabled;
+    bool inputInverted;
+    bool canBeInverted;
+    bool drawMethod;
+
+    ChannelType type;
+    String typeStr;
+    
+    
+
+};
+
+class LfpChannelDisplayInfo : public LfpChannelDisplay,
+    public Button::Listener
+{
+public:
+    LfpChannelDisplayInfo(LfpDisplayCanvas*, LfpDisplay*, int channelNumber);
+
+    void paint(Graphics& g);
+
+    void buttonClicked(Button* button);
+
+    void resized();
+
+    void setEnabledState(bool);
+    void updateType();
+
+private:
+
+    ScopedPointer<UtilityButton> enableButton;
+
+};
+
+class EventDisplayInterface : public Component,
+    public Button::Listener
+{
+public:
+    EventDisplayInterface(LfpDisplay*, LfpDisplayCanvas*, int chNum);
+    ~EventDisplayInterface();
+
+    void paint(Graphics& g);
+
+    void buttonClicked(Button* button);
+
+    void checkEnabledState();
+
+    bool isEnabled;
+
+private:
+
+    int channelNumber;
+
+    LfpDisplay* display;
+    LfpDisplayCanvas* canvas;
+
+    ScopedPointer<UtilityButton> chButton;
+
+};
+
+class LfpViewport : public Viewport
+{
+public:
+    LfpViewport(LfpDisplayCanvas* canvas);
+    void visibleAreaChanged(const Rectangle<int>& newVisibleArea);
+
+private:
+    LfpDisplayCanvas* canvas;
+};
+
+
+#endif  // __LFPDISPLAYCANVAS_H_B711873A__
diff --git a/Source/Plugins/LfpDisplayNodeBeta/LfpDisplayEditor.cpp b/Source/Plugins/LfpDisplayNodeBeta/LfpDisplayEditor.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..cf75ba71b2915b523a32de968c977572cb8c947a
--- /dev/null
+++ b/Source/Plugins/LfpDisplayNodeBeta/LfpDisplayEditor.cpp
@@ -0,0 +1,66 @@
+/*
+    ------------------------------------------------------------------
+
+    This file is part of the Open Ephys GUI
+    Copyright (C) 2013 Open Ephys
+
+    ------------------------------------------------------------------
+
+    This program is free software: you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#include "LfpDisplayEditor.h"
+
+
+LfpDisplayEditor::LfpDisplayEditor(GenericProcessor* parentNode, bool useDefaultParameterEditors=true)
+    : VisualizerEditor(parentNode, useDefaultParameterEditors)
+
+{
+
+    tabText = "LFP";
+
+    desiredWidth = 180;
+
+}
+
+LfpDisplayEditor::~LfpDisplayEditor()
+{
+}
+
+
+Visualizer* LfpDisplayEditor::createNewCanvas()
+{
+
+    LfpDisplayNode* processor = (LfpDisplayNode*) getProcessor();
+    return new LfpDisplayCanvas(processor);
+
+}
+
+void LfpDisplayEditor::buttonCallback(Button* button)
+{
+
+    int gId = button->getRadioGroupId();
+
+    if (gId > 0)
+    {
+        if (canvas != 0)
+        {
+            canvas->setParameter(gId-1, button->getName().getFloatValue());
+        }
+
+    }
+
+}
+
diff --git a/Source/Plugins/LfpDisplayNodeBeta/LfpDisplayEditor.h b/Source/Plugins/LfpDisplayNodeBeta/LfpDisplayEditor.h
new file mode 100644
index 0000000000000000000000000000000000000000..41af1b9d6d150ab99853ec1c9c8c791a603ccf05
--- /dev/null
+++ b/Source/Plugins/LfpDisplayNodeBeta/LfpDisplayEditor.h
@@ -0,0 +1,63 @@
+/*
+    ------------------------------------------------------------------
+
+    This file is part of the Open Ephys GUI
+    Copyright (C) 2013 Open Ephys
+
+    ------------------------------------------------------------------
+
+    This program is free software: you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#ifndef __LFPDISPLAYEDITOR_H_3438800D__
+#define __LFPDISPLAYEDITOR_H_3438800D__
+
+#include "../../../JuceLibraryCode/JuceHeader.h"
+#include "../../Processors/Editors/GenericEditor.h"
+#include "../../UI/UIComponent.h"
+#include "../../UI/DataViewport.h"
+#include "../../Processors/Visualization/DataWindow.h"
+#include "LfpDisplayNode.h"
+#include "LfpDisplayCanvas.h"
+#include "../../Processors/Editors/VisualizerEditor.h"
+
+class Visualizer;
+
+/**
+
+  User interface for the LfpDisplayNode sink.
+
+  @see LfpDisplayNode, LfpDisplayCanvas
+
+*/
+
+class LfpDisplayEditor : public VisualizerEditor
+{
+public:
+    LfpDisplayEditor(GenericProcessor*, bool useDefaultParameterEditors);
+    ~LfpDisplayEditor();
+
+    void buttonCallback(Button* button);
+
+    Visualizer* createNewCanvas();
+
+private:
+
+
+    JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(LfpDisplayEditor);
+
+};
+
+#endif  // __LFPDISPLAYEDITOR_H_3438800D__
diff --git a/Source/Plugins/LfpDisplayNodeBeta/LfpDisplayNode.cpp b/Source/Plugins/LfpDisplayNodeBeta/LfpDisplayNode.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..2823f000d7616c786ac3dd1a07f9b65a675f4e2e
--- /dev/null
+++ b/Source/Plugins/LfpDisplayNodeBeta/LfpDisplayNode.cpp
@@ -0,0 +1,347 @@
+/*
+    ------------------------------------------------------------------
+
+    This file is part of the Open Ephys GUI
+    Copyright (C) 2013 Open Ephys
+
+    ------------------------------------------------------------------
+
+    This program is free software: you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#include "LfpDisplayNode.h"
+#include "LfpDisplayCanvas.h"
+#include <stdio.h>
+
+LfpDisplayNode::LfpDisplayNode()
+    : GenericProcessor("LFP Viewer Beta"),
+      displayGain(1), bufferLength(5.0f),
+      abstractFifo(100)
+{
+    //std::cout << " LFPDisplayNodeConstructor" << std::endl;
+    displayBuffer = new AudioSampleBuffer(8, 100);
+
+    arrayOfOnes = new float[5000];
+
+    for (int n = 0; n < 5000; n++)
+    {
+        arrayOfOnes[n] = 1;
+    }
+
+}
+
+LfpDisplayNode::~LfpDisplayNode()
+{
+
+}
+
+AudioProcessorEditor* LfpDisplayNode::createEditor()
+{
+
+    editor = new LfpDisplayEditor(this, true);
+    return editor;
+
+}
+
+void LfpDisplayNode::updateSettings()
+{
+    std::cout << "Setting num inputs on LfpDisplayNode to " << getNumInputs() << std::endl;
+
+    channelForEventSource.clear();
+    eventSourceNodes.clear();
+    ttlState.clear();
+
+    for (int i = 0; i < eventChannels.size(); i++)
+    {
+        if (!eventSourceNodes.contains(eventChannels[i]->sourceNodeId) && eventChannels[i]->type == EVENT_CHANNEL)
+        {
+            eventSourceNodes.add(eventChannels[i]->sourceNodeId);
+
+        }
+    }\
+
+    numEventChannels = eventSourceNodes.size();
+
+    std::cout << "Found " << numEventChannels << " event channels." << std::endl;
+
+    for (int i = 0; i < eventSourceNodes.size(); i++)
+    {
+        std::cout << "Adding channel " << getNumInputs() + i << " for event source node " << eventSourceNodes[i] << std::endl;
+        channelForEventSource[eventSourceNodes[i]] = getNumInputs() + i;
+        ttlState[eventSourceNodes[i]] = 0;
+        Channel* eventChan = new Channel(this, getNumInputs() + i, EVENT_CHANNEL);
+        eventChan->sourceNodeId = eventSourceNodes[i];
+        channels.add(eventChan); // add a channel for event data for each source node
+    }
+
+    displayBufferIndex.clear();
+    displayBufferIndex.insertMultiple(0, 0, getNumInputs() + numEventChannels);
+
+}
+
+bool LfpDisplayNode::resizeBuffer()
+{
+    int nSamples = (int) getSampleRate()*bufferLength;
+    int nInputs = getNumInputs();
+
+    std::cout << "Resizing buffer. Samples: " << nSamples << ", Inputs: " << nInputs << std::endl;
+
+    if (nSamples > 0 && nInputs > 0)
+    {
+        abstractFifo.setTotalSize(nSamples);
+        displayBuffer->setSize(nInputs + numEventChannels, nSamples); // add extra channels for TTLs
+        return true;
+    }
+    else
+    {
+        return false;
+    }
+
+}
+
+bool LfpDisplayNode::enable()
+{
+
+    if (resizeBuffer())
+    {
+        LfpDisplayEditor* editor = (LfpDisplayEditor*) getEditor();
+        editor->enable();
+        return true;
+    }
+    else
+    {
+        return false;
+    }
+
+}
+
+bool LfpDisplayNode::disable()
+{
+    LfpDisplayEditor* editor = (LfpDisplayEditor*) getEditor();
+    editor->disable();
+    return true;
+}
+
+void LfpDisplayNode::setParameter(int parameterIndex, float newValue)
+{
+    editor->updateParameterButtons(parameterIndex);
+    //Sets Parameter in parameters array for processor
+    Parameter* parameterPointer = parameters.getRawDataPointer();
+    parameterPointer = parameterPointer+parameterIndex;
+    parameterPointer->setValue(newValue, currentChannel);
+
+    //std::cout << "Saving Parameter from " << currentChannel << ", channel ";
+
+    LfpDisplayEditor* ed = (LfpDisplayEditor*) getEditor();
+    if (ed->canvas != 0)
+        ed->canvas->setParameter(parameterIndex, newValue);
+}
+
+void LfpDisplayNode::handleEvent(int eventType, MidiMessage& event, int sampleNum)
+{
+    if (eventType == TTL)
+    {
+        const uint8* dataptr = event.getRawData();
+
+        //int eventNodeId = *(dataptr+1);
+        int eventId = *(dataptr+2);
+        int eventChannel = *(dataptr+3);
+        int eventTime = event.getTimeStamp();
+
+        int eventSourceNodeId = *(dataptr+5);
+
+        int nSamples = numSamples.at(eventSourceNodeId);
+
+        int samplesToFill = nSamples - eventTime;
+
+        //	std::cout << "Received event from " << eventSourceNode << ", channel "
+        //	          << eventChannel << ", with ID " << eventId << ", copying to "
+         //            << channelForEventSource[eventSourceNode] << std::endl;
+        ////
+        int bufferIndex = (displayBufferIndex[channelForEventSource[eventSourceNodeId]] + eventTime - nSamples) % displayBuffer->getNumSamples();
+        
+        bufferIndex = bufferIndex >= 0 ? bufferIndex :
+        displayBuffer->getNumSamples() + bufferIndex;
+
+
+        if (eventId == 1)
+        {
+            ttlState[eventSourceNodeId] |= (1L << eventChannel);
+        }
+        else
+        {
+            ttlState[eventSourceNodeId] &= ~(1L << eventChannel);
+        }
+
+        if (samplesToFill + bufferIndex < displayBuffer->getNumSamples())
+        {
+
+            //std::cout << bufferIndex << " " << samplesToFill << " " << ttlState[eventSourceNode] << std::endl;
+
+            displayBuffer->copyFrom(channelForEventSource[eventSourceNodeId],  // destChannel
+                                    bufferIndex,		// destStartSample
+                                    arrayOfOnes, 		// source
+                                    samplesToFill, 		// numSamples
+                                    float(ttlState[eventSourceNodeId]));   // gain
+        }
+        else
+        {
+
+            int block2Size = (samplesToFill + bufferIndex) % displayBuffer->getNumSamples();
+            int block1Size = samplesToFill - block2Size;
+
+            //std::cout << "OVERFLOW." << std::endl;
+
+            //std::cout << bufferIndex << " " << block1Size << " " << ttlState << std::endl;
+
+            displayBuffer->copyFrom(channelForEventSource[eventSourceNodeId],  // destChannel
+                                    bufferIndex,		// destStartSample
+                                    arrayOfOnes, 		// source
+                                    block1Size, 		// numSamples
+                                    float(ttlState[eventSourceNodeId]));   // gain
+
+            //std::cout << 0 << " " << block2Size << " " << ttlState << std::endl;
+
+            displayBuffer->copyFrom(channelForEventSource[eventSourceNodeId],  // destChannel
+                                    0,		                        // destStartSample
+                                    arrayOfOnes, 		// source
+                                    block2Size, 		// numSamples
+                                    float(ttlState[eventSourceNodeId]));   // gain
+
+
+        }
+
+
+        // 	std::cout << "ttlState: " << ttlState << std::endl;
+
+        // std::cout << "Received event from " << eventNodeId <<
+        //              " on channel " << eventChannel <<
+        //             " with value " << eventId <<
+        //             " at timestamp " << event.getTimeStamp() << std::endl;
+
+
+    }
+
+}
+
+void LfpDisplayNode::initializeEventChannels()
+{
+
+    for (int i = 0; i < eventSourceNodes.size(); i++)
+    {
+
+        int chan = channelForEventSource[eventSourceNodes[i]];
+        int index = displayBufferIndex[chan];
+
+        //std::cout << "Event source node " << i << ", channel " << chan << std::endl;
+
+        int samplesLeft = displayBuffer->getNumSamples() - index;
+
+        int nSamples = numSamples.at(eventSourceNodes[i]);
+
+
+
+        if (nSamples < samplesLeft)
+        {
+
+            //	std::cout << getNumInputs()+1 << " " << displayBufferIndex << " " << totalSamples << " " << ttlState << std::endl;
+            //
+            displayBuffer->copyFrom(chan,  // destChannel
+                                    index,		// destStartSample
+                                    arrayOfOnes, 		// source
+                                    nSamples, 		// numSamples
+                                    float(ttlState[eventSourceNodes[i]]));   // gain
+
+            displayBufferIndex.set(chan, index + nSamples);
+        }
+        else
+        {
+
+            int extraSamples = nSamples - samplesLeft;
+
+            // std::cout << "OVERFLOW." << std::endl;
+            // std::cout << bufferIndex << " " << block1Size << " " << ttlState << std::endl;
+
+            displayBuffer->copyFrom(chan,    // destChannel
+                                    index,		// destStartSample
+                                    arrayOfOnes, 		// source
+                                    samplesLeft, 		// numSamples
+                                    float(ttlState[eventSourceNodes[i]]));   // gain
+            // std::cout << 0 << " " << block2Size << " " << ttlState << std::endl;
+
+            displayBuffer->copyFrom(chan,  // destChannel
+                                    0,		// destStartSample
+                                    arrayOfOnes, 		// source
+                                    extraSamples, 		// numSamples
+                                    float(ttlState[eventSourceNodes[i]]));   // gain
+
+            displayBufferIndex.set(chan, extraSamples);
+        }
+    }   
+}
+
+void LfpDisplayNode::process(AudioSampleBuffer& buffer, MidiBuffer& events)
+{
+    // 1. place any new samples into the displayBuffer
+    //std::cout << "Display node sample count: " << nSamples << std::endl; ///buffer.getNumSamples() << std::endl;
+
+    initializeEventChannels();
+
+    checkForEvents(events); // see if we got any TTL events
+
+	ScopedLock displayLock(displayMutex);
+
+    for (int chan = 0; chan < buffer.getNumChannels(); chan++)
+    {
+         int samplesLeft = displayBuffer->getNumSamples() - displayBufferIndex[chan];
+         int nSamples = getNumSamples(chan);
+
+        if (nSamples < samplesLeft)
+        {
+
+            displayBuffer->copyFrom(chan,  			// destChannel
+                                    displayBufferIndex[chan], // destStartSample
+                                    buffer, 			// source
+                                    chan, 				// source channel
+                                    0,					// source start sample
+                                    nSamples); 			// numSamples
+        
+            displayBufferIndex.set(chan, displayBufferIndex[chan] + nSamples);
+        }
+        else
+        {
+
+            int extraSamples = nSamples - samplesLeft;
+
+            displayBuffer->copyFrom(chan,  				// destChannel
+                                    displayBufferIndex[chan], // destStartSample
+                                        buffer, 			// source
+                                        chan, 				// source channel
+                                        0,					// source start sample
+                                        samplesLeft); 		// numSamples
+
+                displayBuffer->copyFrom(chan,
+                                        0,
+                                        buffer,
+                                        chan,
+                                        samplesLeft,
+                                        extraSamples);
+
+            displayBufferIndex.set(chan, extraSamples);
+        }
+    }
+
+}
+
diff --git a/Source/Plugins/LfpDisplayNodeBeta/LfpDisplayNode.h b/Source/Plugins/LfpDisplayNodeBeta/LfpDisplayNode.h
new file mode 100644
index 0000000000000000000000000000000000000000..16e7148064d75a229d290d6caf07b7103794ff16
--- /dev/null
+++ b/Source/Plugins/LfpDisplayNodeBeta/LfpDisplayNode.h
@@ -0,0 +1,116 @@
+/*
+    ------------------------------------------------------------------
+
+    This file is part of the Open Ephys GUI
+    Copyright (C) 2013 Open Ephys
+
+    ------------------------------------------------------------------
+
+    This program is free software: you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#ifndef __LFPDISPLAYNODE_H_D969A379__
+#define __LFPDISPLAYNODE_H_D969A379__
+
+#include "../../../JuceLibraryCode/JuceHeader.h"
+#include "LfpDisplayEditor.h"
+#include "../../Processors/Editors/VisualizerEditor.h"
+#include "../../Processors/GenericProcessor/GenericProcessor.h"
+
+class DataViewport;
+
+/**
+
+  Holds data in a displayBuffer to be used by the LfpDisplayCanvas
+  for rendering continuous data streams.
+
+  @see GenericProcessor, LfpDisplayEditor, LfpDisplayCanvas
+
+*/
+
+class LfpDisplayNode :  public GenericProcessor
+
+{
+public:
+
+    LfpDisplayNode();
+    ~LfpDisplayNode();
+
+    AudioProcessorEditor* createEditor();
+
+    bool isSink()
+    {
+        return true;
+    }
+
+    void process(AudioSampleBuffer& buffer, MidiBuffer& midiMessages);
+
+    void setParameter(int, float);
+
+    void updateSettings();
+
+    bool enable();
+    bool disable();
+
+    void handleEvent(int, MidiMessage&, int);
+
+    AudioSampleBuffer* getDisplayBufferAddress()
+    {
+        return displayBuffer;
+    }
+    int getDisplayBufferIndex(int chan)
+    {
+        return displayBufferIndex[chan];
+    }
+
+	CriticalSection* getMutex()
+	{
+		return &displayMutex;
+	}
+
+private:
+
+    void initializeEventChannels();
+
+    ScopedPointer<AudioSampleBuffer> displayBuffer;
+
+    Array<int> displayBufferIndex;
+    Array<int> eventSourceNodes;
+    std::map<int, int> channelForEventSource;
+
+    int numEventChannels;
+
+    float displayGain; //
+    float bufferLength; // s
+
+    AbstractFifo abstractFifo;
+
+    int64 bufferTimestamp;
+    std::map<int, int> ttlState;
+    float* arrayOfOnes;
+    int totalSamples;
+
+    bool resizeBuffer();
+
+	CriticalSection displayMutex;
+
+    JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(LfpDisplayNode);
+
+};
+
+
+
+
+#endif  // __LFPDISPLAYNODE_H_D969A379__
diff --git a/Source/Plugins/LfpDisplayNodeBeta/Makefile b/Source/Plugins/LfpDisplayNodeBeta/Makefile
new file mode 100644
index 0000000000000000000000000000000000000000..7ea147feb7214c68e4ac0b8d490b5a6d7705ef7e
--- /dev/null
+++ b/Source/Plugins/LfpDisplayNodeBeta/Makefile
@@ -0,0 +1,39 @@
+
+LIBNAME := $(notdir $(CURDIR))
+OBJDIR := $(OBJDIR)/$(LIBNAME)
+TARGET := $(LIBNAME).so
+
+
+SRC_DIR := ${shell find ./ -type d -print}
+VPATH := $(SOURCE_DIRS)
+
+SRC := $(foreach sdir,$(SRC_DIR),$(wildcard $(sdir)/*.cpp))
+OBJ := $(addprefix $(OBJDIR)/,$(notdir $(SRC:.cpp=.o)))
+
+BLDCMD := $(CXX) -shared -o $(OUTDIR)/$(TARGET) $(OBJ) $(LDFLAGS) $(RESOURCES) $(TARGET_ARCH)
+
+VPATH = $(SRC_DIR)
+
+.PHONY: objdir
+
+$(OUTDIR)/$(TARGET): objdir $(OBJ)
+	-@mkdir -p $(BINDIR)
+	-@mkdir -p $(LIBDIR)
+	-@mkdir -p $(OUTDIR)
+	@echo "Building $(TARGET)"
+	@$(BLDCMD)
+
+$(OBJDIR)/%.o : %.cpp
+	@echo "Compiling $<"
+	@$(CXX) $(CXXFLAGS) -o "$@" -c "$<"
+	
+	
+objdir:
+	-@mkdir -p $(OBJDIR)
+
+clean:
+	@echo "Cleaning $(LIBNAME)"
+	-@rm -rf $(OBJDIR)
+	-@rm -f $(OUTDIR)/$(TARGET)
+
+-include $(OBJ:%.o=%.d)
diff --git a/Source/Plugins/LfpDisplayNodeBeta/OpenEphysLib.cpp b/Source/Plugins/LfpDisplayNodeBeta/OpenEphysLib.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..b9cc0b2f975fe7b215165d30ff7202987bde0a8f
--- /dev/null
+++ b/Source/Plugins/LfpDisplayNodeBeta/OpenEphysLib.cpp
@@ -0,0 +1,70 @@
+/*
+------------------------------------------------------------------
+
+This file is part of the Open Ephys GUI
+Copyright (C) 2013 Open Ephys
+
+------------------------------------------------------------------
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#include "../../Processors/PluginManager/OpenEphysPlugin.h"
+#include "LfpDisplayNode.h"
+#include <string>
+#ifdef WIN32
+#include <Windows.h>
+#define EXPORT __declspec(dllexport)
+#else
+#define EXPORT
+#endif
+
+using namespace Plugin;
+#define NUM_PLUGINS 1
+
+extern "C" EXPORT void getLibInfo(Plugin::LibraryInfo* info)
+{
+	info->apiVersion = PLUGIN_API_VER;
+	info->name = "LFP viewer Beta";
+	info->libVersion = 1;
+	info->numPlugins = NUM_PLUGINS;
+}
+
+extern "C" EXPORT int getPluginInfo(int index, Plugin::PluginInfo* info)
+{
+	switch (index)
+	{
+	case 0:
+		info->type = Plugin::ProcessorPlugin;
+		info->processor.name = "LFP Viewer Beta";
+		info->processor.type = Plugin::SinkProcessor;
+		info->processor.creator = &(Plugin::createProcessor<LfpDisplayNode>);
+		break;
+	default:
+		return -1;
+		break;
+	}
+	return 0;
+}
+
+#ifdef WIN32
+BOOL WINAPI DllMain(IN HINSTANCE hDllHandle,
+	IN DWORD     nReason,
+	IN LPVOID    Reserved)
+{
+	return TRUE;
+}
+
+#endif
\ No newline at end of file