Skip to content

Commit 3fa8abc

Browse files
authored
Merge pull request #383 from jsiegle/development
Restores spikes and event writing in Open Ephys format
2 parents fb245be + 8ee6ceb commit 3fa8abc

File tree

13 files changed

+216
-41
lines changed

13 files changed

+216
-41
lines changed

Plugins/IntanRecordingController/RHD2000Editor.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -737,6 +737,7 @@ void RHD2000Editor::handleAsyncUpdate()
737737
canvas->updateImpedance(impedanceData->streams, impedanceData->channels, impedanceData->magnitudes, impedanceData->phases);
738738
if (saveImpedances)
739739
{
740+
// this may not work with new Record Node architecture
740741
CoreServices::RecordNode::createNewrecordingDir();
741742

742743
String path(CoreServices::RecordNode::getRecordingPath().getFullPathName()

Source/Processors/MessageCenter/MessageCenter.cpp

Lines changed: 30 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -36,22 +36,36 @@ GenericProcessor("Message Center"), newEventAvailable(false), isRecording(false)
3636
0, // number of outputs
3737
44100.0, // sampleRate
3838
128); // blockSize
39+
40+
eventChannel = nullptr;
41+
3942
}
4043

4144
MessageCenter::~MessageCenter()
4245
{
4346

4447
}
4548

46-
void MessageCenter::addSpecialProcessorChannels(Array<EventChannel*>& channels)
49+
void MessageCenter::addSpecialProcessorChannels()
4750
{
48-
clearSettings();
49-
EventChannel* chan = new EventChannel(EventChannel::TEXT, 1, MAX_MSG_LENGTH, CoreServices::getGlobalSampleRate(), this, 0);
50-
chan->setName("GUI Messages");
51-
chan->setDescription("Messages from the GUI Message Center");
52-
channels.add(chan);
53-
eventChannelArray.add(new EventChannel(*chan));
54-
updateChannelIndexes();
51+
52+
if (eventChannel == nullptr)
53+
{
54+
55+
clearSettings();
56+
57+
eventChannel = new EventChannel(EventChannel::TEXT,
58+
1,
59+
MAX_MSG_LENGTH,
60+
CoreServices::getGlobalSampleRate(),
61+
this, 0);
62+
63+
eventChannel->setName("GUI Messages");
64+
eventChannel->setDescription("Messages from the GUI Message Center");
65+
eventChannelArray.add(new EventChannel(*eventChannel));
66+
67+
updateChannelIndexes();
68+
}
5569
}
5670

5771
AudioProcessorEditor* MessageCenter::createEditor()
@@ -63,6 +77,11 @@ AudioProcessorEditor* MessageCenter::createEditor()
6377

6478
}
6579

80+
const EventChannel* MessageCenter::getMessageChannel()
81+
{
82+
return getEventChannel(0);
83+
}
84+
6685
void MessageCenter::setParameter(int parameterIndex, float newValue)
6786
{
6887
if (isRecording)
@@ -114,8 +133,10 @@ void MessageCenter::process(AudioSampleBuffer& buffer)
114133
TextEventPtr event = TextEvent::createTextEvent(getEventChannel(0), CoreServices::getGlobalTimestamp(), eventString);
115134
addEvent(getEventChannel(0), event, 0);
116135

136+
std::cout << "Message Center added event." << std::endl;
137+
117138
newEventAvailable = false;
118139
}
119140

120141

121-
}
142+
}

Source/Processors/MessageCenter/MessageCenter.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,8 @@ class MessageCenter : public GenericProcessor
6161
/** A pointer to the Message Center editor. */
6262
ScopedPointer<MessageCenterEditor> messageCenterEditor;
6363

64+
const EventChannel* getMessageChannel();
65+
6466
bool enable() override;
6567
bool disable() override;
6668

@@ -75,13 +77,15 @@ class MessageCenter : public GenericProcessor
7577
needsToSendTimestampMessage = false;
7678
}
7779

78-
void addSpecialProcessorChannels(Array<EventChannel*>& channel);
80+
void addSpecialProcessorChannels();
7981
private:
8082

8183
bool newEventAvailable;
8284
bool isRecording;
8385
bool needsToSendTimestampMessage;
8486

87+
ScopedPointer<EventChannel> eventChannel;
88+
8589
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(MessageCenter);
8690

8791
};

Source/Processors/MessageCenter/MessageCenterEditor.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,8 @@ class MessageCenterEditor : public AudioProcessorEditor,
6464

6565
String getLabelString();
6666

67+
MessageCenter* messageCenter;
68+
6769
private:
6870

6971
void buttonClicked(Button* button);
@@ -85,8 +87,6 @@ class MessageCenterEditor : public AudioProcessorEditor,
8587
/** A JUCE button used to send messages. */
8688
ScopedPointer<Button> sendMessageButton;
8789

88-
MessageCenter* messageCenter;
89-
9090
Colour incomingBackground;
9191
Colour outgoingBackground;
9292

