Skip to content

Commit 8491492

Browse files
committed
Save timestamps in kwd files (WIP)
1 parent 5e52715 commit 8491492

7 files changed

Lines changed: 95 additions & 30 deletions

File tree

Source/Plugins/KWIKFormat/RecordEngine/HDF5FileFormat.cpp

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,10 @@
4040
#define SPIKE_CHUNK_YSIZE 40
4141
#endif
4242

43+
#ifndef TIMESTAMP_CHUNK_SIZE
44+
#define TIMESTAMP_CHUNK_SIZE 4
45+
#endif
46+
4347
#define MAX_TRANSFORM_SIZE 512
4448

4549
#define MAX_STR_SIZE 256
@@ -675,13 +679,21 @@ void KWDFile::startNewRecording(int recordingNumber, int nChannels, HDF5Recordin
675679
CHECK_ERROR(createGroup(recordPath+"/application_data"));
676680
// CHECK_ERROR(setAttributeArray(F32,info->bitVolts.getRawDataPointer(),info->bitVolts.size(),recordPath+"/application_data",String("channel_bit_volts")));
677681
bitVoltsSet = createDataSet(F32, info->bitVolts.size(), 0, recordPath + "/application_data/channel_bit_volts");
678-
bitVoltsSet->writeDataBlock(info->bitVolts.size(), F32, info->bitVolts.getRawDataPointer());
682+
if (bitVoltsSet.get())
683+
bitVoltsSet->writeDataBlock(info->bitVolts.size(), F32, info->bitVolts.getRawDataPointer());
684+
else
685+
std::cerr << "Error creating bitvolts data set" << std::endl;
679686

680687
CHECK_ERROR(setAttribute(U8,&mSample,recordPath+"/application_data",String("is_multiSampleRate_data")));
681688
CHECK_ERROR(setAttributeArray(F32,info->channelSampleRates.getRawDataPointer(),info->channelSampleRates.size(),recordPath+"/application_data",String("channel_sample_rates")));
682689
recdata = createDataSet(I16,0,nChannels,CHUNK_XSIZE,recordPath+"/data");
683690
if (!recdata.get())
684691
std::cerr << "Error creating data set" << std::endl;
692+
693+
tsData = createDataSet(I64, 0, nChannels, TIMESTAMP_CHUNK_SIZE, recordPath + "/application_data/timestamps");
694+
if (!tsData.get())
695+
std::cerr << "Error creating timestamps data set" << std::endl;
696+
685697
curChan = nChannels;
686698
}
687699

@@ -694,6 +706,7 @@ void KWDFile::stopRecording()
694706
CHECK_ERROR(setAttributeArray(U32,samples.getRawDataPointer(),samples.size(),path,"valid_samples"));
695707
//ScopedPointer does the deletion and destructors the closings
696708
recdata = nullptr;
709+
tsData = nullptr;
697710
}
698711

699712
int KWDFile::createFileStructure()
@@ -728,6 +741,14 @@ void KWDFile::writeRowData(int16* data, int nSamples, int channel)
728741
}
729742
}
730743

744+
void KWDFile::writeTimestamps(int64* ts, int nTs, int channel)
745+
{
746+
if (channel >= 0 && channel < nChannels)
747+
{
748+
CHECK_ERROR(tsData->writeDataRow(channel, nTs, I64, ts));
749+
}
750+
}
751+
731752
//KWE File
732753

733754
KWEFile::KWEFile(String basename) : HDF5FileBase()

Source/Plugins/KWIKFormat/RecordEngine/HDF5FileFormat.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,7 @@ class KWDFile : public HDF5FileBase
128128
void writeBlockData(int16* data, int nSamples);
129129
void writeRowData(int16* data, int nSamples);
130130
void writeRowData(int16* data, int nSamples, int channel);
131+
void writeTimestamps(int64* ts, int nTs, int channel);
131132
String getFileName();
132133

133134
protected:
@@ -140,6 +141,7 @@ class KWDFile : public HDF5FileBase
140141
String filename;
141142
bool multiSample;
142143
ScopedPointer<HDF5RecordingData> recdata;
144+
ScopedPointer<HDF5RecordingData> tsData;
143145

144146
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(KWDFile);
145147
};

Source/Plugins/KWIKFormat/RecordEngine/HDF5Recording.cpp

