29#include <QRegularExpression>
54 if (!stream->open()) {
57 const QList<FiffDirNode::SPtr> blocks = stream->dirtree()->dir_tree_find(
FIFFB_MNE_EVENTS);
60 qWarning(
"MNEEventList::readFif - No event data in %s", qPrintable(path));
64 const auto* values =
reinterpret_cast<const qint32*
>(tag->data());
65 const int nevent =
static_cast<int>(tag->size() / (3 *
sizeof(qint32)));
68 for (
int k = 0; k <
nevent; ++k) {
69 list.
events[k].sample = values[3 * k] - offset;
70 list.
events[k].from =
static_cast<unsigned int>(values[3 * k + 1]);
71 list.
events[k].to =
static_cast<unsigned int>(values[3 * k + 2]);
75 const QList<QByteArray> comments = tag->split(
'\0');
76 for (
int k = 0; k <
nevent && k < comments.size(); ++k) {
77 list.
events[k].comment = QString::fromLatin1(comments[k]);
88 if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
89 qWarning(
"MNEEventList::readText - Cannot open %s", qPrintable(path));
92 static const QRegularExpression whitespace(QStringLiteral(
"\\s+"));
95 QTextStream in(&file);
97 const QString line = in.readLine().trimmed();
98 if (line.isEmpty() || line.startsWith(
'#')) {
101 const QStringList fields = line.split(whitespace);
103 int sample = fields.value(0).toInt(&ok[0]);
104 const float time = fields.value(1).toFloat(&ok[1]);
105 const unsigned int from = fields.value(2).toUInt(&ok[2]);
106 const unsigned int to = fields.value(3).toUInt(&ok[3]);
107 if (fields.size() < 4 || !(ok[0] && ok[1] && ok[2] && ok[3])) {
111 sample =
static_cast<int>(time * sfreq);
115 if (from == 0 && to == 0) {
116 if (offset != sample) {
117 qWarning(
"MNEEventList::readText - First sample of the data (%d) and of %s (%d) differ", offset, qPrintable(path), sample);
124 event.
sample = sample - offset;
127 event.comment = line.section(whitespace, 4).trimmed();
128 list.
events.push_back(event);
130 if (list.
events.empty()) {
131 qWarning(
"MNEEventList::readText - No events read from %s", qPrintable(path));
146 std::vector<qint32> values;
147 values.reserve(3 *
events.size());
149 bool anyComment =
false;
151 values.push_back(event.sample + offset);
152 values.push_back(
static_cast<qint32
>(event.from));
153 values.push_back(
static_cast<qint32
>(event.to));
154 comments +=
event.comment.toLatin1() +
'\0';
155 anyComment = anyComment || !
event.comment.isEmpty();
159 auto list = std::make_unique<FiffTag>();
163 const auto nbytes =
static_cast<qsizetype
>(values.size()) *
static_cast<qsizetype
>(
sizeof(qint32));
164 list->append(
reinterpret_cast<const char*
>(values.data()), nbytes);
165 stream->write_tag(list);
168 auto tag = std::make_unique<FiffTag>();
172 tag->append(comments);
173 stream->write_tag(tag);
185 return a.sample < b.sample;
202 return event.from == 0 && (value == 0 || event.to == value);
211 unsigned int maximum = 0;
213 if (event.from == 0) {
214 maximum = std::max(maximum, event.to);
224 Eigen::MatrixXi matrix(
nevent(), 3);
225 for (
int k = 0; k <
nevent(); ++k) {
226 matrix.row(k) <<
events[k].sample,
static_cast<int>(
events[k].from),
static_cast<int>(
events[k].to);
236 list.
events.resize(matrix.rows());
237 for (Eigen::Index k = 0; k < matrix.rows(); ++k) {
238 list.
events[k].sample = matrix(k, 0);
239 list.
events[k].from =
static_cast<unsigned int>(matrix(k, 1));
240 list.
events[k].to =
static_cast<unsigned int>(matrix(k, 2));
Symbolic FIFF tag, block, value, unit and channel-type constants shared across FIFFLIB.
#define FIFF_MNE_EVENT_LIST
#define FIFF_MNE_EVENT_COMMENTS
FIFF tag: the 16-byte tag header (kind, type, size, next) plus its decoded payload.
FIFF binary tag-stream layer: wraps a QIODevice to read and write FIFF tags, directories,...
Recursive node of the parsed FIFF block tree (FIFFB_* hierarchy with directory entries and children).
Event list with comments: MNE-C text and FIFF event files, sorting, merging and selection.
Core MNE data structures (source spaces, source estimates, hemispheres).
FIFF file I/O, in-memory data structures and high-level readers/writers.
FIFF tag-stream reader/writer: wraps a QIODevice and exposes typed read_* / write_* methods for every...
QSharedPointer< FiffStream > SPtr
static FiffStream::SPtr start_file(QIODevice &p_IODevice)
std::unique_ptr< FiffTag > UPtr
Single trigger-event marker.
Ordered list of trigger events with comments.
static MNEEventList fromMatrix(const Eigen::MatrixXi &matrix)
bool writeFif(const QString &path, int offset=0) const
unsigned int maxOnset() const
static std::optional< MNEEventList > readText(const QString &path, int offset, int oldOffset, float sfreq)
void append(const MNEEventList &other)
std::vector< MNEEvent > events
MNEEventList selectOnsets(unsigned int value=0) const
static std::optional< MNEEventList > readFif(const QString &path, int offset=0)
int nevent() const
Returns the number of events in the list.
Eigen::MatrixXi toMatrix() const