Skip to content
Snippets Groups Projects
Commit 72ad170e authored by Josh Siegle's avatar Josh Siegle
Browse files

Basic implementation of RFMapper

parent 73564a2b
No related branches found
No related tags found
No related merge requests found
......@@ -30,7 +30,7 @@ PhaseDetector::PhaseDetector()
risingPos(false), risingNeg(false), fallingPos(false), fallingNeg(false)
{
}
PhaseDetector::~PhaseDetector()
......
......@@ -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++;
}
}
}
}
*/
}
}
......@@ -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);
};
......
......@@ -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.);
}
}
}
}
}
......@@ -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;
};
......
......@@ -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. */
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment