Skip to content

Commit

Permalink
Merge pull request #551 from admunkucsd/adding_lfp_filtering
Browse files Browse the repository at this point in the history
Adding lfp channel selection filtering
  • Loading branch information
jsiegle authored Aug 3, 2023
2 parents 40f5af3 + d97e5a6 commit 1439387
Show file tree
Hide file tree
Showing 7 changed files with 123 additions and 25 deletions.
4 changes: 3 additions & 1 deletion Plugins/LfpDisplayNode/DisplayBuffer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,8 @@ void DisplayBuffer::addChannel(
ContinuousChannel::Type type,
bool isRecorded,
int group,
float ypos,
float ypos,
String description,
String structure)
{
ChannelMetadata metadata = ChannelMetadata();
Expand All @@ -75,6 +76,7 @@ void DisplayBuffer::addChannel(
metadata.structure = structure;
metadata.type = type;
metadata.isRecorded = isRecorded;
metadata.description = description;

channelMetadata.add(metadata);
channelMap[channelNum] = numChannels;
Expand Down
8 changes: 5 additions & 3 deletions Plugins/LfpDisplayNode/DisplayBuffer.h
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,8 @@ namespace LfpViewer {
ContinuousChannel::Type channelType,
bool isRecorded,
int group = 0,
float ypos = 0,
float ypos = 0,
String description = "",
String structure = "None");

/** Initializes the event channel at the start of each buffer */
Expand All @@ -87,10 +88,11 @@ namespace LfpViewer {
String structure = "None";
ContinuousChannel::Type type;
bool isRecorded = false;
String description = "";
};

Array<ChannelMetadata> channelMetadata;

String name;
int id;

Expand Down Expand Up @@ -128,4 +130,4 @@ namespace LfpViewer {
};


#endif //__DISPLAYBUFFER_H__
#endif //__DISPLAYBUFFER_H__
45 changes: 28 additions & 17 deletions Plugins/LfpDisplayNode/LfpDisplay.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -981,27 +981,38 @@ void LfpDisplay::rebuildDrawableChannelsList()
removeAllChildren(); // start with clean slate

Array<LfpChannelTrack> channelsToDraw; // all visible channels will be added to this array

Array<int> filteredChannels;
if(canvasSplit -> displayBuffer) {
filteredChannels = canvasSplit -> getFilteredChannels();
}
// iterate over all channels and select drawable ones
for (int i = 0, drawableChannelNum = 0; i < channels.size(); i++)
for (int i = 0, drawableChannelNum = 0, filterChannelIndex = 0; i < channels.size(); i++)
{

//std::cout << "Checking for hidden channels" << std::endl;
if (displaySkipAmt == 0 || (i % displaySkipAmt == 0)) // no skips, add all channels
{
channels[i]->setHidden(false);
channelInfo[i]->setHidden(false);

channelInfo[i]->setDrawableChannelNumber(drawableChannelNum++);
channelInfo[i]->resized(); // to update the conditional drawing of enableButton and channel num

channelsToDraw.add(LfpDisplay::LfpChannelTrack{
channels[i],
channelInfo[i]
});
int channelNumber = filteredChannels.size() ? canvasSplit->displayBuffer->channelMetadata[i].description.getIntValue(): -1;
//the filter list can have channels that aren't selected for acqusition; this skips those filtered channels
while(filterChannelIndex < filteredChannels.size() && channelNumber > filteredChannels[filterChannelIndex]){
filterChannelIndex++;
}
if(filteredChannels.size() == 0 || (filterChannelIndex < filteredChannels.size() && channelNumber == filteredChannels[filterChannelIndex])) {
if (displaySkipAmt == 0 || ((filteredChannels.size() ? filterChannelIndex : i) % displaySkipAmt == 0)) // no skips, add all channels
{

addAndMakeVisible(channels[i]);
addAndMakeVisible(channelInfo[i]);
channels[i]->setHidden(false);
channelInfo[i]->setHidden(false);

channelInfo[i]->setDrawableChannelNumber(drawableChannelNum++);
channelInfo[i]->resized(); // to update the conditional drawing of enableButton and channel num

channelsToDraw.add(LfpDisplay::LfpChannelTrack{
channels[i],
channelInfo[i]
});

addAndMakeVisible(channels[i]);
addAndMakeVisible(channelInfo[i]);
}
filterChannelIndex++;
}
else // skip some channels
{
Expand Down
9 changes: 7 additions & 2 deletions Plugins/LfpDisplayNode/LfpDisplayCanvas.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1661,8 +1661,13 @@ void LfpDisplaySplitter::visibleAreaChanged()
void LfpDisplaySplitter::refresh()
{
updateScreenBuffer();

lfpDisplay->refresh(); // redraws only the new part of the screen buffer, unless fullredraw is set to true
if(shouldRebuildChannelList) {
shouldRebuildChannelList = false;
lfpDisplay->rebuildDrawableChannelsList(); // calls resized()/refresh() after rebuilding list
}
else {
lfpDisplay->refresh(); // redraws only the new part of the screen buffer, unless fullredraw is set to true
}
}

void LfpDisplaySplitter::comboBoxChanged(juce::ComboBox *comboBox)
Expand Down
7 changes: 7 additions & 0 deletions Plugins/LfpDisplayNode/LfpDisplayCanvas.h
Original file line number Diff line number Diff line change
Expand Up @@ -340,6 +340,11 @@ class LfpDisplaySplitter : public Component,
uint16 selectedStreamId;

void refreshScreenBuffer();

bool shouldRebuildChannelList = false;

void setFilteredChannels(Array<int> channels){filteredChannels = channels;}
Array<int> getFilteredChannels(){return filteredChannels;}

private:

Expand Down Expand Up @@ -381,6 +386,8 @@ class LfpDisplaySplitter : public Component,
int displayBufferSize;

int scrollBarThickness;

Array<int> filteredChannels = Array<int>();

JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(LfpDisplaySplitter);

Expand Down
69 changes: 67 additions & 2 deletions Plugins/LfpDisplayNode/LfpDisplayNode.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -91,13 +91,14 @@ void LfpDisplayNode::updateSettings()
displayBufferMap[streamId]->sampleRate = channel->getSampleRate();
displayBufferMap[streamId]->name = name;
}

//
displayBufferMap[streamId]->addChannel(channel->getName(), // name
ch, // index
channel->getChannelType(), // type
channel->isRecorded,
0, // group
channel->position.y // ypos
channel->position.y, // ypos
channel-> getDescription()
);
}

Expand Down Expand Up @@ -179,6 +180,11 @@ bool LfpDisplayNode::stopAcquisition()
LfpDisplayEditor* editor = (LfpDisplayEditor*) getEditor();
editor->disable();

for(auto split : splitDisplays) {
Array<int> emptyArray = Array<int>();
split -> setFilteredChannels(emptyArray);
}

for (auto buffer : displayBuffers)
buffer->ttlState = 0;

Expand Down Expand Up @@ -327,3 +333,62 @@ void LfpDisplayNode::acknowledgeTrigger(int id)
{
latestTrigger.set(id, -1);
}

bool LfpDisplayNode::getIntField(DynamicObject::Ptr payload, String name, int& value, int lowerBound, int upperBound) {
if(!payload->hasProperty(name) || !payload->getProperty(name).isInt())
return false;
int tempVal = payload->getProperty(name);
if((upperBound != INT_MIN && tempVal > upperBound) || (lowerBound != INT_MAX && tempVal < lowerBound))
return false;
value = tempVal;
return true;
}


void LfpDisplayNode::handleBroadcastMessage(String msg) {
var parsedMessage = JSON::parse(msg);
if(!parsedMessage.isObject())
return;
DynamicObject::Ptr jsonMessage = parsedMessage.getDynamicObject();
if(jsonMessage == nullptr)
return;
String pluginName= jsonMessage -> getProperty("plugin");
if(pluginName != "LFPViewer") {
return;
}
String command = jsonMessage -> getProperty("command");
DynamicObject::Ptr payload = jsonMessage -> getProperty("payload").getDynamicObject();
if(command == "filter") {
if(payload.get() == nullptr){
LOGD("Tried to filter in LFPViewer, but could not find a payload");
return;
}
int split, start, rows, cols, colsPerRow, end;
if(!getIntField(payload, "split", split, 0, 2) || !getIntField(payload, "start", start, 0)) {
LOGD("Tried to filter in LFPViewer, but a valid split and start weren't provided");
return;
}
Array<int> channelNames;
//If an end is specificed add channels from start to end
//Else calculate the rectangular selection based on rows and columns
if(getIntField(payload, "end", end, 0)) {
for(int index = 0; index < (end - start); index++) {
channelNames.add(start + index);
}
}
else {
if(!getIntField(payload, "rows", rows, 0) || !getIntField(payload, "cols", cols, 0) || !getIntField(payload, "colsPerRow", colsPerRow, 0)) {
LOGD("Tried to filter by rectangular selection in LFPViewer, but valid row/column/columnsPerRow counts weren't provided");
return;
}
for(int row = 0; row < rows; row++) {
for(int col = 0; col < cols; col++) {
channelNames.add(start + col + row*colsPerRow);
}
}
}
splitDisplays[split] -> setFilteredChannels(channelNames);
splitDisplays[split] -> shouldRebuildChannelList = true;
}
}

6 changes: 6 additions & 0 deletions Plugins/LfpDisplayNode/LfpDisplayNode.h
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,12 @@ class LfpDisplayNode : public GenericProcessor
/** Acknowledges receipt of a trigger for a given split display*/
void acknowledgeTrigger(int splitId);

/** Reads from int value from payload, returns if the value was found and is within bounds*/
bool getIntField(DynamicObject::Ptr payload, String name, int& value, int lowerBound = INT_MAX, int upperBound = INT_MIN);

/** Handles messages from other processors during acquisition*/
void handleBroadcastMessage(String msg) override;

private:

/** Initializes trigger channels within a process block*/
Expand Down

0 comments on commit 1439387

Please sign in to comment.