diff --git a/Source/Plugins/PhaseDetector/PhaseDetector.cpp b/Source/Plugins/PhaseDetector/PhaseDetector.cpp
index 40681ebe2f323e2c197094a98a7d0b0e5aa93833..db7e754f9a87116c9a6d30e558adf0e06f551b45 100644
--- a/Source/Plugins/PhaseDetector/PhaseDetector.cpp
+++ b/Source/Plugins/PhaseDetector/PhaseDetector.cpp
@@ -30,7 +30,7 @@ PhaseDetector::PhaseDetector()
       risingPos(false), risingNeg(false), fallingPos(false), fallingNeg(false)
 
 {
-
+    
 }
 
 PhaseDetector::~PhaseDetector()
diff --git a/Source/Plugins/RFMapper/RFMapper.cpp b/Source/Plugins/RFMapper/RFMapper.cpp
index bb2d8ea327b32d3e7f7d3d43f38ab7d25a2e9ef7..da35b3e7e4b25d5e53ca4206593bf8ecc4ff0dce 100644
--- a/Source/Plugins/RFMapper/RFMapper.cpp
+++ b/Source/Plugins/RFMapper/RFMapper.cpp
@@ -30,12 +30,14 @@
 #include "RFMapperEditor.h"
 
 RFMapper::RFMapper()
-    : GenericProcessor("RF Mapper") //, threshold(200.0), state(true)
+    : GenericProcessor("RF Mapper"), redrawRequested(false), displayBufferSize(100)
 
 {
 	//Without a custom editor, generic parameter controls can be added
     //parameters.add(Parameter("thresh", 0.0, 500.0, 200.0, 0));
 
+    electrodes.clear();
+
 }
 
 RFMapper::~RFMapper()
@@ -56,8 +58,41 @@ AudioProcessorEditor* RFMapper::createEditor()
 	return editor;
 }
 
+void RFMapper::updateSettings()
+{
+    //std::cout << "Setting num inputs on SpikeDisplayNode to " << getNumInputs() << std::endl;
+
+    electrodes.clear();
+
+    for (int i = 0; i < eventChannels.size(); i++)
+    {
+        ChannelType type = eventChannels[i]->getType();
+
+        if (type == ELECTRODE_CHANNEL)
+        {
+
+            Electrode elec;
+			elec.numChannels = static_cast<SpikeChannel*>(eventChannels[i]->extraData.get())->numChannels;
+
+            elec.name = eventChannels[i]->getName();
+            elec.currentSpikeIndex = 0;
+            elec.mostRecentSpikes.ensureStorageAllocated(displayBufferSize);
+
+            for (int j = 0; j < elec.numChannels; j++)
+            {
+                elec.displayThresholds.add(0);
+                elec.detectorThresholds.add(0);
+            }
+
+            electrodes.add(elec);
+
+        }
+    }
+
+}
+
 
-void RFMapper::setParameter(int parameterIndex, float newValue)
+void RFMapper::setParameter(int param, float newValue)
 {
 
     //Parameter& p =  parameters.getReference(parameterIndex);
@@ -66,63 +101,108 @@ void RFMapper::setParameter(int parameterIndex, float newValue)
     //threshold = newValue;
 
     //std::cout << float(p[0]) << std::endl;
-    editor->updateParameterButtons(parameterIndex);
+    if (param == 2)   // redraw
+    {
+        redrawRequested = true;
+
+    }
+}
+
+bool RFMapper::enable()
+{
+    std::cout << "RFMapper::enable()" << std::endl;
+    RFMapperEditor* editor = (RFMapperEditor*) getEditor();
+
+    editor->enable();
+    return true;
+
+}
+
+bool RFMapper::disable()
+{
+    std::cout << "RFMapper disabled!" << std::endl;
+    RFMapperEditor* editor = (RFMapperEditor*) getEditor();
+    editor->disable();
+    return true;
+}
+
+int RFMapper::getNumElectrodes()
+{
+	return electrodes.size();
 }
 
