Skip to content

Commit

Permalink
Add PLUGIN_API OpenEphysAction
Browse files Browse the repository at this point in the history
  • Loading branch information
medengineer committed Dec 7, 2023
1 parent 8ca9cd7 commit 2450618
Show file tree
Hide file tree
Showing 14 changed files with 207 additions and 36 deletions.
17 changes: 11 additions & 6 deletions Plugins/BasicSpikeDisplay/SpikeDetector/SpikeDetector.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -396,7 +396,7 @@ SpikeChannel* SpikeDetector::addSpikeChannel (SpikeChannel::Type type,
String name,
int index)
{

Array<var> selectedChannels;
Array<int> localChannels;

Expand Down Expand Up @@ -579,12 +579,17 @@ SpikeChannel* SpikeDetector::addSpikeChannel (SpikeChannel::Type type,

}

void SpikeDetector::removeSpikeChannel (SpikeChannel* spikeChannel)
void SpikeDetector::removeSpikeChannel(String spikeChannelKey)
{

LOGD("Removing spike channel: ", spikeChannel->getName(), " from stream ", spikeChannel->getStreamId());

spikeChannels.removeObject(spikeChannel);
for (int i = 0; i < spikeChannels.size(); i++)
{
if (spikeChannels[i]->getIdentifier() == spikeChannelKey)
{
LOGD("Removing spike channel: ", spikeChannels[i]->getName(), " from stream ", spikeChannels[i]->getStreamId());
spikeChannels.removeObject(spikeChannels[i]);
break;
}
}

//Reset electrode and channel counters if no more spike channels after this delete
if (!spikeChannels.size())
Expand Down
4 changes: 2 additions & 2 deletions Plugins/BasicSpikeDisplay/SpikeDetector/SpikeDetector.h
Original file line number Diff line number Diff line change
Expand Up @@ -232,8 +232,8 @@ class SpikeDetector : public GenericProcessor
String name = "",
int index = -1);

/** Removes a spike channel, based on a SpikeChannel pointer. */
void removeSpikeChannel (SpikeChannel*);
/** Removes a spike channel, based on a SpikeChannel identifier. */
void removeSpikeChannel (String);
// =====================================================================

/** Get array of local SpikeChannel objects for a given dataStream*/
Expand Down
76 changes: 60 additions & 16 deletions Plugins/BasicSpikeDisplay/SpikeDetector/SpikeDetectorActions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,10 +28,11 @@
AddSpikeChannels::AddSpikeChannels(SpikeDetector* processor_,
DataStream* stream_,
SpikeChannel::Type type_,
int count_, //adds multiple channels atonce
int count_, //adds multiple channels at once
Array<int> startChannels_) :
processor(processor_),
streamId(stream_->getStreamId()),
OpenEphysAction("AddSpikeChannels"),
spikeDetector(processor_),
streamKey(stream_->getKey()),
type(type_),
count(count_),
startChannels(startChannels_)
Expand All @@ -54,33 +55,68 @@ bool AddSpikeChannels::perform()
if (i < startChannels.size())
startChannel = startChannels[i];

processor->addSpikeChannel(type, streamId, startChannel);
//TODO: Should add a convenience function for this
uint16 streamId = 0;
for (auto stream : spikeDetector->getDataStreams())
{
if (stream->getKey() == streamKey)
{
streamId = stream->getStreamId();
break;
}
}
if (streamId == 0) return false;

//TODO: Pass stream name instead of streamId once this is working
SpikeChannel* spikeChannel = spikeDetector->addSpikeChannel(type, streamId, startChannel);
addedSpikeChannels.add(spikeChannel->getIdentifier());
}
spikeDetector->registerUndoableAction(spikeDetector->getNodeId(), this);
CoreServices::updateSignalChain(spikeDetector);

return true;
}

bool AddSpikeChannels::undo()
{
uint16 streamId = 0;
for (auto stream : spikeDetector->getDataStreams())
{
if (stream->getKey() == streamKey)
{
streamId = stream->getStreamId();
break;
}
}
if (streamId == 0) return false;
for (int i = 0; i < count; i++)
processor->removeSpikeChannel(processor->getSpikeChannelsForStream(streamId).getLast());
spikeDetector->removeSpikeChannel(addedSpikeChannels[i]);
CoreServices::updateSignalChain(spikeDetector);
return true;
}

void AddSpikeChannels::restoreOwner(GenericProcessor* owner)
{
LOGD("RESTORING OWNER FOR: AddSpikeChannels");
spikeDetector = (SpikeDetector*)owner;
}

