diff --git a/xdf.cpp b/xdf.cpp
index 1891640..2ada86e 100644
--- a/xdf.cpp
+++ b/xdf.cpp
@@ -12,7 +12,7 @@
//GNU General Public License for more details.
//You should have received a copy of the GNU General Public License
-//along with this program. If not, see .
+//along with this program. If not, see .
//If you have questions, contact author at yida.lin@outlook.com
@@ -20,7 +20,7 @@
#include
#include
-#include //pugi XML parser
+#include "pugixml.hpp" //pugi XML parser
#include
#include
#include "smarc/smarc.h" //resampling library
@@ -28,6 +28,7 @@
#include //std::accumulate
#include // bind2nd
#include
+#include
Xdf::Xdf()
{
@@ -40,14 +41,14 @@ int Xdf::load_xdf(std::string filename)
/* //uncompress if necessary
- char ext[_MAX_EXT]; //for file extension
+ char ext[_MAX_EXT]; //for file extension
- _splitpath_s ( argv[1], NULL, NULL, NULL, NULL, NULL, NULL, ext, NULL );
- if (strcmp(ext, ".xdfz") == 0)
- {
- //uncompress
- }
- */
+ _splitpath_s ( argv[1], NULL, NULL, NULL, NULL, NULL, NULL, ext, NULL );
+ if (strcmp(ext, ".xdfz") == 0)
+ {
+ //uncompress
+ }
+ */
std::vector idmap; //remaps stream id's onto indices in streams
@@ -79,254 +80,110 @@ int Xdf::load_xdf(std::string filename)
//for each chunk
while (1)
{
- uint64_t ChLen = readLength(file);//chunk length
+ uint64_t ChLen = readLength(file); //chunk length
if (ChLen == 0)
break;
- uint16_t tag; //read tag of the chunk, 6 possibilities
+ uint16_t tag; //read tag of the chunk, 6 possibilities
readBin(file, &tag);
switch (tag)
{
case 1: //[FileHeader]
- {
- char* buffer = new char[ChLen - 2];
- file.read(buffer, ChLen - 2);
- fileHeader = buffer;
+ {
+ char* buffer = new char[ChLen - 2];
+ file.read(buffer, ChLen - 2);
+ fileHeader = buffer;
- pugi::xml_document doc;
+ pugi::xml_document doc;
- doc.load_buffer_inplace(buffer, ChLen - 2);
+ doc.load_buffer_inplace(buffer, ChLen - 2);
- pugi::xml_node info = doc.child("info");
+ pugi::xml_node info = doc.child("info");
- version = info.child("version").text().as_float();
+ version = info.child("version").text().as_float();
- delete[] buffer;
- }
+ delete[] buffer;
+ }
break;
case 2: //read [StreamHeader] chunk
- {
- //read [StreamID]
- uint32_t streamID;
- int index;
- Xdf::readBin(file, &streamID);
- std::vector::iterator it {std::find(idmap.begin(),idmap.end(),streamID)};
- if (it == idmap.end())
{
- index = idmap.size();
- idmap.emplace_back(streamID);
- streams.emplace_back();
- }
- else
- index = std::distance(idmap.begin(), it);
+ //read [StreamID]
+ uint32_t streamID;
+ int index;
+ Xdf::readBin(file, &streamID);
+ std::vector::iterator it{std::find(idmap.begin(), idmap.end(), streamID)};
+ if (it == idmap.end())
+ {
+ index = idmap.size();
+ idmap.emplace_back(streamID);
+ streams.emplace_back();
+ }
+ else
+ index = std::distance(idmap.begin(), it);
- pugi::xml_document doc;
+ pugi::xml_document doc;
- //read [Content]
- char* buffer = new char[ChLen - 6];
- file.read(buffer, ChLen - 6);
- streams[index].streamHeader = buffer;
+ //read [Content]
+ char* buffer = new char[ChLen - 6];
+ file.read(buffer, ChLen - 6);
+ streams[index].streamHeader = buffer;
- doc.load_buffer_inplace(buffer, ChLen - 6);
+ doc.load_buffer_inplace(buffer, ChLen - 6);
- pugi::xml_node info = doc.child("info");
- pugi::xml_node desc = info.child("desc");
+ pugi::xml_node info = doc.child("info");
+ pugi::xml_node desc = info.child("desc");
- streams[index].info.channel_count = info.child("channel_count").text().as_int();
- streams[index].info.nominal_srate = info.child("nominal_srate").text().as_double();
- streams[index].info.name = info.child("name").text().get();
- streams[index].info.type = info.child("type").text().get();
- streams[index].info.channel_format = info.child("channel_format").text().get();
+ streams[index].info.channel_count = info.child("channel_count").text().as_int();
+ streams[index].info.nominal_srate = info.child("nominal_srate").text().as_double();
+ streams[index].info.name = info.child("name").text().get();
+ streams[index].info.type = info.child("type").text().get();
+ streams[index].info.channel_format = info.child("channel_format").text().get();
- for (auto channel = desc.child("channels").child("channel"); channel; channel = channel.next_sibling("channel"))
- {
- streams[index].info.channels.emplace_back();
+ for (auto channel = desc.child("channels").child("channel"); channel; channel = channel.
+ next_sibling("channel"))
+ {
+ streams[index].info.channels.emplace_back();
- for (auto const &entry : channel.children())
- streams[index].info.channels.back().emplace(entry.name(), entry.child_value());
- }
+ for (auto const& entry : channel.children())
+ streams[index].info.channels.back().emplace(entry.name(), entry.child_value());
+ }
- if (streams[index].info.nominal_srate > 0)
- streams[index].sampling_interval = 1 / streams[index].info.nominal_srate;
- else
- streams[index].sampling_interval = 0;
+ if (streams[index].info.nominal_srate > 0)
+ streams[index].sampling_interval = 1 / streams[index].info.nominal_srate;
+ else
+ streams[index].sampling_interval = 0;
- delete[] buffer;
- }
+ delete[] buffer;
+ }
break;
case 3: //read [Samples] chunk
- {
- //read [StreamID]
- uint32_t streamID;
- int index;
- Xdf::readBin(file, &streamID);
- std::vector::iterator it {std::find(idmap.begin(),idmap.end(),streamID)};
- if (it == idmap.end())
- {
- index = idmap.size();
- idmap.emplace_back(streamID);
- streams.emplace_back();
- }
- else
- index = std::distance(idmap.begin(), it);
-
-
- //read [NumSampleBytes], [NumSamples]
- uint64_t numSamp = readLength(file);
-
- //check the data type
- if (streams[index].info.channel_format.compare("float32") == 0)
{
- //if the time series is empty
- if (streams[index].time_series.empty())
- streams[index].time_series.resize(streams[index].info.channel_count);
-
- //for each sample
- for (size_t i = 0; i < numSamp; i++)
+ //read [StreamID]
+ uint32_t streamID;
+ int index;
+ Xdf::readBin(file, &streamID);
+ std::vector::iterator it{std::find(idmap.begin(), idmap.end(), streamID)};
+ if (it == idmap.end())
{
- //read or deduce time stamp
- auto tsBytes = readBin(file);
-
- double ts; //temporary time stamp
-
- if (tsBytes == 8)
- {
- Xdf::readBin(file, &ts);
- streams[index].time_stamps.emplace_back(ts);
- }
- else
- {
- ts = streams[index].last_timestamp + streams[index].sampling_interval;
- streams[index].time_stamps.emplace_back(ts);
- }
-
- streams[index].last_timestamp = ts;
-
- //read the data
- for (int v = 0; v < streams[index].info.channel_count; ++v)
- {
- float data;
- Xdf::readBin(file, &data);
- streams[index].time_series[v].emplace_back(data);
- }
+ index = idmap.size();
+ idmap.emplace_back(streamID);
+ streams.emplace_back();
}
- }
- else if (streams[index].info.channel_format.compare("double64") == 0)
- {
- //if the time series is empty
- if (streams[index].time_series.empty())
- streams[index].time_series.resize(streams[index].info.channel_count);
+ else
+ index = std::distance(idmap.begin(), it);
- //for each sample
- for (size_t i = 0; i < numSamp; i++)
- {
- //read or deduce time stamp
- auto tsBytes = readBin(file);
- double ts; //temporary time stamp
+ //read [NumSampleBytes], [NumSamples]
+ uint64_t numSamp = readLength(file);
- if (tsBytes == 8)
- {
- Xdf::readBin(file, &ts);
- streams[index].time_stamps.emplace_back(ts);
- }
- else
- {
- ts = streams[index].last_timestamp + streams[index].sampling_interval;
- streams[index].time_stamps.emplace_back(ts);
- }
-
- streams[index].last_timestamp = ts;
-
- //read the data
- for (int v = 0; v < streams[index].info.channel_count; ++v)
- {
- double data;
- Xdf::readBin(file, &data);
- streams[index].time_series[v].emplace_back(data);
- }
- }
- }
- else if (streams[index].info.channel_format.compare("int8") == 0)
- {
//if the time series is empty
if (streams[index].time_series.empty())
- streams[index].time_series.resize(streams[index].info.channel_count);
-
- //for each sample
- for (size_t i = 0; i < numSamp; i++)
{
- //read or deduce time stamp
- auto tsBytes = readBin(file);
-
- double ts; //temporary time stamp
-
- if (tsBytes == 8)
- {
- Xdf::readBin(file, &ts);
- streams[index].time_stamps.emplace_back(ts);
- }
- else
- {
- ts = streams[index].last_timestamp + streams[index].sampling_interval;
- streams[index].time_stamps.emplace_back(ts);
- }
-
- streams[index].last_timestamp = ts;
-
- //read the data
- for (int v = 0; v < streams[index].info.channel_count; ++v)
- {
- int8_t data;
- Xdf::readBin(file, &data);
- streams[index].time_series[v].emplace_back(data);
- }
- }
- }
- else if (streams[index].info.channel_format.compare("int16") == 0)
- {
- //if the time series is empty
- if (streams[index].time_series.empty())
streams[index].time_series.resize(streams[index].info.channel_count);
-
- //for each sample
- for (size_t i = 0; i < numSamp; i++)
- {
- //read or deduce time stamp
- auto tsBytes = readBin(file);
-
- double ts; //temporary time stamp
-
- if (tsBytes == 8)
- {
- Xdf::readBin(file, &ts);
- streams[index].time_stamps.emplace_back(ts);
- }
- else
- {
- ts = streams[index].last_timestamp + streams[index].sampling_interval;
- streams[index].time_stamps.emplace_back(ts);
- }
-
- streams[index].last_timestamp = ts;
-
- //read the data
- for (int v = 0; v < streams[index].info.channel_count; ++v)
- {
- int16_t data;
- Xdf::readBin(file, &data);
- streams[index].time_series[v].emplace_back(data);
- }
}
- }
- else if (streams[index].info.channel_format.compare("int32") == 0)
- {
- //if the time series is empty
- if (streams[index].time_series.empty())
- streams[index].time_series.resize(streams[index].info.channel_count);
//for each sample
for (size_t i = 0; i < numSamp; i++)
@@ -334,7 +191,7 @@ int Xdf::load_xdf(std::string filename)
//read or deduce time stamp
auto tsBytes = readBin(file);
- double ts; //temporary time stamp
+ double ts; //temporary time stamp
if (tsBytes == 8)
{
@@ -349,140 +206,140 @@ int Xdf::load_xdf(std::string filename)
streams[index].last_timestamp = ts;
- //read the data
- for (int v = 0; v < streams[index].info.channel_count; ++v)
- {
- int32_t data;
- Xdf::readBin(file, &data);
- streams[index].time_series[v].emplace_back(data);
- }
- }
- }
- else if (streams[index].info.channel_format.compare("int64") == 0)
- {
- //if the time series is empty
- if (streams[index].time_series.empty())
- streams[index].time_series.resize(streams[index].info.channel_count);
-
- //for each sample
- for (size_t i = 0; i < numSamp; i++)
- {
- //read or deduce time stamp
- auto tsBytes = readBin(file);
-
- double ts; //temporary time stamp
-
- if (tsBytes == 8)
+ if (streams[index].info.channel_format.compare("string") == 0)
{
- Xdf::readBin(file, &ts);
- streams[index].time_stamps.emplace_back(ts);
+ for (int v = 0; v < streams[index].info.channel_count; ++v)
+ {
+ auto length = Xdf::readLength(file);
+ char* buffer = new char[length + 1];
+ file.read(buffer, length);
+ buffer[length] = '\0';
+
+ streams[index].time_series[v].emplace_back(buffer);
+ }
}
else
{
- ts = streams[index].last_timestamp + streams[index].sampling_interval;
- streams[index].time_stamps.emplace_back(ts);
+ //read the data
+ if (streams[index].info.channel_format.compare("float32") == 0)
+ {
+ for (int v = 0; v < streams[index].info.channel_count; ++v)
+ {
+ float data;
+ Xdf::readBin(file, &data);
+ streams[index].time_series[v].emplace_back(data);
+ }
+ }
+ else if (streams[index].info.channel_format.compare("double64") == 0)
+ {
+ for (int v = 0; v < streams[index].info.channel_count; ++v)
+ {
+ double data;
+ Xdf::readBin(file, &data);
+ streams[index].time_series[v].emplace_back(data);
+ }
+ }
+ else if (streams[index].info.channel_format.compare("int8_t") == 0)
+ {
+ for (int v = 0; v < streams[index].info.channel_count; ++v)
+ {
+ int8_t data;
+ Xdf::readBin(file, &data);
+ streams[index].time_series[v].emplace_back(data);
+ }
+ }
+ else if (streams[index].info.channel_format.compare("int16_t") == 0)
+ {
+ for (int v = 0; v < streams[index].info.channel_count; ++v)
+ {
+ int16_t data;
+ Xdf::readBin(file, &data);
+ streams[index].time_series[v].emplace_back(data);
+ }
+ }
+ else if (streams[index].info.channel_format.compare("int32_t") == 0)
+ {
+ for (int v = 0; v < streams[index].info.channel_count; ++v)
+ {
+ int data;
+ Xdf::readBin(file, &data);
+ streams[index].time_series[v].emplace_back(data);
+ }
+ }
+ else if (streams[index].info.channel_format.compare("int64_t") == 0)
+ {
+ for (int v = 0; v < streams[index].info.channel_count; ++v)
+ {
+ int64_t data;
+ Xdf::readBin(file, &data);
+ streams[index].time_series[v].emplace_back(data);
+ }
+ }
}
-
- streams[index].last_timestamp = ts;
-
- //read the data
- for (int v = 0; v < streams[index].info.channel_count; ++v)
- {
- int64_t data;
- Xdf::readBin(file, &data);
- streams[index].time_series[v].emplace_back(data);
- }
- }
- }
- else if (streams[index].info.channel_format.compare("string") == 0)
- {
- //for each event
- for (size_t i = 0; i < numSamp; i++)
- {
- //read or deduce time stamp
- auto tsBytes = readBin(file);
-
- double ts; //temporary time stamp
-
- if (tsBytes == 8)
- Xdf::readBin(file, &ts);
- else
- ts = streams[index].last_timestamp + streams[index].sampling_interval;
-
- //read the event
- auto length = Xdf::readLength(file);
-
- char* buffer = new char[length + 1];
- file.read(buffer, length);
- buffer[length] = '\0';
- eventMap.emplace_back(std::make_pair(buffer, ts), index);
- delete[] buffer;
- streams[index].last_timestamp = ts;
}
}
- }
break;
case 4: //read [ClockOffset] chunk
- {
- uint32_t streamID;
- int index;
- Xdf::readBin(file, &streamID);
- std::vector::iterator it {std::find(idmap.begin(),idmap.end(),streamID)};
- if (it == idmap.end())
{
- index = idmap.size();
- idmap.emplace_back(streamID);
- streams.emplace_back();
- }
- else
- index = std::distance(idmap.begin(), it);
+ uint32_t streamID;
+ int index;
+ Xdf::readBin(file, &streamID);
+ std::vector::iterator it{std::find(idmap.begin(), idmap.end(), streamID)};
+ if (it == idmap.end())
+ {
+ index = idmap.size();
+ idmap.emplace_back(streamID);
+ streams.emplace_back();
+ }
+ else
+ index = std::distance(idmap.begin(), it);
- double collectionTime;
- double offsetValue;
+ double collectionTime;
+ double offsetValue;
- Xdf::readBin(file, &collectionTime);
- Xdf::readBin(file, &offsetValue);
+ Xdf::readBin(file, &collectionTime);
+ Xdf::readBin(file, &offsetValue);
- streams[index].clock_times.emplace_back(collectionTime);
- streams[index].clock_values.emplace_back(offsetValue);
- }
+ streams[index].clock_times.emplace_back(collectionTime);
+ streams[index].clock_values.emplace_back(offsetValue);
+ }
break;
case 6: //read [StreamFooter] chunk
- {
- pugi::xml_document doc;
-
- //read [StreamID]
- uint32_t streamID;
- int index;
- Xdf::readBin(file, &streamID);
- std::vector::iterator it {std::find(idmap.begin(),idmap.end(),streamID)};
- if (it == idmap.end())
{
- index = idmap.size();
- idmap.emplace_back(streamID);
- streams.emplace_back();
- }
- else
- index = std::distance(idmap.begin(), it);
+ pugi::xml_document doc;
+
+ //read [StreamID]
+ uint32_t streamID;
+ int index;
+ Xdf::readBin(file, &streamID);
+ std::vector::iterator it{std::find(idmap.begin(), idmap.end(), streamID)};
+ if (it == idmap.end())
+ {
+ index = idmap.size();
+ idmap.emplace_back(streamID);
+ streams.emplace_back();
+ }
+ else
+ index = std::distance(idmap.begin(), it);
- char* buffer = new char[ChLen - 6];
- file.read(buffer, ChLen - 6);
- streams[index].streamFooter = buffer;
+ char* buffer = new char[ChLen - 6];
+ file.read(buffer, ChLen - 6);
+ streams[index].streamFooter = buffer;
- doc.load_buffer_inplace(buffer, ChLen - 6);
+ doc.load_buffer_inplace(buffer, ChLen - 6);
- pugi::xml_node info = doc.child("info");
+ pugi::xml_node info = doc.child("info");
- streams[index].info.first_timestamp = info.child("first_timestamp").text().as_double();
- streams[index].info.last_timestamp = info.child("last_timestamp").text().as_double();
- streams[index].info.measured_srate = info.child("measured_srate").text().as_double();
- streams[index].info.sample_count = info.child("sample_count").text().as_int();
- delete[] buffer;
- }
+ streams[index].info.first_timestamp = info.child("first_timestamp").text().as_double();
+ streams[index].info.last_timestamp = info.child("last_timestamp").text().as_double();
+ streams[index].info.measured_srate = info.child("measured_srate").text().as_double();
+ streams[index].info.sample_count = info.child("sample_count").text().as_int();
+ delete[] buffer;
+ }
break;
- case 5: //skip other chunk types (Boundary, ...)
+ case 5: //skip other chunk types (Boundary, ...)
file.seekg(ChLen - 2, file.cur);
break;
default:
@@ -496,7 +353,7 @@ int Xdf::load_xdf(std::string filename)
clock_t halfWay = clock() - time;
std::cout << "it took " << halfWay << " clicks (" << ((float)halfWay) / CLOCKS_PER_SEC << " seconds)"
- << " reading XDF data" << std::endl;
+ << " reading XDF data" << std::endl;
//==========================================================
@@ -534,18 +391,18 @@ int Xdf::load_xdf(std::string filename)
void Xdf::syncTimeStamps()
{
// Sync time stamps
- for (auto &stream : this->streams)
+ for (auto& stream : this->streams)
{
if (!stream.clock_times.empty())
{
- size_t m = 0; // index iterating through stream.time_stamps
- size_t n = 0; // index iterating through stream.clock_times
+ size_t m = 0; // index iterating through stream.time_stamps
+ size_t n = 0; // index iterating through stream.clock_times
while (m < stream.time_stamps.size())
{
if (stream.clock_times[n] < stream.time_stamps[m])
{
- while (n < stream.clock_times.size() - 1 && stream.clock_times[n+1] < stream.time_stamps[m])
+ while (n < stream.clock_times.size() - 1 && stream.clock_times[n + 1] < stream.time_stamps[m])
{
n++;
}
@@ -561,15 +418,15 @@ void Xdf::syncTimeStamps()
}
// Sync event time stamps
- for (auto &elem : this->eventMap)
+ for (auto& elem : this->eventMap)
{
if (!this->streams[elem.second].clock_times.empty())
{
- size_t k = 0; // index iterating through streams[elem.second].clock_times
+ size_t k = 0; // index iterating through streams[elem.second].clock_times
while (k < this->streams[elem.second].clock_times.size() - 1)
{
- if (this->streams[elem.second].clock_times[k+1] < elem.first.second)
+ if (this->streams[elem.second].clock_times[k + 1] < elem.first.second)
{
k++;
}
@@ -579,7 +436,8 @@ void Xdf::syncTimeStamps()
}
}
- elem.first.second += this->streams[elem.second].clock_values[k]; // apply the last offset value to the timestamp; if there hasn't yet been an offset value take the first recorded one
+ elem.first.second += this->streams[elem.second].clock_values[k];
+ // apply the last offset value to the timestamp; if there hasn't yet been an offset value take the first recorded one
}
}
@@ -591,7 +449,7 @@ void Xdf::syncTimeStamps()
double min = NAN;
double max = NAN;
- for (auto const &elem : this->eventMap)
+ for (auto const& elem : this->eventMap)
{
if (elem.second == (int)k)
{
@@ -612,10 +470,11 @@ void Xdf::syncTimeStamps()
}
else
{
- if (streams[k].time_stamps.size() > 0) {
+ if (streams[k].time_stamps.size() > 0)
+ {
streams[k].info.first_timestamp = streams[k].time_stamps.front();
- streams[k].info.last_timestamp = streams[k].time_stamps.back();
- }
+ streams[k].info.last_timestamp = streams[k].time_stamps.back();
+ }
}
}
}
@@ -628,18 +487,19 @@ void Xdf::resample(int userSrate)
clock_t time = clock();
#define BUF_SIZE 8192
- for (auto &stream : streams)
+ for (auto& stream : streams)
{
if (!stream.time_series.empty() &&
- stream.info.nominal_srate != userSrate &&
- stream.info.nominal_srate != 0)
+ !stream.info.channel_format.compare("string") &&
+ stream.info.nominal_srate != userSrate &&
+ stream.info.nominal_srate != 0)
{
- int fsin = stream.info.nominal_srate; // input samplerate
- int fsout = userSrate; // output samplerate
- double bandwidth = 0.95; // bandwidth
- double rp = 0.1; // passband ripple factor
- double rs = 140; // stopband attenuation
- double tol = 0.000001; // tolerance
+ int fsin = stream.info.nominal_srate; // input samplerate
+ int fsout = userSrate; // output samplerate
+ double bandwidth = 0.95; // bandwidth
+ double rp = 0.1; // passband ripple factor
+ double rs = 140; // stopband attenuation
+ double tol = 0.000001; // tolerance
// initialize smarc filter
struct PFilter* pfilt = smarc_init_pfilter(fsin, fsout, bandwidth, rp,
@@ -650,38 +510,67 @@ void Xdf::resample(int userSrate)
// initialize smarc filter state
struct PState* pstate = smarc_init_pstate(pfilt);
- for (auto &row : stream.time_series)
+ for (auto& row : stream.time_series)
{
// initialize buffers
int read = 0;
int written = 0;
- const int OUT_BUF_SIZE = (int) smarc_get_output_buffer_size(pfilt, row.size());
+ const int OUT_BUF_SIZE = (int)smarc_get_output_buffer_size(pfilt, row.size());
double* inbuf = new double[row.size()];
double* outbuf = new double[OUT_BUF_SIZE];
-
- std::copy(row.begin(), row.end(), inbuf);
-
- read = row.size();
-
+ // Fill inbuf with the numeric values from the row
+ for (auto& val : row)
+ {
+ std::visit([&inbuf, &read](auto&& arg)
+ {
+ using T = std::decay_t;
+ if constexpr (std::is_arithmetic_v)
+ {
+ inbuf[read++] = static_cast(arg); // Convert to double
+ }
+ }, val);
+ }
// resample signal block
written = smarc_resample(pfilt, pstate, inbuf, read, outbuf, OUT_BUF_SIZE);
- // do what you want with your output
- row.resize(written);
- std::copy ( outbuf, outbuf+written, row.begin() );
+ // Replace original values with the resampled output
+ read = 0;
+ for (auto& val : row)
+ {
+ // Only replace numeric values
+ std::visit([&outbuf, &read](auto&& arg)
+ {
+ using T = std::decay_t;
+ if constexpr (std::is_arithmetic_v)
+ {
+ arg = static_cast(outbuf[read++]);
+ }
+ }, val);
+ }
// flushing last values
written = smarc_resample_flush(pfilt, pstate, outbuf, OUT_BUF_SIZE);
- // do what you want with your output
- row.resize(row.size() + written);
- std::copy ( outbuf, outbuf+written, row.begin() + row.size() - written );
+ // Add any remaining flushed values
+ read = 0;
+ for (auto& val : row)
+ {
+ // Only replace numeric values
+ std::visit([&outbuf, &read](auto&& arg)
+ {
+ using T = std::decay_t;
+ if constexpr (std::is_arithmetic_v)
+ {
+ arg = static_cast(outbuf[read++]);
+ }
+ }, val);
+ }
// you are done with converting your signal.
// If you want to reuse the same converter to process another signal
// just reset the state:
- smarc_reset_pstate(pstate,pfilt);
+ smarc_reset_pstate(pstate, pfilt);
delete[] inbuf;
delete[] outbuf;
@@ -708,11 +597,11 @@ void Xdf::resample(int userSrate)
time = clock() - time;
std::cout << "it took " << time << " clicks (" << ((float)time) / CLOCKS_PER_SEC << " seconds)"
- << " resampling" << std::endl;
+ << " resampling" << std::endl;
}
//function of reading the length of each chunk
-uint64_t Xdf::readLength(std::ifstream &file)
+uint64_t Xdf::readLength(std::ifstream& file)
{
uint8_t bytes = 0;
Xdf::readBin(file, &bytes);
@@ -731,7 +620,7 @@ uint64_t Xdf::readLength(std::ifstream &file)
break;
default:
std::cout << "Invalid variable-length integer length ("
- << static_cast(bytes) << ") encountered.\n";
+ << static_cast(bytes) << ") encountered.\n";
return 0;
}
@@ -741,7 +630,7 @@ uint64_t Xdf::readLength(std::ifstream &file)
void Xdf::findMinMax()
{
//find the smallest timestamp of all streams
- for (auto const &stream : streams)
+ for (auto const& stream : streams)
{
if (!std::isnan(stream.info.first_timestamp))
{
@@ -749,14 +638,14 @@ void Xdf::findMinMax()
break;
}
}
- for (auto const &stream : streams)
+ for (auto const& stream : streams)
{
if (!std::isnan(stream.info.first_timestamp) && stream.info.first_timestamp < minTS)
minTS = stream.info.first_timestamp;
}
//find the max timestamp of all streams
- for (auto const &stream : streams)
+ for (auto const& stream : streams)
{
if (!std::isnan(stream.info.last_timestamp) && stream.info.last_timestamp > maxTS)
maxTS = stream.info.last_timestamp;
@@ -769,38 +658,47 @@ void Xdf::findMajSR()
typedef int sampRate;
typedef int numChannel;
- std::vector > srateMap; // pairs of all the streams
+ std::vector> srateMap; // pairs of all the streams
//find out whether a sample rate already exists in srateMap
- for (auto const &stream : streams)
+ for (auto const& stream : streams)
{
if (stream.info.nominal_srate != 0)
{
- std::vector >::iterator it {std::find_if(srateMap.begin(), srateMap.end(),
- [&](const std::pair &element)
- {return element.first == stream.info.nominal_srate; })} ;
+ std::vector>::iterator it{
+ std::find_if(srateMap.begin(), srateMap.end(),
+ [&](const std::pair& element)
+ {
+ return element.first == stream.info.nominal_srate;
+ })
+ };
//if it doesn't, add it here
if (it == srateMap.end())
srateMap.emplace_back(stream.info.nominal_srate, stream.info.channel_count);
//if it already exists, add additional channel numbers to that sample rate
else
{
- int index (std::distance(srateMap.begin(),it)) ;
+ int index(std::distance(srateMap.begin(), it));
srateMap[index].second += stream.info.channel_count;
}
}
}
- if(srateMap.size() > 0){
+ if (srateMap.size() > 0)
+ {
//search the srateMap to see which sample rate has the most channels
- int index (std::distance(srateMap.begin(),
- std::max_element(srateMap.begin(),srateMap.end(),
- [] (const std::pair &largest,
- const std::pair &first)
- { return largest.second < first.second; })));
+ int index(std::distance(srateMap.begin(),
+ std::max_element(srateMap.begin(), srateMap.end(),
+ [](const std::pair& largest,
+ const std::pair& first)
+ {
+ return largest.second < first.second;
+ })));
majSR = srateMap[index].first; //the sample rate that has the most channels
- } else {
+ }
+ else
+ {
majSR = 0; //if there are no streams with a fixed sample reate
}
}
@@ -810,7 +708,7 @@ void Xdf::calcTotalChannel()
//calculating total channel count, and indexing them onto streamMap
for (size_t c = 0; c < streams.size(); c++)
{
- if(!streams[c].time_series.empty())
+ if (!streams[c].time_series.empty())
{
totalCh += streams[c].info.channel_count;
@@ -828,11 +726,12 @@ void Xdf::calcTotalLength(int sampleRate)
void Xdf::freeUpTimeStamps()
{
//free up as much memory as possible
- for (auto &stream : streams)
+ for (auto& stream : streams)
{
//we don't need to keep all the time stamps unless it's a stream with irregular samples
//filter irregular streams and string streams
- if (stream.info.nominal_srate != 0 && !stream.time_stamps.empty() && stream.info.channel_format.compare("string"))
+ if (stream.info.nominal_srate != 0 && !stream.time_stamps.empty() && stream.info.channel_format.
+ compare("string"))
{
std::vector nothing;
//however we still need to keep the first time stamp of each stream to decide at which position the signal should start
@@ -844,9 +743,9 @@ void Xdf::freeUpTimeStamps()
void Xdf::adjustTotalLength()
{
- for (auto const &stream : streams)
+ for (auto const& stream : streams)
{
- if(!stream.time_series.empty())
+ if (!stream.time_series.empty())
{
if (totalLen < stream.time_series.front().size())
totalLen = stream.time_series.front().size();
@@ -856,7 +755,7 @@ void Xdf::adjustTotalLength()
void Xdf::getHighestSampleRate()
{
- for (auto const &stream : streams)
+ for (auto const& stream : streams)
{
if (stream.info.nominal_srate > maxSR)
maxSR = stream.info.nominal_srate;
@@ -865,35 +764,37 @@ void Xdf::getHighestSampleRate()
void Xdf::loadSampleRateMap()
{
- for (auto const &stream : streams)
+ for (auto const& stream : streams)
sampleRateMap.emplace(stream.info.nominal_srate);
}
-void Xdf::detrend()
-{
- for (auto &stream : streams)
- {
- for (auto &row : stream.time_series)
- {
- long double init = 0.0;
- long double mean = std::accumulate(row.begin(), row.end(), init) / row.size();
- for(auto &val: row) val -= mean;
- offsets.emplace_back(mean);
- }
- }
-}
+/*
+ void Xdf::detrend()
+ {
+ for (auto &stream : streams)
+ {
+ for (auto &row : stream.time_series)
+ {
+ long double init = 0.0;
+ long double mean = std::accumulate(row.begin(), row.end(), init) / row.size();
+ for(auto &val: row) val -= mean;
+ offsets.emplace_back(mean);
+ }
+ }
+ }
+ */
void Xdf::calcEffectiveSrate()
{
- for (auto &stream : streams)
+ for (auto& stream : streams)
{
if (stream.info.nominal_srate)
{
try
{
stream.info.effective_sample_rate
- = stream.info.sample_count /
- (stream.info.last_timestamp - stream.info.first_timestamp);
+ = stream.info.sample_count /
+ (stream.info.last_timestamp - stream.info.first_timestamp);
if (stream.info.effective_sample_rate)
effectiveSampleRateVector.emplace_back(stream.info.effective_sample_rate);
@@ -902,19 +803,19 @@ void Xdf::calcEffectiveSrate()
doc.load_string(stream.streamFooter.c_str());
pugi::xml_node sampleCount = doc.child("info").child("sample_count");
pugi::xml_node effectiveSampleRate
- = doc.child("info").insert_child_after("effective_sample_rate", sampleCount);
+ = doc.child("info").insert_child_after("effective_sample_rate", sampleCount);
effectiveSampleRate.append_child(pugi::node_pcdata)
- .set_value(std::to_string(stream.info.effective_sample_rate).c_str());
+ .set_value(std::to_string(stream.info.effective_sample_rate).c_str());
std::stringstream buffer;
doc.save(buffer);
stream.streamFooter = buffer.str();
}
- catch (std::exception &e)
+ catch (std::exception& e)
{
std::cerr << "Error calculating effective sample rate. "
- << e.what() << std::endl;
+ << e.what() << std::endl;
}
}
}
@@ -934,7 +835,8 @@ int Xdf::writeEventsToXDF(std::string file_path)
//Num Length Bytes
file.put(4);
//length
- int length = streams[userAddedStream].streamHeader.size() + 6; //+6 because of the length int itself and short int tag
+ int length = streams[userAddedStream].streamHeader.size() + 6;
+ //+6 because of the length int itself and short int tag
file.write((char*)&length, 4);
//tag
@@ -944,7 +846,7 @@ int Xdf::writeEventsToXDF(std::string file_path)
int streamNumber = userAddedStream + 1; //+1 because the stream IDs in XDF are 1 based instead of 0 based
file.write((char*)&streamNumber, 4);
//content
- file.write(streams[userAddedStream].streamHeader.c_str(), length - 6);//length - 6 is the string length
+ file.write(streams[userAddedStream].streamHeader.c_str(), length - 6); //length - 6 is the string length
//write samples chunk
//Num Length Bytes
@@ -952,12 +854,12 @@ int Xdf::writeEventsToXDF(std::string file_path)
//length
//add the bytes of all following actions together
int64_t stringTotalLength = 0;
- for (auto const &event : userCreatedEvents)
+ for (auto const& event : userCreatedEvents)
stringTotalLength += event.first.size();
int64_t sampleChunkLength = 2 + 4 + 1 + 4 +
- userCreatedEvents.size() *
- (1 + 8 + 1 + 4) + stringTotalLength;
+ userCreatedEvents.size() *
+ (1 + 8 + 1 + 4) + stringTotalLength;
file.write((char*)&sampleChunkLength, 8);
@@ -975,7 +877,7 @@ int Xdf::writeEventsToXDF(std::string file_path)
file.write((char*)&numSamples, 4);
//samples
- for (auto const &event : userCreatedEvents)
+ for (auto const& event : userCreatedEvents)
{
//TimeStampBytes
file.put(8);
@@ -1021,11 +923,11 @@ void Xdf::createLabels()
{
// +1 for 1 based numbers; for user convenience only. The internal computation is still 0 based
std::string label = "Stream " + std::to_string(st + 1) + " - Channel " + std::to_string(ch + 1)
- + " - " + std::to_string((int)streams[st].info.nominal_srate) + " Hz\n";
+ + " - " + std::to_string((int)streams[st].info.nominal_srate) + " Hz\n";
label += streams[st].info.name + '\n';
- for (auto const &entry : streams[st].info.channels[ch])
+ for (auto const& entry : streams[st].info.channels[ch])
{
if (entry.second != "")
label += entry.first + " : " + entry.second + '\n';
@@ -1048,9 +950,9 @@ void Xdf::createLabels()
{
// +1 for 1 based numbers; for user convenience only. The internal computation is still 0 based
std::string label = "Stream " + std::to_string(st + 1) +
- " - Channel " + std::to_string(ch + 1) + " - " +
- std::to_string((int)streams[st].info.nominal_srate) +
- " Hz\n" + streams[st].info.name + '\n' + streams[st].info.type + '\n';
+ " - Channel " + std::to_string(ch + 1) + " - " +
+ std::to_string((int)streams[st].info.nominal_srate) +
+ " Hz\n" + streams[st].info.name + '\n' + streams[st].info.type + '\n';
label += streams[st].info.name + '\n';
@@ -1073,25 +975,28 @@ void Xdf::createLabels()
void Xdf::loadDictionary()
{
//loop through the eventMap
- for (auto const &entry : eventMap)
+ for (auto const& entry : eventMap)
{
//search the dictionary to see whether an event is already in it
- auto it = std::find(dictionary.begin(),dictionary.end(),entry.first.first);
+ auto it = std::find(dictionary.begin(), dictionary.end(), entry.first.first);
//if it isn't yet
if (it == dictionary.end())
- { //add it to the dictionary, also store its index into eventType vector for future use
+ {
+ //add it to the dictionary, also store its index into eventType vector for future use
eventType.emplace_back(dictionary.size());
dictionary.emplace_back(entry.first.first);
}
//if it's already in there
- else //store its index into eventType vector
+ else //store its index into eventType vector
eventType.emplace_back(std::distance(dictionary.begin(), it));
}
}
-template T Xdf::readBin(std::istream& is, T* obj) {
- T dummy;
- if(!obj) obj = &dummy;
- is.read(reinterpret_cast(obj), sizeof(T));
- return *obj;
+template
+T Xdf::readBin(std::istream& is, T* obj)
+{
+ T dummy;
+ if (!obj) obj = &dummy;
+ is.read(reinterpret_cast(obj), sizeof(T));
+ return *obj;
}
diff --git a/xdf.h b/xdf.h
index 47e73a1..4e6b77f 100644
--- a/xdf.h
+++ b/xdf.h
@@ -27,6 +27,7 @@
#include