-void RFMapper::process(AudioSampleBuffer& buffer,
-                               MidiBuffer& events)
+void RFMapper::process(AudioSampleBuffer& buffer, MidiBuffer& events)
 {
-	/**
-	Generic structure for processing buffer data 
-	*/
-	int nChannels = buffer.getNumChannels();
-	for (int chan = 0; chan < nChannels; chan++)
-	{
-		int nSamples = getNumSamples(chan);
-		/**
-		Do something here.
-		
-		To obtain a read-only pointer to the n sample of a channel:
-		float* samplePtr = buffer.getReadPointer(chan,n);
-		
-		To obtain a read-write pointer to the n sample of a channel:
-		float* samplePtr = buffer.getWritePointer(chan,n);
-
-		All the samples in a channel are consecutive, so this example is valid:
-		float* samplePtr = buffer.getWritePointer(chan,0);
-		for (i=0; i < nSamples; i++)
-		{
-			*(samplePtr+i) = (*samplePtr+i)+offset;
-		}
-		
-		See also documentation and examples for buffer.copyFrom and buffer.addFrom to operate on entire channels at once.
-
-		To add a TTL event generated on the n-th sample:
-		addEvents(events, TTL, n);
-
-		
-		*/
-	}
-
-	/** Simple example that creates an event when the first channel goes under a negative threshold
-
-    for (int i = 0; i < getNumSamples(channels[0]->sourceNodeId); i++)
+
+    checkForEvents(events); // automatically calls 'handleEvent
+
+    if (redrawRequested)
     {
-        if ((*buffer.getReadPointer(0, i) < -threshold) && !state)
+    	//std::cout << "redraw" << std::endl;
+        for (int i = 0; i < getNumElectrodes(); i++)
         {
-    
-	        // generate midi event
-            addEvent(events, TTL, i);
-    
-	        state = true;
-    
-	    } else if ((*buffer.getReadPointer(0, i) > -threshold + bufferZone)  && state)
+
+            Electrode& e = electrodes.getReference(i);
+
+            // transfer buffered spikes to spike plot
+            for (int j = 0; j < e.currentSpikeIndex; j++)
+            {
+                //std::cout << "Transferring spikes." << std::endl;
+                e.rfMap->processSpikeObject(e.mostRecentSpikes[j]);
+                e.currentSpikeIndex = 0;
+            }
+
+        }
+
+        redrawRequested = false;
+    }
+
+}
+
+void RFMapper::addRFMapForElectrode(RFMap* rf, int i)
+{
+    Electrode& e = electrodes.getReference(i);
+    e.rfMap = rf;
+}
+
+
+void RFMapper::handleEvent(int eventType, MidiMessage& event, int samplePosition)
+{
+
+    //std::cout << "Received event of type " << eventType << std::endl;
+
+    if (eventType == SPIKE)
+    {
+
+        const uint8_t* dataptr = event.getRawData();
+        int bufferSize = event.getRawDataSize();
+
+        if (bufferSize > 0)
         {
-            state = false;
+
+            SpikeObject newSpike;
+
+            bool isValid = unpackSpike(&newSpike, dataptr, bufferSize);
+
+            if (isValid)
+            {
+                int electrodeNum = newSpike.source;
+
+                Electrode& e = electrodes.getReference(electrodeNum);
+                // std::cout << electrodeNum << std::endl;
+
+                // add to buffer
+                if (e.currentSpikeIndex < displayBufferSize)
+                {
+                    //  std::cout << "Adding spike " << e.currentSpikeIndex + 1 << std::endl;
+                    e.mostRecentSpikes.set(e.currentSpikeIndex, newSpike);
+                    e.currentSpikeIndex++;
+                }
+
+            }
+
         }
-    
-	}
-	*/
 
+    }
 
 }
diff --git a/Source/Plugins/RFMapper/RFMapper.h b/Source/Plugins/RFMapper/RFMapper.h
index 8ab1629f77f717d6a8443fbd21484c5dfcaccc20..35419ac016d184ce49868348340b09a788223da5 100644
--- a/Source/Plugins/RFMapper/RFMapper.h
+++ b/Source/Plugins/RFMapper/RFMapper.h
@@ -29,6 +29,9 @@
 #endif
 
 #include <ProcessorHeaders.h>
+#include <SpikeLib.h>
+
+class RFMap;
 
 /**
 
@@ -67,6 +70,10 @@ public:
 		return true;
 	}
 
+    void updateSettings();
+
+    int getNumElectrodes();
+
 	/** If the processor has a custom editor, this method must be defined to instantiate it. */
 	AudioProcessorEditor* createEditor();
 