RemoveSpikeChannels::RemoveSpikeChannels(SpikeDetector* processor_,
DataStream* stream_,
Array<SpikeChannel*> spikeChannelsToRemove_,
Array<int> indeces_) :
processor(processor_),
spikeChannelsToRemove(spikeChannelsToRemove_),
OpenEphysAction("RemoveSpikeChannels"),
spikeDetector(processor_),
indeces(indeces_),
streamId(stream_->getStreamId())
streamKey(stream_->getKey())
{
settings = std::make_unique<XmlElement>("SPIKE_CHANNELS");

for (auto spikeChannel : spikeChannelsToRemove)
for (auto spikeChannel : spikeChannelsToRemove_)
{
if (spikeChannel->isLocal())
{
LOGD("REMOVING SPIKE CHANNEL: ", spikeChannel->getName());

XmlElement* spikeParamsXml = settings->createNewChildElement("SPIKE_CHANNEL");

Expand All @@ -106,6 +142,8 @@ RemoveSpikeChannels::RemoveSpikeChannels(SpikeDetector* processor_,
}

spikeChannel->getParameter("waveform_type")->toXml(spikeParamsXml);

spikeChannelsToRemove.add(spikeChannel->getIdentifier());
}
}
}
Expand All @@ -114,10 +152,18 @@ RemoveSpikeChannels::~RemoveSpikeChannels()
{
}

void RemoveSpikeChannels::restoreOwner(GenericProcessor* processor)
{
spikeDetector = (SpikeDetector*)processor;
}

bool RemoveSpikeChannels::perform()
{
for (auto spikeChannel : spikeChannelsToRemove)
processor->removeSpikeChannel(spikeChannel);
spikeDetector->removeSpikeChannel(spikeChannel);
spikeDetector->registerUndoableAction(spikeDetector->getNodeId(), this);
CoreServices::updateSignalChain(spikeDetector);

return true;
}

Expand All @@ -128,19 +174,17 @@ bool RemoveSpikeChannels::undo()
{
String name = spikeParamsXml->getStringAttribute("name", "");

//std::cout << "SPIKE CHANNEL NAME: " << name << std::endl;

double sample_rate = spikeParamsXml->getDoubleAttribute("sample_rate", 0.0f);
String stream_name = spikeParamsXml->getStringAttribute("stream_name", "");
int stream_source = spikeParamsXml->getIntAttribute("stream_source", 0);

SpikeChannel::Type type = SpikeChannel::typeFromNumChannels(spikeParamsXml->getIntAttribute("num_channels", 1));

if (!processor->alreadyLoaded(name, type, stream_source, stream_name))
if (!spikeDetector->alreadyLoaded(name, type, stream_source, stream_name))
{
uint16 streamId = processor->findSimilarStream(stream_source, stream_name, sample_rate, true);
uint16 streamId = spikeDetector->findSimilarStream(stream_source, stream_name, sample_rate, true);

SpikeChannel* spikeChannel = processor->addSpikeChannel(type, streamId, -1, name, indeces[idx]);
SpikeChannel* spikeChannel = spikeDetector->addSpikeChannel(type, streamId, -1, name, indeces[idx]);

spikeChannel->getParameter("local_channels")->fromXml(spikeParamsXml);

Expand All @@ -160,6 +204,6 @@ bool RemoveSpikeChannels::undo()
}
idx++;
}
CoreServices::updateSignalChain(processor->getEditor());
CoreServices::updateSignalChain(spikeDetector);
return true;
}
21 changes: 14 additions & 7 deletions Plugins/BasicSpikeDisplay/SpikeDetector/SpikeDetectorActions.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
#include <ProcessorHeaders.h>

#include "SpikeDetector.h"
#include "SpikeDetectorEditor.h"

/**
Adds a spike channel to the spike detector,
Expand All @@ -35,7 +36,7 @@
Undo: removes the spike channel from the
spike detector.
*/
class AddSpikeChannels : public UndoableAction
class AddSpikeChannels : public OpenEphysAction
{

public:
Expand All @@ -50,6 +51,8 @@ class AddSpikeChannels : public UndoableAction
/** Destructor */
~AddSpikeChannels();

void restoreOwner(GenericProcessor* processor) override;

/** Perform the action*/
bool perform();

Expand All @@ -60,16 +63,18 @@ class AddSpikeChannels : public UndoableAction

private:

SpikeDetector* processor;
uint16 streamId;
SpikeDetector* spikeDetector;
String streamKey;
SpikeChannel::Type type;
Array<int> startChannels;

Array<String> addedSpikeChannels;

int count;

};

class RemoveSpikeChannels : public UndoableAction
class RemoveSpikeChannels : public OpenEphysAction
{

public:
Expand All @@ -83,6 +88,8 @@ class RemoveSpikeChannels : public UndoableAction
/** Destructor */
~RemoveSpikeChannels();

void restoreOwner(GenericProcessor* processor) override;

/** Perform the action*/
bool perform();

Expand All @@ -93,9 +100,9 @@ class RemoveSpikeChannels : public UndoableAction

private:

SpikeDetector* processor;
uint16 streamId;
Array<SpikeChannel*> spikeChannelsToRemove;
SpikeDetector* spikeDetector;
String streamKey;
Array<String> spikeChannelsToRemove;
Array<SpikeChannel*> removedSpikeChannels;
Array<int> indeces;

Expand Down
23 changes: 19 additions & 4 deletions Plugins/BasicSpikeDisplay/SpikeDetector/SpikeDetectorEditor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,8 @@ void SpikeDetectorEditor::buttonClicked(Button* button)
spikeChannels,
acquisitionIsActive);