Lines changed: 63 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@
2323

2424
#include "HDF5Recording.h"
2525
#define MAX_BUFFER_SIZE 10000
26+
#define CHANNEL_TIMESTAMP_PREALLOC_SIZE 16
27+
#define TIMESTAMP_EACH_NSAMPLES 1024
2628

2729
HDF5Recording::HDF5Recording() : processorIndex(-1), hasAcquired(false)
2830
{
@@ -37,7 +39,7 @@ HDF5Recording::~HDF5Recording()
3739
delete intBuffer;
3840
}
3941

40-
String HDF5Recording::getEngineID()
42+
String HDF5Recording::getEngineID() const
4143
{
4244
return "KWIK";
4345
}
@@ -73,6 +75,8 @@ void HDF5Recording::resetChannels()
7375
processorMap.clear();
7476
infoArray.clear();
7577
recordedChanToKWDChan.clear();
78+
channelLeftOverSamples.clear();
79+
channelTimestampArray.clear();
7680
if (spikesFile)
7781
spikesFile->resetChannels();
7882
}
@@ -129,31 +133,11 @@ void HDF5Recording::openFiles(File rootFolder, int experimentNumber, int recordi
129133
int procPos = processorRecPos[index];
130134
recordedChanToKWDChan.add(procPos);
131135
processorRecPos.set(index, procPos+1);
136+
channelTimestampArray.add(new Array<int64>);
137+
channelTimestampArray.getLast()->ensureStorageAllocated(CHANNEL_TIMESTAMP_PREALLOC_SIZE);
138+
channelLeftOverSamples.add(0);
132139
}
133-
#if 0
134-
for (int i = 0; i < processorMap.size(); i++)
135-
{
136-
int index = processorMap[i];
137-
if (getChannel(i)->getRecordState())
138-
{
139-
if (!fileArray[index]->isOpen())
140-
{
141-
fileArray[index]->initFile(getChannel(i)->nodeId,basepath);
142-
if (hasAcquired)
143-
infoArray[index]->start_time = (*timestamps)[getChannel(i)->sourceNodeId]; //the timestamps of the first channel
144-
else
145-
infoArray[index]->start_time = 0;
146-
}
147-
channelsPerProcessor.set(index, channelsPerProcessor[index] + 1);
148-
bitVoltsArray[index]->add(getChannel(i)->bitVolts);
149-
sampleRatesArray[index]->add(getChannel(i)->sampleRate);
150-
if (getChannel(i)->sampleRate != infoArray[index]->sample_rate)
151-
{
152-
infoArray[index]->multiSample = true;
153-
}
154-
}
155-
}
156-
#endif
140+
157141
for (int i = 0; i < fileArray.size(); i++)
158142
{
159143
if ((!fileArray[i]->isOpen()) && (fileArray[i]->isReadyToOpen()))
@@ -196,6 +180,18 @@ void HDF5Recording::closeFiles()
196180
}
197181
channelsPerProcessor.set(i, 0);
198182
}
183+
recordedChanToKWDChan.clear();
184+
channelTimestampArray.clear();
185+
channelLeftOverSamples.clear();
186+
}
187+
188+
void HDF5Recording::startChannelBlock()
189+
{
190+
int nCh = channelTimestampArray.size();
191+
for (int i = 0; i < nCh; ++i)
192+
{
193+
channelTimestampArray[i]->clearQuick();
194+
}
199195
}
200196

