diff --git a/Builds/VisualStudio2013/open-ephys.sln b/Builds/VisualStudio2013/open-ephys.sln index 59a9d10ba28a4b47817570df74b1433044daefbb..04e5ad8e940f5a2fd76f23d26080ccf301f4f1c9 100644 --- a/Builds/VisualStudio2013/open-ephys.sln +++ b/Builds/VisualStudio2013/open-ephys.sln @@ -1,6 +1,9 @@ -Microsoft Visual Studio Solution File, Format Version 11.00 +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Express 2013 for Windows Desktop +VisualStudioVersion = 12.0.21005.1 # Visual Studio 2013 -Project("{5A05F353-1D63-394C-DFB0-981BB2309002}") = "open-ephys", "open-ephys.vcxproj", "{9C924D66-7DEC-1AEF-B375-DB8666BFB909}" +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "open-ephys", "open-ephys.vcxproj", "{9C924D66-7DEC-1AEF-B375-DB8666BFB909}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution diff --git a/Source/Processors/Channel/Channel.cpp b/Source/Processors/Channel/Channel.cpp index e3a20afb7daffa9ce07d6e6c95a3353114d5f32b..dee6db3795fc79dd44c7fd20268591618f4d0e16 100644 --- a/Source/Processors/Channel/Channel.cpp +++ b/Source/Processors/Channel/Channel.cpp @@ -70,6 +70,7 @@ Channel::Channel(const Channel& ch) y = ch.y; z = ch.z; impedance = ch.impedance; + extraData = ch.extraData; setRecordState(false); } @@ -138,14 +139,8 @@ void Channel::createDefaultName() case EVENT_CHANNEL: name = String("EVENT"); break; - case SINGLE_ELECTRODE: - name = String("SE"); - break; - case STEREOTRODE: - name = String("ST"); - break; - case TETRODE: - name = String("TT"); + case ELECTRODE_CHANNEL: + name = String("ELEC"); break; case MESSAGE_CHANNEL: name = String("MSG"); @@ -153,3 +148,17 @@ void Channel::createDefaultName() name += index; } + +bool Channel::getRecordState() +{ + return isRecording; +} + +ChannelExtraData::ChannelExtraData(void* ptr, int size) + : dataPtr(ptr), dataSize(size) +{ +} + +ChannelExtraData::~ChannelExtraData() +{ +} \ No newline at end of file diff --git a/Source/Processors/Channel/Channel.h b/Source/Processors/Channel/Channel.h index af53777607ddace822aa8a1ca8780e7e851a35ec..f7dceb166c84c2ba93e85ebf36cba11e7ca1a201 100644 --- a/Source/Processors/Channel/Channel.h +++ b/Source/Processors/Channel/Channel.h @@ -32,6 +32,7 @@ #include <stdio.h> class GenericProcessor; +class ChannelExtraData; /** @@ -87,10 +88,7 @@ public: void setRecordState(bool t); // {isRecording = t;} /** Sets whether or not the channel will record. */ - bool getRecordState() - { - return isRecording; - } + bool getRecordState(); /** Sets the bitVolts value for this channel. */ void setBitVolts(float bitVolts); @@ -154,6 +152,8 @@ public: /** Impedance of this channel. */ float impedance; + /** For use with special event channels. */ + ReferenceCountedObjectPtr<ChannelExtraData> extraData; private: @@ -167,4 +167,13 @@ private: }; +class ChannelExtraData : public ReferenceCountedObject +{ +public: + ChannelExtraData(void* data, int size); + virtual ~ChannelExtraData(); + void* const dataPtr; + const int dataSize; +}; + #endif // __CHANNEL_H_DABDFE3F__ diff --git a/Source/Processors/Editors/PeriStimulusTimeHistogramEditor.cpp b/Source/Processors/Editors/PeriStimulusTimeHistogramEditor.cpp index 95d1ec5e052765802a066bd7063500fc471379af..db90e2bb8761cece31a49db9ed1898debb5c39f7 100644 --- a/Source/Processors/Editors/PeriStimulusTimeHistogramEditor.cpp +++ b/Source/Processors/Editors/PeriStimulusTimeHistogramEditor.cpp @@ -278,12 +278,12 @@ void PeriStimulusTimeHistogramEditor::buttonEvent(Button* button) PopupMenu m; - m.addItem(1,"TTL",true, processor->saveTTLs); + /* m.addItem(1,"TTL",true, processor->saveTTLs); m.addItem(2,"Network Events",true, processor->saveNetworkEvents); m.addItem(7,"Network Events [when recording is off]",true, processor->saveNetworkEventsWhenNotRecording); - m.addItem(3,"Eye Tracking",true, processor->saveEyeTracking); + m.addItem(3,"Eye Tracking",true, processor->saveEyeTracking);*/ - m.addItem(4,"Sorted Spikes: TS only ",true, processor->spikeSavingMode == 1); + //m.addItem(4,"Sorted Spikes: TS only ",true, processor->spikeSavingMode == 1); m.addItem(5,"Sorted Spikes: TS+waveform",true, processor->spikeSavingMode == 2); m.addItem(6,"All Spikes: TS+waveform",true, processor->spikeSavingMode == 3); diff --git a/Source/Processors/GenericProcessor/GenericProcessor.h b/Source/Processors/GenericProcessor/GenericProcessor.h index 32059caf80c5ea182793fb2c1b704c0e2037e919..1135db44a1b6573be25ff1d671552b23212aa28f 100755 --- a/Source/Processors/GenericProcessor/GenericProcessor.h +++ b/Source/Processors/GenericProcessor/GenericProcessor.h @@ -25,7 +25,7 @@ #define __GENERICPROCESSOR_H_1F469DAF__ enum ChannelType {HEADSTAGE_CHANNEL = 0, AUX_CHANNEL = 1, ADC_CHANNEL = 2, EVENT_CHANNEL = 3, - SINGLE_ELECTRODE = 4, STEREOTRODE = 5, TETRODE = 6, MESSAGE_CHANNEL = 7 + ELECTRODE_CHANNEL = 4, MESSAGE_CHANNEL = 5 }; #include "../../../JuceLibraryCode/JuceHeader.h" diff --git a/Source/Processors/PSTH/PeriStimulusTimeHistogramNode.cpp b/Source/Processors/PSTH/PeriStimulusTimeHistogramNode.cpp index 3aa78eb1f00041fb0f5d7c618082e53eca96e898..31dc71c595b7e710466b53517e4f0879903dcb51 100644 --- a/Source/Processors/PSTH/PeriStimulusTimeHistogramNode.cpp +++ b/Source/Processors/PSTH/PeriStimulusTimeHistogramNode.cpp @@ -37,7 +37,6 @@ PeriStimulusTimeHistogramNode::PeriStimulusTimeHistogramNode() : GenericProcessor("PSTH"), displayBufferSize(5), redrawRequested(false) { trialCircularBuffer = nullptr; - eventFile = nullptr; isRecording = false; saveEyeTracking = saveTTLs = saveNetworkEvents = false; saveNetworkEventsWhenNotRecording = false; @@ -114,13 +113,19 @@ void PeriStimulusTimeHistogramNode::allocateTrialCircularBuffer() void PeriStimulusTimeHistogramNode::updateSettings() { - delete trialCircularBuffer; trialCircularBuffer = nullptr; if (trialCircularBuffer == nullptr && getSampleRate() > 0 && getNumInputs() > 0) { allocateTrialCircularBuffer(); syncInternalDataStructuresWithSpikeSorter(); } + electrodeChannels.clear(); + for (int k = 0; k < eventChannels.size(); k++) + { + if ((eventChannels[k]->type == ELECTRODE_CHANNEL) && + (static_cast<SpikeChannel*>(eventChannels[k]->extraData.get())->dataType == SpikeChannel::Sorted)) + electrodeChannels.add(eventChannels[k]); + } recordNode = getProcessorGraph()->getRecordNode(); // diskWriteLock = recordNode->getLock(); @@ -137,6 +142,16 @@ bool PeriStimulusTimeHistogramNode::enable() std::cout << "PeriStimulusTimeHistogramNode::enable()" << std::endl; PeriStimulusTimeHistogramEditor* editor = (PeriStimulusTimeHistogramEditor*) getEditor(); editor->enable(); + + recordNode->registerSpikeSource(this); + for (int i = 0; i < electrodeChannels.size(); i++) + { + SpikeRecordInfo *recElec = new SpikeRecordInfo(); + recElec->name = electrodeChannels[i]->name; + recElec->numChannels = static_cast<SpikeChannel*>(electrodeChannels[i]->extraData.get())->numChannels; + recElec->sampleRate = settings.sampleRate; + electrodeChannels[i]->recordIndex = recordNode->addSpikeElectrode(recElec); + } return true; @@ -186,186 +201,22 @@ void PeriStimulusTimeHistogramNode::process(AudioSampleBuffer& buffer, MidiBuffe -void PeriStimulusTimeHistogramNode::dumpStartStopRecordEventToDisk(int64 ts, bool startRecord) -{ - const ScopedLock myScopedLock(diskWriteLock); - #define SESSION 10 - uint8 eventType = SESSION; - - // write event type - fwrite(&eventType, 1,1, eventFile); - // write event size - int16 eventSize = 1 +2+ 8; // start/stop(1) + recordnumber (2) + timestamp (8) - fwrite(&eventSize, 2,1, eventFile); - // write event data - // 1. Start/stop - fwrite(&startRecord, 1,1, eventFile); - // 2. record number - fwrite(&recordingNumber, 2,1, eventFile); - // 3. the software timestamp - fwrite(&ts, 8,1, eventFile); - - -} - -void PeriStimulusTimeHistogramNode::dumpNetworkEventToDisk(String S, int64 ts) -{ - const ScopedLock myScopedLock(diskWriteLock); - - uint8 eventType = NETWORK; - - // write event type - fwrite(&eventType, 1,1, eventFile); - // write event size - int16 eventSize = S.getNumBytesAsUTF8() + 8; // string length + timestamp - fwrite(&eventSize, 2,1, eventFile); - // write event data - // 1. the network event string - fwrite(S.toUTF8(), S.getNumBytesAsUTF8(), 1, eventFile); - // 2. the software timestamp - fwrite(&ts, 8,1, eventFile); - - -} - -void PeriStimulusTimeHistogramNode::dumpSpikeEventToDisk(SpikeObject *s, bool dumpWave) -{ - const ScopedLock myScopedLock(diskWriteLock); - - - - uint8 eventType = SPIKE; - - // write event type - fwrite(&eventType, 1,1, eventFile); - int16 eventSize = 8+8+2+2+2+2+2 + s->nChannels*4; // ts, ts, sorted id, electrode ID, num channels, num data per channel + 4x gains - - if (dumpWave) - eventSize += 2*(s->nSamples*s->nChannels); // uint16 per samples - - // write event size - fwrite(&eventSize, 2,1, eventFile); - - // write event data - // 1. software ts - fwrite(&s->timestamp_software, 8,1, eventFile); - // 2. hardware ts - fwrite(&s->timestamp, 8,1, eventFile); - // 3. sorted ID - fwrite(&s->sortedId, 2,1, eventFile); - // 4. electrod ID - fwrite(&s->electrodeID, 2,1, eventFile); - - // 5. Channel in which threshold was detected - fwrite(&s->channel, 2,1, eventFile); - - // 6. num channels - fwrite(&s->nChannels, 2,1, eventFile); - - // 7. gains - fwrite(&s->gain, 4,s->nChannels, eventFile); - - // 8. num data points per channel - fwrite(&s->nSamples, 2,1, eventFile); - if (dumpWave) - fwrite(&s->data, 2,s->nSamples*s->nChannels, eventFile); - - -} -void PeriStimulusTimeHistogramNode::dumpTTLeventToDisk(int channel, bool risingEdge, int64 ttl_timestamp_software, int64 ttl_timestamp_hardware, int samplePosition ) -{ - const ScopedLock myScopedLock(diskWriteLock); - uint8 eventType = TTL; - - // write event type - fwrite(&eventType, 1,1, eventFile); - // write event size - int16 eventSize = 1 + 2 + 8 + 8; // rising/falling(1) + software ts (8) + hardware ts (8) - fwrite(&eventSize, 2,1, eventFile); - // write event data - // 1. rising/falling edge - fwrite(&risingEdge, 1, 1, eventFile); - // 2. channel - fwrite(&channel, 2,1,eventFile); - // 2. software ts - fwrite(&ttl_timestamp_software, 8,1, eventFile); - // 3. hardware ts - fwrite(&ttl_timestamp_hardware, 8,1, eventFile); - - -} -/* -void PeriStimulusTimeHistogramNode::dumpEyeTrackingEventToDisk(EyePosition pos) -{ - diskWriteLock->enter(); - - uint8 eventType = EYE_POSITION; - - // write event type - fwrite(&eventType, 1,1, eventFile); - // write event size - int16 eventSize = 8 + 8 + 8 + 8 + 8 +8 +8; // x,y,xc,yc,pupil,timestamp - fwrite(&eventSize, 2,1, eventFile); - // write event data - // 1. eye x position - fwrite(&pos.x, 8,1, eventFile); - // 2. eye y position - fwrite(&pos.y, 8,1, eventFile); - - - // 3. calibrated eye x position - fwrite(&pos.xc, 8,1, eventFile); - // 4. calibrated eye y position - fwrite(&pos.yc, 8,1, eventFile); - - // 5. eye pupil - fwrite(&pos.pupil, 8,1, eventFile); - // 6. software timestamp - fwrite(&pos.software_timestamp, 8,1, eventFile); - // 7. hardware timestamp - fwrite(&pos.hardware_timestamp, 8,1, eventFile); - - diskWriteLock->exit(); -} -*/ -void PeriStimulusTimeHistogramNode::dumpTimestampEventToDisk(int64 softwareTS,int64 hardwareTS) -{ - const ScopedLock myScopedLock(diskWriteLock); - - uint8 eventType = TIMESTAMP; - - // write event type - fwrite(&eventType, 1,1, eventFile); - // write event size - int16 eventSize = 8 + 8; // software ts (8) + hardware ts (8) - fwrite(&eventSize, 2,1, eventFile); - // write event data - // 1. software ts - fwrite(&softwareTS, 8,1, eventFile); - // 2. hardware ts - fwrite(&hardwareTS, 8,1, eventFile); - - - -} - void PeriStimulusTimeHistogramNode::syncInternalDataStructuresWithSpikeSorter() { - ProcessorGraph *g = getProcessorGraph(); - Array<GenericProcessor*> p = g->getListOfProcessors(); - for (int k=0;k<p.size();k++) + Array<Electrode*> electrodes; + + for (int k=0;k<eventChannels.size();k++) { - if (p[k]->getName() == "Spike Sorter") + if ((eventChannels[k]->type == ELECTRODE_CHANNEL) && + ( static_cast<SpikeChannel*>(eventChannels[k]->extraData.get())->dataType == SpikeChannel::Sorted )) { - SpikeSorter *node = (SpikeSorter*)p[k]; - Array<Electrode*> electrodes = node->getElectrodes(); - - // for each electrode, verify that - // 1. We have it in our internal structure - // 2. All channels match - // 3. We have all sorted unit information - trialCircularBuffer->syncInternalDataStructuresWithSpikeSorter(electrodes); + electrodes.add(static_cast<Electrode*>(eventChannels[k]->extraData->dataPtr)); } + // for each electrode, verify that + // 1. We have it in our internal structure + // 2. All channels match + // 3. We have all sorted unit information + trialCircularBuffer->syncInternalDataStructuresWithSpikeSorter(electrodes); } } @@ -388,7 +239,6 @@ void PeriStimulusTimeHistogramNode::modifyTimeRange(double preSec_, double postS TrialCircularBufferParams params = trialCircularBuffer->getParams(); params.preSec = preSec_; params.postSec = postSec_; - delete trialCircularBuffer; trialCircularBuffer = new TrialCircularBuffer(params); trialCircularBuffer->syncInternalDataStructuresWithSpikeSorter(electrodes); @@ -404,13 +254,13 @@ void PeriStimulusTimeHistogramNode::handleNetworkMessage(StringTS s) ed->updateCanvas(); } - if (isRecording && saveNetworkEvents) + /* if (isRecording && saveNetworkEvents) { dumpNetworkEventToDisk(s.getString(),s.timestamp); } else if (!isRecording && saveNetworkEvents && saveNetworkEventsWhenNotRecording) { networkEventsHistory.push(s); - } + }*/ } void PeriStimulusTimeHistogramNode::handleEvent(int eventType, MidiMessage& event, int samplePosition) @@ -449,7 +299,7 @@ void PeriStimulusTimeHistogramNode::handleEvent(int eventType, MidiMessage& even memcpy(&hardware_timestamp, dataptr + 4, 8); // remember to skip first four bytes memcpy(&software_timestamp, dataptr + 12, 8); // remember to skip first four bytes - if (isRecording) + /* if (isRecording) { if (syncCounter == 0) { @@ -462,7 +312,7 @@ void PeriStimulusTimeHistogramNode::handleEvent(int eventType, MidiMessage& even syncCounter++; if (syncCounter > 10) syncCounter = 0; - } + }*/ } if (eventType == TTL) @@ -479,8 +329,7 @@ void PeriStimulusTimeHistogramNode::handleEvent(int eventType, MidiMessage& even //memcpy(&ttl_timestamp_hardware, dataptr+12, 8); if (ttl_raise) trialCircularBuffer->addTTLevent(channel,ttl_timestamp_software,ttl_timestamp_hardware, ttl_raise, true); - if (isRecording && saveTTLs) - dumpTTLeventToDisk(channel,ttl_raise,ttl_timestamp_software,ttl_timestamp_hardware,samplePosition ); + } if (eventType == SPIKE) @@ -497,12 +346,15 @@ void PeriStimulusTimeHistogramNode::handleEvent(int eventType, MidiMessage& even } if (isRecording) { - if (spikeSavingMode == 1 && newSpike.sortedId > 0) - dumpSpikeEventToDisk(&newSpike, false); + if (spikeSavingMode == 1 && newSpike.sortedId > 0) + recordNode->writeSpike(newSpike, electrodeChannels[newSpike.source]->recordIndex); + //dumpSpikeEventToDisk(&newSpike, false); else if (spikeSavingMode == 2 && newSpike.sortedId > 0) - dumpSpikeEventToDisk(&newSpike, true); + recordNode->writeSpike(newSpike, electrodeChannels[newSpike.source]->recordIndex); + //dumpSpikeEventToDisk(&newSpike, true); else if (spikeSavingMode == 3) - dumpSpikeEventToDisk(&newSpike, true); + recordNode->writeSpike(newSpike, electrodeChannels[newSpike.source]->recordIndex); + //dumpSpikeEventToDisk(&newSpike, true); } } } @@ -510,136 +362,12 @@ void PeriStimulusTimeHistogramNode::handleEvent(int eventType, MidiMessage& even } - - -String PeriStimulusTimeHistogramNode::generateHeader() -{ - - String header = "header.format = 'Open Ephys Data Format'; \n"; - header += "header.version = 0.32;"; - header += "header.header_bytes = "; - header += String(HEADER_SIZE); - header += ";\n"; - header += "header.description = 'each record is size-varying. First is the record size (16-bit), followed by record type (uint8), followed by the actual data (which vary, depending on the type) '; \n"; - header += "header.date_created = '"; - header += recordNode->generateDateString(); - header += "';\n"; - header += "header.channel = '"; - header += "events"; - header += "';\n"; - header += "header.channelType = 'Event';\n"; - header += "header.sampleRate = "; - // all channels need to have the same sample rate under the current scheme - header += String(getSampleRate()); - header += ";\n"; - header += "header.blockLength = "; - header += BLOCK_LENGTH; - header += ";\n"; - header += "header.bufferSize = "; - header += getAudioComponent()->getBufferSize(); - header += ";\n"; - header += "header.bitVolts = "; - if (recordNode->channels.size() > 0) - { - header += String(recordNode->channels[0]->bitVolts); - } - else - { - header += String(getDefaultBitVolts()); - } - - header += ";\n"; - - Time t; - header += "header.ticksPerSec = "; - header += String(t.getHighResolutionTicksPerSecond()); - header += ";\n"; - - header = header.paddedRight(' ', HEADER_SIZE); - return header; - -} - - - -void PeriStimulusTimeHistogramNode::openFile(String filename) -{ - std::cout << "OPENING FILE: " << filename << std::endl; - - File f = File(filename); - - bool fileExists = f.exists(); - - const ScopedLock myScopedLock(diskWriteLock); - - eventFile = fopen(filename.toUTF8(), "ab"); - - if (!fileExists) - { - // create and write header - std::cout << "Writing header." << std::endl; - String header = generateHeader(); - int headerSize = header.getNumBytesAsUTF8(); - std::cout << "File ID: " << eventFile << ", number of bytes: " << headerSize << std::endl; - fwrite(header.toUTF8(), header.getNumBytesAsUTF8(), 1, eventFile); - std::cout << "Wrote header." << std::endl; - } - else - { - std::cout << "File already exists, just opening." << std::endl; - } - -} - - void PeriStimulusTimeHistogramNode::startRecording() { - if (!isRecording) - { - File dataDirectory = recordNode->getDataDirectory(); - - if (dataDirectory.getFullPathName().length() == 0) - { - // temporary fix in case nothing is returned by the record node. - dataDirectory = File::getSpecialLocation(File::userHomeDirectory); - } - - String baseDirectory = dataDirectory.getFullPathName(); - String eventChannelFilename = baseDirectory + dataDirectory.separatorString + "all_channels.events"; - openFile(eventChannelFilename); - - // dump network events that arrived when we weren't recording - if (saveNetworkEventsWhenNotRecording) - { - while (networkEventsHistory.size() > 0) - { - StringTS s = networkEventsHistory.front(); - dumpNetworkEventToDisk(s.getString(),s.timestamp); - networkEventsHistory.pop(); - } - } - -// recordingNumber = recordNode->getRecordingNumber(); - Time t; - dumpStartStopRecordEventToDisk(t.getHighResolutionTicks(), true); - isRecording = true; - - } - - + isRecording = true; } void PeriStimulusTimeHistogramNode::stopRecording() { - if (isRecording) - { - // close files, etc. - const ScopedLock myScopedLock(diskWriteLock); - std::cout << "CLOSING EVENT FILE: " << std::endl; - if (eventFile != nullptr) - fclose(eventFile); - - - isRecording = false; - } -} + isRecording = false; +} \ No newline at end of file diff --git a/Source/Processors/PSTH/PeriStimulusTimeHistogramNode.h b/Source/Processors/PSTH/PeriStimulusTimeHistogramNode.h index f5c3fdc8e46517fd0077bd781e5f57e0b3afdc82..5a54dbe9be89180feb57e5b7145c7b43f7828923 100644 --- a/Source/Processors/PSTH/PeriStimulusTimeHistogramNode.h +++ b/Source/Processors/PSTH/PeriStimulusTimeHistogramNode.h @@ -80,7 +80,7 @@ public: void loadCustomParametersFromXml(); void modifyTimeRange(double preSec_, double postSec_); - TrialCircularBuffer *trialCircularBuffer; + ScopedPointer<TrialCircularBuffer> trialCircularBuffer; bool saveTTLs, saveNetworkEvents,saveEyeTracking ; int spikeSavingMode; bool saveNetworkEventsWhenNotRecording; @@ -90,17 +90,6 @@ public: void handleNetworkMessage(StringTS s); private: - FILE* eventFile; - String generateHeader(); - void openFile(String filename); - - void dumpNetworkEventToDisk(String S, int64 ts); - void dumpSpikeEventToDisk(SpikeObject *s, bool dumpWave); - void dumpTimestampEventToDisk(int64 softwareTS,int64 hardwareTS); - void dumpTTLeventToDisk(int channel,bool risingEdge, int64 ttl_timestamp_software, int64 ttl_timestamp_hardware, int samplePosition ); - void dumpStartStopRecordEventToDisk(int64 ts, bool startRecord); -// void dumpEyeTrackingEventToDisk(EyePosition pos); - bool isRecording; int displayBufferSize; bool redrawRequested; @@ -109,8 +98,9 @@ private: std::queue<StringTS> networkEventsHistory; RecordNode* recordNode; - uint16 recordingNumber; +// uint16 recordingNumber; CriticalSection diskWriteLock; + Array<Channel*> electrodeChannels; JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(PeriStimulusTimeHistogramNode); diff --git a/Source/Processors/SpikeDetector/SpikeDetector.cpp b/Source/Processors/SpikeDetector/SpikeDetector.cpp index bc53a8b64a8f9ff558ba1b14de3f3f69e396f1e2..c51bbc4dccc531794c8a84b3fbcf5b93cc8bd8c5 100755 --- a/Source/Processors/SpikeDetector/SpikeDetector.cpp +++ b/Source/Processors/SpikeDetector/SpikeDetector.cpp @@ -88,21 +88,10 @@ void SpikeDetector::updateSettings() for (int i = 0; i < electrodes.size(); i++) { - Channel* ch; - - switch (electrodes[i]->numChannels) - { - case 1: - ch = new Channel(this, i, SINGLE_ELECTRODE); - break; - case 2: - ch = new Channel(this, i, STEREOTRODE); - break; - case 4: - ch = new Channel(this, i, TETRODE); - break; - } - + Channel* ch = new Channel(this,i,ELECTRODE_CHANNEL); + ch->name = generateSpikeElectrodeName(electrodes[i]->numChannels, ch->index); + SpikeChannel* spk = new SpikeChannel(SpikeChannel::Plain, electrodes[i]->numChannels, NULL, 0); + ch->extraData = spk; eventChannels.add(ch); } diff --git a/Source/Processors/SpikeDisplayNode/SpikeDisplayNode.cpp b/Source/Processors/SpikeDisplayNode/SpikeDisplayNode.cpp index fa1c2f702f5173f36be76fe578f0b6290e78d9c1..7b0253be6e2a5a606e506f0dd098103ef350336b 100755 --- a/Source/Processors/SpikeDisplayNode/SpikeDisplayNode.cpp +++ b/Source/Processors/SpikeDisplayNode/SpikeDisplayNode.cpp @@ -60,24 +60,12 @@ void SpikeDisplayNode::updateSettings() { ChannelType type = eventChannels[i]->getType(); - if (type == SINGLE_ELECTRODE || type == STEREOTRODE || type == TETRODE) + if (type == ELECTRODE_CHANNEL) { Electrode elec; + elec.numChannels = static_cast<SpikeChannel*>(eventChannels[i]->extraData.get())->numChannels; - switch (type) - { - case SINGLE_ELECTRODE: - elec.numChannels = 1; - break; - case STEREOTRODE: - elec.numChannels = 2; - break; - case TETRODE: - elec.numChannels = 4; - break; - } - elec.name = eventChannels[i]->getName(); elec.currentSpikeIndex = 0; elec.mostRecentSpikes.ensureStorageAllocated(displayBufferSize); diff --git a/Source/Processors/SpikeSorter/SpikeSorter.cpp b/Source/Processors/SpikeSorter/SpikeSorter.cpp index 0eab93df0bbb9bc089fd0b6bcb3a8f36c6150a85..58b284e79e56e66dbba1947538095cd498a0a19b 100644 --- a/Source/Processors/SpikeSorter/SpikeSorter.cpp +++ b/Source/Processors/SpikeSorter/SpikeSorter.cpp @@ -192,20 +192,10 @@ void SpikeSorter::updateSettings() for (int i = 0; i < electrodes.size(); i++) { - Channel* ch; - - switch (electrodes[i]->numChannels) - { - case 1: - ch = new Channel(this, i, SINGLE_ELECTRODE); - break; - case 2: - ch = new Channel(this, i, STEREOTRODE); - break; - case 4: - ch = new Channel(this, i, TETRODE); - break; - } + Channel* ch = new Channel(this,i,ELECTRODE_CHANNEL); + ch->name = generateSpikeElectrodeName(electrodes[i]->numChannels, ch->index); + SpikeChannel* spk = new SpikeChannel(SpikeChannel::Sorted, electrodes[i]->numChannels, electrodes[i], sizeof(Electrode)); + ch->extraData = spk; eventChannels.add(ch); } diff --git a/Source/Processors/Visualization/SpikeObject.cpp b/Source/Processors/Visualization/SpikeObject.cpp index 702b9cc53a4b1754aa331bfe3420261ed66e93b8..ce61eb9ba80c350afa20e0a361843fdb26d9fd09 100755 --- a/Source/Processors/Visualization/SpikeObject.cpp +++ b/Source/Processors/Visualization/SpikeObject.cpp @@ -400,3 +400,28 @@ int microSecondsToSpikeTimeBin(SpikeObject *s, float t, int ch) } +SpikeChannel::SpikeChannel(SpikeDataType type, int nChans, void* ptr, int size) + : dataType(type), numChannels(nChans), ChannelExtraData(ptr, size) +{ +} + +String generateSpikeElectrodeName(int numChannels, int index) +{ + String name; + switch (numChannels) + { + case 1: + name = String("SE"); + break; + case 2: + name = String("ST"); + break; + case 4: + name = String("TT"); + break; + default: + name = String("ELEC"); + break; + } + return name + String(index); +} \ No newline at end of file diff --git a/Source/Processors/Visualization/SpikeObject.h b/Source/Processors/Visualization/SpikeObject.h index a386ee0ef097f0c557f559a68b3a2eb64dac16a6..c3a06c0736c2e3e50c2f8808dadd4dc81a72ef38 100755 --- a/Source/Processors/Visualization/SpikeObject.h +++ b/Source/Processors/Visualization/SpikeObject.h @@ -29,6 +29,8 @@ #include <stdint.h> #include <math.h> +#include "../Channel/Channel.h" + #define SPIKE_METADATA_SIZE 42 #define MAX_NUMBER_OF_SPIKE_CHANNELS 4 #define MAX_NUMBER_OF_SPIKE_CHANNEL_SAMPLES 80 @@ -37,6 +39,21 @@ #define MAX_SPIKE_BUFFER_LEN 512 // max length of spike buffer in bytes // the true max calculated from the spike values below is actually 507 +/** Class to store spike data in event channels */ +class SpikeChannel : public ChannelExtraData +{ +public: + enum SpikeDataType { Plain = 0, Sorted = 1}; + + SpikeChannel(SpikeDataType type, int nChans, void* ptr, int size); + + const SpikeDataType dataType; + const int numChannels; +}; + +/** Simple generic function to name spike electrode channels */ +String generateSpikeElectrodeName(int numChannels, int index); + #define SPIKE_BASE_CODE 100 /**