currentConfigWindow->update(processor->getSpikeChannelsForStream(getCurrentStream()));

CallOutBox& myBox
= CallOutBox::launchAsynchronously(std::unique_ptr<Component>(currentConfigWindow),
button->getScreenBounds(),
Expand All @@ -80,18 +82,30 @@ void SpikeDetectorEditor::buttonClicked(Button* button)

}

void SpikeDetectorEditor::updateConfigurationWindow()
{
if (currentConfigWindow != nullptr)
{
SpikeDetector* processor = (SpikeDetector*)getProcessor();
currentConfigWindow->update(processor->getSpikeChannelsForStream(getCurrentStream()));
}
}

void SpikeDetectorEditor::addSpikeChannels(PopupConfigurationWindow* window, SpikeChannel::Type type, int count, Array<int> startChannels)
{
SpikeDetector* processor = (SpikeDetector*)getProcessor();

LOGD("** ADDING TO CURRENT STREAM: ", getCurrentStream());

DataStream* stream = processor->getDataStream(getCurrentStream());

AddSpikeChannels* action = new AddSpikeChannels(processor, stream, type, count, startChannels);

CoreServices::getUndoManager()->beginNewTransaction();
CoreServices::getUndoManager()->perform(action);
CoreServices::getUndoManager()->perform((UndoableAction*)action);

CoreServices::updateSignalChain(this);
// Now called in perform
//CoreServices::updateSignalChain(this);

if (window != nullptr)
window->update(processor->getSpikeChannelsForStream(getCurrentStream()));
Expand All @@ -109,9 +123,10 @@ void SpikeDetectorEditor::removeSpikeChannels(PopupConfigurationWindow* window,
RemoveSpikeChannels* action = new RemoveSpikeChannels(processor, stream, spikeChannelsToRemove, indeces);

CoreServices::getUndoManager()->beginNewTransaction();
CoreServices::getUndoManager()->perform(action);
CoreServices::getUndoManager()->perform((UndoableAction*)action);

CoreServices::updateSignalChain(this);
// Now called in perform
//CoreServices::updateSignalChain(this);

if (window != nullptr)
window->update(processor->getSpikeChannelsForStream(getCurrentStream()));
Expand Down
3 changes: 3 additions & 0 deletions Plugins/BasicSpikeDisplay/SpikeDetector/SpikeDetectorEditor.h
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,9 @@ class SpikeDetectorEditor : public GenericEditor,
/** Called by PopupConfigurationWindow*/
int getNumChannelsForCurrentStream();

/** Update configuration window */
void updateConfigurationWindow();

private:

std::unique_ptr<UtilityButton> configureButton;
Expand Down
7 changes: 7 additions & 0 deletions Source/Processors/Actions/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
#Open Ephys GUI direcroty-specific file

#add files in this folder
add_sources(open-ephys
OpenEphysAction.cpp
OpenEphysAction.h
)
4 changes: 4 additions & 0 deletions Source/Processors/Actions/OpenEphysAction.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
#include "OpenEphysAction.h"

// Definition of the static map
std::map<std::string, std::vector<OpenEphysAction*>> OpenEphysAction::actionsByKey;
46 changes: 46 additions & 0 deletions Source/Processors/Actions/OpenEphysAction.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
#include <JuceHeader.h>

#include <map>
#include <vector>
#include <string>

#ifndef OPENEPHYSACTION_H_INCLUDED
#define OPENEPHYSACTION_H_INCLUDED

class PLUGIN_API OpenEphysAction : public UndoableAction {
public:
//OpenEphysAction(GenericProcessor* p) {};
OpenEphysAction(const std::string& actionKey) : key(actionKey) {
// Add this action to the static map
//actionsByKey[key].push_back(this);
}

// Implement the UndoableAction methods
bool perform() override = 0;

// Implement the UndoableAction methods
bool undo() override = 0;

// Example static method to access actions by key
/*
static std::vector<OpenEphysAction*>& getActionsByKey(const std::string& actionKey) {
return actionsByKey[actionKey];
}
*/
virtual void restoreOwner(GenericProcessor* p) = 0;

String getIdentifier() {
return key;
}

private:

GenericProcessor* processor;
//std::string key; // Private member to store the action key

// Static map to store actions by keys
//static std::map<std::string, std::vector<OpenEphysAction*>> actionsByKey;
std::string key;
};

#endif // OPENEPHYSACTION_H_INCLUDED
2 changes: 2 additions & 0 deletions Source/Processors/GenericProcessor/GenericProcessor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,8 @@

const String GenericProcessor::m_unusedNameString("xxx-UNUSED-OPEN-EPHYS-xxx");

std::map<int, std::vector<OpenEphysAction*>> GenericProcessor::undoableActions;

GenericProcessor::GenericProcessor(const String& name, bool headlessMode_)
: GenericProcessorBase(name)
, ParameterOwner(ParameterOwner::Type::OTHER)
Expand Down
Loading

0 comments on commit 2450618

Please sign in to comment.