@@ -85,11 +92,15 @@ public:
          */
     void process(AudioSampleBuffer& buffer, MidiBuffer& events);
 
+    void handleEvent(int, MidiMessage&, int);
+
     /** The method that standard controls on the editor will call.
 		It is recommended that any variables used by the "process" function 
 		are modified only through this method while data acquisition is active. */
     void setParameter(int parameterIndex, float newValue);
 
+    void addRFMapForElectrode(RFMap* rf, int i);
+
 	/** Optional method called every time the signal chain is refreshed or changed in any way.
 		
 		Allows the processor to handle variations in the channel configuration or any other parameter
@@ -98,6 +109,9 @@ public:
 		structure shouldn't be manipulated outside of this method.
 	*/
 	//void updateSettings();
+    bool enable();
+    bool disable();
+
 
 private:
 
@@ -108,6 +122,29 @@ private:
     // float threshold;
     // bool state;
 
+    struct Electrode
+    {
+        String name;
+
+        int numChannels;
+
+        Array<float> displayThresholds;
+        Array<float> detectorThresholds;
+
+        Array<SpikeObject> mostRecentSpikes;
+        int currentSpikeIndex;
+
+        int recordIndex;
+
+        RFMap* rfMap;
+
+    };
+
+    Array<Electrode> electrodes;
+
+    int displayBufferSize;
+    bool redrawRequested;
+
     JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(RFMapper);
 
 };
diff --git a/Source/Plugins/RFMapper/RFMapperEditor.cpp b/Source/Plugins/RFMapper/RFMapperEditor.cpp
index adabc34bae60eda3908693b824a8b8faeb33cef5..f1c2663c66f369eaa448b678a092cc1c07f8f3d8 100644
--- a/Source/Plugins/RFMapper/RFMapperEditor.cpp
+++ b/Source/Plugins/RFMapper/RFMapperEditor.cpp
@@ -31,6 +31,18 @@ RFMapperEditor::RFMapperEditor(GenericProcessor* parentNode, bool useDefaultPara
     tabText = "Mapper";
     
     desiredWidth = 180;
+
+    electrodeSelector = new ComboBox();
+    electrodeSelector->setBounds(35,40,100,20);
+    electrodeSelector->addListener(this);
+
+    addAndMakeVisible(electrodeSelector);
+
+    unitSelector = new ComboBox();
+    unitSelector->setBounds(35,70,100,20);
+    unitSelector->addListener(this);
+
+    addAndMakeVisible(unitSelector);
     
 }
 
@@ -43,31 +55,68 @@ Visualizer* RFMapperEditor::createNewCanvas()
 {
     
     RFMapper* processor = (RFMapper*) getProcessor();
-    return new RFMapperCanvas(processor);
+    canvas = new RFMapperCanvas(processor);
+    return canvas;
     
 }
 
-void RFMapperEditor::buttonCallback(Button* button)
+void RFMapperEditor::comboBoxChanged(ComboBox* c)
 {
+
+    RFMapperCanvas* rfmc = (RFMapperCanvas*) canvas.get();
+    
+    if (c == electrodeSelector)
+    {
+        rfmc->setCurrentElectrode(c->getSelectedId()-1);
+    } else if (c == unitSelector)
+    {
+        rfmc->setCurrentUnit(c->getSelectedId()-1);
+    }
     
-    int gId = button->getRadioGroupId();
+}
+
+void RFMapperEditor::updateSettings()
+{
+    RFMapper* processor = (RFMapper*) getProcessor();
+
+    int numElectrodes = processor->getNumElectrodes();
     
-    if (gId > 0)
+    electrodeSelector->clear();
+    unitSelector->clear();
+
+    if (numElectrodes > 0)
     {
-        if (canvas != 0)
+
+        for (int i = 1; i <= numElectrodes; i++)
         {
-            canvas->setParameter(gId-1, button->getName().getFloatValue());
+            String itemName = "Electrode ";
+            itemName += String(i);
+            std::cout << i << " " << itemName << std::endl;
+            electrodeSelector->addItem(itemName, i);
         }
+
+        electrodeSelector->setSelectedId(1, dontSendNotification);
+
+        unitSelector->addItem("MUA", 1);
         
+        for (int i = 1; i <= 5; i++)
+        {
+            String itemName = "Unit ";
+            itemName += String(i);
+            unitSelector->addItem(itemName, i + 1);
+        }
+
+        unitSelector->setSelectedId(1, dontSendNotification);
     }
-    
-}
 