Source/Processors/ProcessorGraph/ProcessorGraph.cpp

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -346,6 +346,9 @@ void ProcessorGraph::updateConnections(Array<SignalChainTabButton*, CriticalSect
346346
//TODO: This is will be removed when probe based audio node added.
347347
connectProcessorToAudioNode(source);
348348

349+
//if (source->isRecordNode())
350+
// connectProcessorToMessageCenter(source);
351+
349352
// find the next dest that's not a merger or splitter
350353
GenericProcessor* prev = source;
351354

@@ -447,14 +450,16 @@ void ProcessorGraph::updateConnections(Array<SignalChainTabButton*, CriticalSect
447450
connectProcessors(conn.source, dest, conn.connectContinuous, conn.connectEvents);
448451
}
449452
}
453+
454+
//OwnedArray<EventChannel> extraChannels;
455+
getMessageCenter()->addSpecialProcessorChannels();
450456

451457
getAudioNode()->updatePlaybackBuffer();
452458

453-
Array<EventChannel*> extraChannels;
454-
getMessageCenter()->addSpecialProcessorChannels(extraChannels);
455-
459+
/*
456460
for (auto& recordNode : getRecordNodes())
457461
recordNode->addSpecialProcessorChannels(extraChannels);
462+
*/
458463

459464
} // end method
460465

@@ -553,6 +558,19 @@ void ProcessorGraph::connectProcessorToAudioNode(GenericProcessor* source)
553558

554559
}
555560

561+
562+
void ProcessorGraph::connectProcessorToMessageCenter(GenericProcessor* source)
563+
{
564+
565+
// connect event channel
566+
addConnection(getMessageCenter()->getNodeId(), // sourceNodeID
567+
midiChannelIndex, // sourceNodeChannelIndex
568+
source->getNodeId(), // destNodeID
569+
midiChannelIndex); // destNodeChannelIndex
570+
571+
}
572+
573+
556574
GenericProcessor* ProcessorGraph::createProcessorFromDescription(Array<var>& description)
557575
{
558576
GenericProcessor* processor = nullptr;

Source/Processors/ProcessorGraph/ProcessorGraph.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,7 @@ class ProcessorGraph : public AudioProcessorGraph
119119
void connectProcessors(GenericProcessor* source, GenericProcessor* dest,
120120
bool connectContinuous, bool connectEvents);
121121
void connectProcessorToAudioNode(GenericProcessor* source);
122+
void connectProcessorToMessageCenter(GenericProcessor* source);
122123

123124
int64 m_startSoftTimestamp{ 0 };
124125
const GenericProcessor* m_timestampSource{ nullptr };

Source/Processors/RecordNode/BinaryFormat/BinaryRecording.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -695,4 +695,4 @@ RecordEngineManager* BinaryRecording::getEngineManager()
695695
void BinaryRecording::setParameter(EngineParameter& parameter)
696696
{
697697
boolParameter(0, m_saveTTLWords);
698-
}
698+
}

Source/Processors/RecordNode/BinaryFormat/NpyFile.cpp

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,19 @@ bool NpyFile::openFile(String path)
7979
// output stream buffer size defaults to 32768 bytes, but is irrelevant because
8080
// each updateHeader() call triggers a m_file->flush() to disk:
8181
m_file = file.createOutputStream();
82+
83+
if (m_file == nullptr)
84+
{
85+
LOGD("FAILED to open file @", path);
86+
}
87+
else
88+
{
89+
String pad = "";
90+
for (int i = 0; i < 162 - path.length(); i++)
91+
pad += " ";
92+
LOGD("Successfully opened file @", path, pad, m_file);
93+
}
94+
8295
if (!m_file)
8396
return false;
8497

@@ -156,7 +169,8 @@ void NpyFile::writeHeader(const Array<NpyType>& typeList)
156169

