From 04568c9eea0b99c6c6eedeffa6e2f0a65ae3dce3 Mon Sep 17 00:00:00 2001 From: Yida Lin Date: Thu, 26 Dec 2024 21:05:53 -0800 Subject: [PATCH 01/37] std::variant --- .vscode/settings.json | 3 +++ xdf.cpp | 30 ++++++++++++++++++++++++++++++ xdf.h | 7 ++++++- 3 files changed, 39 insertions(+), 1 deletion(-) create mode 100644 .vscode/settings.json diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..4ab2520 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,3 @@ +{ + "C_Cpp.default.compilerPath": "c:\\Qt\\Tools\\mingw730_64\\bin\\g++.exe" +} \ No newline at end of file diff --git a/xdf.cpp b/xdf.cpp index 2ada86e..50bfda4 100644 --- a/xdf.cpp +++ b/xdf.cpp @@ -156,6 +156,36 @@ int Xdf::load_xdf(std::string filename) else streams[index].sampling_interval = 0; + Stream& stream = streams[index]; + const int channel_count = stream.info.channel_count; + if (const std::string_view channel_format = stream.info.channel_format; + channel_format.compare("string") == 0) + { + stream.time_series = std::vector>( + channel_count); + } + else if (channel_format.compare("float32") == 0) + { + stream.time_series = std::vector>( + channel_count); + } + else if (channel_format.compare("double64") == 0) + { + stream.time_series = std::vector>( + channel_count); + } + else if (channel_format.compare("int8_t") == 0 || + channel_format.compare("int16_t") == 0 || + channel_format.compare("int32_t") == 0) + { + stream.time_series = std::vector>(channel_count); + } + else if (channel_format.compare("int64_t") == 0) + { + stream.time_series = std::vector>( + channel_count); + } + delete[] buffer; } break; diff --git a/xdf.h b/xdf.h index 4e6b77f..516bd72 100644 --- a/xdf.h +++ b/xdf.h @@ -55,7 +55,12 @@ class Xdf struct Stream { //! A 2D vector which stores the time series of a stream. Each row represents a channel. - std::vector>> time_series; + std::variant< + std::vector>, + std::vector>, + std::vector>, + std::vector>, + std::vector>> time_series; std::vector time_stamps; /*!< A vector to store time stamps. */ std::string streamHeader; /*!< Raw XML of stream header chunk. */ std::string streamFooter; /*!< Raw XML of stream footer chunk. */ From c9230e3a83c03b5b45d2799dc072bc377f6691b8 Mon Sep 17 00:00:00 2001 From: Yida Lin Date: Thu, 26 Dec 2024 21:17:59 -0800 Subject: [PATCH 02/37] read_time_series --- xdf.cpp | 78 ++++++++++++++++++++++++++++++++++++--------------------- xdf.h | 4 +++ 2 files changed, 54 insertions(+), 28 deletions(-) diff --git a/xdf.cpp b/xdf.cpp index 50bfda4..a74ff95 100644 --- a/xdf.cpp +++ b/xdf.cpp @@ -30,6 +30,41 @@ #include #include +namespace xdf { +namespace { + +/*! + * \brief Read a binary scalar variable from an input stream. + * + * readBin is a convenience wrapper for the common + * file.read((char*) var, sizeof(var)) + * operation. Examples: + * double foo = readBin(file); // use return value + * readBin(file, &foo); // read directly into foo + * \param is an input stream to read from + * \param obj pointer to a variable to load the data into or nullptr + * \return the read data + */ +template +T read_bin(std::istream& is, T* obj = nullptr) +{ + T dummy; + if (!obj) obj = &dummy; + is.read(reinterpret_cast(obj), sizeof(T)); + return *obj; +} + + +template +void read_time_series(std::istream& is, std::vector>* time_series) { + for (int v = 0; v < time_series->size(); ++v) + { + (*time_series)[v].push_back(read_bin(is)); + } +} + +} // namespace + Xdf::Xdf() { } @@ -112,7 +147,7 @@ int Xdf::load_xdf(std::string filename) //read [StreamID] uint32_t streamID; int index; - Xdf::readBin(file, &streamID); + read_bin(file, &streamID); std::vector::iterator it{std::find(idmap.begin(), idmap.end(), streamID)}; if (it == idmap.end()) { @@ -194,7 +229,7 @@ int Xdf::load_xdf(std::string filename) //read [StreamID] uint32_t streamID; int index; - Xdf::readBin(file, &streamID); + read_bin(file, &streamID); std::vector::iterator it{std::find(idmap.begin(), idmap.end(), streamID)}; if (it == idmap.end()) { @@ -209,12 +244,6 @@ int Xdf::load_xdf(std::string filename) //read [NumSampleBytes], [NumSamples] uint64_t numSamp = readLength(file); - //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++) { @@ -225,7 +254,7 @@ int Xdf::load_xdf(std::string filename) if (tsBytes == 8) { - Xdf::readBin(file, &ts); + read_bin(file, &ts); streams[index].time_stamps.emplace_back(ts); } else @@ -256,7 +285,7 @@ int Xdf::load_xdf(std::string filename) for (int v = 0; v < streams[index].info.channel_count; ++v) { float data; - Xdf::readBin(file, &data); + read_bin(file, &data); streams[index].time_series[v].emplace_back(data); } } @@ -265,7 +294,7 @@ int Xdf::load_xdf(std::string filename) for (int v = 0; v < streams[index].info.channel_count; ++v) { double data; - Xdf::readBin(file, &data); + read_bin(file, &data); streams[index].time_series[v].emplace_back(data); } } @@ -274,7 +303,7 @@ int Xdf::load_xdf(std::string filename) for (int v = 0; v < streams[index].info.channel_count; ++v) { int8_t data; - Xdf::readBin(file, &data); + read_bin(file, &data); streams[index].time_series[v].emplace_back(data); } } @@ -283,7 +312,7 @@ int Xdf::load_xdf(std::string filename) for (int v = 0; v < streams[index].info.channel_count; ++v) { int16_t data; - Xdf::readBin(file, &data); + read_bin(file, &data); streams[index].time_series[v].emplace_back(data); } } @@ -292,7 +321,7 @@ int Xdf::load_xdf(std::string filename) for (int v = 0; v < streams[index].info.channel_count; ++v) { int data; - Xdf::readBin(file, &data); + read_bin(file, &data); streams[index].time_series[v].emplace_back(data); } } @@ -301,7 +330,7 @@ int Xdf::load_xdf(std::string filename) for (int v = 0; v < streams[index].info.channel_count; ++v) { int64_t data; - Xdf::readBin(file, &data); + read_bin(file, &data); streams[index].time_series[v].emplace_back(data); } } @@ -313,7 +342,7 @@ int Xdf::load_xdf(std::string filename) { uint32_t streamID; int index; - Xdf::readBin(file, &streamID); + read_bin(file, &streamID); std::vector::iterator it{std::find(idmap.begin(), idmap.end(), streamID)}; if (it == idmap.end()) { @@ -328,8 +357,8 @@ int Xdf::load_xdf(std::string filename) double collectionTime; double offsetValue; - Xdf::readBin(file, &collectionTime); - Xdf::readBin(file, &offsetValue); + read_bin(file, &collectionTime); + read_bin(file, &offsetValue); streams[index].clock_times.emplace_back(collectionTime); streams[index].clock_values.emplace_back(offsetValue); @@ -342,7 +371,7 @@ int Xdf::load_xdf(std::string filename) //read [StreamID] uint32_t streamID; int index; - Xdf::readBin(file, &streamID); + read_bin(file, &streamID); std::vector::iterator it{std::find(idmap.begin(), idmap.end(), streamID)}; if (it == idmap.end()) { @@ -634,7 +663,7 @@ void Xdf::resample(int userSrate) uint64_t Xdf::readLength(std::ifstream& file) { uint8_t bytes = 0; - Xdf::readBin(file, &bytes); + read_bin(file, &bytes); uint64_t length = 0; switch (bytes) @@ -1022,11 +1051,4 @@ void Xdf::loadDictionary() } } -template -T Xdf::readBin(std::istream& is, T* obj) -{ - T dummy; - if (!obj) obj = &dummy; - is.read(reinterpret_cast(obj), sizeof(T)); - return *obj; -} +} // namespace xdf diff --git a/xdf.h b/xdf.h index 516bd72..de64444 100644 --- a/xdf.h +++ b/xdf.h @@ -29,6 +29,8 @@ #include #include +namespace xdf { + /*! \class Xdf * * Xdf class is designed to store the data of an entire XDF file. @@ -321,4 +323,6 @@ class Xdf }; +} // namespace xdf + #endif // XDF_H From f2f47abb5f8da5afc4eac537c45152347c8f893c Mon Sep 17 00:00:00 2001 From: Yida Lin Date: Fri, 27 Dec 2024 18:45:51 -0800 Subject: [PATCH 03/37] std:visit --- xdf.cpp | 114 +++++++++++++++++--------------------------------------- xdf.h | 19 ++-------- 2 files changed, 37 insertions(+), 96 deletions(-) diff --git a/xdf.cpp b/xdf.cpp index a74ff95..f981944 100644 --- a/xdf.cpp +++ b/xdf.cpp @@ -36,11 +36,11 @@ namespace { /*! * \brief Read a binary scalar variable from an input stream. * - * readBin is a convenience wrapper for the common + * read_bin is a convenience wrapper for the common * file.read((char*) var, sizeof(var)) * operation. Examples: - * double foo = readBin(file); // use return value - * readBin(file, &foo); // read directly into foo + * double foo = read_bin(file); // use return value + * read_bin(file, &foo); // read directly into foo * \param is an input stream to read from * \param obj pointer to a variable to load the data into or nullptr * \return the read data @@ -54,10 +54,9 @@ T read_bin(std::istream& is, T* obj = nullptr) return *obj; } - template void read_time_series(std::istream& is, std::vector>* time_series) { - for (int v = 0; v < time_series->size(); ++v) + for (size_t v = 0; v < time_series->size(); ++v) { (*time_series)[v].push_back(read_bin(is)); } @@ -121,7 +120,7 @@ int Xdf::load_xdf(std::string filename) break; uint16_t tag; //read tag of the chunk, 6 possibilities - readBin(file, &tag); + read_bin(file, &tag); switch (tag) { @@ -209,9 +208,17 @@ int Xdf::load_xdf(std::string filename) stream.time_series = std::vector>( channel_count); } - else if (channel_format.compare("int8_t") == 0 || - channel_format.compare("int16_t") == 0 || - channel_format.compare("int32_t") == 0) + else if (channel_format.compare("int8_t") == 0) + { + stream.time_series = std::vector>( + channel_count); + } + else if (channel_format.compare("int16_t") == 0) + { + stream.time_series = std::vector>( + channel_count); + } + else if (channel_format.compare("int32_t") == 0) { stream.time_series = std::vector>(channel_count); } @@ -248,7 +255,7 @@ int Xdf::load_xdf(std::string filename) for (size_t i = 0; i < numSamp; i++) { //read or deduce time stamp - auto tsBytes = readBin(file); + auto tsBytes = read_bin(file); double ts; //temporary time stamp @@ -264,77 +271,24 @@ int Xdf::load_xdf(std::string filename) } streams[index].last_timestamp = ts; + Stream& stream = streams[index]; - if (streams[index].info.channel_format.compare("string") == 0) - { - 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 - { - //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; - read_bin(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; - read_bin(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; - read_bin(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) + std::visit([this, &file](auto&& arg) { + using T = std::decay_t; + if constexpr (std::is_same_v) { + for (int v = 0; v < arg.size(); ++v) { - int16_t data; - read_bin(file, &data); - streams[index].time_series[v].emplace_back(data); + auto length = Xdf::readLength(file); + char* buffer = new char[length + 1]; + file.read(buffer, length); + buffer[length] = '\0'; + arg[v].emplace_back(buffer); + delete[] buffer; } + } else { + read_time_series(file, &arg); } - else if (streams[index].info.channel_format.compare("int32_t") == 0) - { - for (int v = 0; v < streams[index].info.channel_count; ++v) - { - int data; - read_bin(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; - read_bin(file, &data); - streams[index].time_series[v].emplace_back(data); - } - } - } + }, stream.time_series); } } break; @@ -669,13 +623,13 @@ uint64_t Xdf::readLength(std::ifstream& file) switch (bytes) { case 1: - length = readBin(file); + length = read_bin(file); break; case 4: - length = readBin(file); + length = read_bin(file); break; case 8: - length = readBin(file); + length = read_bin(file); break; default: std::cout << "Invalid variable-length integer length (" diff --git a/xdf.h b/xdf.h index de64444..9380b8b 100644 --- a/xdf.h +++ b/xdf.h @@ -58,10 +58,12 @@ class Xdf { //! A 2D vector which stores the time series of a stream. Each row represents a channel. std::variant< + std::vector>, + std::vector>, std::vector>, + std::vector>, std::vector>, std::vector>, - std::vector>, std::vector>> time_series; std::vector time_stamps; /*!< A vector to store time stamps. */ std::string streamHeader; /*!< Raw XML of stream header chunk. */ @@ -306,21 +308,6 @@ class Xdf * \return The length of the upcoming chunk (in bytes). */ uint64_t readLength(std::ifstream &file); - - /*! - * \brief Read a binary scalar variable from an input stream. - * - * readBin is a convenience wrapper for the common - * file.read((char*) var, sizeof(var)) - * operation. Examples: - * double foo = readBin(file); // use return value - * readBin(file, &foo); // read directly into foo - * \param is an input stream to read from - * \param obj pointer to a variable to load the data into or nullptr - * \return the read data - */ - template T readBin(std::istream& is, T* obj = nullptr); - }; } // namespace xdf From 2b50bc515bf976603ca75561ae15483de5767781 Mon Sep 17 00:00:00 2001 From: Yida Lin Date: Fri, 27 Dec 2024 19:52:16 -0800 Subject: [PATCH 04/37] resample --- xdf.cpp | 93 ++++++++++++++++++++++++++------------------------------- 1 file changed, 43 insertions(+), 50 deletions(-) diff --git a/xdf.cpp b/xdf.cpp index f981944..70d5d76 100644 --- a/xdf.cpp +++ b/xdf.cpp @@ -500,9 +500,9 @@ void Xdf::resample(int userSrate) clock_t time = clock(); #define BUF_SIZE 8192 - for (auto& stream : streams) + for (Stream& stream : streams) { - if (!stream.time_series.empty() && + if (stream.time_series.index() != std::variant_npos && !stream.info.channel_format.compare("string") && stream.info.nominal_srate != userSrate && stream.info.nominal_srate != 0) @@ -523,71 +523,64 @@ void Xdf::resample(int userSrate) // initialize smarc filter state struct PState* pstate = smarc_init_pstate(pfilt); - 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()); - double* inbuf = new double[row.size()]; - double* outbuf = new double[OUT_BUF_SIZE]; - - // Fill inbuf with the numeric values from the row - for (auto& val : row) + std::visit([&pfilt, &pstate](auto&& arg) { + using T = typename std::decay_t::value_type::value_type; + for (std::vector& row : arg) { - std::visit([&inbuf, &read](auto&& arg) + // initialize buffers + int read = 0; + int written = 0; + 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]; + + // Fill inbuf with the numeric values from the row + if constexpr (std::is_arithmetic_v) { - using T = std::decay_t; - if constexpr (std::is_arithmetic_v) + for (const T& val : row) { - inbuf[read++] = static_cast(arg); // Convert to double + inbuf[read++] = static_cast(val); // Convert to double } - }, val); - } - // resample signal block - written = smarc_resample(pfilt, pstate, inbuf, read, outbuf, OUT_BUF_SIZE); + } - // Replace original values with the resampled output - read = 0; - for (auto& val : row) - { + // resample signal block + written = smarc_resample(pfilt, pstate, inbuf, read, outbuf, OUT_BUF_SIZE); + + // Replace original values with the resampled output + read = 0; // Only replace numeric values - std::visit([&outbuf, &read](auto&& arg) + if constexpr (std::is_arithmetic_v) { - using T = std::decay_t; - if constexpr (std::is_arithmetic_v) + for (auto& val : row) { - arg = static_cast(outbuf[read++]); + val = static_cast(outbuf[read++]); } - }, val); - } + } - // flushing last values - written = smarc_resample_flush(pfilt, pstate, outbuf, OUT_BUF_SIZE); + // flushing last values + written = smarc_resample_flush(pfilt, pstate, outbuf, OUT_BUF_SIZE); - // Add any remaining flushed values - read = 0; - for (auto& val : row) - { + // Add any remaining flushed values + read = 0; // Only replace numeric values - std::visit([&outbuf, &read](auto&& arg) + if constexpr (std::is_arithmetic_v) { - using T = std::decay_t; - if constexpr (std::is_arithmetic_v) + for (auto& val : row) { - arg = static_cast(outbuf[read++]); + val = 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); + // 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); + + delete[] inbuf; + delete[] outbuf; + } + }, stream.time_series); - delete[] inbuf; - delete[] outbuf; - } // release smarc filter state smarc_destroy_pstate(pstate); From b8eef6a85797ba3773143bf5ee9f1d43a8b495e9 Mon Sep 17 00:00:00 2001 From: Yida Lin Date: Fri, 27 Dec 2024 19:58:35 -0800 Subject: [PATCH 05/37] temp --- xdf.cpp | 5 +++-- xdf.h | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/xdf.cpp b/xdf.cpp index 70d5d76..b54521a 100644 --- a/xdf.cpp +++ b/xdf.cpp @@ -714,9 +714,10 @@ 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.index() != std::variant_npos && + streams[c].info.channel_format.compare("string") != 0) { - totalCh += streams[c].info.channel_count; + numerical_channel_count_ += streams[c].info.channel_count; for (int i = 0; i < streams[c].info.channel_count; i++) streamMap.emplace_back(c); diff --git a/xdf.h b/xdf.h index 9380b8b..035b856 100644 --- a/xdf.h +++ b/xdf.h @@ -104,7 +104,7 @@ class Xdf double minTS = 0; /*!< The smallest time stamp across all streams. */ double maxTS = 0; /*!< The largest time stamp across all streams. */ - size_t totalCh = 0; /*!< The total number of channel count. */ + size_t numerical_channel_count_ = 0; /*!< The total number of numericla channels. */ int majSR = 0; /*!< The sample rate that has the most channels across all streams. */ int maxSR = 0; /*!< Highest sample rate across all streams. */ std::vector effectiveSampleRateVector; /*!< Effective Sample Rate of each stream. */ From 10af71e2ca363a88abfb5e5640cec4ed167890a0 Mon Sep 17 00:00:00 2001 From: Yida Lin Date: Fri, 27 Dec 2024 20:31:46 -0800 Subject: [PATCH 06/37] compiling --- xdf.cpp | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/xdf.cpp b/xdf.cpp index b54521a..8e286b7 100644 --- a/xdf.cpp +++ b/xdf.cpp @@ -752,10 +752,12 @@ void Xdf::adjustTotalLength() { for (auto const& stream : streams) { - if (!stream.time_series.empty()) + if (stream.time_series.index() != std::variant_npos && + stream.info.channel_format.compare("string") != 0) { - if (totalLen < stream.time_series.front().size()) - totalLen = stream.time_series.front().size(); + std::visit([this](auto&& time_series) { + totalLen = std::max(totalLen, time_series.front().size()); + }, stream.time_series); } } } @@ -953,7 +955,7 @@ void Xdf::createLabels() } else { - for (size_t ch = 0; ch < streams[st].time_series.size(); ch++) + for (size_t ch = 0; ch < streams[st].info.channel_count; ch++) { // +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) + From 00549c9ad28495aec90b7f85fc3a65ddfac524ee Mon Sep 17 00:00:00 2001 From: Yida Lin Date: Fri, 27 Dec 2024 23:03:03 -0800 Subject: [PATCH 07/37] read_bin --- xdf.cpp | 47 +++++++++++++++++------------------------------ 1 file changed, 17 insertions(+), 30 deletions(-) diff --git a/xdf.cpp b/xdf.cpp index 8e286b7..b0b671e 100644 --- a/xdf.cpp +++ b/xdf.cpp @@ -46,12 +46,11 @@ namespace { * \return the read data */ template -T read_bin(std::istream& is, T* obj = nullptr) +T read_bin(std::istream& is) { - T dummy; - if (!obj) obj = &dummy; - is.read(reinterpret_cast(obj), sizeof(T)); - return *obj; + T obj; + is.read(reinterpret_cast(&obj), sizeof(T)); + return obj; } template @@ -119,10 +118,8 @@ int Xdf::load_xdf(std::string filename) if (ChLen == 0) break; - uint16_t tag; //read tag of the chunk, 6 possibilities - read_bin(file, &tag); - - switch (tag) + //read tag of the chunk, 6 possibilities + switch (const auto tag = read_bin(file); tag) { case 1: //[FileHeader] { @@ -144,9 +141,9 @@ int Xdf::load_xdf(std::string filename) case 2: //read [StreamHeader] chunk { //read [StreamID] - uint32_t streamID; + const auto streamID = read_bin(file); int index; - read_bin(file, &streamID); + std::vector::iterator it{std::find(idmap.begin(), idmap.end(), streamID)}; if (it == idmap.end()) { @@ -234,9 +231,8 @@ int Xdf::load_xdf(std::string filename) case 3: //read [Samples] chunk { //read [StreamID] - uint32_t streamID; + const auto streamID = read_bin(file); int index; - read_bin(file, &streamID); std::vector::iterator it{std::find(idmap.begin(), idmap.end(), streamID)}; if (it == idmap.end()) { @@ -261,7 +257,7 @@ int Xdf::load_xdf(std::string filename) if (tsBytes == 8) { - read_bin(file, &ts); + ts = read_bin(file); streams[index].time_stamps.emplace_back(ts); } else @@ -294,9 +290,8 @@ int Xdf::load_xdf(std::string filename) break; case 4: //read [ClockOffset] chunk { - uint32_t streamID; + const auto streamID = read_bin(file); int index; - read_bin(file, &streamID); std::vector::iterator it{std::find(idmap.begin(), idmap.end(), streamID)}; if (it == idmap.end()) { @@ -307,15 +302,11 @@ int Xdf::load_xdf(std::string filename) else index = std::distance(idmap.begin(), it); + const auto collection_time = read_bin(file); + const auto offset_value = read_bin(file); - double collectionTime; - double offsetValue; - - read_bin(file, &collectionTime); - read_bin(file, &offsetValue); - - streams[index].clock_times.emplace_back(collectionTime); - streams[index].clock_values.emplace_back(offsetValue); + streams[index].clock_times.push_back(collection_time); + streams[index].clock_values.push_back(offset_value); } break; case 6: //read [StreamFooter] chunk @@ -323,9 +314,8 @@ int Xdf::load_xdf(std::string filename) pugi::xml_document doc; //read [StreamID] - uint32_t streamID; + const auto streamID = read_bin(file); int index; - read_bin(file, &streamID); std::vector::iterator it{std::find(idmap.begin(), idmap.end(), streamID)}; if (it == idmap.end()) { @@ -609,11 +599,8 @@ void Xdf::resample(int userSrate) //function of reading the length of each chunk uint64_t Xdf::readLength(std::ifstream& file) { - uint8_t bytes = 0; - read_bin(file, &bytes); uint64_t length = 0; - - switch (bytes) + switch (const auto bytes = read_bin(file); bytes) { case 1: length = read_bin(file); From 1966de971252bfb8629d349a44d251ab58331606 Mon Sep 17 00:00:00 2001 From: Yida Lin Date: Fri, 27 Dec 2024 23:04:09 -0800 Subject: [PATCH 08/37] move --- xdf.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/xdf.cpp b/xdf.cpp index b0b671e..f8a57af 100644 --- a/xdf.cpp +++ b/xdf.cpp @@ -57,7 +57,7 @@ template void read_time_series(std::istream& is, std::vector>* time_series) { for (size_t v = 0; v < time_series->size(); ++v) { - (*time_series)[v].push_back(read_bin(is)); + (*time_series)[v].push_back(std::move(read_bin(is))); } } From aacba8da66756e70afd6df68b3cfc6e9a990c41b Mon Sep 17 00:00:00 2001 From: Yida Lin Date: Fri, 27 Dec 2024 23:05:46 -0800 Subject: [PATCH 09/37] foreach --- xdf.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/xdf.cpp b/xdf.cpp index f8a57af..3acc935 100644 --- a/xdf.cpp +++ b/xdf.cpp @@ -55,9 +55,9 @@ T read_bin(std::istream& is) template void read_time_series(std::istream& is, std::vector>* time_series) { - for (size_t v = 0; v < time_series->size(); ++v) + for (std::vector& row : *time_series) { - (*time_series)[v].push_back(std::move(read_bin(is))); + row.push_back(std::move(read_bin(is))); } } From c0d0202ce5684779c1b0e1bc6022fb880b93b268 Mon Sep 17 00:00:00 2001 From: Yida Lin Date: Fri, 27 Dec 2024 23:07:57 -0800 Subject: [PATCH 10/37] stream_id --- xdf.cpp | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/xdf.cpp b/xdf.cpp index 3acc935..2a942ef 100644 --- a/xdf.cpp +++ b/xdf.cpp @@ -141,14 +141,14 @@ int Xdf::load_xdf(std::string filename) case 2: //read [StreamHeader] chunk { //read [StreamID] - const auto streamID = read_bin(file); + const auto stream_id = read_bin(file); int index; - std::vector::iterator it{std::find(idmap.begin(), idmap.end(), streamID)}; + std::vector::iterator it{std::find(idmap.begin(), idmap.end(), stream_id)}; if (it == idmap.end()) { index = idmap.size(); - idmap.emplace_back(streamID); + idmap.emplace_back(stream_id); streams.emplace_back(); } else @@ -231,13 +231,13 @@ int Xdf::load_xdf(std::string filename) case 3: //read [Samples] chunk { //read [StreamID] - const auto streamID = read_bin(file); + const auto stream_id = read_bin(file); int index; - std::vector::iterator it{std::find(idmap.begin(), idmap.end(), streamID)}; + std::vector::iterator it{std::find(idmap.begin(), idmap.end(), stream_id)}; if (it == idmap.end()) { index = idmap.size(); - idmap.emplace_back(streamID); + idmap.emplace_back(stream_id); streams.emplace_back(); } else @@ -290,13 +290,13 @@ int Xdf::load_xdf(std::string filename) break; case 4: //read [ClockOffset] chunk { - const auto streamID = read_bin(file); + const auto stream_id = read_bin(file); int index; - std::vector::iterator it{std::find(idmap.begin(), idmap.end(), streamID)}; + std::vector::iterator it{std::find(idmap.begin(), idmap.end(), stream_id)}; if (it == idmap.end()) { index = idmap.size(); - idmap.emplace_back(streamID); + idmap.emplace_back(stream_id); streams.emplace_back(); } else @@ -314,13 +314,13 @@ int Xdf::load_xdf(std::string filename) pugi::xml_document doc; //read [StreamID] - const auto streamID = read_bin(file); + const auto stream_id = read_bin(file); int index; - std::vector::iterator it{std::find(idmap.begin(), idmap.end(), streamID)}; + std::vector::iterator it{std::find(idmap.begin(), idmap.end(), stream_id)}; if (it == idmap.end()) { index = idmap.size(); - idmap.emplace_back(streamID); + idmap.emplace_back(stream_id); streams.emplace_back(); } else From fd57357c4ab451dd52da602384956a49bfdef124 Mon Sep 17 00:00:00 2001 From: Yida Lin Date: Fri, 27 Dec 2024 23:13:50 -0800 Subject: [PATCH 11/37] == string --- xdf.cpp | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/xdf.cpp b/xdf.cpp index 2a942ef..bdacd35 100644 --- a/xdf.cpp +++ b/xdf.cpp @@ -190,36 +190,36 @@ int Xdf::load_xdf(std::string filename) Stream& stream = streams[index]; const int channel_count = stream.info.channel_count; if (const std::string_view channel_format = stream.info.channel_format; - channel_format.compare("string") == 0) + channel_format == "string") { stream.time_series = std::vector>( channel_count); } - else if (channel_format.compare("float32") == 0) + else if (channel_format == "float32") { stream.time_series = std::vector>( channel_count); } - else if (channel_format.compare("double64") == 0) + else if (channel_format == "double64") { stream.time_series = std::vector>( channel_count); } - else if (channel_format.compare("int8_t") == 0) + else if (channel_format == "int8_t") { stream.time_series = std::vector>( channel_count); } - else if (channel_format.compare("int16_t") == 0) + else if (channel_format == "int16_t") { stream.time_series = std::vector>( channel_count); } - else if (channel_format.compare("int32_t") == 0) + else if (channel_format == "int32_t") { stream.time_series = std::vector>(channel_count); } - else if (channel_format.compare("int64_t") == 0) + else if (channel_format == "int64_t") { stream.time_series = std::vector>( channel_count); @@ -447,7 +447,7 @@ void Xdf::syncTimeStamps() // Update first and last time stamps in stream footer for (size_t k = 0; k < this->streams.size(); k++) { - if (streams[k].info.channel_format.compare("string") == 0) + if (streams[k].info.channel_format == "string") { double min = NAN; double max = NAN; @@ -493,7 +493,7 @@ void Xdf::resample(int userSrate) for (Stream& stream : streams) { if (stream.time_series.index() != std::variant_npos && - !stream.info.channel_format.compare("string") && + stream.info.channel_format != "string" && stream.info.nominal_srate != userSrate && stream.info.nominal_srate != 0) { @@ -702,7 +702,7 @@ void Xdf::calcTotalChannel() for (size_t c = 0; c < streams.size(); c++) { if (streams[c].time_series.index() != std::variant_npos && - streams[c].info.channel_format.compare("string") != 0) + streams[c].info.channel_format != "string") { numerical_channel_count_ += streams[c].info.channel_count; @@ -740,7 +740,7 @@ void Xdf::adjustTotalLength() for (auto const& stream : streams) { if (stream.time_series.index() != std::variant_npos && - stream.info.channel_format.compare("string") != 0) + stream.info.channel_format != "string") { std::visit([this](auto&& time_series) { totalLen = std::max(totalLen, time_series.front().size()); From bcd9eb3240c3d40abfdcbfbbc86bf89d4f016340 Mon Sep 17 00:00:00 2001 From: Yida Lin Date: Fri, 27 Dec 2024 23:23:21 -0800 Subject: [PATCH 12/37] const --- xdf.cpp | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/xdf.cpp b/xdf.cpp index bdacd35..ea753b8 100644 --- a/xdf.cpp +++ b/xdf.cpp @@ -187,6 +187,8 @@ int Xdf::load_xdf(std::string filename) else streams[index].sampling_interval = 0; + delete[] buffer; + Stream& stream = streams[index]; const int channel_count = stream.info.channel_count; if (const std::string_view channel_format = stream.info.channel_format; @@ -224,8 +226,6 @@ int Xdf::load_xdf(std::string filename) stream.time_series = std::vector>( channel_count); } - - delete[] buffer; } break; case 3: //read [Samples] chunk @@ -251,7 +251,7 @@ int Xdf::load_xdf(std::string filename) for (size_t i = 0; i < numSamp; i++) { //read or deduce time stamp - auto tsBytes = read_bin(file); + const auto tsBytes = read_bin(file); double ts; //temporary time stamp @@ -270,11 +270,12 @@ int Xdf::load_xdf(std::string filename) Stream& stream = streams[index]; std::visit([this, &file](auto&& arg) { - using T = std::decay_t; + using T = typename std::remove_reference_t + ::value_type::value_type; if constexpr (std::is_same_v) { for (int v = 0; v < arg.size(); ++v) { - auto length = Xdf::readLength(file); + const auto length = Xdf::readLength(file); char* buffer = new char[length + 1]; file.read(buffer, length); buffer[length] = '\0'; @@ -513,9 +514,10 @@ void Xdf::resample(int userSrate) // initialize smarc filter state struct PState* pstate = smarc_init_pstate(pfilt); - std::visit([&pfilt, &pstate](auto&& arg) { - using T = typename std::decay_t::value_type::value_type; - for (std::vector& row : arg) + std::visit([&pfilt, &pstate](auto&& time_series) { + using T = typename std::remove_reference_t + ::value_type::value_type; + for (std::vector& row : time_series) { // initialize buffers int read = 0; From 01e446d6b898ba5d4017abdb6b83a1f4e1db25b9 Mon Sep 17 00:00:00 2001 From: Yida Lin Date: Fri, 27 Dec 2024 23:24:28 -0800 Subject: [PATCH 13/37] nodiscard --- xdf.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/xdf.cpp b/xdf.cpp index ea753b8..26d48b9 100644 --- a/xdf.cpp +++ b/xdf.cpp @@ -46,7 +46,7 @@ namespace { * \return the read data */ template -T read_bin(std::istream& is) +[[nodiscard]] T read_bin(std::istream& is) { T obj; is.read(reinterpret_cast(&obj), sizeof(T)); From 6c310fe1274b8942e6f58f7d2c15e60af8733e65 Mon Sep 17 00:00:00 2001 From: Yida Lin Date: Fri, 27 Dec 2024 23:27:53 -0800 Subject: [PATCH 14/37] time_series --- xdf.cpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/xdf.cpp b/xdf.cpp index 26d48b9..cbed695 100644 --- a/xdf.cpp +++ b/xdf.cpp @@ -269,21 +269,21 @@ int Xdf::load_xdf(std::string filename) streams[index].last_timestamp = ts; Stream& stream = streams[index]; - std::visit([this, &file](auto&& arg) { - using T = typename std::remove_reference_t - ::value_type::value_type; + std::visit([this, &file](auto&& time_series) { + using T = typename std::remove_reference_t + ::value_type::value_type; if constexpr (std::is_same_v) { - for (int v = 0; v < arg.size(); ++v) + for (std::vector& row : time_series) { - const auto length = Xdf::readLength(file); + const uint64_t length = Xdf::readLength(file); char* buffer = new char[length + 1]; file.read(buffer, length); buffer[length] = '\0'; - arg[v].emplace_back(buffer); + row.emplace_back(buffer); delete[] buffer; } } else { - read_time_series(file, &arg); + read_time_series(file, &time_series); } }, stream.time_series); } From 15d79737465e38fad6b9ad869705e0081c99c9b2 Mon Sep 17 00:00:00 2001 From: Yida Lin Date: Fri, 27 Dec 2024 23:50:04 -0800 Subject: [PATCH 15/37] fix --- xdf.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/xdf.h b/xdf.h index 035b856..6786273 100644 --- a/xdf.h +++ b/xdf.h @@ -104,7 +104,7 @@ class Xdf double minTS = 0; /*!< The smallest time stamp across all streams. */ double maxTS = 0; /*!< The largest time stamp across all streams. */ - size_t numerical_channel_count_ = 0; /*!< The total number of numericla channels. */ + size_t numerical_channel_count_ = 0; /*!< The total number of numerical channels. */ int majSR = 0; /*!< The sample rate that has the most channels across all streams. */ int maxSR = 0; /*!< Highest sample rate across all streams. */ std::vector effectiveSampleRateVector; /*!< Effective Sample Rate of each stream. */ From 2ab0489331ec5011989715cb5054120d1f1a1eb4 Mon Sep 17 00:00:00 2001 From: Yida Lin Date: Sat, 28 Dec 2024 06:57:09 -0800 Subject: [PATCH 16/37] channel_format --- xdf.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/xdf.cpp b/xdf.cpp index cbed695..3601f5d 100644 --- a/xdf.cpp +++ b/xdf.cpp @@ -226,6 +226,10 @@ int Xdf::load_xdf(std::string filename) stream.time_series = std::vector>( channel_count); } + else { + throw std::runtime_error("Unexpected channel format: " + + std::string(channel_format)); + } } break; case 3: //read [Samples] chunk From d30cea4a7c1579f4a2e7aba863cd49dc888656d7 Mon Sep 17 00:00:00 2001 From: Yida Lin Date: Sat, 28 Dec 2024 11:16:04 -0800 Subject: [PATCH 17/37] cleanup --- .vscode/settings.json | 3 --- 1 file changed, 3 deletions(-) delete mode 100644 .vscode/settings.json diff --git a/.vscode/settings.json b/.vscode/settings.json deleted file mode 100644 index 4ab2520..0000000 --- a/.vscode/settings.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "C_Cpp.default.compilerPath": "c:\\Qt\\Tools\\mingw730_64\\bin\\g++.exe" -} \ No newline at end of file From 6cd76329c7e841302eb2ff836fa319f360bb75bc Mon Sep 17 00:00:00 2001 From: Yida Lin Date: Sat, 28 Dec 2024 19:54:14 -0800 Subject: [PATCH 18/37] read_length --- xdf.cpp | 82 +++++++++++++++++++++++++++++---------------------------- xdf.h | 11 -------- 2 files changed, 42 insertions(+), 51 deletions(-) diff --git a/xdf.cpp b/xdf.cpp index 3601f5d..05a0b91 100644 --- a/xdf.cpp +++ b/xdf.cpp @@ -53,8 +53,46 @@ template return obj; } + +/*! + * \brief Returns the length of the upcoming chunk, or the number of samples. + * + * While loading XDF file there are 2 cases where this function will be + * needed. One is to get the length of each chunk, one is to get the + * number of samples when loading the time series (Chunk tag 3). + * \param file is the XDF file that is being loaded in the type of `std::ifstream`. + * \return The length of the upcoming chunk (in bytes). + */ +uint64_t read_length(std::istream& is) +{ + switch (const auto bytes = read_bin(is); bytes) + { + case 1: + return read_bin(is); + case 4: + return read_bin(is); + case 8: + return read_bin(is); + default: + throw std::runtime_error("Invalid variable-length integer length: " + + std::to_string(static_cast(bytes))); + } +} + template void read_time_series(std::istream& is, std::vector>* time_series) { + if constexpr (std::is_same_v) { + for (std::vector& row : *time_series) + { + const uint64_t length = read_length(is); + char* buffer = new char[length + 1]; + is.read(buffer, length); + buffer[length] = '\0'; + row.emplace_back(buffer); + delete[] buffer; + } + return; + } for (std::vector& row : *time_series) { row.push_back(std::move(read_bin(is))); @@ -113,7 +151,7 @@ int Xdf::load_xdf(std::string filename) //for each chunk while (1) { - uint64_t ChLen = readLength(file); //chunk length + uint64_t ChLen = read_length(file); //chunk length if (ChLen == 0) break; @@ -249,7 +287,7 @@ int Xdf::load_xdf(std::string filename) //read [NumSampleBytes], [NumSamples] - uint64_t numSamp = readLength(file); + uint64_t numSamp = read_length(file); //for each sample for (size_t i = 0; i < numSamp; i++) @@ -273,22 +311,10 @@ int Xdf::load_xdf(std::string filename) streams[index].last_timestamp = ts; Stream& stream = streams[index]; - std::visit([this, &file](auto&& time_series) { + std::visit([&file](auto&& time_series) { using T = typename std::remove_reference_t ::value_type::value_type; - if constexpr (std::is_same_v) { - for (std::vector& row : time_series) - { - const uint64_t length = Xdf::readLength(file); - char* buffer = new char[length + 1]; - file.read(buffer, length); - buffer[length] = '\0'; - row.emplace_back(buffer); - delete[] buffer; - } - } else { - read_time_series(file, &time_series); - } + read_time_series(file, &time_series); }, stream.time_series); } } @@ -602,30 +628,6 @@ void Xdf::resample(int userSrate) << " resampling" << std::endl; } -//function of reading the length of each chunk -uint64_t Xdf::readLength(std::ifstream& file) -{ - uint64_t length = 0; - switch (const auto bytes = read_bin(file); bytes) - { - case 1: - length = read_bin(file); - break; - case 4: - length = read_bin(file); - break; - case 8: - length = read_bin(file); - break; - default: - std::cout << "Invalid variable-length integer length (" - << static_cast(bytes) << ") encountered.\n"; - return 0; - } - - return length; -} - void Xdf::findMinMax() { //find the smallest timestamp of all streams diff --git a/xdf.h b/xdf.h index 6786273..56c5c3b 100644 --- a/xdf.h +++ b/xdf.h @@ -297,17 +297,6 @@ class Xdf * \sa sampleRateMap */ void loadSampleRateMap(); - - /*! - * \brief This function will get the length of the upcoming chunk, or the number of samples. - * - * While loading XDF file there are 2 cases where this function will be - * needed. One is to get the length of each chunk, one is to get the - * number of samples when loading the time series (Chunk tag 3). - * \param file is the XDF file that is being loaded in the type of `std::ifstream`. - * \return The length of the upcoming chunk (in bytes). - */ - uint64_t readLength(std::ifstream &file); }; } // namespace xdf From d6266bda2cddc4370f6c044331578220561c9f8c Mon Sep 17 00:00:00 2001 From: Yida Lin Date: Sat, 28 Dec 2024 19:57:00 -0800 Subject: [PATCH 19/37] index --- xdf.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/xdf.cpp b/xdf.cpp index 05a0b91..ef1cb7c 100644 --- a/xdf.cpp +++ b/xdf.cpp @@ -309,13 +309,12 @@ int Xdf::load_xdf(std::string filename) } streams[index].last_timestamp = ts; - Stream& stream = streams[index]; std::visit([&file](auto&& time_series) { using T = typename std::remove_reference_t ::value_type::value_type; read_time_series(file, &time_series); - }, stream.time_series); + }, streams[index].time_series); } } break; From d3bc0ff1af1160b70c4b7be8695696a0551b18bb Mon Sep 17 00:00:00 2001 From: Yida Lin Date: Sat, 28 Dec 2024 20:37:58 -0800 Subject: [PATCH 20/37] emplace --- xdf.cpp | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/xdf.cpp b/xdf.cpp index ef1cb7c..10d6c80 100644 --- a/xdf.cpp +++ b/xdf.cpp @@ -232,37 +232,38 @@ int Xdf::load_xdf(std::string filename) if (const std::string_view channel_format = stream.info.channel_format; channel_format == "string") { - stream.time_series = std::vector>( + stream.time_series.emplace>>( channel_count); } else if (channel_format == "float32") { - stream.time_series = std::vector>( + stream.time_series.emplace>>( channel_count); } else if (channel_format == "double64") { - stream.time_series = std::vector>( + stream.time_series.emplace>>( channel_count); } else if (channel_format == "int8_t") { - stream.time_series = std::vector>( + stream.time_series.emplace>>( channel_count); } else if (channel_format == "int16_t") { - stream.time_series = std::vector>( + stream.time_series.emplace>>( channel_count); } else if (channel_format == "int32_t") { - stream.time_series = std::vector>(channel_count); + stream.time_series.emplace>>( + channel_count); } else if (channel_format == "int64_t") { - stream.time_series = std::vector>( - channel_count); + stream.time_series.emplace>>( + channel_count); } else { throw std::runtime_error("Unexpected channel format: " From 5f967d6e6361b99fef51f615ae294520fc35e4c6 Mon Sep 17 00:00:00 2001 From: Yida Lin Date: Sat, 28 Dec 2024 23:08:34 -0800 Subject: [PATCH 21/37] detrend --- xdf.cpp | 39 ++++++++++++++++++++++++--------------- 1 file changed, 24 insertions(+), 15 deletions(-) diff --git a/xdf.cpp b/xdf.cpp index 10d6c80..f6652ad 100644 --- a/xdf.cpp +++ b/xdf.cpp @@ -772,21 +772,30 @@ void Xdf::loadSampleRateMap() 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 (Stream &stream : streams) + { + std::visit([this](auto&& time_series) { + using T = typename std::remove_reference_t + ::value_type::value_type; + if constexpr (std::is_arithmetic_v) { + for (auto& row : 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.push_back(mean); + } + } + }, stream.time_series); + } +} + void Xdf::calcEffectiveSrate() { From 5331114fc3468ed9e68188fc3603531757ae9210 Mon Sep 17 00:00:00 2001 From: Yida Lin Date: Sat, 28 Dec 2024 23:12:02 -0800 Subject: [PATCH 22/37] cleanup --- xdf.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/xdf.cpp b/xdf.cpp index f6652ad..ee1d326 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,16 +20,16 @@ #include #include -#include "pugixml.hpp" //pugi XML parser #include #include -#include "smarc/smarc.h" //resampling library #include /* clock_t, clock, CLOCKS_PER_SEC */ #include //std::accumulate -#include // bind2nd #include #include +#include "pugixml.hpp" //pugi XML parser +#include "smarc/smarc.h" //resampling library + namespace xdf { namespace { From b70a0d85e0505f2b11d84edd3d765de17d8b9dfc Mon Sep 17 00:00:00 2001 From: Yida Lin Date: Sat, 28 Dec 2024 23:15:59 -0800 Subject: [PATCH 23/37] decay --- xdf.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/xdf.cpp b/xdf.cpp index ee1d326..00ed998 100644 --- a/xdf.cpp +++ b/xdf.cpp @@ -312,8 +312,8 @@ int Xdf::load_xdf(std::string filename) streams[index].last_timestamp = ts; std::visit([&file](auto&& time_series) { - using T = typename std::remove_reference_t - ::value_type::value_type; + using T = typename std::decay_t + ::value_type::value_type; read_time_series(file, &time_series); }, streams[index].time_series); } @@ -545,7 +545,7 @@ void Xdf::resample(int userSrate) struct PState* pstate = smarc_init_pstate(pfilt); std::visit([&pfilt, &pstate](auto&& time_series) { - using T = typename std::remove_reference_t + using T = typename std::decay_t ::value_type::value_type; for (std::vector& row : time_series) { @@ -778,7 +778,7 @@ void Xdf::detrend() for (Stream &stream : streams) { std::visit([this](auto&& time_series) { - using T = typename std::remove_reference_t + using T = typename std::decay_t ::value_type::value_type; if constexpr (std::is_arithmetic_v) { for (auto& row : time_series) From 758a94373f8150116eaec30a9f25582bb5ca48ed Mon Sep 17 00:00:00 2001 From: Yida Lin Date: Sat, 28 Dec 2024 23:40:11 -0800 Subject: [PATCH 24/37] event map --- xdf.cpp | 96 +++++++++------------------------------------------------ xdf.h | 25 ++++++--------- 2 files changed, 23 insertions(+), 98 deletions(-) diff --git a/xdf.cpp b/xdf.cpp index 00ed998..1e013c8 100644 --- a/xdf.cpp +++ b/xdf.cpp @@ -402,12 +402,10 @@ int Xdf::load_xdf(std::string filename) getHighestSampleRate(); - loadSampleRateMap(); + loadSampleRateSet(); calcTotalChannel(); - loadDictionary(); - calcEffectiveSrate(); //loading finishes, close file @@ -425,7 +423,7 @@ int Xdf::load_xdf(std::string filename) void Xdf::syncTimeStamps() { // Sync time stamps - for (auto& stream : this->streams) + for (Stream& stream : streams) { if (!stream.clock_times.empty()) { @@ -451,64 +449,13 @@ void Xdf::syncTimeStamps() } } - // Sync event time stamps - 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 - - while (k < this->streams[elem.second].clock_times.size() - 1) - { - if (this->streams[elem.second].clock_times[k + 1] < elem.first.second) - { - k++; - } - else - { - break; - } - } - - 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 - } - } - // Update first and last time stamps in stream footer - for (size_t k = 0; k < this->streams.size(); k++) + for (Stream& stream : streams) { - if (streams[k].info.channel_format == "string") - { - double min = NAN; - double max = NAN; - - for (auto const& elem : this->eventMap) - { - if (elem.second == (int)k) - { - if (std::isnan(min) || elem.first.second < min) - { - min = elem.first.second; - } - - if (std::isnan(max) || elem.first.second > max) - { - max = elem.first.second; - } - } - } - - streams[k].info.first_timestamp = min; - streams[k].info.last_timestamp = max; - } - else + if (stream.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(); - } + stream.info.first_timestamp = stream.time_stamps.front(); + stream.info.last_timestamp = stream.time_stamps.back(); } } } @@ -766,10 +713,15 @@ void Xdf::getHighestSampleRate() } } -void Xdf::loadSampleRateMap() +void Xdf::loadSampleRateSet() { - for (auto const& stream : streams) - sampleRateMap.emplace(stream.info.nominal_srate); + for (const Stream& stream : streams) + { + if (stream.info.channel_format != "string") + { + sample_rates.insert(stream.info.nominal_srate); + } + } } @@ -985,24 +937,4 @@ void Xdf::createLabels() } } -void Xdf::loadDictionary() -{ - //loop through the 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); - //if it isn't yet - if (it == dictionary.end()) - { - //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 - eventType.emplace_back(std::distance(dictionary.begin(), it)); - } -} - } // namespace xdf diff --git a/xdf.h b/xdf.h index 56c5c3b..b654ab2 100644 --- a/xdf.h +++ b/xdf.h @@ -25,7 +25,7 @@ #include #include #include -#include +#include #include #include @@ -125,12 +125,12 @@ class Xdf */ typedef double eventTimeStamp; - std::vector, int> > eventMap;/*!< The vector to store all the events across all streams. - * The format is <, streamNum>. */ - std::vector dictionary;/*!< The vector to store unique event types with no repetitions. \sa eventMap */ - std::vector eventType; /*!< The vector to store events by their index in the dictionary.\sa dictionary, eventMap */ + // std::vector, int> > eventMap;/*!< The vector to store all the events across all streams. + // * The format is <, streamNum>. */ + // std::vector dictionary;/*!< The vector to store unique event types with no repetitions. \sa eventMap */ + // std::vector eventType; /*!< The vector to store events by their index in the dictionary.\sa dictionary, eventMap */ std::vector labels; /*!< The vector to store descriptive labels of each channel. */ - std::set sampleRateMap; /*!< The vector to store all sample rates across all the streams. */ + std::unordered_set sample_rates; /*!< The vector to store all sample rates across all the streams. */ std::vector offsets; /*!< Offsets of each channel after using subtractMean() function */ std::string fileHeader; /*!< Raw XML of the file header. */ @@ -284,19 +284,12 @@ class Xdf */ void getHighestSampleRate(); - /*! - * \brief Copy all unique types of events from _eventMap_ to - * _dictionary_ with no repeats. - * \sa dictionary, eventMap - */ - void loadDictionary(); - /*! * \brief Load every sample rate appeared in the current file into - * member variable `sampleRateMap`. - * \sa sampleRateMap + * member variable `sample_rates`. + * \sa sampleRateSet */ - void loadSampleRateMap(); + void loadSampleRateSet(); }; } // namespace xdf From 07c5e8a0d0e1b0578a3fcd787f0e21b482dded2a Mon Sep 17 00:00:00 2001 From: Yida Lin Date: Sat, 28 Dec 2024 23:44:52 -0800 Subject: [PATCH 25/37] cleanup --- xdf.cpp | 7 +------ xdf.h | 6 +----- 2 files changed, 2 insertions(+), 11 deletions(-) diff --git a/xdf.cpp b/xdf.cpp index 1e013c8..4272e85 100644 --- a/xdf.cpp +++ b/xdf.cpp @@ -63,7 +63,7 @@ template * \param file is the XDF file that is being loaded in the type of `std::ifstream`. * \return The length of the upcoming chunk (in bytes). */ -uint64_t read_length(std::istream& is) +[[nodiscard]] uint64_t read_length(std::istream& is) { switch (const auto bytes = read_bin(is); bytes) { @@ -101,10 +101,6 @@ void read_time_series(std::istream& is, std::vector>* time_series } // namespace -Xdf::Xdf() -{ -} - int Xdf::load_xdf(std::string filename) { clock_t time; @@ -724,7 +720,6 @@ void Xdf::loadSampleRateSet() } } - void Xdf::detrend() { for (Stream &stream : streams) diff --git a/xdf.h b/xdf.h index b654ab2..de54dee 100644 --- a/xdf.h +++ b/xdf.h @@ -42,7 +42,7 @@ class Xdf { public: //! Default constructor with no parameter. - Xdf(); + explicit Xdf() = default; //subclass for single streams /*! \class Stream @@ -125,10 +125,6 @@ class Xdf */ typedef double eventTimeStamp; - // std::vector, int> > eventMap;/*!< The vector to store all the events across all streams. - // * The format is <, streamNum>. */ - // std::vector dictionary;/*!< The vector to store unique event types with no repetitions. \sa eventMap */ - // std::vector eventType; /*!< The vector to store events by their index in the dictionary.\sa dictionary, eventMap */ std::vector labels; /*!< The vector to store descriptive labels of each channel. */ std::unordered_set sample_rates; /*!< The vector to store all sample rates across all the streams. */ std::vector offsets; /*!< Offsets of each channel after using subtractMean() function */ From 52500239b3134663f5ded6fb19afb951d91ed237 Mon Sep 17 00:00:00 2001 From: Yida Lin Date: Sat, 28 Dec 2024 23:56:28 -0800 Subject: [PATCH 26/37] stream --- xdf.cpp | 143 ++++++++++++++++---------------------------------------- xdf.h | 25 ++-------- 2 files changed, 46 insertions(+), 122 deletions(-) diff --git a/xdf.cpp b/xdf.cpp index 4272e85..545fb12 100644 --- a/xdf.cpp +++ b/xdf.cpp @@ -176,54 +176,42 @@ int Xdf::load_xdf(std::string filename) { //read [StreamID] const auto stream_id = read_bin(file); - int index; - - std::vector::iterator it{std::find(idmap.begin(), idmap.end(), stream_id)}; - if (it == idmap.end()) - { - index = idmap.size(); - idmap.emplace_back(stream_id); - streams.emplace_back(); - } - else - index = std::distance(idmap.begin(), it); - pugi::xml_document doc; + Stream& stream = streams[stream_id]; //read [Content] char* buffer = new char[ChLen - 6]; file.read(buffer, ChLen - 6); - streams[index].streamHeader = buffer; + stream.streamHeader = buffer; doc.load_buffer_inplace(buffer, ChLen - 6); 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(); + stream.info.channel_count = info.child("channel_count").text().as_int(); + stream.info.nominal_srate = info.child("nominal_srate").text().as_double(); + stream.info.name = info.child("name").text().get(); + stream.info.type = info.child("type").text().get(); + stream.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(); + stream.info.channels.emplace_back(); for (auto const& entry : channel.children()) - streams[index].info.channels.back().emplace(entry.name(), entry.child_value()); + stream.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; + if (stream.info.nominal_srate > 0) + stream.sampling_interval = 1 / stream.info.nominal_srate; else - streams[index].sampling_interval = 0; + stream.sampling_interval = 0; delete[] buffer; - Stream& stream = streams[index]; const int channel_count = stream.info.channel_count; if (const std::string_view channel_format = stream.info.channel_format; channel_format == "string") @@ -271,20 +259,9 @@ int Xdf::load_xdf(std::string filename) { //read [StreamID] const auto stream_id = read_bin(file); - int index; - std::vector::iterator it{std::find(idmap.begin(), idmap.end(), stream_id)}; - if (it == idmap.end()) - { - index = idmap.size(); - idmap.emplace_back(stream_id); - streams.emplace_back(); - } - else - index = std::distance(idmap.begin(), it); - - //read [NumSampleBytes], [NumSamples] - uint64_t numSamp = read_length(file); + const uint64_t numSamp = read_length(file); + Stream& stream = streams[stream_id]; //for each sample for (size_t i = 0; i < numSamp; i++) @@ -297,43 +274,33 @@ int Xdf::load_xdf(std::string filename) if (tsBytes == 8) { ts = read_bin(file); - streams[index].time_stamps.emplace_back(ts); + stream.time_stamps.emplace_back(ts); } else { - ts = streams[index].last_timestamp + streams[index].sampling_interval; - streams[index].time_stamps.emplace_back(ts); + ts = stream.last_timestamp + stream.sampling_interval; + stream.time_stamps.emplace_back(ts); } - streams[index].last_timestamp = ts; + stream.last_timestamp = ts; std::visit([&file](auto&& time_series) { using T = typename std::decay_t ::value_type::value_type; read_time_series(file, &time_series); - }, streams[index].time_series); + }, stream.time_series); } } break; case 4: //read [ClockOffset] chunk { const auto stream_id = read_bin(file); - int index; - std::vector::iterator it{std::find(idmap.begin(), idmap.end(), stream_id)}; - if (it == idmap.end()) - { - index = idmap.size(); - idmap.emplace_back(stream_id); - streams.emplace_back(); - } - else - index = std::distance(idmap.begin(), it); - const auto collection_time = read_bin(file); const auto offset_value = read_bin(file); - streams[index].clock_times.push_back(collection_time); - streams[index].clock_values.push_back(offset_value); + Stream& stream = streams[stream_id]; + stream.clock_times.push_back(collection_time); + stream.clock_values.push_back(offset_value); } break; case 6: //read [StreamFooter] chunk @@ -342,30 +309,20 @@ int Xdf::load_xdf(std::string filename) //read [StreamID] const auto stream_id = read_bin(file); - int index; - std::vector::iterator it{std::find(idmap.begin(), idmap.end(), stream_id)}; - if (it == idmap.end()) - { - index = idmap.size(); - idmap.emplace_back(stream_id); - streams.emplace_back(); - } - else - index = std::distance(idmap.begin(), it); - + Stream& stream = streams[stream_id]; char* buffer = new char[ChLen - 6]; file.read(buffer, ChLen - 6); - streams[index].streamFooter = buffer; + stream.streamFooter = buffer; doc.load_buffer_inplace(buffer, ChLen - 6); 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(); + stream.info.first_timestamp = info.child("first_timestamp").text().as_double(); + stream.info.last_timestamp = info.child("last_timestamp").text().as_double(); + stream.info.measured_srate = info.child("measured_srate").text().as_double(); + stream.info.sample_count = info.child("sample_count").text().as_int(); delete[] buffer; } break; @@ -400,8 +357,6 @@ int Xdf::load_xdf(std::string filename) loadSampleRateSet(); - calcTotalChannel(); - calcEffectiveSrate(); //loading finishes, close file @@ -419,7 +374,7 @@ int Xdf::load_xdf(std::string filename) void Xdf::syncTimeStamps() { // Sync time stamps - for (Stream& stream : streams) + for (auto& [stream_id, stream] : streams) { if (!stream.clock_times.empty()) { @@ -446,7 +401,7 @@ void Xdf::syncTimeStamps() } // Update first and last time stamps in stream footer - for (Stream& stream : streams) + for (auto& [stream_id, stream] : streams) { if (stream.time_stamps.size() > 0) { @@ -464,7 +419,7 @@ void Xdf::resample(int userSrate) clock_t time = clock(); #define BUF_SIZE 8192 - for (Stream& stream : streams) + for (auto& [stream_id, stream] : streams) { if (stream.time_series.index() != std::variant_npos && stream.info.channel_format != "string" && @@ -574,7 +529,7 @@ void Xdf::resample(int userSrate) void Xdf::findMinMax() { //find the smallest timestamp of all streams - for (auto const& stream : streams) + for (const auto& [stream_id, stream] : streams) { if (!std::isnan(stream.info.first_timestamp)) { @@ -582,14 +537,14 @@ void Xdf::findMinMax() break; } } - for (auto const& stream : streams) + for (const auto& [stream_id, 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 (const auto& [stream_id, stream] : streams) { if (!std::isnan(stream.info.last_timestamp) && stream.info.last_timestamp > maxTS) maxTS = stream.info.last_timestamp; @@ -605,7 +560,7 @@ void Xdf::findMajSR() std::vector> srateMap; // pairs of all the streams //find out whether a sample rate already exists in srateMap - for (auto const& stream : streams) + for (const auto& [stream_id, stream] : streams) { if (stream.info.nominal_srate != 0) { @@ -647,22 +602,6 @@ void Xdf::findMajSR() } } -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.index() != std::variant_npos && - streams[c].info.channel_format != "string") - { - numerical_channel_count_ += streams[c].info.channel_count; - - for (int i = 0; i < streams[c].info.channel_count; i++) - streamMap.emplace_back(c); - } - } -} - void Xdf::calcTotalLength(int sampleRate) { totalLen = (maxTS - minTS) * sampleRate; @@ -671,7 +610,7 @@ void Xdf::calcTotalLength(int sampleRate) void Xdf::freeUpTimeStamps() { //free up as much memory as possible - for (auto& stream : streams) + for (auto& [stream_id, 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 @@ -688,7 +627,7 @@ void Xdf::freeUpTimeStamps() void Xdf::adjustTotalLength() { - for (auto const& stream : streams) + for (const auto& [stream_id, stream] : streams) { if (stream.time_series.index() != std::variant_npos && stream.info.channel_format != "string") @@ -702,7 +641,7 @@ void Xdf::adjustTotalLength() void Xdf::getHighestSampleRate() { - for (auto const& stream : streams) + for (const auto& [stream_id, stream] : streams) { if (stream.info.nominal_srate > maxSR) maxSR = stream.info.nominal_srate; @@ -711,7 +650,7 @@ void Xdf::getHighestSampleRate() void Xdf::loadSampleRateSet() { - for (const Stream& stream : streams) + for (const auto& [stream_id, stream] : streams) { if (stream.info.channel_format != "string") { @@ -722,7 +661,7 @@ void Xdf::loadSampleRateSet() void Xdf::detrend() { - for (Stream &stream : streams) + for (auto& [stream_id, stream] : streams) { std::visit([this](auto&& time_series) { using T = typename std::decay_t @@ -746,7 +685,7 @@ void Xdf::detrend() void Xdf::calcEffectiveSrate() { - for (auto& stream : streams) + for (auto& [stream_id, stream] : streams) { if (stream.info.nominal_srate) { diff --git a/xdf.h b/xdf.h index de54dee..5443482 100644 --- a/xdf.h +++ b/xdf.h @@ -22,12 +22,12 @@ #ifndef XDF_H #define XDF_H +#include #include -#include -#include +#include #include -#include #include +#include namespace xdf { @@ -77,7 +77,7 @@ class Xdf std::string type; /*!< Type of the current stream. */ std::string channel_format;/*!< Channel format of the current stream. */ - std::vector > channels;/*!< A vector to store the meta-data of the channels of the current stream. */ + std::vector > channels;/*!< A vector to store the meta-data of the channels of the current stream. */ std::vector > clock_offsets; /*!< A vector to store clock offsets from the ClockOffset chunk. */ @@ -96,7 +96,7 @@ class Xdf //XDF properties================================================================================= - std::vector streams; /*!< A vector to store all the streams of the current XDF file. */ + std::unordered_map streams; /*!< A vector to store all the streams of the current XDF file. */ float version; /*!< The version of XDF file */ uint64_t totalLen = 0; /*!< The total length is the product of the range between the smallest @@ -104,13 +104,10 @@ class Xdf double minTS = 0; /*!< The smallest time stamp across all streams. */ double maxTS = 0; /*!< The largest time stamp across all streams. */ - size_t numerical_channel_count_ = 0; /*!< The total number of numerical channels. */ int majSR = 0; /*!< The sample rate that has the most channels across all streams. */ int maxSR = 0; /*!< Highest sample rate across all streams. */ std::vector effectiveSampleRateVector; /*!< Effective Sample Rate of each stream. */ double fileEffectiveSampleRate = 0; /*!< If effective sample rates in all the streams are the same, this is the value. */ - std::vector streamMap;/*!< A vector indexes which channels belong to which stream. - * The index is the same as channel number; the actual content is the stream Number */ /*! * \brief Used as `std::vector, int> >` @@ -230,18 +227,6 @@ class Xdf */ void calcEffectiveSrate(); - /*! - * \brief Calculate the total channel count and store the result - * in `totalCh`. - * - * Channels of both regular and irregular sample rates are included. - * The streams with the channel format `string` are excluded, and are - * stored in `eventMap` instead. - * - * \sa totalCh, eventMap - */ - void calcTotalChannel(); - /*! * \brief Find the sample rate that has the most channels. * From 971e3c3da3831fcef9ef5893bf3f26eb257fdab0 Mon Sep 17 00:00:00 2001 From: Yida Lin Date: Sat, 28 Dec 2024 23:59:12 -0800 Subject: [PATCH 27/37] doc --- xdf.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/xdf.h b/xdf.h index 5443482..e19629f 100644 --- a/xdf.h +++ b/xdf.h @@ -96,7 +96,7 @@ class Xdf //XDF properties================================================================================= - std::unordered_map streams; /*!< A vector to store all the streams of the current XDF file. */ + std::unordered_map streams; /*!< Maps all stream IDs to streams in the XDF file. */ float version; /*!< The version of XDF file */ uint64_t totalLen = 0; /*!< The total length is the product of the range between the smallest From 0c64d66edb0a8bd6e76161827f0757b227f8cecc Mon Sep 17 00:00:00 2001 From: Yida Lin Date: Sun, 29 Dec 2024 00:18:30 -0800 Subject: [PATCH 28/37] size_t --- xdf.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/xdf.cpp b/xdf.cpp index 545fb12..643236d 100644 --- a/xdf.cpp +++ b/xdf.cpp @@ -633,7 +633,11 @@ void Xdf::adjustTotalLength() stream.info.channel_format != "string") { std::visit([this](auto&& time_series) { - totalLen = std::max(totalLen, time_series.front().size()); + const size_t row_length = time_series.front().size(); + if (totalLen < row_length) + { + totalLen = row_length; + } }, stream.time_series); } } From dc09e815cad36f640c0b17bf515aac0bc532afab Mon Sep 17 00:00:00 2001 From: Yida Lin Date: Sun, 29 Dec 2024 13:50:36 -0800 Subject: [PATCH 29/37] istream --- xdf.cpp | 31 ++++++++++++++++--------------- 1 file changed, 16 insertions(+), 15 deletions(-) diff --git a/xdf.cpp b/xdf.cpp index 643236d..ffbe521 100644 --- a/xdf.cpp +++ b/xdf.cpp @@ -46,10 +46,10 @@ namespace { * \return the read data */ template -[[nodiscard]] T read_bin(std::istream& is) +[[nodiscard]] T read_bin(std::istream& istream) { T obj; - is.read(reinterpret_cast(&obj), sizeof(T)); + istream.read(reinterpret_cast(&obj), sizeof(T)); return obj; } @@ -63,16 +63,16 @@ template * \param file is the XDF file that is being loaded in the type of `std::ifstream`. * \return The length of the upcoming chunk (in bytes). */ -[[nodiscard]] uint64_t read_length(std::istream& is) +[[nodiscard]] uint64_t read_length(std::istream& istream) { - switch (const auto bytes = read_bin(is); bytes) + switch (const auto bytes = read_bin(istream); bytes) { case 1: - return read_bin(is); + return read_bin(istream); case 4: - return read_bin(is); + return read_bin(istream); case 8: - return read_bin(is); + return read_bin(istream); default: throw std::runtime_error("Invalid variable-length integer length: " + std::to_string(static_cast(bytes))); @@ -80,22 +80,23 @@ template } template -void read_time_series(std::istream& is, std::vector>* time_series) { +void read_time_series(std::istream& istream, + std::vector>* time_series) { if constexpr (std::is_same_v) { for (std::vector& row : *time_series) { - const uint64_t length = read_length(is); + const uint64_t length = read_length(istream); char* buffer = new char[length + 1]; - is.read(buffer, length); + istream.read(buffer, length); buffer[length] = '\0'; row.emplace_back(buffer); delete[] buffer; } - return; - } - for (std::vector& row : *time_series) - { - row.push_back(std::move(read_bin(is))); + } else { + for (std::vector& row : *time_series) + { + row.push_back(std::move(read_bin(istream))); + } } } From a11fa73388717098232bb143ec0bc986c1591bd1 Mon Sep 17 00:00:00 2001 From: Yida Lin Date: Sun, 29 Dec 2024 13:56:39 -0800 Subject: [PATCH 30/37] num_samples --- xdf.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/xdf.cpp b/xdf.cpp index ffbe521..b2d3882 100644 --- a/xdf.cpp +++ b/xdf.cpp @@ -261,11 +261,11 @@ int Xdf::load_xdf(std::string filename) //read [StreamID] const auto stream_id = read_bin(file); //read [NumSampleBytes], [NumSamples] - const uint64_t numSamp = read_length(file); + const uint64_t num_samples = read_length(file); Stream& stream = streams[stream_id]; //for each sample - for (size_t i = 0; i < numSamp; i++) + for (size_t i = 0; i < num_samples; i++) { //read or deduce time stamp const auto tsBytes = read_bin(file); From 2984bde848ae228b9176cfec6c52f1c3c13c059d Mon Sep 17 00:00:00 2001 From: Yida Lin Date: Sun, 29 Dec 2024 14:00:45 -0800 Subject: [PATCH 31/37] T --- xdf.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/xdf.cpp b/xdf.cpp index b2d3882..a9b97e0 100644 --- a/xdf.cpp +++ b/xdf.cpp @@ -472,7 +472,7 @@ void Xdf::resample(int userSrate) // Only replace numeric values if constexpr (std::is_arithmetic_v) { - for (auto& val : row) + for (T& val : row) { val = static_cast(outbuf[read++]); } @@ -486,7 +486,7 @@ void Xdf::resample(int userSrate) // Only replace numeric values if constexpr (std::is_arithmetic_v) { - for (auto& val : row) + for (T& val : row) { val = static_cast(outbuf[read++]); } From 34636a08f8605a4d8e2aca3b58356addb175d3cd Mon Sep 17 00:00:00 2001 From: Yida Lin Date: Sun, 29 Dec 2024 17:15:14 -0800 Subject: [PATCH 32/37] doc --- xdf.cpp | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/xdf.cpp b/xdf.cpp index a9b97e0..a783b73 100644 --- a/xdf.cpp +++ b/xdf.cpp @@ -34,13 +34,12 @@ namespace xdf { namespace { /*! - * \brief Read a binary scalar variable from an input stream. + * \brief Reads a binary scalar variable from an input stream. * * read_bin is a convenience wrapper for the common * file.read((char*) var, sizeof(var)) * operation. Examples: - * double foo = read_bin(file); // use return value - * read_bin(file, &foo); // read directly into foo + * double foo = read_bin(file); * \param is an input stream to read from * \param obj pointer to a variable to load the data into or nullptr * \return the read data @@ -60,7 +59,7 @@ template * While loading XDF file there are 2 cases where this function will be * needed. One is to get the length of each chunk, one is to get the * number of samples when loading the time series (Chunk tag 3). - * \param file is the XDF file that is being loaded in the type of `std::ifstream`. + * \param file is the XDF file that is being loaded. * \return The length of the upcoming chunk (in bytes). */ [[nodiscard]] uint64_t read_length(std::istream& istream) From 4bc0d2e28018b641a99142595ec0a28774dbc8e7 Mon Sep 17 00:00:00 2001 From: Yida Lin Date: Sun, 29 Dec 2024 17:18:04 -0800 Subject: [PATCH 33/37] doc --- xdf.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/xdf.cpp b/xdf.cpp index a783b73..255549b 100644 --- a/xdf.cpp +++ b/xdf.cpp @@ -78,6 +78,13 @@ template } } +/*! + * \brief Reads N samples from `istream` and appends to each row of + * `time_series`, where N is the number of channels in `time_series`. + * + * \param istream the input stream. + * \param time_series the 2D vector to append to. + */ template void read_time_series(std::istream& istream, std::vector>* time_series) { From 7e458621dc2394359ef6519dd30a03aa30f342a8 Mon Sep 17 00:00:00 2001 From: Yida Lin Date: Sun, 29 Dec 2024 17:25:25 -0800 Subject: [PATCH 34/37] size_t --- xdf.cpp | 6 +----- xdf.h | 2 +- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/xdf.cpp b/xdf.cpp index 255549b..5c86737 100644 --- a/xdf.cpp +++ b/xdf.cpp @@ -640,11 +640,7 @@ void Xdf::adjustTotalLength() stream.info.channel_format != "string") { std::visit([this](auto&& time_series) { - const size_t row_length = time_series.front().size(); - if (totalLen < row_length) - { - totalLen = row_length; - } + totalLen = std::max(totalLen, time_series.front().size()); }, stream.time_series); } } diff --git a/xdf.h b/xdf.h index e19629f..231085a 100644 --- a/xdf.h +++ b/xdf.h @@ -99,7 +99,7 @@ class Xdf std::unordered_map streams; /*!< Maps all stream IDs to streams in the XDF file. */ float version; /*!< The version of XDF file */ - uint64_t totalLen = 0; /*!< The total length is the product of the range between the smallest + size_t totalLen = 0; /*!< The total length is the product of the range between the smallest *time stamp and the largest multiplied by the major sample rate. */ double minTS = 0; /*!< The smallest time stamp across all streams. */ From a077b7c8d66799ea36cf860de0a6bd822cd1321f Mon Sep 17 00:00:00 2001 From: Yida Lin Date: Mon, 30 Dec 2024 00:36:31 -0800 Subject: [PATCH 35/37] channel --- xdf.cpp | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/xdf.cpp b/xdf.cpp index 5c86737..5673382 100644 --- a/xdf.cpp +++ b/xdf.cpp @@ -79,7 +79,7 @@ template } /*! - * \brief Reads N samples from `istream` and appends to each row of + * \brief Reads N samples from `istream` and appends to each channel of * `time_series`, where N is the number of channels in `time_series`. * * \param istream the input stream. @@ -89,19 +89,19 @@ template void read_time_series(std::istream& istream, std::vector>* time_series) { if constexpr (std::is_same_v) { - for (std::vector& row : *time_series) + for (std::vector& channel : *time_series) { const uint64_t length = read_length(istream); char* buffer = new char[length + 1]; istream.read(buffer, length); buffer[length] = '\0'; - row.emplace_back(buffer); + channel.emplace_back(buffer); delete[] buffer; } } else { - for (std::vector& row : *time_series) + for (std::vector& channel : *time_series) { - row.push_back(std::move(read_bin(istream))); + channel.push_back(std::move(read_bin(istream))); } } } @@ -452,19 +452,19 @@ void Xdf::resample(int userSrate) std::visit([&pfilt, &pstate](auto&& time_series) { using T = typename std::decay_t ::value_type::value_type; - for (std::vector& row : time_series) + for (std::vector& channel : time_series) { // initialize buffers int read = 0; int written = 0; - const int OUT_BUF_SIZE = (int)smarc_get_output_buffer_size(pfilt, row.size()); - double* inbuf = new double[row.size()]; + const int OUT_BUF_SIZE = (int)smarc_get_output_buffer_size(pfilt, channel.size()); + double* inbuf = new double[channel.size()]; double* outbuf = new double[OUT_BUF_SIZE]; - // Fill inbuf with the numeric values from the row + // Fill inbuf with the numeric values from the channel if constexpr (std::is_arithmetic_v) { - for (const T& val : row) + for (const T& val : channel) { inbuf[read++] = static_cast(val); // Convert to double } @@ -478,7 +478,7 @@ void Xdf::resample(int userSrate) // Only replace numeric values if constexpr (std::is_arithmetic_v) { - for (T& val : row) + for (T& val : channel) { val = static_cast(outbuf[read++]); } @@ -492,7 +492,7 @@ void Xdf::resample(int userSrate) // Only replace numeric values if constexpr (std::is_arithmetic_v) { - for (T& val : row) + for (T& val : channel) { val = static_cast(outbuf[read++]); } @@ -674,11 +674,11 @@ void Xdf::detrend() using T = typename std::decay_t ::value_type::value_type; if constexpr (std::is_arithmetic_v) { - for (auto& row : time_series) + for (std::vector& channel : time_series) { long double init = 0.0; - long double mean = std::accumulate(row.begin(), row.end(), init) / row.size(); - for (auto& val: row) + long double mean = std::accumulate(channel.begin(), channel.end(), init) / channel.size(); + for (T& val: channel) { val -= mean; } From 27d6510355c876210857820d471965cde99a4de8 Mon Sep 17 00:00:00 2001 From: Yida Lin Date: Mon, 30 Dec 2024 00:45:32 -0800 Subject: [PATCH 36/37] time_stamp_bytes --- xdf.cpp | 22 ++++++---------------- 1 file changed, 6 insertions(+), 16 deletions(-) diff --git a/xdf.cpp b/xdf.cpp index 5673382..827a03c 100644 --- a/xdf.cpp +++ b/xdf.cpp @@ -274,22 +274,12 @@ int Xdf::load_xdf(std::string filename) for (size_t i = 0; i < num_samples; i++) { //read or deduce time stamp - const auto tsBytes = read_bin(file); - - double ts; //temporary time stamp - - if (tsBytes == 8) - { - ts = read_bin(file); - stream.time_stamps.emplace_back(ts); - } - else - { - ts = stream.last_timestamp + stream.sampling_interval; - stream.time_stamps.emplace_back(ts); - } - - stream.last_timestamp = ts; + const auto time_stamp_bytes = read_bin(file); + const double time_stamp = time_stamp_bytes == 8 + ? read_bin(file) + : stream.last_timestamp + stream.sampling_interval; + stream.time_stamps.push_back(time_stamp); + stream.last_timestamp = time_stamp; std::visit([&file](auto&& time_series) { using T = typename std::decay_t From 60932adf9a80c2ff15acfc44b94d36dbdb2862e1 Mon Sep 17 00:00:00 2001 From: Yida Lin Date: Mon, 30 Dec 2024 01:00:34 -0800 Subject: [PATCH 37/37] Delete loadSampleRateSet --- xdf.cpp | 13 ------------- xdf.h | 8 -------- 2 files changed, 21 deletions(-) diff --git a/xdf.cpp b/xdf.cpp index 827a03c..d45e234 100644 --- a/xdf.cpp +++ b/xdf.cpp @@ -352,8 +352,6 @@ int Xdf::load_xdf(std::string filename) getHighestSampleRate(); - loadSampleRateSet(); - calcEffectiveSrate(); //loading finishes, close file @@ -645,17 +643,6 @@ void Xdf::getHighestSampleRate() } } -void Xdf::loadSampleRateSet() -{ - for (const auto& [stream_id, stream] : streams) - { - if (stream.info.channel_format != "string") - { - sample_rates.insert(stream.info.nominal_srate); - } - } -} - void Xdf::detrend() { for (auto& [stream_id, stream] : streams) diff --git a/xdf.h b/xdf.h index 231085a..17dbe18 100644 --- a/xdf.h +++ b/xdf.h @@ -123,7 +123,6 @@ class Xdf typedef double eventTimeStamp; std::vector labels; /*!< The vector to store descriptive labels of each channel. */ - std::unordered_set sample_rates; /*!< The vector to store all sample rates across all the streams. */ std::vector offsets; /*!< Offsets of each channel after using subtractMean() function */ std::string fileHeader; /*!< Raw XML of the file header. */ @@ -264,13 +263,6 @@ class Xdf * \sa maxSR */ void getHighestSampleRate(); - - /*! - * \brief Load every sample rate appeared in the current file into - * member variable `sample_rates`. - * \sa sampleRateSet - */ - void loadSampleRateSet(); }; } // namespace xdf