+    updateVisualizer();
+}
 
 
-RFMapperCanvas::RFMapperCanvas(RFMapper* sr) : processor(sr)
+RFMapperCanvas::RFMapperCanvas(RFMapper* sr) : processor(sr), currentMap(0)
 {
-    
+
+    rfMaps.clear();
 }
 
 
@@ -77,12 +126,14 @@ RFMapperCanvas::~RFMapperCanvas(){
     
 void RFMapperCanvas::beginAnimation()
 {
-    
+    startCallbacks();
+    std::cout << "RF Mapper beginning animation." << std::endl;
+
 }
 
 void RFMapperCanvas::endAnimation()
 {
-    
+    stopCallbacks();
 }
     
 void RFMapperCanvas::refreshState()
@@ -91,23 +142,179 @@ void RFMapperCanvas::refreshState()
 
 void RFMapperCanvas::update()
 {
-    
+    int nMaps = processor->getNumElectrodes();
+
+    clearRfMaps();
+
+    for (int i = 0; i < nMaps; i++)
+    {
+        RFMap* rf = addRFMap(i);
+        processor->addRFMapForElectrode(rf, i);
+    }
+
+    addAndMakeVisible(rfMaps[currentMap]);
+
+    resized();
+    repaint();
+
 }
     
 void RFMapperCanvas::setParameter(int, float) {}
 
 void RFMapperCanvas::paint(Graphics& g)
 {
-    g.fillAll(Colours::orange);
+    g.fillAll(Colours::grey);
 }
     
 void RFMapperCanvas::refresh()
 {
+    processor->setParameter(2, 0.0f); // request redraw
     
+    repaint();
+
+    //::cout << "Refresh" << std::endl;
 }
     
 void RFMapperCanvas::resized()
 {
+    if (rfMaps.size() > 0)
+        rfMaps[currentMap]->setBounds(0, 0, getWidth(), getHeight());
+
+    repaint();
+}
     
+
+void RFMapperCanvas::clearRfMaps()
+{
+    rfMaps.clear();
+
+}
+
+RFMap* RFMapperCanvas::addRFMap(int electrodeNum)
+{
+
+    std::cout << "Adding new rf map." << std::endl;
+
+    RFMap* rfMap = new RFMap(this, electrodeNum);
+    rfMaps.add(rfMap);
+
+    return rfMap;
+}
+
+void RFMapperCanvas::setCurrentElectrode(int electrodeNum)
+{
+    currentMap = electrodeNum;
+
+    update();
+}
+
+void RFMapperCanvas::setCurrentUnit(int unitNum)
+{
+    rfMaps[currentMap]->setCurrentUnit(unitNum);
+}
+
+RFMap::RFMap(RFMapperCanvas*, int elecNum)
+{
+    map = AudioSampleBuffer(50,30);
+
+    random = Random();
+
+    unitId = 0;
+
+    reset();
+}
+
+RFMap::~RFMap()
+{
+
+}
+
+void RFMap::reset()
+{
+    float numXPixels = map.getNumChannels();
+    float numYPixels = map.getNumSamples();
+
+    for (int n = 0; n < numXPixels; n++)
+    {
+        for (int m = 0; m < numYPixels; m++)
+        {
+            map.setSample(n,m, 0.);
+        }
+    }
+
+    repaint();
+}
+
+void RFMap::paint(Graphics& g)
+{
+    float numXPixels = map.getNumChannels();
+    float numYPixels = map.getNumSamples();
+
+    float xHeight = getWidth()/numXPixels;
+    float yHeight = getHeight()/numYPixels;
+
+    for (int n = 0; n < numXPixels; n++)
+    {
+        for (int m = 0; m < numYPixels; m++)
+        {
+            float colourIndex = map.getSample(n,m);
+
+            if (colourIndex == 0.)
+            {
+                g.setColour(Colours::grey);
+            } else if (colourIndex == 1.)
+            {
+                g.setColour(Colours::white);
+            } else {
+                g.setColour(Colours::black);
+            }
+
+            g.fillRect(n*xHeight, m*yHeight, xHeight, yHeight);
+        }
+    }
+}
+void RFMap::resized()
+{
+
+}
+
+void RFMap::setCurrentUnit(int unit)
+{
+    unitId = unit;
 }
+
+void RFMap::processSpikeObject(const SpikeObject& s)
+{
+
+    //std::cout << "Got spike." << std::endl;
+
+    if (s.sortedId == unitId)
+    {
+
+        float numXPixels = map.getNumChannels();
+        float numYPixels = map.getNumSamples();
+
+        for (int n = 0; n < numXPixels; n++)
+        {
+            for (int m = 0; m < numYPixels; m++)
+            {
+                float colourIndex = random.nextFloat();
+
+                if (colourIndex < 0.33)
+                {
+                    map.setSample(n,m,-1.);
+                } else if (colourIndex > 0.33 && colourIndex < 0.66)
+                {
+                    map.setSample(n,m, 0.);
+                } else {
+                    map.setSample(n,m,1.);
+                }
+
+            }
+        }
+
+    }
+
     
+
+}
diff --git a/Source/Plugins/RFMapper/RFMapperEditor.h b/Source/Plugins/RFMapper/RFMapperEditor.h
index 6954321d2511ec9c05ac6b2c25ecb8c3ac538b03..c26755c314bcf47390fc22a006e4545e58474a7d 100644
--- a/Source/Plugins/RFMapper/RFMapperEditor.h
+++ b/Source/Plugins/RFMapper/RFMapperEditor.h
@@ -26,6 +26,7 @@ along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
 #include <VisualizerEditorHeaders.h>
 #include <VisualizerWindowHeaders.h>
+#include <SpikeLib.h>
 
 #include "RFMapper.h"
 
@@ -39,18 +40,22 @@ class Visualizer;
  
  */
 
-class RFMapperEditor : public VisualizerEditor
+class RFMapperEditor : public VisualizerEditor, public ComboBox::Listener
 {
 public:
     RFMapperEditor(GenericProcessor*, bool useDefaultParameterEditors);
     ~RFMapperEditor();
     
-    void buttonCallback(Button* button);
+    void updateSettings();
+
+    void comboBoxChanged(ComboBox* c);
     
     Visualizer* createNewCanvas();
     
 private:
-    
+
+    ScopedPointer<ComboBox> electrodeSelector;
+    ScopedPointer<ComboBox> unitSelector;
     
     JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(RFMapperEditor);
 };
@@ -72,6 +77,9 @@ public:
     void setParameter(int, int, int, float) {}
     
     void paint(Graphics& g);
+
+    void setCurrentUnit(int);
+    void setCurrentElectrode(int);
     
     void refresh();
     
@@ -80,6 +88,36 @@ public:
 private:
     RFMapper* processor;
 
+    OwnedArray<RFMap> rfMaps;
+
+    void clearRfMaps();
+    RFMap* addRFMap(int);
+
+    int currentMap;
+
+};
+
+class RFMap : public Component
+{
+public:
+    RFMap(RFMapperCanvas*, int elecNum);
+    virtual ~RFMap();
+
+    AudioSampleBuffer map;
+
+    void paint(Graphics& g);
+    void resized();
+    void reset();
+
+    void processSpikeObject(const SpikeObject& s);
+
+    Random random;
+
+    void setCurrentUnit(int);
+    int unitId;
+
+
+
 };
 
 
diff --git a/Source/Plugins/SpikeRaster/SpikeRaster.h b/Source/Plugins/SpikeRaster/SpikeRaster.h
index 98839df1b0a0f35d1225e7f0e3cec62391fd9675..33176b1dfccba1321a24e82206abef30cb505539 100644
--- a/Source/Plugins/SpikeRaster/SpikeRaster.h
+++ b/Source/Plugins/SpikeRaster/SpikeRaster.h
@@ -85,6 +85,8 @@ public:
          */
     void process(AudioSampleBuffer& buffer, MidiBuffer& events);
 
+    void handleEvent(int, MidiMessage&, int);
+
     /** The method that standard controls on the editor will call.
 		It is recommended that any variables used by the "process" function 
 		are modified only through this method while data acquisition is active. */