157170
void NpyFile::updateHeader()
158171
{
159-
if (m_file != NULL)
172+
173+
if (true)
160174
{
161175
// overwrite the shape part of the header - even without explicitly calling
162176
// m_file->flush(), overwriting seems to trigger a flush to disk,

Source/Processors/RecordNode/OpenEphysFormat/OriginalRecording.cpp

Lines changed: 26 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ String OriginalRecording::getEngineID() const
6969

7070
void OriginalRecording::addSpikeElectrode(int index, const SpikeChannel* elec)
7171
{
72-
spikeFileArray.add(nullptr);
72+
//spikeFileArray.add(nullptr); // deprecated
7373
}
7474

7575
void OriginalRecording::resetChannels()
@@ -91,7 +91,7 @@ void OriginalRecording::openFiles(File rootFolder, int experimentNumber, int rec
9191
processorArray.clear();
9292
lastProcId = 0;
9393

94-
//openFile(rootFolder, getEventChannel(0), 0);
94+
openFile(rootFolder, getEventChannel(0), 0);
9595
openMessageFile(rootFolder);
9696

9797
int nChannels = getNumRecordedChannels();
@@ -103,10 +103,15 @@ void OriginalRecording::openFiles(File rootFolder, int experimentNumber, int rec
103103
blockIndex.add(0);
104104
samplesSinceLastTimestamp.add(0);
105105
}
106-
for (int i = 0; i < spikeFileArray.size(); i++)
106+
107+
int nSpikes = getNumRecordedSpikes();
108+
109+
for (int i = 0; i < nSpikes; i++)
107110
{
111+
spikeFileArray.add(nullptr);
108112
openSpikeFile(rootFolder, getSpikeChannel(i), i);
109113
}
114+
110115
}
111116

112117
void OriginalRecording::openFile(File rootFolder, const InfoObjectCommon* ch, int channelIndex)
@@ -214,11 +219,14 @@ void OriginalRecording::openSpikeFile(File rootFolder, const SpikeChannel* elec,
214219

215220
if (!fileExists)
216221
{
222+
217223
String header = generateSpikeHeader(elec);
218224
fwrite(header.toUTF8(), 1, header.getNumBytesAsUTF8(), spFile);
225+
std::cout << "Wrote header." << std::endl;
219226
}
220227
diskWriteLock.exit();
221228
spikeFileArray.set(channelIndex, spFile);
229+
std::cout << "Added file." << std::endl;
222230

223231
}
224232

@@ -257,8 +265,8 @@ String OriginalRecording::getFileName(int channelIndex)
257265
{
258266
String filename;
259267
const DataChannel* ch = getDataChannel(channelIndex);
260-
261-
filename += String(static_cast<int>(ch->getCurrentNodeID()));
268+
269+
filename += String(static_cast<int>(ch->getSourceNodeID()));
262270
filename += "_";
263271
if (renameFiles)
264272
filename += renamedPrefix + String(getDataChannel(channelIndex)->getCurrentNodeChannelIdx() + 1);
@@ -592,6 +600,7 @@ void OriginalRecording::closeFiles()
592600
}
593601
}
594602
fileArray.clear();
603+
595604
blockIndex.clear();
596605
samplesSinceLastTimestamp.clear();
597606
for (int i = 0; i < spikeFileArray.size(); i++)
@@ -630,12 +639,18 @@ void OriginalRecording::closeFiles()
630639

631640
void OriginalRecording::writeSpike(int electrodeIndex, const SpikeEvent* spike)
632641
{
642+
//std::cout << "Electrode index: " << electrodeIndex << std::endl;
643+
633644
if (spikeFileArray[electrodeIndex] == nullptr)
634645
return;
635646

647+
//std::cout << "Got spike" << std::endl;
648+
636649
HeapBlock<char> spikeBuffer;
637650
const SpikeChannel* channel = getSpikeChannel(electrodeIndex);
638651

652+
//std::cout << "Got spike channel" << std::endl;
653+
639654
int totalSamples = channel->getTotalSamples() * channel->getNumChannels();
640655
int numChannels = channel->getNumChannels();
641656
int chanSamples = channel->getTotalSamples();
@@ -658,6 +673,8 @@ void OriginalRecording::writeSpike(int electrodeIndex, const SpikeEvent* spike)
658673
zeromem(spikeBuffer.getData() + 32, 2 * sizeof(float));
659674
*reinterpret_cast<uint16*>(spikeBuffer.getData() + 40) = channel->getSampleRate();
660675

676+
//std::cout << "Allocated memory" << std::endl;
677+
661678
int ptrIdx = 0;
662679
uint16* dataIntPtr = reinterpret_cast<uint16*>(spikeBuffer.getData() + 42);
663680
const float* spikeDataPtr = spike->getDataPointer();
@@ -683,6 +700,8 @@ void OriginalRecording::writeSpike(int electrodeIndex, const SpikeEvent* spike)
683700
ptrIdx += sizeof(int16);
684701
}
685702

703+
//std::cout << "Starting disk write" << std::endl;
704+
686705
diskWriteLock.enter();
687706

688707
fwrite(spikeBuffer, 1, totalBytes, spikeFileArray[electrodeIndex]);
@@ -693,6 +712,8 @@ void OriginalRecording::writeSpike(int electrodeIndex, const SpikeEvent* spike)
693712
spikeFileArray[electrodeIndex]); // ptr to FILE object
694713

695714
diskWriteLock.exit();
715+
716+
//std::cout << "Wrote to file" << std::endl;
696717
}
697718

698719
void OriginalRecording::writeXml()

Source/Processors/RecordNode/RecordEngine.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ class PLUGIN_API RecordEngine
6565
/** All the public methods (except registerManager) are called by RecordNode or RecordingThread:
6666
When acquisition starts (in the specified order):
6767
1-resetChannels
68-
2-registerProcessor, addChannel, registerSpikeSource, addspikeelectrode
68+
2-registerProcessor, addChannel, registerSpikeSource, addSpikeElectrode
6969
3-configureEngine (which calls setParameter)
7070
3-startAcquisition
7171
When recording starts (in the specified order):

0 commit comments

Comments
 (0)