201197
void HDF5Recording::writeData(int writeChannel, int realChannel, const float* buffer, int size)
@@ -208,6 +204,48 @@ void HDF5Recording::writeData(int writeChannel, int realChannel, const float* bu
208204
fileArray[index]->writeRowData(intBuffer, size, recordedChanToKWDChan[writeChannel]);
209205
// int64 t2 = Time::getHighResolutionTicks();
210206
// std::cout << "record time: " << float(t2 - t1) / float(Time::getHighResolutionTicksPerSecond()) << std::endl;
207+
int64 sampleOffset = channelLeftOverSamples[writeChannel];
208+
if (writeChannel == 0)
209+
std::cout << "Write " << size << " off " << sampleOffset << " ts " << getTimestamp(realChannel) << " - ";
210+
if (sampleOffset + size >= TIMESTAMP_EACH_NSAMPLES)
211+
{
212+
int64 currentTimestamp = getTimestamp(realChannel);
213+
if (sampleOffset > 0)
214+
{
215+
currentTimestamp = getTimestamp(realChannel) + TIMESTAMP_EACH_NSAMPLES - sampleOffset;
216+
}
217+
218+
for (int samp = 0; samp < size; samp += TIMESTAMP_EACH_NSAMPLES)
219+
{
220+
if (writeChannel == 0)
221+
std::cout << "w: " << currentTimestamp << " ";
222+
channelTimestampArray[writeChannel]->add(currentTimestamp);
223+
currentTimestamp += TIMESTAMP_EACH_NSAMPLES;
224+
}
225+
226+
channelLeftOverSamples.set(writeChannel, (size + sampleOffset) % TIMESTAMP_EACH_NSAMPLES);
227+
}
228+
else
229+
{
230+
channelLeftOverSamples.set(writeChannel, sampleOffset + size);
231+
}
232+
if (writeChannel == 0)
233+
std::cout << std::endl;
234+
}
235+
236+
void HDF5Recording::endChannelBlock()
237+
{
238+
int nCh = channelTimestampArray.size();
239+
for (int ch = 0; ch < nCh; ++ch)
240+
{
241+
int tsSize = channelTimestampArray[ch]->size();
242+
if (tsSize > 0)
243+
{
244+
int realChan = getRealChannel(ch);
245+
int index = processorMap[getChannel(realChan)->recordIndex];
246+
fileArray[index]->writeTimestamps(channelTimestampArray[ch]->getRawDataPointer(), tsSize, ch);
247+
}
248+
}
211249
}
212250

213251
void HDF5Recording::writeEvent(int eventType, const MidiMessage& event, int64 timestamp)

Source/Plugins/KWIKFormat/RecordEngine/HDF5Recording.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ class HDF5Recording : public RecordEngine
3232
public:
3333
HDF5Recording();
3434
~HDF5Recording();
35-
String getEngineID();
35+
String getEngineID() const override;
3636
void openFiles(File rootFolder, int experimentNumber, int recordingNumber) override;
3737
void closeFiles() override;
3838
void writeData(int writeChannel, int realChannel, const float* buffer, int size) override;
@@ -43,6 +43,8 @@ class HDF5Recording : public RecordEngine
4343
void registerProcessor(const GenericProcessor* processor) override;
4444
void resetChannels() override;
4545
void startAcquisition() override;
46+
void startChannelBlock() override;
47+
void endChannelBlock() override;
4648

4749
static RecordEngineManager* getEngineManager();
4850
private:
@@ -54,6 +56,8 @@ class HDF5Recording : public RecordEngine
5456
Array<int> recordedChanToKWDChan;
5557
OwnedArray<Array<float>> bitVoltsArray;
5658
OwnedArray<Array<float>> sampleRatesArray;
59+
OwnedArray<Array<int64>> channelTimestampArray;
60+
Array<int> channelLeftOverSamples;
5761
OwnedArray<KWDFile> fileArray;
5862
OwnedArray<HDF5RecordingInfo> infoArray;
5963
ScopedPointer<KWEFile> eventFile;

Source/Processors/RecordNode/OriginalRecording.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ OriginalRecording::~OriginalRecording()
6262
delete recordMarker;*/
6363
}
6464

65-
String OriginalRecording::getEngineID()
65+
String OriginalRecording::getEngineID() const
6666
{
6767
return "OPENEPHYS";
6868
}

Source/Processors/RecordNode/OriginalRecording.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ class OriginalRecording : public RecordEngine
4545
~OriginalRecording();
4646

4747
void setParameter(EngineParameter& parameter);
48-
String getEngineID();
48+
String getEngineID() const override;
4949
void openFiles(File rootFolder, int experimentNumber, int recordingNumber) override;
5050
void closeFiles() override;
5151
void writeData(int writeChannel, int realChannel, const float* buffer, int size) override;

Source/Processors/RecordNode/RecordEngine.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ class PLUGIN_API RecordEngine
5959
public:
6060
RecordEngine();
6161
virtual ~RecordEngine();
62-
virtual String getEngineID() =0;
62+
virtual String getEngineID() const =0;
6363

6464
/** All the public methods (except registerManager) are called by RecordNode or RecordingThread:
6565
When acquisition starts (in the specified order):

0 commit comments

Comments
 (0)