v2.0.0
Loading...
Searching...
No Matches
fiff_stream.cpp
Go to the documentation of this file.
1//=============================================================================================================
25
26//=============================================================================================================
27// INCLUDES
28//=============================================================================================================
29
30#include "fiff_stream.h"
31#include "fiff_tag.h"
32#include "fiff_dir_node.h"
33#include "fiff_ctf_comp.h"
34#include "fiff_info.h"
35#include "fiff_info_base.h"
36#include "fiff_raw_data.h"
37#include "fiff_cov.h"
38#include "fiff_evoked_set.h"
39#include "fiff_coord_trans.h"
40#include "fiff_ch_info.h"
41#include "fiff_ch_pos.h"
42#include "fiff_dig_point.h"
43#include "fiff_id.h"
44#include "fiff_digitizer_data.h"
45#include "fiff_dig_point.h"
46
47#include <math/linalg.h>
48#include <math/numerics.h>
49#include <utils/ioutils.h>
50
51#include <functional>
52#include <time.h>
53
54//=============================================================================================================
55// EIGEN INCLUDES
56//=============================================================================================================
57
58#include <Eigen/LU>
59#include <Eigen/Dense>
60
61//=============================================================================================================
62// QT INCLUDES
63//=============================================================================================================
64
65#include <QFile>
66#include <QTcpSocket>
67#include <QDebug>
68
69//=============================================================================================================
70// USED NAMESPACES
71//=============================================================================================================
72
73using namespace FIFFLIB;
74using namespace UTILSLIB;
75using namespace Eigen;
76
77//=============================================================================================================
78// DEFINE MEMBER METHODS
79//=============================================================================================================
80
81FiffStream::FiffStream(QIODevice* p_pIODevice)
82: QDataStream(p_pIODevice)
83{
84 this->setFloatingPointPrecision(QDataStream::SinglePrecision);
85 this->setByteOrder(QDataStream::BigEndian);
86 this->setVersion(QDataStream::Qt_5_0);
87}
88
89//=============================================================================================================
90
92 QIODevice::OpenMode mode)
93: QDataStream(a, mode)
94{
95 this->setFloatingPointPrecision(QDataStream::SinglePrecision);
96 this->setByteOrder(QDataStream::BigEndian);
97 this->setVersion(QDataStream::Qt_5_0);
98}
99
100//=============================================================================================================
101
103{
104 QFile* t_pFile = qobject_cast<QFile*>(this->device());
105 QString p_sFileName;
106 if (t_pFile)
107 p_sFileName = t_pFile->fileName();
108 else
109 p_sFileName = QString("TCPSocket");
110
111 return p_sFileName;
112}
113
114//=============================================================================================================
115
117{
118 return m_id;
119}
120
121//=============================================================================================================
122
123QList<FiffDirEntry::SPtr>& FiffStream::dir()
124{
125 return m_dir;
126}
127
128//=============================================================================================================
129
130const QList<FiffDirEntry::SPtr>& FiffStream::dir() const
131{
132 return m_dir;
133}
134
135//=============================================================================================================
136
138{
139 return m_dir.size();
140}
141
142//=============================================================================================================
143
145{
146 return m_dirtree;
147}
148
149//=============================================================================================================
150
152{
153 return this->write_int(FIFF_BLOCK_END, &kind, 1, next);
154}
155
156//=============================================================================================================
157
159{
160 fiff_int_t datasize = 0;
161
162 *this << static_cast<qint32>(FIFF_NOP);
163 *this << static_cast<qint32>(FIFFT_VOID);
164 *this << static_cast<qint32>(datasize);
165 *this << static_cast<qint32>(FIFFV_NEXT_NONE);
166}
167
168//=============================================================================================================
169
171{
173 this->end_block(FIFFB_MEAS);
174 this->end_file();
175 this->close();
176}
177
178//=============================================================================================================
179
180bool FiffStream::get_evoked_entries(const QList<FiffDirNode::SPtr>& evoked_node, QStringList& comments, QList<fiff_int_t>& aspect_kinds, QString& t)
181{
182 comments.clear();
183 aspect_kinds.clear();
184 QList<FiffDirNode::SPtr>::ConstIterator ev;
185
186 FiffTag::UPtr t_pTag;
187 qint32 kind, pos, k;
188
189 for (ev = evoked_node.begin(); ev != evoked_node.end(); ++ev) {
190 for (k = 0; k < (*ev)->nent(); ++k) {
191 kind = (*ev)->dir[k]->kind;
192 pos = (*ev)->dir[k]->pos;
193 if (kind == FIFF_COMMENT) {
194 this->read_tag(t_pTag, pos);
195 comments.append(t_pTag->toString());
196 }
197 }
198 FiffDirNode::SPtr my_aspect = (*ev)->dir_tree_find(FIFFB_ASPECT)[0];
199 for (k = 0; k < my_aspect->nent(); ++k) {
200 kind = my_aspect->dir[k]->kind;
201 pos = my_aspect->dir[k]->pos;
202 if (kind == FIFF_ASPECT_KIND) {
203 this->read_tag(t_pTag, pos);
204 aspect_kinds.append(*t_pTag->toInt());
205 }
206 }
207 }
208
209 if (comments.size() != aspect_kinds.size() || comments.size() == 0) {
210 qWarning("Dataset names in FIF file could not be found.");
211 return false;
212 }
213
214 t = QString();
215 for (k = 0; k < aspect_kinds.size(); ++k) {
216 t += QString("%1 - \"%2\" (").arg(k).arg(comments[k]);
217 if (aspect_kinds[k] == FIFFV_ASPECT_AVERAGE)
218 t += QString("FIFFV_ASPECT_AVERAGE)\n");
219 else if (aspect_kinds[k] == FIFFV_ASPECT_STD_ERR)
220 t += QString("FIFFV_ASPECT_STD_ERR)\n");
221 else
222 t += QString("unknown)\n");
223 }
224
225 return true;
226}
227
228//=============================================================================================================
229
230bool FiffStream::open(QIODevice::OpenModeFlag mode)
231{
232 QString t_sFileName = this->streamName();
233 FiffTag::UPtr t_pTag;
234
235 /*
236 * Try to open...
237 */
238 if (!this->device()->open(mode)) {
239 qCritical("Cannot open %s\n", t_sFileName.toUtf8().constData()); //consider throw
240 return false;
241 }
242
243 if (!check_beginning(t_pTag)) // Supposed to get the id already in the beginning - read once approach - for TCP/IP support
244 return false;
245
246 /*
247 * Read id and directory pointer
248 */
249 if (t_pTag->kind != FIFF_FILE_ID) {
250 qCritical("FIFF file should start with FIFF_FILE_ID!"); //consider throw
251 this->device()->close();
252 return false;
253 }
254 m_id = t_pTag->toFiffID();
255
256 this->read_tag(t_pTag);
257 if (t_pTag->kind != FIFF_DIR_POINTER) {
258 qWarning("Fiff::open: file does have a directory pointer"); //consider throw
259 this->device()->close();
260 return false;
261 }
262
263 //
264 // Read or create the directory tree
265 //
266 qInfo("Creating tag directory for %s...", t_sFileName.toUtf8().constData());
267 m_dir.clear();
268 qint32 dirpos = *t_pTag->toInt();
269 /*
270 * Do we have a directory or not?
271 */
272 if (dirpos <= 0) { /* Must do it in the hard way... */
273 bool ok = false;
274 m_dir = this->make_dir(&ok);
275 if (!ok) {
276 qCritical("Could not create tag directory!");
277 return false;
278 }
279 } else { /* Just read the directory */
280 if (!this->read_tag(t_pTag, dirpos)) {
281 qCritical("Could not read the tag directory (file probably damaged)!");
282 return false;
283 }
284 m_dir = t_pTag->toDirEntry();
285 }
286
287 /*
288 * Check for a mistake
289 */
290 if (m_dir[m_dir.size() - 2]->kind == FIFF_DIR) {
291 m_dir.removeLast();
292 m_dir[m_dir.size() - 1]->kind = -1;
293 m_dir[m_dir.size() - 1]->type = -1;
294 m_dir[m_dir.size() - 1]->size = -1;
295 m_dir[m_dir.size() - 1]->pos = -1;
296 }
297
298 //
299 // Create the directory tree structure
300 //
301 if ((this->m_dirtree = this->make_subtree(m_dir)) == nullptr)
302 return false;
303 else
304 this->m_dirtree->parent.clear();
305
306 //
307 // Back to the beginning
308 //
309 this->device()->seek(SEEK_SET); //fseek(fid,0,'bof');
310 return true;
311}
312
313//=============================================================================================================
314
316{
317 if (this->device()->isOpen())
318 this->device()->close();
319
320 return true;
321}
322
323//=============================================================================================================
324
325FiffDirNode::SPtr FiffStream::make_subtree(QList<FiffDirEntry::SPtr>& dentry)
326{
327 FiffDirNode::SPtr defaultNode;
329 FiffDirNode::SPtr child;
330 FiffTag::UPtr t_pTag;
331 QList<FiffDirEntry::SPtr> dir;
332 qint32 current = 0;
333
334 node->dir_tree = dentry;
335 node->nent_tree = 1;
336 node->parent = FiffDirNode::SPtr();
337 node->type = FIFFB_ROOT;
338
339 if (dentry[current]->kind == FIFF_BLOCK_START) {
340 if (!this->read_tag(t_pTag, dentry[current]->pos))
341 return defaultNode;
342 else
343 node->type = *t_pTag->toInt();
344 } else {
345 node->id = this->id();
346 }
347
348 ++current;
349 int level = 0;
350 for (; current < dentry.size(); ++current) {
351 ++node->nent_tree;
352 if (dentry[current]->kind == FIFF_BLOCK_START) {
353 level++;
354 if (level == 1) {
355 QList<FiffDirEntry::SPtr> sub_dentry = dentry.mid(current);
356 if (!(child = this->make_subtree(sub_dentry)))
357 return defaultNode;
358 child->parent = node;
359 node->children.append(child);
360 }
361 } else if (dentry[current]->kind == FIFF_BLOCK_END) {
362 level--;
363 if (level < 0)
364 break;
365 } else if (dentry[current]->kind == -1)
366 break;
367 else if (level == 0) {
368 /*
369 * Take the node id from the parent block id,
370 * block id, or file id. Let the block id
371 * take precedence over parent block id and file id
372 */
373 if (((dentry[current]->kind == FIFF_PARENT_BLOCK_ID || dentry[current]->kind == FIFF_FILE_ID) && node->id.isEmpty()) || dentry[current]->kind == FIFF_BLOCK_ID) {
374 if (!this->read_tag(t_pTag, dentry[current]->pos))
375 return defaultNode;
376 node->id = t_pTag->toFiffID();
377 }
378 dir.append(FiffDirEntry::SPtr(new FiffDirEntry(*dentry[current]))); //Memcopy necessary here - or is a pointer fine?
379 }
380 }
381 /*
382 * Strip unused entries
383 */
384 node->dir = dir;
385 return node;
386}
387
388//=============================================================================================================
389
391{
392 QList<FiffDirNode::SPtr> node = p_Node->dir_tree_find(FIFFB_MNE_BAD_CHANNELS);
393 FiffTag::UPtr t_pTag;
394
395 QStringList bads;
396
397 if (node.size() > 0)
398 if (node[0]->find_tag(this, FIFF_MNE_CH_NAME_LIST, t_pTag))
399 bads = split_name_list(t_pTag->toString());
400
401 return bads;
402}
403
404//=============================================================================================================
405
412
413//=============================================================================================================
414
415bool FiffStream::attach_env(const QString& workingDir, const QString& command)
416{
417 int insert_blocks[] = {FIFFB_MNE, FIFFB_MEAS, FIFFB_MRI, FIFFB_BEM, -1};
418
419 int b, k, insert;
420 FiffTag::UPtr t_pTag;
421
423
424 /*
425 * Find an appropriate position to insert
426 */
427 for (insert = -1, b = 0; insert_blocks[b] >= 0; b++) {
428 for (k = 0; k < nent(); k++) {
429 if (dir()[k]->kind == FIFF_BLOCK_START) {
430 if (!read_tag(t_pTag, dir()[k]->pos))
431 return false;
432 if (*(t_pTag->toInt()) == insert_blocks[b]) {
433 insert = k;
434 break;
435 }
436 }
437 }
438 if (insert >= 0)
439 break;
440 }
441 if (insert < 0) {
442 qCritical("Suitable place for environment insertion not found.");
443 return false;
444 }
445
446 /*
447 * Inline fiff_insert_after logic
448 */
449 int where = insert;
450 if (where < 0 || where >= nent() - 1) {
451 qCritical("illegal insertion point in fiff_insert_after!");
452 return false;
453 }
454
455 FiffTag::UPtr t_pTagNext;
456 QList<FiffDirEntry::SPtr> old_dir = dir();
457 QList<FiffDirEntry::SPtr> this_ent = old_dir.mid(where);
458
459 if (!read_tag(t_pTagNext, this_ent[0]->pos))
460 return false;
461 /*
462 * Update next info to be sequential
463 */
464 qint64 next_tmp = device()->pos();
465 /*
466 * Go to the end of the file
467 */
468 device()->seek(device()->size());
469 /*
470 * Copy the beginning of old directory
471 */
472 QList<FiffDirEntry::SPtr> new_dir = old_dir.mid(0, where + 1);
473
474 qint64 old_end = device()->pos();
475 /*
476 * Write the MNE_ENV block tags
477 */
478 FiffDirEntry::SPtr new_this;
479
480 new_this = FiffDirEntry::SPtr(new FiffDirEntry);
481 new_this->kind = FIFF_BLOCK_START;
482 new_this->type = FIFFT_INT;
483 new_this->size = 1 * 4;
484 new_this->pos = start_block(FIFFB_MNE_ENV);
485 new_dir.append(new_this);
486
487 new_this = FiffDirEntry::SPtr(new FiffDirEntry);
488 new_this->kind = FIFF_BLOCK_ID;
489 new_this->type = FIFFT_ID_STRUCT;
490 new_this->size = 5 * 4;
491 new_this->pos = write_id(FIFF_BLOCK_ID, id);
492 new_dir.append(new_this);
493
494 new_this = FiffDirEntry::SPtr(new FiffDirEntry);
495 new_this->kind = FIFF_MNE_ENV_WORKING_DIR;
496 new_this->type = FIFFT_STRING;
497 new_this->size = workingDir.size();
498 new_this->pos = write_string(FIFF_MNE_ENV_WORKING_DIR, workingDir);
499 new_dir.append(new_this);
500
501 new_this = FiffDirEntry::SPtr(new FiffDirEntry);
502 new_this->kind = FIFF_MNE_ENV_COMMAND_LINE;
503 new_this->type = FIFFT_STRING;
504 new_this->size = command.size();
505 new_this->pos = write_string(FIFF_MNE_ENV_COMMAND_LINE, command);
506 new_dir.append(new_this);
507
508 new_this = FiffDirEntry::SPtr(new FiffDirEntry);
509 new_this->kind = FIFF_BLOCK_END;
510 new_this->type = FIFFT_INT;
511 new_this->size = 1 * 4;
512 new_this->pos = end_block(FIFFB_MNE_ENV, next_tmp);
513 new_dir.append(new_this);
514
515 /*
516 * Copy the rest of the old directory
517 */
518 new_dir.append(old_dir.mid(where + 1));
519 /*
520 * Update the branching tag
521 */
522 t_pTagNext->next = static_cast<qint32>(old_end);
523 write_tag(t_pTagNext, this_ent[0]->pos);
524
525 dir() = new_dir;
526
527 return true;
528}
529
530//=============================================================================================================
531
532bool FiffStream::read_cov(const FiffDirNode::SPtr& p_Node, fiff_int_t cov_kind, FiffCov& p_covData)
533{
534 p_covData.clear();
535
536 //
537 // Find all covariance matrices
538 //
539 QList<FiffDirNode::SPtr> covs = p_Node->dir_tree_find(FIFFB_MNE_COV);
540 if (covs.size() == 0) {
541 qWarning("No covariance matrices found");
542 return false;
543 }
544 //
545 // Is any of the covariance matrices a noise covariance
546 //
547 qint32 p = 0;
548 FiffTag::UPtr tag;
549 bool success = false;
550 fiff_int_t dim, nfree, nn;
551 QStringList names;
552 bool diagmat = false;
553 VectorXd eig;
554 MatrixXd eigvec;
555 VectorXd cov_diag;
556 MatrixXd cov;
557 VectorXd cov_sparse;
558 QStringList bads;
559 for (p = 0; p < covs.size(); ++p) {
560 success = covs[p]->find_tag(this, FIFF_MNE_COV_KIND, tag);
561 if (success && *tag->toInt() == cov_kind) {
562 FiffDirNode::SPtr current = covs[p];
563 //
564 // Find all the necessary data
565 //
566 if (!current->find_tag(this, FIFF_MNE_COV_DIM, tag)) {
567 qWarning("Covariance matrix dimension not found.\n");
568 return false;
569 }
570 dim = *tag->toInt();
571 if (!current->find_tag(this, FIFF_MNE_COV_NFREE, tag))
572 nfree = -1;
573 else
574 nfree = *tag->toInt();
575
576 if (current->find_tag(this, FIFF_MNE_ROW_NAMES, tag)) {
577 names = FiffStream::split_name_list(tag->toString());
578 if (names.size() != dim) {
579 qWarning("Number of names does not match covariance matrix dimension\n");
580 return false;
581 }
582 }
583 if (!current->find_tag(this, FIFF_MNE_COV, tag)) {
584 if (!current->find_tag(this, FIFF_MNE_COV_DIAG, tag)) {
585 qWarning("No covariance matrix data found\n");
586 return false;
587 } else {
588 //
589 // Diagonal is stored
590 //
591 if (tag->type == FIFFT_DOUBLE) {
592 cov_diag = Map<const VectorXd>(tag->toDouble(), dim);
593 } else if (tag->type == FIFFT_FLOAT) {
594 cov_diag = Map<const VectorXf>(tag->toFloat(), dim).cast<double>();
595 } else {
596 qCritical("Illegal data type for covariance matrix\n");
597 return false;
598 }
599
600 diagmat = true;
601 qInfo("\t%d x %d diagonal covariance (kind = %d) found.\n", dim, dim, cov_kind);
602 }
603 } else {
604 VectorXd vals;
605 nn = dim * (dim + 1) / 2;
606 if (tag->type == FIFFT_DOUBLE) {
607 vals = Map<const VectorXd>(tag->toDouble(), nn);
608 } else if (tag->type == FIFFT_FLOAT) {
609 vals = Map<const VectorXf>(tag->toFloat(), nn).cast<double>();
610 } else {
611 qDebug() << tag->getInfo();
612 return false;
613 }
614
615 if (!Numerics::issparse(vals)) {
616 //
617 // Lower diagonal is stored
618 //
619 cov = MatrixXd::Zero(dim, dim);
620
621 // XXX : should remove for loops
622 qint32 q = 0;
623 for (qint32 j = 0; j < dim; ++j) {
624 for (qint32 k = 0; k <= j; ++k) {
625 cov(j, k) = vals(q);
626 ++q;
627 }
628 }
629 for (qint32 j = 0; j < dim; ++j)
630 for (qint32 k = j + 1; k < dim; ++k)
631 cov(j, k) = cov(k, j);
632
633 diagmat = false;
634 qInfo("\t%d x %d full covariance (kind = %d) found.\n", dim, dim, cov_kind);
635
636 } else {
637 diagmat = false;
638 qDebug() << "ToDo: FiffStream::read_cov - this needs to be debugged.\n";
639 cov = vals;
640 qInfo("\t%d x %d sparse covariance (kind = %d) found.\n", dim, dim, cov_kind);
641 }
642 //MATLAB
643 // if ~issparse(tag.data)
644 // //
645 // // Lower diagonal is stored
646 // //
647 // qDebug() << tag->getInfo();
648 // vals = tag.data;
649 // data = zeros(dim,dim);
650 // % XXX : should remove for loops
651 // q = 1;
652 // for j = 1:dim
653 // for k = 1:j
654 // data(j,k) = vals(q);
655 // q = q + 1;
656 // end
657 // end
658 // for j = 1:dim
659 // for k = j+1:dim
660 // data(j,k) = data(k,j);
661 // end
662 // end
663 // diagmat = false;
664 // fprintf('\t%d x %d full covariance (kind = %d) found.\n',dim,dim,cov_kind);
665 // else
666 // diagmat = false;
667 // data = tag.data;
668 // fprintf('\t%d x %d sparse covariance (kind = %d) found.\n',dim,dim,cov_kind);
669 // end
670 //MATLAB END
671 }
672 //
673 // Read the possibly precomputed decomposition
674 //
675 FiffTag::UPtr tag1;
676 FiffTag::UPtr tag2;
677 if (current->find_tag(this, FIFF_MNE_COV_EIGENVALUES, tag1) && current->find_tag(this, FIFF_MNE_COV_EIGENVECTORS, tag2)) {
678 eig = VectorXd(Map<const VectorXd>(tag1->toDouble(), dim));
679 eigvec = tag2->toFloatMatrix().cast<double>();
680 eigvec.transposeInPlace();
681 }
682 //
683 // Read the projection operator
684 //
685 QList<FiffProj> projs = this->read_proj(current);
686 //
687 // Read the bad channel list
688 //
689 bads = this->read_bad_channels(current);
690 //
691 // Put it together
692 //
693 p_covData.clear();
694
695 p_covData.kind = cov_kind;
696 p_covData.diag = diagmat;
697 p_covData.dim = dim;
698 p_covData.names = names;
699
700 if (cov_diag.size() > 0)
701 p_covData.data = cov_diag;
702 else if (cov.size() > 0)
703 p_covData.data = cov;
704 else if (cov_sparse.size() > 0)
705 p_covData.data = cov_sparse;
706
707 p_covData.projs = projs;
708 p_covData.bads = bads;
709 p_covData.nfree = nfree;
710 p_covData.eig = eig;
711 p_covData.eigvec = eigvec;
712
713 //
714 return true;
715 }
716 }
717
718 qInfo("Did not find the desired covariance matrix\n");
719 return false;
720}
721
722//=============================================================================================================
723
724QList<FiffCtfComp> FiffStream::read_ctf_comp(const FiffDirNode::SPtr& p_Node, const QList<FiffChInfo>& p_Chs)
725{
726 QList<FiffCtfComp> compdata;
727 QList<FiffDirNode::SPtr> t_qListComps = p_Node->dir_tree_find(FIFFB_MNE_CTF_COMP_DATA);
728
729 qint32 k, p;
730 fiff_int_t kind, pos;
731 FiffTag::UPtr t_pTag;
732 for (k = 0; k < t_qListComps.size(); ++k) {
733 FiffDirNode::SPtr node = t_qListComps[k];
734 //
735 // Read the data we need
736 //
738 this->read_named_matrix(node, FIFF_MNE_CTF_COMP_DATA, *mat.data());
739 for (p = 0; p < node->nent(); ++p) {
740 kind = node->dir[p]->kind;
741 pos = node->dir[p]->pos;
742 if (kind == FIFF_MNE_CTF_COMP_KIND) {
743 this->read_tag(t_pTag, pos);
744 break;
745 }
746 }
747 if (!t_pTag) {
748 qWarning("Compensation type not found\n");
749 return {};
750 }
751 //
752 // Get the compensation kind and map it to a simple number
753 //
754 FiffCtfComp one;
755 one.ctfkind = *t_pTag->toInt();
756
757 t_pTag.reset();
758
759 one.kind = -1;
760 if (one.ctfkind == 1194410578) //hex2dec('47314252')
761 one.kind = 1;
762 else if (one.ctfkind == 1194476114) //hex2dec('47324252')
763 one.kind = 2;
764 else if (one.ctfkind == 1194541650) //hex2dec('47334252')
765 one.kind = 3;
766 else if (one.ctfkind == 1194479433)
767 one.kind = 4;
768 else if (one.ctfkind == 1194544969)
769 one.kind = 5;
770 else
771 one.kind = one.ctfkind;
772
773 for (p = 0; p < node->nent(); ++p) {
774 kind = node->dir[p]->kind;
775 pos = node->dir[p]->pos;
776 if (kind == FIFF_MNE_CTF_COMP_CALIBRATED) {
777 this->read_tag(t_pTag, pos);
778 break;
779 }
780 }
781 bool calibrated;
782 if (!t_pTag)
783 calibrated = false;
784 else
785 calibrated = static_cast<bool>(*t_pTag->toInt());
786
787 one.save_calibrated = calibrated;
788 one.data = mat;
789 if (!one.calibrate(p_Chs))
790 return {};
791 compdata.append(one);
792 }
793
794 if (compdata.size() > 0)
795 qInfo("\tRead %lld compensation matrices\n", static_cast<long long>(compdata.size()));
796
797 return compdata;
798}
799
800//=============================================================================================================
801
803{
805 fiff_int_t kind = -1;
806 fiff_int_t pos = -1;
807 int npoint = 0;
808 FiffTag::UPtr t_pTag;
809
810 QList<FiffDirNode::SPtr> t_qListDigData = p_Node->dir_tree_find(FIFFB_ISOTRAK);
811
812 //Check if digitizer data is available
813 if (t_qListDigData.isEmpty()) {
814 t_qListDigData = p_Node->dir_tree_find(FIFFB_MRI_SET);
815
816 if (t_qListDigData.isEmpty()) {
817 qWarning("No Isotrak data found in %s", this->streamName().toLatin1().data());
818 return false;
819 } else {
820 p_digData.coord_frame = FIFFV_COORD_MRI;
821 }
822 } else {
823 p_digData.coord_frame = FIFFV_COORD_HEAD;
824 }
825
826 // Read actual data and store it
827 for (int k = 0; k < t_qListDigData.first()->nent(); ++k) {
828 kind = t_qListDigData.first()->dir[k]->kind;
829 pos = t_qListDigData.first()->dir[k]->pos;
830
831 switch (kind) {
832 case FIFF_DIG_POINT:
833 this->read_tag(t_pTag, pos);
834 p_digData.points.append(t_pTag->toDigPoint());
835 break;
837 this->read_tag(t_pTag, pos);
838 p_digData.coord_frame = *t_pTag->toInt();
839 break;
840 }
841 }
842
843 npoint = p_digData.points.size();
844
845 if (npoint == 0) {
846 qWarning("No digitizer data in %s", this->streamName().toLatin1().data());
847 return false;
848 }
849
850 for (auto& dig : p_digData.points) {
851 dig.coord_frame = p_digData.coord_frame;
852 }
853
854 //Add other information as default
855 p_digData.filename = this->streamName();
856 p_digData.npoint = npoint;
857
858 for (int k = 0; k < p_digData.npoint; k++) {
859 p_digData.active.append(1);
860 p_digData.discard.append(0);
861 }
862
863 return true;
864}
865
866//=============================================================================================================
867
869{
870 p_InfoForward.clear();
871
872 //
873 // Find the desired blocks
874 //
875 QList<FiffDirNode::SPtr> parent_meg = p_Node->dir_tree_find(FIFFB_MNE_PARENT_MEAS_FILE);
876
877 if (parent_meg.size() == 0) {
878 qWarning("No parent MEG information found in operator\n");
879 return false;
880 }
881
882 FiffTag::UPtr t_pTag;
883
884 QList<FiffChInfo> chs;
885 FiffCoordTrans cand;
886 fiff_int_t kind = -1;
887 fiff_int_t pos = -1;
888
889 for (qint32 k = 0; k < parent_meg[0]->nent(); ++k) {
890 kind = parent_meg[0]->dir[k]->kind;
891 pos = parent_meg[0]->dir[k]->pos;
892 if (kind == FIFF_CH_INFO) {
893 this->read_tag(t_pTag, pos);
894 chs.append(t_pTag->toChInfo());
895 }
896 }
897
898 //
899 // Add the channel information and make a list of channel names
900 // for convenience
901 //
902 p_InfoForward.chs = chs;
903 for (qint32 c = 0; c < p_InfoForward.chs.size(); ++c)
904 p_InfoForward.ch_names << p_InfoForward.chs[c].ch_name;
905
906 p_InfoForward.nchan = chs.size();
907
908 //
909 // Get the MEG device <-> head coordinate transformation
910 //
911 if (parent_meg[0]->find_tag(this, FIFF_COORD_TRANS, t_pTag)) {
912 cand = t_pTag->toCoordTrans();
913 if (cand.from == FIFFV_COORD_DEVICE && cand.to == FIFFV_COORD_HEAD)
914 p_InfoForward.dev_head_t = cand;
915 else if (cand.from == FIFFV_MNE_COORD_CTF_HEAD && cand.to == FIFFV_COORD_HEAD)
916 p_InfoForward.ctf_head_t = cand;
917 else
918 qWarning("MEG device/head coordinate transformation not found");
919 } else
920 qWarning("MEG/head coordinate transformation not found.\n");
921
922 //
923 // Load the bad channel list
924 //
925 p_InfoForward.bads = this->read_bad_channels(p_Node);
926
927 return true;
928}
929
930//=============================================================================================================
931
933{
934 // if (info)
935 // delete info;
936 info.clear();
937 //
938 // Find the desired blocks
939 //
940 QList<FiffDirNode::SPtr> meas = p_Node->dir_tree_find(FIFFB_MEAS);
941
942 if (meas.size() == 0) {
943 qWarning("Could not find measurement data\n");
944 return false;
945 }
946 //
947 QList<FiffDirNode::SPtr> meas_info = meas[0]->dir_tree_find(FIFFB_MEAS_INFO);
948 if (meas_info.count() == 0) {
949 qWarning("Could not find measurement info\n");
950 // delete meas[0];
951 return false;
952 }
953 //
954 // Read measurement info
955 //
956 FiffTag::UPtr t_pTag;
957
958 fiff_int_t nchan = -1;
959 float sfreq = -1.0f;
960 float linefreq = -1.0f;
961 QList<FiffChInfo> chs;
962 float lowpass = -1.0f;
963 float highpass = -1.0f;
964
965 int proj_id = 0;
966 QString proj_name = "";
967 QString xplotter_layout = "";
968
969 QString utc_offset = "";
970 fiff_int_t gantry_angle = -1;
971
972 QString experimenter = "";
973 QString description = "";
974
975 FiffChInfo t_chInfo;
976
977 FiffCoordTrans cand; // = nullptr;
978 FiffCoordTrans dev_head_t; // = nullptr;
979 FiffCoordTrans ctf_head_t; // = nullptr;
980 QList<FiffCoordTrans> all_coord_trans;
981
982 fiff_int_t meas_date[2];
983 meas_date[0] = -1;
984 meas_date[1] = -1;
985
986 fiff_int_t kind = -1;
987 fiff_int_t pos = -1;
988
989 for (qint32 k = 0; k < meas_info[0]->nent(); ++k) {
990 kind = meas_info[0]->dir[k]->kind;
991 pos = meas_info[0]->dir[k]->pos;
992 switch (kind) {
993 case FIFF_NCHAN:
994 this->read_tag(t_pTag, pos);
995 nchan = *t_pTag->toInt();
996 break;
997 case FIFF_SFREQ:
998 this->read_tag(t_pTag, pos);
999 sfreq = *t_pTag->toFloat();
1000 break;
1001 case FIFF_LINE_FREQ:
1002 this->read_tag(t_pTag, pos);
1003 linefreq = *t_pTag->toFloat();
1004 break;
1005 case FIFF_CH_INFO:
1006 this->read_tag(t_pTag, pos);
1007 chs.append(t_pTag->toChInfo());
1008 break;
1009 case FIFF_LOWPASS:
1010 this->read_tag(t_pTag, pos);
1011 lowpass = *t_pTag->toFloat();
1012 break;
1013 case FIFF_HIGHPASS:
1014 this->read_tag(t_pTag, pos);
1015 highpass = *t_pTag->toFloat();
1016 break;
1017 case FIFF_MEAS_DATE:
1018 this->read_tag(t_pTag, pos);
1019 meas_date[0] = t_pTag->toInt()[0];
1020 meas_date[1] = t_pTag->toInt()[1];
1021 break;
1022 case FIFF_COORD_TRANS:
1023 //ToDo: This has to be debugged!!
1024 this->read_tag(t_pTag, pos);
1025 cand = t_pTag->toCoordTrans();
1026 all_coord_trans.append(cand);
1027 if (cand.from == FIFFV_COORD_DEVICE && cand.to == FIFFV_COORD_HEAD)
1028 dev_head_t = cand;
1029 else if (cand.from == FIFFV_MNE_COORD_CTF_HEAD && cand.to == FIFFV_COORD_HEAD)
1030 ctf_head_t = cand;
1031 break;
1032 case FIFF_PROJ_ID:
1033 this->read_tag(t_pTag, pos);
1034 proj_id = *t_pTag->toInt();
1035 break;
1036 case FIFF_PROJ_NAME:
1037 this->read_tag(t_pTag, pos);
1038 proj_name = t_pTag->toString();
1039 break;
1041 this->read_tag(t_pTag, pos);
1042 xplotter_layout = t_pTag->toString();
1043 break;
1044 case FIFF_EXPERIMENTER:
1045 this->read_tag(t_pTag, pos);
1046 experimenter = t_pTag->toString();
1047 break;
1048 case FIFF_DESCRIPTION:
1049 this->read_tag(t_pTag, pos);
1050 description = t_pTag->toString();
1051 break;
1052 case FIFF_GANTRY_ANGLE:
1053 this->read_tag(t_pTag, pos);
1054 // MNE-Python writes this as float; older writers used int.
1055 if (t_pTag->getType() == FIFFT_FLOAT) {
1056 gantry_angle = static_cast<fiff_int_t>(*t_pTag->toFloat());
1057 } else if (t_pTag->getType() == FIFFT_INT) {
1058 gantry_angle = *t_pTag->toInt();
1059 }
1060 break;
1061 case FIFF_UTC_OFFSET:
1062 this->read_tag(t_pTag, pos);
1063 utc_offset = t_pTag->toString();
1064 break;
1065 }
1066 }
1067 //
1068 // Check that we have everything we need
1069 //
1070 if (nchan < 0) {
1071 qWarning("Number of channels in not defined\n");
1072 return false;
1073 }
1074 if (sfreq < 0) {
1075 qWarning("Sampling frequency is not defined\n");
1076 return false;
1077 }
1078 if (linefreq < 0) {
1079 qWarning("Line frequency is not defined\n");
1080 }
1081 if (chs.size() == 0) {
1082 qWarning("Channel information not defined\n");
1083 return false;
1084 }
1085 if (chs.size() != nchan) {
1086 qWarning("Incorrect number of channel definitions found\n");
1087 return false;
1088 }
1089
1090 if (dev_head_t.isEmpty() || ctf_head_t.isEmpty()) {
1091 QList<FiffDirNode::SPtr> hpi_result = meas_info[0]->dir_tree_find(FIFFB_HPI_RESULT);
1092 if (hpi_result.size() == 1) {
1093 for (qint32 k = 0; k < hpi_result[0]->nent(); ++k) {
1094 kind = hpi_result[0]->dir[k]->kind;
1095 pos = hpi_result[0]->dir[k]->pos;
1096 if (kind == FIFF_COORD_TRANS) {
1097 this->read_tag(t_pTag, pos);
1098 cand = t_pTag->toCoordTrans();
1099 if (cand.from == FIFFV_COORD_DEVICE && cand.to == FIFFV_COORD_HEAD)
1100 dev_head_t = cand;
1101 else if (cand.from == FIFFV_MNE_COORD_CTF_HEAD && cand.to == FIFFV_COORD_HEAD)
1102 ctf_head_t = cand;
1103 }
1104 }
1105 }
1106 }
1107 //
1108 // Locate the Polhemus data
1109 //
1110 QList<FiffDirNode::SPtr> isotrak = meas_info[0]->dir_tree_find(FIFFB_ISOTRAK);
1111
1112 QList<FiffDigPoint> dig;
1113 fiff_int_t coord_frame = FIFFV_COORD_HEAD;
1114 FiffCoordTrans dig_trans;
1115 qint32 k = 0;
1116
1117 if (isotrak.size() == 1) {
1118 for (k = 0; k < isotrak[0]->nent(); ++k) {
1119 kind = isotrak[0]->dir[k]->kind;
1120 pos = isotrak[0]->dir[k]->pos;
1121 if (kind == FIFF_DIG_POINT) {
1122 this->read_tag(t_pTag, pos);
1123 dig.append(t_pTag->toDigPoint());
1124 } else {
1125 if (kind == FIFF_MNE_COORD_FRAME) {
1126 this->read_tag(t_pTag, pos);
1127 coord_frame = *t_pTag->toInt();
1128 } else if (kind == FIFF_COORD_TRANS) {
1129 this->read_tag(t_pTag, pos);
1130 dig_trans = t_pTag->toCoordTrans();
1131 }
1132 }
1133 }
1134 }
1135 for (k = 0; k < dig.size(); ++k)
1136 dig[k].coord_frame = coord_frame;
1137
1138 if (!dig_trans.isEmpty()) //if exist('dig_trans','var')
1139 if (dig_trans.from != coord_frame && dig_trans.to != coord_frame)
1140 dig_trans.clear();
1141
1142 //
1143 // Locate the acquisition information
1144 //
1145 QList<FiffDirNode::SPtr> acqpars = meas_info[0]->dir_tree_find(FIFFB_DACQ_PARS);
1146 QString acq_pars;
1147 QString acq_stim;
1148 if (acqpars.size() == 1) {
1149 for (k = 0; k < acqpars[0]->nent(); ++k) {
1150 kind = acqpars[0]->dir[k]->kind;
1151 pos = acqpars[0]->dir[k]->pos;
1152 if (kind == FIFF_DACQ_PARS) {
1153 this->read_tag(t_pTag, pos);
1154 acq_pars = t_pTag->toString();
1155 } else if (kind == FIFF_DACQ_STIM) {
1156 this->read_tag(t_pTag, pos);
1157 acq_stim = t_pTag->toString();
1158 }
1159 }
1160 }
1161 //
1162 // Load the SSP data
1163 //
1164 QList<FiffProj> projs = this->read_proj(meas_info[0]); //ToDo Member Function
1165 //
1166 // Load the CTF compensation data
1167 //
1168 QList<FiffCtfComp> comps = this->read_ctf_comp(meas_info[0], chs); //ToDo Member Function
1169 //
1170 // Load the bad channel list
1171 //
1172 QStringList bads = this->read_bad_channels(p_Node);
1173 //
1174 // Put the data together
1175 //
1176 // info = new FiffInfo();
1177 if (p_Node->id.version != -1)
1178 info.file_id = p_Node->id;
1179 else
1180 info.file_id.version = -1;
1181
1182 //
1183 // Make the most appropriate selection for the measurement id
1184 //
1185 if (meas_info[0]->parent_id.version == -1) {
1186 if (meas_info[0]->id.version == -1) {
1187 if (meas[0]->id.version == -1) {
1188 if (meas[0]->parent_id.version == -1)
1189 info.meas_id = info.file_id;
1190 else
1191 info.meas_id = meas[0]->parent_id;
1192 } else
1193 info.meas_id = meas[0]->id;
1194 } else
1195 info.meas_id = meas_info[0]->id;
1196 } else
1197 info.meas_id = meas_info[0]->parent_id;
1198
1199 if (meas_date[0] == -1) {
1200 info.meas_date[0] = info.meas_id.time.secs;
1201 info.meas_date[1] = info.meas_id.time.usecs;
1202 } else {
1203 info.meas_date[0] = meas_date[0];
1204 info.meas_date[1] = meas_date[1];
1205 }
1206
1207 info.nchan = nchan;
1208 info.sfreq = sfreq;
1209 info.linefreq = linefreq;
1210
1211 if (highpass != -1.0f)
1212 info.highpass = highpass;
1213 else
1214 info.highpass = 0.0f;
1215
1216 if (lowpass != -1.0f)
1217 info.lowpass = lowpass;
1218 else
1219 info.lowpass = info.sfreq / 2.0;
1220
1221 //
1222 // Add the channel information and make a list of channel names
1223 // for convenience
1224 //
1225 info.chs = chs;
1226 for (qint32 c = 0; c < info.nchan; ++c)
1227 info.ch_names << info.chs[c].ch_name;
1228
1229 //
1230 // Add the coordinate transformations
1231 //
1232 info.dev_head_t = dev_head_t;
1233 info.ctf_head_t = ctf_head_t;
1234 info.all_coord_trans = all_coord_trans;
1235 if (!info.dev_head_t.isEmpty() && !info.ctf_head_t.isEmpty())
1237 else
1238 info.dev_ctf_t.clear();
1239
1240 //
1241 // All kinds of auxliary stuff
1242 //
1243 info.dig = dig;
1244 if (!dig_trans.isEmpty())
1245 info.dig_trans = dig_trans;
1246
1247 info.experimenter = experimenter;
1248 info.description = description;
1249 info.proj_id = proj_id;
1250 info.proj_name = proj_name;
1251 info.xplotter_layout = xplotter_layout;
1252 info.gantry_angle = gantry_angle;
1253 info.utc_offset = utc_offset;
1254
1255 info.bads = bads;
1256 info.projs = projs;
1257 info.comps = comps;
1258 info.acq_pars = acq_pars;
1259 info.acq_stim = acq_stim;
1260
1261 //
1262 // Locate the HPI coil excitation frequencies
1263 //
1264 // They live in one FIFFB_HPI_COIL block per coil inside the
1265 // FIFFB_HPI_MEAS block. Each coil block carries a FIFF_HPI_COIL_FREQ tag.
1266 // Files without an HPI measurement simply leave the list empty.
1267 //
1268 QList<FiffDirNode::SPtr> hpi_meas = meas_info[0]->dir_tree_find(FIFFB_HPI_MEAS);
1269 if (!hpi_meas.isEmpty()) {
1270 QList<FiffDirNode::SPtr> hpi_coils = hpi_meas[0]->dir_tree_find(FIFFB_HPI_COIL);
1271
1272 for (qint32 c = 0; c < hpi_coils.size(); ++c) {
1273 for (qint32 e = 0; e < hpi_coils[c]->nent(); ++e) {
1274 if (hpi_coils[c]->dir[e]->kind != FIFF_HPI_COIL_FREQ) {
1275 continue;
1276 }
1277
1278 this->read_tag(t_pTag, hpi_coils[c]->dir[e]->pos);
1279 info.hpi_coil_freqs.append(*t_pTag->toFloat());
1280 break;
1281 }
1282 }
1283 }
1284
1285 p_NodeInfo = meas[0];
1286
1287 return true;
1288}
1289
1290//=============================================================================================================
1291
1293{
1294 mat.clear();
1295
1296 FiffDirNode::SPtr node = p_Node;
1297 //
1298 // Descend one level if necessary
1299 //
1300 bool found_it = false;
1301 if (node->type != FIFFB_MNE_NAMED_MATRIX) {
1302 for (int k = 0; k < node->nchild(); ++k) {
1303 if (node->children[k]->type == FIFFB_MNE_NAMED_MATRIX) {
1304 if (node->children[k]->has_tag(matkind)) {
1305 node = node->children[k];
1306 found_it = true;
1307 break;
1308 }
1309 }
1310 }
1311 if (!found_it) {
1312 qWarning("Fiff::read_named_matrix: Desired named matrix (kind = %d) not available\n", matkind);
1313 return false;
1314 }
1315 } else {
1316 if (!node->has_tag(matkind)) {
1317 qWarning("Desired named matrix (kind = %d) not available", matkind);
1318 return false;
1319 }
1320 }
1321
1322 FiffTag::UPtr t_pTag;
1323 //
1324 // Read everything we need
1325 //
1326 if (!node->find_tag(this, matkind, t_pTag)) {
1327 qWarning("Matrix data missing.\n");
1328 return false;
1329 } else {
1330 //qDebug() << "Is Matrix" << t_pTag->isMatrix() << "Special Type:" << t_pTag->getType();
1331 mat.data = t_pTag->toFloatMatrix().cast<double>();
1332 mat.data.transposeInPlace();
1333 }
1334
1335 mat.nrow = mat.data.rows();
1336 mat.ncol = mat.data.cols();
1337
1338 if (node->find_tag(this, FIFF_MNE_NROW, t_pTag))
1339 if (*t_pTag->toInt() != mat.nrow) {
1340 qWarning("Number of rows in matrix data and FIFF_MNE_NROW tag do not match");
1341 return false;
1342 }
1343 if (node->find_tag(this, FIFF_MNE_NCOL, t_pTag))
1344 if (*t_pTag->toInt() != mat.ncol) {
1345 qWarning("Number of columns in matrix data and FIFF_MNE_NCOL tag do not match");
1346 return false;
1347 }
1348
1349 QString row_names;
1350 if (node->find_tag(this, FIFF_MNE_ROW_NAMES, t_pTag))
1351 row_names = t_pTag->toString();
1352
1353 QString col_names;
1354 if (node->find_tag(this, FIFF_MNE_COL_NAMES, t_pTag))
1355 col_names = t_pTag->toString();
1356
1357 //
1358 // Put it together
1359 //
1360 if (!row_names.isEmpty())
1361 mat.row_names = split_name_list(row_names);
1362
1363 if (!col_names.isEmpty())
1364 mat.col_names = split_name_list(col_names);
1365
1366 if (mat.row_names.size() != mat.nrow) {
1367 qWarning("FiffStream::read_named_matrix - Number of rows in matrix data and row names do not match\n");
1368 }
1369
1370 if (mat.col_names.size() != mat.ncol) {
1371 qWarning("FiffStream::read_named_matrix - Number of columns in matrix data and column names do not match\n");
1372 }
1373
1374 return true;
1375}
1376
1377//=============================================================================================================
1378
1379QList<FiffProj> FiffStream::read_proj(const FiffDirNode::SPtr& p_Node)
1380{
1381 QList<FiffProj> projdata; // = struct('kind',{},'active',{},'desc',{},'data',{});
1382 //
1383 // Locate the projection data
1384 //
1385 QList<FiffDirNode::SPtr> t_qListNodes = p_Node->dir_tree_find(FIFFB_PROJ);
1386 if (t_qListNodes.size() == 0)
1387 return projdata;
1388
1389 FiffTag::UPtr t_pTag;
1390 t_qListNodes[0]->find_tag(this, FIFF_NCHAN, t_pTag);
1391 fiff_int_t global_nchan = 0;
1392 if (t_pTag)
1393 global_nchan = *t_pTag->toInt();
1394
1395 fiff_int_t nchan;
1396 QList<FiffDirNode::SPtr> t_qListItems = t_qListNodes[0]->dir_tree_find(FIFFB_PROJ_ITEM);
1397 for (qint32 i = 0; i < t_qListItems.size(); ++i) {
1398 //
1399 // Find all desired tags in one item
1400 //
1401 FiffDirNode::SPtr t_pFiffDirTreeItem = t_qListItems[i];
1402 t_pFiffDirTreeItem->find_tag(this, FIFF_NCHAN, t_pTag);
1403 if (t_pTag)
1404 nchan = *t_pTag->toInt();
1405 else
1406 nchan = global_nchan;
1407
1408 t_pFiffDirTreeItem->find_tag(this, FIFF_DESCRIPTION, t_pTag);
1409 QString desc; // maybe, in some cases this has to be a struct.
1410 if (t_pTag) {
1411 desc = t_pTag->toString();
1412 } else {
1413 t_pFiffDirTreeItem->find_tag(this, FIFF_NAME, t_pTag);
1414 if (t_pTag)
1415 desc = t_pTag->toString();
1416 else {
1417 qWarning("Projection item description missing\n");
1418 return projdata;
1419 }
1420 }
1421 // t_pFiffDirTreeItem->find_tag(this, FIFF_PROJ_ITEM_CH_NAME_LIST, t_pTag);
1422 // QString namelist;
1423 // if (t_pTag)
1424 // {
1425 // namelist = t_pTag->toString();
1426 // }
1427 // else
1428 // {
1429 // qCritical("Projection item channel list missing");
1430 // return projdata;
1431 // }
1432 t_pFiffDirTreeItem->find_tag(this, FIFF_PROJ_ITEM_KIND, t_pTag);
1433 fiff_int_t kind;
1434 if (t_pTag) {
1435 kind = *t_pTag->toInt();
1436 } else {
1437 qWarning("Projection item kind missing");
1438 return projdata;
1439 }
1440 t_pFiffDirTreeItem->find_tag(this, FIFF_PROJ_ITEM_NVEC, t_pTag);
1441 fiff_int_t nvec;
1442 if (t_pTag) {
1443 nvec = *t_pTag->toInt();
1444 } else {
1445 qWarning("Number of projection vectors not specified\n");
1446 return projdata;
1447 }
1448 t_pFiffDirTreeItem->find_tag(this, FIFF_PROJ_ITEM_CH_NAME_LIST, t_pTag);
1449 QStringList names;
1450 if (t_pTag) {
1451 names = split_name_list(t_pTag->toString());
1452 } else {
1453 qWarning("Projection item channel list missing\n");
1454 return projdata;
1455 }
1456 t_pFiffDirTreeItem->find_tag(this, FIFF_PROJ_ITEM_VECTORS, t_pTag);
1457 MatrixXd data; // = nullptr;
1458 if (t_pTag) {
1459 data = t_pTag->toFloatMatrix().cast<double>();
1460 data.transposeInPlace();
1461 } else {
1462 qWarning("Projection item data missing\n");
1463 return projdata;
1464 }
1465 t_pFiffDirTreeItem->find_tag(this, FIFF_MNE_PROJ_ITEM_ACTIVE, t_pTag);
1466 bool active;
1467 if (t_pTag)
1468 active = *t_pTag->toInt();
1469 else
1470 active = false;
1471
1472 if (data.cols() != names.size()) {
1473 qWarning("Number of channel names does not match the size of data matrix\n");
1474 return projdata;
1475 }
1476
1477 //
1478 // create a named matrix for the data
1479 //
1480 QStringList defaultList;
1481 FiffNamedMatrix t_fiffNamedMatrix(nvec, nchan, defaultList, names, data);
1482
1483 FiffProj one(kind, active, desc, t_fiffNamedMatrix);
1484 //
1485 projdata.append(one);
1486 }
1487
1488 if (projdata.size() > 0) {
1489 qInfo("\tRead a total of %lld projection items:\n", static_cast<long long>(projdata.size()));
1490 for (qint32 k = 0; k < projdata.size(); ++k) {
1491 qInfo("\t\t%s (%d x %d) %s\n", projdata[k].desc.toUtf8().constData(), projdata[k].data->nrow, projdata[k].data->ncol, projdata[k].active ? "active" : "idle");
1492 }
1493 }
1494
1495 return projdata;
1496}
1497
1498//=============================================================================================================
1499
1501{
1502 if (pos >= 0) {
1503 this->device()->seek(pos);
1504 }
1505
1506 if (!p_pTag)
1507 return false;
1508
1509 //
1510 // Read data when available
1511 //
1512 if (p_pTag->size() > 0) {
1513 this->readRawData(p_pTag->data(), p_pTag->size());
1515 }
1516
1517 if (p_pTag->next != FIFFV_NEXT_SEQ)
1518 this->device()->seek(p_pTag->next); //fseek(fid,tag.next,'bof');
1519
1520 return true;
1521}
1522
1523//=============================================================================================================
1524
1526{
1527 fiff_long_t pos = this->device()->pos();
1528
1529 p_pTag = std::make_unique<FiffTag>();
1530
1531 //Option 1
1532 // t_DataStream.readRawData((char *)p_pTag, FIFFC_TAG_INFO_SIZE);
1533 // p_pTag->kind = Fiff::swap_int(p_pTag->kind);
1534 // p_pTag->type = Fiff::swap_int(p_pTag->type);
1535 // p_pTag->size = Fiff::swap_int(p_pTag->size);
1536 // p_pTag->next = Fiff::swap_int(p_pTag->next);
1537
1538 //Option 2
1539 *this >> p_pTag->kind;
1540 *this >> p_pTag->type;
1541 qint32 size;
1542 *this >> size;
1543 p_pTag->resize(size);
1544 *this >> p_pTag->next;
1545
1546 // qDebug() << "read_tag_info" << " Kind:" << p_pTag->kind << " Type:" << p_pTag->type << " Size:" << p_pTag->size() << " Next:" << p_pTag->next;
1547
1548 if (p_bDoSkip) {
1549 QTcpSocket* t_qTcpSocket = qobject_cast<QTcpSocket*>(this->device());
1550 if (t_qTcpSocket) {
1551 this->skipRawData(p_pTag->size());
1552 } else {
1553 if (p_pTag->next > 0) {
1554 if (!this->device()->seek(p_pTag->next)) {
1555 qCritical("fseek"); //fseek(fid,tag.next,'bof');
1556 pos = -1;
1557 }
1558 } else if (p_pTag->size() > 0 && p_pTag->next == FIFFV_NEXT_SEQ) {
1559 if (!this->device()->seek(this->device()->pos() + p_pTag->size())) {
1560 qCritical("fseek"); //fseek(fid,tag.size,'cof');
1561 pos = -1;
1562 }
1563 }
1564 }
1565 }
1566 return pos;
1567}
1568
1569//=============================================================================================================
1570
1572{
1573 while (this->device()->bytesAvailable() < 16)
1574 this->device()->waitForReadyRead(10);
1575
1576 // if(!this->read_tag_info(p_pTag, false))
1577 // return false;
1578 this->read_tag_info(p_pTag, false);
1579
1580 while (this->device()->bytesAvailable() < p_pTag->size())
1581 this->device()->waitForReadyRead(10);
1582
1583 if (!this->read_tag_data(p_pTag))
1584 return false;
1585
1586 return true;
1587}
1588
1589//=============================================================================================================
1590
1592 fiff_long_t pos)
1593{
1594 if (pos >= 0) {
1595 this->device()->seek(pos);
1596 }
1597
1598 p_pTag = std::make_unique<FiffTag>();
1599
1600 //
1601 // Read fiff tag header from stream
1602 //
1603 *this >> p_pTag->kind;
1604 *this >> p_pTag->type;
1605 qint32 size;
1606 *this >> size;
1607 p_pTag->resize(size);
1608 *this >> p_pTag->next;
1609
1610 // qDebug() << "read_tag" << " Kind:" << p_pTag->kind << " Type:" << p_pTag->type << " Size:" << p_pTag->size() << " Next:" << p_pTag->next;
1611
1612 //
1613 // Read data when available
1614 //
1615 int endian;
1616 if (this->byteOrder() == QDataStream::LittleEndian) {
1617 endian = FIFFV_LITTLE_ENDIAN;
1618 //qInfo("Endian: Little");
1619 } else {
1620 endian = FIFFV_BIG_ENDIAN;
1621 //qInfo("Endian: Big");
1622 }
1623
1624 if (p_pTag->size() > 0) {
1625 this->readRawData(p_pTag->data(), p_pTag->size());
1626
1627 //FiffTag::convert_tag_data(p_pTag,FIFFV_BIG_ENDIAN,FIFFV_NATIVE_ENDIAN);
1629 }
1630
1631 if (p_pTag->next != FIFFV_NEXT_SEQ)
1632 this->device()->seek(p_pTag->next); //fseek(fid,tag.next,'bof');
1633
1634 return true;
1635}
1636
1637//=============================================================================================================
1638
1639bool FiffStream::setup_read_raw(QIODevice& p_IODevice,
1640 FiffRawData& data,
1641 bool allow_maxshield,
1642 bool is_littleEndian)
1643{
1644 //
1645 // Open the file
1646 //
1647 FiffStream::SPtr t_pStream(new FiffStream(&p_IODevice));
1648 QString t_sFileName = t_pStream->streamName();
1649
1650 if (is_littleEndian) {
1651 //qInfo("Setting stream to little Endian");
1652 t_pStream->setByteOrder(QDataStream::LittleEndian);
1653 }
1654
1655 qInfo("Opening raw data %s...\n", t_sFileName.toUtf8().constData());
1656
1657 if (!t_pStream->open()) {
1658 return false;
1659 }
1660
1661 //
1662 // Read the measurement info
1663 //
1664 FiffInfo info; // = nullptr;
1665 FiffDirNode::SPtr meas;
1666 if (!t_pStream->read_meas_info(t_pStream->dirtree(), info, meas))
1667 return false;
1668
1669 //
1670 // Locate the data of interest
1671 //
1672 QList<FiffDirNode::SPtr> raw = meas->dir_tree_find(FIFFB_RAW_DATA);
1673 if (raw.size() == 0) {
1674 raw = meas->dir_tree_find(FIFFB_CONTINUOUS_DATA);
1675 if (allow_maxshield) {
1676 // for (qint32 i = 0; i < raw.size(); ++i)
1677 // if(raw[i])
1678 // delete raw[i];
1679 raw = meas->dir_tree_find(FIFFB_SMSH_RAW_DATA);
1680 qInfo("Maxshield data found\n");
1681
1682 if (raw.size() == 0) {
1683 qWarning("No raw data in %s\n", t_sFileName.toUtf8().constData());
1684 return false;
1685 }
1686 } else {
1687 if (raw.size() == 0) {
1688 qWarning("No raw data in %s\n", t_sFileName.toUtf8().constData());
1689 return false;
1690 }
1691 }
1692 }
1693 //
1694 // Set up the output structure
1695 //
1696 info.filename = t_sFileName;
1697
1698 data.clear();
1699 data.file = t_pStream; // fid;
1700 data.info = info;
1701 data.first_samp = 0;
1702 data.last_samp = 0;
1703 //
1704 // Process the directory
1705 //
1706 QList<FiffDirEntry::SPtr> dir = raw[0]->dir;
1707 fiff_int_t nent = raw[0]->nent();
1708 fiff_int_t nchan = info.nchan;
1709 fiff_int_t first = 0;
1710 fiff_int_t first_samp = 0;
1711 fiff_int_t first_skip = 0;
1712 //
1713 // A malformed file may have a raw data block with an empty directory.
1714 // Bail out cleanly instead of indexing past the end of dir below.
1715 //
1716 if (dir.isEmpty()) {
1717 qWarning("No directory entries in raw data block of %s\n", t_sFileName.toUtf8().constData());
1718 return false;
1719 }
1720 //
1721 // The per-buffer sample count below is derived by dividing the data
1722 // buffer size by the channel count. A malformed measurement info with no
1723 // channels would cause a division by zero, so reject it up front.
1724 //
1725 if (nchan <= 0) {
1726 qWarning("Measurement info of %s reports %d channels; cannot read raw data\n", t_sFileName.toUtf8().constData(), nchan);
1727 return false;
1728 }
1729 //
1730 // Get first sample tag if it is there
1731 //
1732 FiffTag::UPtr t_pTag;
1733 if (dir[first]->kind == FIFF_FIRST_SAMPLE) {
1734 t_pStream->read_tag(t_pTag, dir[first]->pos);
1735 first_samp = *t_pTag->toInt();
1736 ++first;
1737 }
1738 //
1739 // Omit initial skip
1740 //
1741 if (first < dir.size() && dir[first]->kind == FIFF_DATA_SKIP) {
1742 //
1743 // This first skip can be applied only after we know the buffer size
1744 //
1745 t_pStream->read_tag(t_pTag, dir[first]->pos);
1746 first_skip = *t_pTag->toInt();
1747 ++first;
1748 }
1749 data.first_samp = first_samp;
1750 //
1751 // Go through the remaining tags in the directory
1752 //
1753 QList<FiffRawDir> rawdir;
1754 // rawdir = struct('ent',{},'first',{},'last',{},'nsamp',{});
1755 fiff_int_t nskip = 0;
1756 fiff_int_t nsamp = 0;
1757 for (qint32 k = first; k < nent; ++k) {
1758 FiffDirEntry::SPtr ent = dir[k];
1759 if (ent->kind == FIFF_DATA_SKIP) {
1760 t_pStream->read_tag(t_pTag, ent->pos);
1761 nskip = *t_pTag->toInt();
1762 } else if (ent->kind == FIFF_DATA_BUFFER) {
1763 //
1764 // Figure out the number of samples in this buffer
1765 //
1766 switch (ent->type) {
1767 case FIFFT_DAU_PACK16:
1768 nsamp = ent->size / (2 * nchan);
1769 break;
1770 case FIFFT_SHORT:
1771 nsamp = ent->size / (2 * nchan);
1772 break;
1773 case FIFFT_FLOAT:
1774 nsamp = ent->size / (4 * nchan);
1775 break;
1776 case FIFFT_INT:
1777 nsamp = ent->size / (4 * nchan);
1778 break;
1779 case FIFFT_DOUBLE:
1780 nsamp = ent->size / (8 * nchan);
1781 break;
1782 default:
1783 qWarning("Cannot handle data buffers of type %d\n", ent->type);
1784 return false;
1785 }
1786 //
1787 // Do we have an initial skip pending?
1788 //
1789 if (first_skip > 0) {
1790 first_samp += nsamp * first_skip;
1791 data.first_samp = first_samp;
1792 first_skip = 0;
1793 }
1794 //
1795 // Do we have a skip pending?
1796 //
1797 if (nskip > 0) {
1798 FiffRawDir t_RawDir;
1799 // Readers recognise a skip by ent->kind == -1 (the FiffDirEntry default) and fill it with zeros.
1800 t_RawDir.ent = FiffDirEntry::SPtr(new FiffDirEntry);
1801 t_RawDir.first = first_samp;
1802 t_RawDir.last = first_samp + nskip * nsamp - 1; //ToDo -1 right or is that MATLAB syntax
1803 t_RawDir.nsamp = nskip * nsamp;
1804 rawdir.append(t_RawDir);
1805 first_samp = first_samp + nskip * nsamp;
1806 nskip = 0;
1807 }
1808 //
1809 // Add a data buffer
1810 //
1811 FiffRawDir t_RawDir;
1812 t_RawDir.ent = ent;
1813 t_RawDir.first = first_samp;
1814 t_RawDir.last = first_samp + nsamp - 1; //ToDo -1 right or is that MATLAB syntax
1815 t_RawDir.nsamp = nsamp;
1816 rawdir.append(t_RawDir);
1817 first_samp += nsamp;
1818 }
1819 }
1820 data.last_samp = first_samp - 1; //ToDo -1 right or is that MATLAB syntax
1821 //
1822 // Add the calibration factors
1823 //
1824 RowVectorXd cals(data.info.nchan);
1825 cals.setZero();
1826 for (qint32 k = 0; k < data.info.nchan; ++k)
1827 cals[k] = static_cast<double>(data.info.chs[k].range) * data.info.chs[k].cal;
1828 //
1829 data.cals = cals;
1830 data.rawdir = rawdir;
1831 //data->proj = [];
1832 //data.comp = [];
1833 //
1834 qInfo("\tRange : %d ... %d = %9.3f ... %9.3f secs",
1835 data.first_samp, data.last_samp,
1836 static_cast<double>(data.first_samp) / data.info.sfreq,
1837 static_cast<double>(data.last_samp) / data.info.sfreq);
1838 qInfo("Ready.");
1839 data.file->close();
1840
1841 return true;
1842}
1843
1844//=============================================================================================================
1845
1846QStringList FiffStream::split_name_list(QString p_sNameList)
1847{
1848 return p_sNameList.replace(" ", "").split(":");
1849}
1850
1851//=============================================================================================================
1852
1854{
1855 return this->write_int(FIFF_BLOCK_START, &kind);
1856}
1857
1858//=============================================================================================================
1859
1861{
1862 FiffStream::SPtr p_pStream(new FiffStream(&p_IODevice));
1863 QString t_sFileName = p_pStream->streamName();
1864
1865 if (!p_IODevice.isOpen()) {
1866 if (!p_pStream->device()->open(QIODevice::WriteOnly)) {
1867 qWarning("Cannot write to %s\n", t_sFileName.toUtf8().constData()); //consider throw
1868 FiffStream::SPtr p_pEmptyStream;
1869 return p_pEmptyStream;
1870 }
1871 }
1872
1873 //
1874 // Write the compulsory items
1875 //
1876 p_pStream->write_id(FIFF_FILE_ID); //1
1877 int null_pointer = FIFFV_NEXT_NONE;
1878 p_pStream->write_int(FIFF_DIR_POINTER, &null_pointer); //2
1879 p_pStream->write_int(FIFF_FREE_LIST, &null_pointer); //3
1880 //
1881 // Ready for more
1882 //
1883 return p_pStream;
1884}
1885
1886//=============================================================================================================
1887
1889{
1890 FiffStream::SPtr t_pStream(new FiffStream(&p_IODevice));
1891 QString t_sFileName = t_pStream->streamName();
1892
1893 /*
1894 * ReadWrite creates the file, so a path that is not there would be turned into
1895 * an empty file that then fails to parse, leaving the caller's directory dirty.
1896 * Updating a file that does not exist is never the intent.
1897 */
1898 QFile* t_pFile = qobject_cast<QFile*>(&p_IODevice);
1899 if (t_pFile != nullptr && !t_pFile->exists()) {
1900 qCritical("Cannot open %s for update: no such file", t_sFileName.toUtf8().constData());
1901 return FiffStream::SPtr();
1902 }
1903
1904 /*
1905 * Try to open...
1906 */
1907 if (!t_pStream->open(QIODevice::ReadWrite)) {
1908 qCritical("Cannot open %s\n", t_sFileName.toUtf8().constData()); //consider throw
1909 return FiffStream::SPtr();
1910 }
1911
1912 FiffTag::UPtr t_pTag;
1913 long dirpos, pointerpos;
1914
1915 QFile* file = qobject_cast<QFile*>(t_pStream->device());
1916
1917 if (file != nullptr) {
1918 /*
1919 * Ensure that the last tag in the directory has next set to FIFF_NEXT_NONE
1920 */
1921 pointerpos = t_pStream->dir()[t_pStream->nent() - 2]->pos;
1922 if (!t_pStream->read_tag(t_pTag, pointerpos)) {
1923 qCritical("Could not read last tag in the directory list!");
1924 t_pStream->close();
1925 return FiffStream::SPtr();
1926 }
1927 if (t_pTag->next != FIFFV_NEXT_NONE) {
1928 t_pTag->next = FIFFV_NEXT_NONE;
1929 t_pStream->write_tag(t_pTag, pointerpos);
1930 }
1931 /*
1932 * Read directory pointer
1933 */
1934 pointerpos = t_pStream->dir()[1]->pos;
1935 if (!t_pStream->read_tag(t_pTag, pointerpos)) {
1936 qCritical("Could not read directory pointer!");
1937 t_pStream->close();
1938 return FiffStream::SPtr();
1939 }
1940 /*
1941 * Do we have a directory?
1942 */
1943 dirpos = *t_pTag->toInt();
1944 if (dirpos > 0) {
1945 /*
1946 * Yes! We will ignore it.
1947 */
1948 t_pStream->write_dir_pointer(-1, pointerpos);
1949 /*
1950 * Clean up the trailing end
1951 */
1952 file->resize(dirpos); //truncate file to new size
1953 }
1954 /*
1955 * Seek to end for writing
1956 */
1957 t_pStream->device()->seek(file->size()); //SEEK_END
1958 }
1959 return t_pStream;
1960}
1961
1962//=============================================================================================================
1963
1965 const FiffInfo& info,
1966 RowVectorXd& cals,
1967 MatrixXi sel,
1968 bool bResetRange)
1969{
1970 //
1971 // We will always write floats
1972 //
1973 fiff_int_t data_type = 4;
1974
1975 // The channel list is authoritative: nchan is -1 until a reader sets it
1976 if (sel.cols() == 0) {
1977 sel.resize(1, info.chs.size());
1978 for (qint32 k = 0; k < info.chs.size(); ++k)
1979 sel(0, k) = k;
1980 }
1981
1982 QList<FiffChInfo> chs;
1983
1984 for (qint32 k = 0; k < sel.cols(); ++k)
1985 chs << info.chs.at(sel(0, k));
1986
1987 fiff_int_t nchan = chs.size();
1988
1989 //
1990 // Create the file and save the essentials
1991 //
1992 FiffStream::SPtr t_pStream = start_file(p_IODevice); //1, 2, 3
1993 if (!t_pStream) {
1994 return t_pStream;
1995 }
1996 t_pStream->start_block(FIFFB_MEAS); //4
1997 t_pStream->write_id(FIFF_BLOCK_ID); //5
1998 if (info.meas_id.version != -1) {
1999 t_pStream->write_id(FIFF_PARENT_BLOCK_ID, info.meas_id); //6
2000 }
2001 //
2002 //
2003 // Measurement info
2004 //
2005 t_pStream->start_block(FIFFB_MEAS_INFO); //7
2006
2007#ifndef WASMBUILD
2008 //
2009 // Blocks from the original
2010 //
2011 QList<fiff_int_t> blocks;
2013 bool have_hpi_result = false;
2014 bool have_isotrak = false;
2015 if (blocks.size() > 0 && !info.filename.isEmpty()) {
2016 QFile t_qFile(info.filename); //ToDo this has to be adapted for TCPSocket
2017 FiffStream::SPtr t_pStream2(new FiffStream(&t_qFile));
2018
2019 if (!t_pStream2->open()) {
2020 qDebug() << "Failed to open file. Returning early";
2021 return t_pStream;
2022 }
2023
2024 for (qint32 k = 0; k < blocks.size(); ++k) {
2025 QList<FiffDirNode::SPtr> nodes = t_pStream2->dirtree()->dir_tree_find(blocks[k]);
2026 FiffDirNode::copy_tree(t_pStream2, t_pStream2->dirtree()->id, nodes, t_pStream);
2027 if (blocks[k] == FIFFB_HPI_RESULT && nodes.size() > 0)
2028 have_hpi_result = true;
2029
2030 if (blocks[k] == FIFFB_ISOTRAK && nodes.size() > 0)
2031 have_isotrak = true;
2032 }
2033
2034 t_pStream2 = FiffStream::SPtr();
2035 }
2036#endif
2037
2038 //
2039 // megacq parameters
2040 //
2041 if (!info.acq_pars.isEmpty() || !info.acq_stim.isEmpty()) {
2042 t_pStream->start_block(FIFFB_DACQ_PARS);
2043 if (!info.acq_pars.isEmpty())
2044 t_pStream->write_string(FIFF_DACQ_PARS, info.acq_pars);
2045
2046 if (!info.acq_stim.isEmpty())
2047 t_pStream->write_string(FIFF_DACQ_STIM, info.acq_stim);
2048
2049 t_pStream->end_block(FIFFB_DACQ_PARS);
2050 }
2051
2052#ifndef WASMBUILD
2053 //
2054 // Coordinate transformations if the HPI result block was not there
2055 //
2056 if (!have_hpi_result) {
2057 if (!info.dev_head_t.isEmpty())
2058 t_pStream->write_coord_trans(info.dev_head_t);
2059
2060 if (!info.ctf_head_t.isEmpty())
2061 t_pStream->write_coord_trans(info.ctf_head_t);
2062 }
2063 //
2064 // Polhemus data
2065 //
2066 if (info.dig.size() > 0 && !have_isotrak) {
2067 t_pStream->start_block(FIFFB_ISOTRAK);
2068 for (qint32 k = 0; k < info.dig.size(); ++k)
2069 t_pStream->write_dig_point(info.dig[k]);
2070
2071 t_pStream->end_block(FIFFB_ISOTRAK);
2072 }
2073#endif
2074
2075 //
2076 // Projectors
2077 //
2078 t_pStream->write_proj(info.projs);
2079 //
2080 // CTF compensation info
2081 //
2082 t_pStream->write_ctf_comp(info.comps);
2083 //
2084 // Bad channels
2085 //
2086 if (info.bads.size() > 0) {
2087 t_pStream->start_block(FIFFB_MNE_BAD_CHANNELS);
2088 t_pStream->write_name_list(FIFF_MNE_CH_NAME_LIST, info.bads);
2089 t_pStream->end_block(FIFFB_MNE_BAD_CHANNELS);
2090 }
2091 //
2092 // General
2093 //
2094 t_pStream->write_float(FIFF_SFREQ, &info.sfreq);
2095 t_pStream->write_float(FIFF_HIGHPASS, &info.highpass);
2096 t_pStream->write_float(FIFF_LOWPASS, &info.lowpass);
2097 t_pStream->write_float(FIFF_LINE_FREQ, &info.linefreq);
2098 t_pStream->write_int(FIFF_GANTRY_ANGLE, &info.gantry_angle);
2099 t_pStream->write_int(FIFF_NCHAN, &nchan);
2100 t_pStream->write_int(FIFF_DATA_PACK, &data_type);
2101 t_pStream->write_int(FIFF_PROJ_ID, &info.proj_id);
2102 t_pStream->write_string(FIFF_EXPERIMENTER, info.experimenter);
2103 t_pStream->write_string(FIFF_DESCRIPTION, info.description);
2104 t_pStream->write_string(FIFF_PROJ_NAME, info.proj_name);
2105 t_pStream->write_string(FIFF_XPLOTTER_LAYOUT, info.xplotter_layout);
2106 if (info.meas_date[0] != -1)
2107 t_pStream->write_int(FIFF_MEAS_DATE, info.meas_date, 2);
2108 //
2109 // Channel info
2110 //
2111 cals = RowVectorXd(nchan);
2112 for (qint32 k = 0; k < nchan; ++k) {
2113 //
2114 // Scan numbers may have been messed up
2115 //
2116 chs[k].scanNo = k + 1;
2117 if (bResetRange) {
2118 chs[k].range = 1.0; // Reset to 1.0 because we always write floats.
2119 }
2120 cals[k] = chs[k].cal;
2121 t_pStream->write_ch_info(chs[k]);
2122 }
2123 //
2124 //
2125 t_pStream->end_block(FIFFB_MEAS_INFO);
2126 //
2127 // Start the raw data
2128 //
2129 t_pStream->start_block(FIFFB_RAW_DATA);
2130
2131 return t_pStream;
2132}
2133
2134//=============================================================================================================
2135
2137{
2138 /*
2139 * Write tag to specified position
2140 */
2141 if (pos >= 0) {
2142 this->device()->seek(pos);
2143 } else { //SEEK_END
2144 QFile* file = qobject_cast<QFile*>(this->device());
2145 if (file)
2146 this->device()->seek(file->size());
2147 }
2148 pos = this->device()->pos();
2149
2150 fiff_int_t datasize = p_pTag->size();
2151
2152 *this << static_cast<qint32>(p_pTag->kind);
2153 *this << static_cast<qint32>(p_pTag->type);
2154 *this << static_cast<qint32>(datasize);
2155 *this << static_cast<qint32>(p_pTag->next);
2156
2157 /*
2158 * Do we have data?
2159 */
2160 if (datasize > 0) {
2161 // read_tag hands out host byte order; FIFF files are big-endian.
2162 auto fileTag = std::make_unique<FiffTag>(*p_pTag);
2164 this->writeRawData(fileTag->data(), datasize);
2165 }
2166
2167 return pos;
2168}
2169
2170//=============================================================================================================
2171
2173{
2174 fiff_long_t pos = this->device()->pos();
2175
2176 //typedef struct _fiffChPosRec {
2177 // fiff_int_t coil_type; /*!< What kind of coil. */
2178 // fiff_float_t r0[3]; /*!< Coil coordinate system origin */
2179 // fiff_float_t ex[3]; /*!< Coil coordinate system x-axis unit vector */
2180 // fiff_float_t ey[3]; /*!< Coil coordinate system y-axis unit vector */
2181 // fiff_float_t ez[3]; /*!< Coil coordinate system z-axis unit vector */
2182 //} fiffChPosRec,*fiffChPos; /*!< Measurement channel position and coil type */
2183
2184 //typedef struct _fiffChInfoRec {
2185 // fiff_int_t scanNo; /*!< Scanning order # */
2186 // fiff_int_t logNo; /*!< Logical channel # */
2187 // fiff_int_t kind; /*!< Kind of channel */
2188 // fiff_float_t range; /*!< Voltmeter range (only applies to raw data ) */
2189 // fiff_float_t cal; /*!< Calibration from volts to... */
2190 // fiff_ch_pos_t chpos; /*!< Channel location */
2191 // fiff_int_t unit; /*!< Unit of measurement */
2192 // fiff_int_t unit_mul; /*!< Unit multiplier exponent */
2193 // fiff_char_t ch_name[16]; /*!< Descriptive name for the channel */
2194 //} fiffChInfoRec,*fiffChInfo; /*!< Description of one channel */
2195 fiff_int_t datasize = 4 * 13 + 4 * 7 + 16;
2196
2197 *this << static_cast<qint32>(FIFF_CH_INFO);
2198 *this << static_cast<qint32>(FIFFT_CH_INFO_STRUCT);
2199 *this << static_cast<qint32>(datasize);
2200 *this << static_cast<qint32>(FIFFV_NEXT_SEQ);
2201
2202 //
2203 // Start writing fiffChInfoRec
2204 //
2205 *this << static_cast<qint32>(ch.scanNo);
2206 *this << static_cast<qint32>(ch.logNo);
2207 *this << static_cast<qint32>(ch.kind);
2208
2209 *this << ch.range;
2210 *this << ch.cal;
2211
2212 //
2213 // FiffChPos follows
2214 //
2215 write_ch_pos(ch.chpos);
2216
2217 //
2218 // unit and unit multiplier
2219 //
2220 *this << static_cast<qint32>(ch.unit);
2221 *this << static_cast<qint32>(ch.unit_mul);
2222
2223 //
2224 // Finally channel name
2225 //
2226 fiff_int_t len = ch.ch_name.size();
2227 QString ch_name;
2228 if (len > 15)
2229 ch_name = ch.ch_name.mid(0, 15);
2230 else
2231 ch_name = ch.ch_name;
2232
2233 len = ch_name.size();
2234
2235 this->writeRawData(ch_name.toUtf8().constData(), len);
2236
2237 if (len < 16) {
2238 const char* chNull = "";
2239 for (qint32 i = 0; i < 16 - len; ++i)
2240 this->writeRawData(chNull, 1);
2241 }
2242
2243 return pos;
2244}
2245
2246//=============================================================================================================
2247
2249{
2250 fiff_long_t pos = this->device()->pos();
2251
2252 //
2253 // FiffChPos
2254 //
2255 *this << static_cast<qint32>(chpos.coil_type);
2256
2257 qint32 i;
2258 // r0
2259 for (i = 0; i < 3; ++i)
2260 *this << chpos.r0[i];
2261 // ex
2262 for (i = 0; i < 3; ++i)
2263 *this << chpos.ex[i];
2264 // ey
2265 for (i = 0; i < 3; ++i)
2266 *this << chpos.ey[i];
2267 // ez
2268 for (i = 0; i < 3; ++i)
2269 *this << chpos.ez[i];
2270
2271 return pos;
2272}
2273
2274//=============================================================================================================
2275
2277{
2278 fiff_long_t pos = this->device()->pos();
2279
2280 //?typedef struct _fiffCoordTransRec {
2281 // fiff_int_t from; /*!< Source coordinate system. */
2282 // fiff_int_t to; /*!< Destination coordinate system. */
2283 // fiff_float_t rot[3][3]; /*!< The forward transform (rotation part) */
2284 // fiff_float_t move[3]; /*!< The forward transform (translation part) */
2285 // fiff_float_t invrot[3][3]; /*!< The inverse transform (rotation part) */
2286 // fiff_float_t invmove[3]; /*!< The inverse transform (translation part) */
2287 //} *fiffCoordTrans, fiffCoordTransRec; /*!< Coordinate transformation descriptor */
2288 fiff_int_t datasize = 4 * 2 * 12 + 4 * 2;
2289
2290 *this << static_cast<qint32>(FIFF_COORD_TRANS);
2291 *this << static_cast<qint32>(FIFFT_COORD_TRANS_STRUCT);
2292 *this << static_cast<qint32>(datasize);
2293 *this << static_cast<qint32>(FIFFV_NEXT_SEQ);
2294
2295 //
2296 // Start writing fiffCoordTransRec
2297 //
2298 *this << static_cast<qint32>(trans.from);
2299 *this << static_cast<qint32>(trans.to);
2300
2301 //
2302 // The transform...
2303 //
2304 qint32 r, c;
2305 for (r = 0; r < 3; ++r)
2306 for (c = 0; c < 3; ++c)
2307 *this << static_cast<float>(trans.trans(r, c));
2308 for (r = 0; r < 3; ++r)
2309 *this << static_cast<float>(trans.trans(r, 3));
2310
2311 //
2312 // ...and its inverse
2313 //
2314 for (r = 0; r < 3; ++r)
2315 for (c = 0; c < 3; ++c)
2316 *this << static_cast<float>(trans.invtrans(r, c));
2317 for (r = 0; r < 3; ++r)
2318 *this << static_cast<float>(trans.invtrans(r, 3));
2319
2320 return pos;
2321}
2322
2323//=============================================================================================================
2324
2326{
2327 fiff_long_t pos = this->device()->pos();
2328
2330
2331 //
2332 // Dimensions etc.
2333 //
2334 this->write_int(FIFF_MNE_COV_KIND, &p_FiffCov.kind);
2335 this->write_int(FIFF_MNE_COV_DIM, &p_FiffCov.dim);
2336 if (p_FiffCov.nfree > 0)
2337 this->write_int(FIFF_MNE_COV_NFREE, &p_FiffCov.nfree);
2338 //
2339 // Channel names
2340 //
2341 if (p_FiffCov.names.size() > 0)
2342 this->write_name_list(FIFF_MNE_ROW_NAMES, p_FiffCov.names);
2343 //
2344 // Data
2345 //
2346 if (p_FiffCov.diag)
2347 this->write_double(FIFF_MNE_COV_DIAG, p_FiffCov.data.col(0).data(), p_FiffCov.data.rows());
2348 else {
2349 // if issparse(cov.data)
2350 // fiff_write_float_sparse_rcs(fid,FIFF.FIFF_MNE_COV,cov.data);
2351 // else
2352 // {
2353 // Store lower triangle including diagonal (matches read_cov format)
2354 qint32 dim = p_FiffCov.dim;
2355 qint32 n = dim * (dim + 1) / 2;
2356
2357 // The loop below writes all n entries, but that is not provable at
2358 // compile time, so start from a defined state rather than passing a
2359 // possibly-uninitialised buffer to write_double.
2360 VectorXd vals = VectorXd::Zero(n);
2361 qint32 count = 0;
2362 for (qint32 i = 0; i < dim; ++i)
2363 for (qint32 j = 0; j <= i; ++j)
2364 vals(count++) = p_FiffCov.data(i, j);
2365
2366 this->write_double(FIFF_MNE_COV, vals.data(), vals.size());
2367 // }
2368 }
2369 //
2370 // Eigenvalues and vectors if present
2371 //
2372 if (p_FiffCov.eig.size() > 0 && p_FiffCov.eigvec.size() > 0) {
2373 this->write_float_matrix(FIFF_MNE_COV_EIGENVECTORS, p_FiffCov.eigvec.cast<float>());
2374 this->write_double(FIFF_MNE_COV_EIGENVALUES, p_FiffCov.eig.data(), p_FiffCov.eig.size());
2375 }
2376 //
2377 // Projection operator
2378 //
2379 this->write_proj(p_FiffCov.projs);
2380 //
2381 // Bad channels
2382 //
2383 if (p_FiffCov.bads.size() > 0) {
2385 this->write_name_list(FIFF_MNE_CH_NAME_LIST, p_FiffCov.bads);
2387 }
2388 //
2389 // Done!
2390 //
2391 this->end_block(FIFFB_MNE_COV);
2392
2393 return pos;
2394}
2395
2396//=============================================================================================================
2397
2398fiff_long_t FiffStream::write_ctf_comp(const QList<FiffCtfComp>& comps)
2399{
2400 fiff_long_t pos = this->device()->pos();
2401
2402 if (comps.size() <= 0)
2403 return -1;
2404 //
2405 // This is very simple in fact
2406 //
2408 for (qint32 k = 0; k < comps.size(); ++k) {
2409 FiffCtfComp comp(comps[k]);
2411 //
2412 // Write the compensation kind
2413 //
2415 qint32 save_calibrated = comp.save_calibrated;
2416 this->write_int(FIFF_MNE_CTF_COMP_CALIBRATED, &save_calibrated);
2417 //
2418 // Compensators are calibrated in memory; unless they are to be saved that way, undo it
2419 // (mne _write_ctf_comp)
2420 //
2421 if (!comps[k].save_calibrated) {
2422 // A compensator built in memory has no calibration factors to undo
2423 if (comp.rowcals.size() == comp.data->data.rows())
2424 comp.data->data = comp.rowcals.reshaped().cwiseInverse().asDiagonal() * comp.data->data;
2425 if (comp.colcals.size() == comp.data->data.cols())
2426 comp.data->data = comp.data->data * comp.colcals.reshaped().cwiseInverse().asDiagonal();
2427 }
2428
2429 this->write_named_matrix(FIFF_MNE_CTF_COMP_DATA, *comp.data.data());
2431 }
2433
2434 return pos;
2435}
2436
2437//=============================================================================================================
2438
2440{
2441 fiff_long_t pos = this->device()->pos();
2442
2443 //?typedef struct _fiffDigPointRec {
2444 // fiff_int_t kind; /*!< FIFF_POINT_CARDINAL,
2445 // * FIFF_POINT_HPI, or
2446 // * FIFF_POINT_EEG */
2447 // fiff_int_t ident; /*!< Number identifying this point */
2448 // fiff_float_t r[3]; /*!< Point location */
2449 //} *fiffDigPoint,fiffDigPointRec; /*!< Digitization point description */
2450 fiff_int_t datasize = 5 * 4;
2451
2452 *this << static_cast<qint32>(FIFF_DIG_POINT);
2453 *this << static_cast<qint32>(FIFFT_DIG_POINT_STRUCT);
2454 *this << static_cast<qint32>(datasize);
2455 *this << static_cast<qint32>(FIFFV_NEXT_SEQ);
2456
2457 //
2458 // Start writing fiffDigPointRec
2459 //
2460 *this << static_cast<qint32>(dig.kind);
2461 *this << static_cast<qint32>(dig.ident);
2462 for (qint32 i = 0; i < 3; ++i)
2463 *this << dig.r[i];
2464
2465 return pos;
2466}
2467
2468//=============================================================================================================
2469
2471{
2472 /*
2473 * Write entires to specified position
2474 */
2475 if (pos >= 0) {
2476 this->device()->seek(pos);
2477 } else { //SEEK_END
2478 QFile* file = qobject_cast<QFile*>(this->device());
2479 if (file)
2480 this->device()->seek(file->size());
2481 }
2482 pos = this->device()->pos();
2483
2484 fiff_int_t datasize = 1 * 4;
2485
2486 *this << static_cast<qint32>(FIFF_DIR_POINTER);
2487 *this << static_cast<qint32>(FIFFT_INT);
2488 *this << static_cast<qint32>(datasize);
2489 *this << static_cast<qint32>(next);
2490
2491 *this << dirpos;
2492
2493 return pos;
2494}
2495
2496//=============================================================================================================
2497
2498fiff_long_t FiffStream::write_dir_entries(const QList<FiffDirEntry::SPtr>& dir, fiff_long_t pos)
2499{
2500 // /** Directories are composed of these structures. *
2501 // typedef struct _fiffDirEntryRec {
2502 // fiff_int_t kind; /**< Tag number *
2503 // fiff_int_t type; /**< Data type *
2504 // fiff_int_t size; /**< How many bytes *
2505 // fiff_int_t pos; /**< Location in file
2506 // * Note: the data is located at pos +
2507 // * FIFFC_DATA_OFFSET *
2508 // } fiffDirEntryRec,*fiffDirEntry;/**< Directory is composed of these *
2509
2510 /*
2511 * Write entires to specified position
2512 */
2513 if (pos >= 0) {
2514 this->device()->seek(pos);
2515 } else { //SEEK_END
2516 QFile* file = qobject_cast<QFile*>(this->device());
2517 if (file)
2518 this->device()->seek(file->size());
2519 }
2520
2521 pos = this->device()->pos();
2522
2523 fiff_int_t nent = dir.size();
2524 fiff_int_t datasize = nent * static_cast<fiff_int_t>(sizeof(FiffDirEntry));
2525
2526 *this << static_cast<qint32>(FIFF_DIR);
2527 *this << static_cast<qint32>(FIFFT_DIR_ENTRY_STRUCT);
2528 *this << static_cast<qint32>(datasize);
2529 *this << static_cast<qint32>(FIFFV_NEXT_NONE);
2530
2531 //
2532 // Start writing FiffDirEntries
2533 //
2534 for (qint32 i = 0; i < nent; ++i) {
2535 *this << static_cast<qint32>(dir[i]->kind);
2536 *this << static_cast<qint32>(dir[i]->type);
2537 *this << static_cast<qint32>(dir[i]->size);
2538 *this << static_cast<qint32>(dir[i]->pos);
2539 }
2540
2541 return pos;
2542}
2543
2544//=============================================================================================================
2545
2547{
2548 fiff_long_t pos = this->device()->pos();
2549
2550 qint32 datasize = nel * 8;
2551
2552 *this << static_cast<qint32>(kind);
2553 *this << static_cast<qint32>(FIFFT_DOUBLE);
2554 *this << datasize;
2555 *this << static_cast<qint32>(FIFFV_NEXT_SEQ);
2556
2557 //
2558 // Write doubles as raw 8-byte big-endian values.
2559 // FiffStream sets QDataStream::SinglePrecision, which causes
2560 // operator<<(double) to write only 4 bytes. We must bypass that
2561 // to emit the full 8-byte IEEE 754 representation.
2562 //
2563 for (qint32 i = 0; i < nel; ++i) {
2564 qint64 bits;
2565 memcpy(&bits, &data[i], sizeof(double));
2566 *this << bits;
2567 }
2568
2569 return pos;
2570}
2571
2572//=============================================================================================================
2573
2575{
2576 fiff_long_t pos = this->device()->pos();
2577
2578 qint32 datasize = nel * 4;
2579
2580 *this << static_cast<qint32>(kind);
2581 *this << static_cast<qint32>(FIFFT_FLOAT);
2582 *this << datasize;
2583 *this << static_cast<qint32>(FIFFV_NEXT_SEQ);
2584
2585 for (qint32 i = 0; i < nel; ++i)
2586 *this << data[i];
2587
2588 return pos;
2589}
2590
2591//=============================================================================================================
2592
2594{
2595 fiff_long_t pos = this->device()->pos();
2596
2597 qint32 numel = mat.rows() * mat.cols();
2598
2599 fiff_int_t datasize = 4 * numel + 4 * 3;
2600
2601 *this << static_cast<qint32>(kind);
2602 *this << static_cast<qint32> FIFFT_MATRIX_FLOAT;
2603 *this << static_cast<qint32>(datasize);
2604 *this << static_cast<qint32>(FIFFV_NEXT_SEQ);
2605
2606 qint32 i, j;
2607 // Storage order: row-major
2608 for (i = 0; i < mat.rows(); ++i)
2609 for (j = 0; j < mat.cols(); ++j)
2610 *this << mat(i, j);
2611
2612 qint32 dims[3];
2613 dims[0] = mat.cols();
2614 dims[1] = mat.rows();
2615 dims[2] = 2;
2616
2617 for (i = 0; i < 3; ++i)
2618 *this << dims[i];
2619
2620 return pos;
2621}
2622
2623//=============================================================================================================
2624
2625fiff_long_t FiffStream::write_float_sparse_ccs(fiff_int_t kind, const SparseMatrix<float>& mat)
2626{
2627 fiff_long_t pos = this->device()->pos();
2628
2629 //
2630 // nnz values
2631 // nnz row indices
2632 // ncol+1 pointers
2633 // dims
2634 // nnz
2635 // ndim
2636 //
2637 qint32 nnzm = mat.nonZeros();
2638 qint32 ncol = mat.cols();
2639 fiff_int_t datasize = 4 * nnzm + 4 * nnzm + 4 * (ncol + 1) + 4 * 4;
2640 //
2641 // Nonzero entries
2642 //
2643 using T = Eigen::Triplet<float>;
2644 std::vector<T> s;
2645 s.reserve(mat.nonZeros());
2646 for (int k = 0; k < mat.outerSize(); ++k)
2647 for (SparseMatrix<float>::InnerIterator it(mat, k); it; ++it)
2648 s.push_back(T(it.row(), it.col(), it.value()));
2649
2650 s = Linalg::sortrows<float>(s, 1);
2651
2652 //[ rows, starts ] = unique(s(:,1),'first');
2653 std::vector<qint32> cols, starts;
2654 qint32 v_old = -1;
2655 quint32 i;
2656 for (i = 0; i < s.size(); ++i) {
2657 if (static_cast<signed>(s[i].col()) != v_old) {
2658 v_old = s[i].col();
2659 cols.push_back(s[i].col());
2660 starts.push_back(i);
2661 }
2662 }
2663
2664 *this << static_cast<qint32>(kind);
2665 *this << static_cast<qint32> FIFFT_CCS_MATRIX_FLOAT;
2666 *this << static_cast<qint32>(datasize);
2667 *this << static_cast<qint32>(FIFFV_NEXT_SEQ);
2668
2669 //
2670 // The data values
2671 //
2672 for (i = 0; i < s.size(); ++i)
2673 *this << s[i].value();
2674
2675 //
2676 // Row indices
2677 //
2678 for (i = 0; i < s.size(); ++i)
2679 *this << s[i].row();
2680
2681 //
2682 // Pointers
2683 //
2684 RowVectorXi ptrs = RowVectorXi::Ones(ncol + 1);
2685 ptrs.array() *= -1;
2686 quint32 k;
2687 for (k = 0; k < cols.size(); ++k)
2688 ptrs[cols[k]] = starts[k];
2689 ptrs[ncol] = nnzm;
2690 //
2691 // Fill in pointers for empty columns
2692 //
2693 for (k = ncol; k >= 1; --k)
2694 if (ptrs[k - 1] < 0)
2695 ptrs[k - 1] = ptrs[k];
2696 //
2697 for (i = 0; i < static_cast<quint32>(ptrs.size()); ++i)
2698 *this << ptrs[i];
2699 //
2700 // Dimensions
2701 //
2702 qint32 dims[4];
2703 dims[0] = mat.nonZeros();
2704 dims[1] = mat.rows();
2705 dims[2] = mat.cols();
2706 dims[3] = 2;
2707
2708 for (i = 0; i < 4; ++i)
2709 *this << dims[i];
2710
2711 return pos;
2712}
2713
2714//=============================================================================================================
2715
2716fiff_long_t FiffStream::write_float_sparse_rcs(fiff_int_t kind, const SparseMatrix<float>& mat)
2717{
2718 fiff_long_t pos = this->device()->pos();
2719
2720 //
2721 // nnz values
2722 // nnz column indices
2723 // nrow+1 pointers
2724 // dims
2725 // nnz
2726 // ndim
2727 //
2728 qint32 nnzm = mat.nonZeros();
2729 qint32 nrow = mat.rows();
2730 fiff_int_t datasize = 4 * nnzm + 4 * nnzm + 4 * (nrow + 1) + 4 * 4;
2731 //
2732 // Nonzero entries
2733 //
2734 using T = Eigen::Triplet<float>;
2735 std::vector<T> s;
2736 s.reserve(mat.nonZeros());
2737 for (int k = 0; k < mat.outerSize(); ++k)
2738 for (SparseMatrix<float>::InnerIterator it(mat, k); it; ++it)
2739 s.push_back(T(it.row(), it.col(), it.value()));
2740
2742
2743 //[ rows, starts ] = unique(s(:,1),'first');
2744 std::vector<qint32> rows, starts;
2745 qint32 v_old = -1;
2746 quint32 i;
2747 for (i = 0; i < s.size(); ++i) {
2748 if (static_cast<signed>(s[i].row()) != v_old) {
2749 v_old = s[i].row();
2750 rows.push_back(s[i].row());
2751 starts.push_back(i);
2752 }
2753 }
2754
2755 //
2756 // Write tag info header
2757 //
2758 *this << static_cast<qint32>(kind);
2759 *this << static_cast<qint32> FIFFT_RCS_MATRIX_FLOAT;
2760 *this << static_cast<qint32>(datasize);
2761 *this << static_cast<qint32>(FIFFV_NEXT_SEQ);
2762
2763 //
2764 // The data values
2765 //
2766 for (i = 0; i < s.size(); ++i)
2767 *this << s[i].value();
2768
2769 //
2770 // Column indices
2771 //
2772 for (i = 0; i < s.size(); ++i)
2773 *this << s[i].col();
2774
2775 //
2776 // Pointers
2777 //
2778 RowVectorXi ptrs = RowVectorXi::Ones(nrow + 1);
2779 ptrs.array() *= -1;
2780 quint32 k;
2781 for (k = 0; k < rows.size(); ++k)
2782 ptrs[rows[k]] = starts[k];
2783 ptrs[nrow] = nnzm;
2784
2785 //
2786 // Fill in pointers for empty rows
2787 //
2788 for (k = nrow; k >= 1; --k)
2789 if (ptrs[k - 1] < 0)
2790 ptrs[k - 1] = ptrs[k];
2791
2792 //
2793 for (i = 0; i < static_cast<quint32>(ptrs.size()); ++i)
2794 *this << ptrs[i];
2795
2796 //
2797 // Dimensions
2798 //
2799 qint32 dims[4];
2800 dims[0] = mat.nonZeros();
2801 dims[1] = mat.rows();
2802 dims[2] = mat.cols();
2803 dims[3] = 2;
2804
2805 for (i = 0; i < 4; ++i)
2806 *this << dims[i];
2807
2808 return pos;
2809}
2810
2811//=============================================================================================================
2812
2814{
2815 fiff_long_t pos = this->device()->pos();
2816
2817 FiffId t_id = id;
2818
2819 if (t_id.isEmpty()) {
2820 //
2821 // Create a new one
2822 //
2823 t_id = FiffId::new_file_id();
2824 }
2825
2826 //
2827 //
2828 fiff_int_t datasize = 5 * 4; // The id comprises five integers
2829
2830 *this << static_cast<qint32>(kind);
2831 *this << static_cast<qint32>(FIFFT_ID_STRUCT);
2832 *this << static_cast<qint32>(datasize);
2833 *this << static_cast<qint32>(FIFFV_NEXT_SEQ);
2834 //
2835 // Collect the bits together for one write
2836 //
2837 qint32 data[5];
2838 data[0] = t_id.version;
2839 data[1] = t_id.machid[0];
2840 data[2] = t_id.machid[1];
2841 data[3] = t_id.time.secs;
2842 data[4] = t_id.time.usecs;
2843
2844 for (qint32 i = 0; i < 5; ++i)
2845 *this << data[i];
2846
2847 return pos;
2848}
2849
2850//=============================================================================================================
2851
2853{
2854 fiff_long_t pos = this->device()->pos();
2855
2856 //
2857 // Information from the MEG file
2858 //
2860 this->write_string(FIFF_MNE_FILE_NAME, p_FiffInfoBase.filename);
2861 if (!p_FiffInfoBase.meas_id.isEmpty())
2862 this->write_id(FIFF_PARENT_BLOCK_ID, p_FiffInfoBase.meas_id);
2863
2864 //
2865 // General
2866 //
2867 this->write_int(FIFF_NCHAN, &p_FiffInfoBase.nchan);
2868
2869 //
2870 // Channel info
2871 //
2872 qint32 k;
2873 QList<FiffChInfo> chs;
2874 for (k = 0; k < p_FiffInfoBase.nchan; ++k)
2875 chs << p_FiffInfoBase.chs[k];
2876
2877 for (k = 0; k < p_FiffInfoBase.nchan; ++k) {
2878 //
2879 // Scan numbers may have been messed up
2880 //
2881 chs[k].scanNo = k + 1; //+1 because
2882 this->write_ch_info(chs[k]);
2883 }
2884
2885 //
2886 // Blocks from the original -> skip this
2887 //
2888 bool have_hpi_result = false;
2889
2890 //
2891 // Coordinate transformations if the HPI result block was not there
2892 //
2893 if (!have_hpi_result) {
2894 if (!p_FiffInfoBase.dev_head_t.isEmpty())
2895 this->write_coord_trans(p_FiffInfoBase.dev_head_t);
2896 if (!p_FiffInfoBase.ctf_head_t.isEmpty())
2897 this->write_coord_trans(p_FiffInfoBase.ctf_head_t);
2898 }
2899
2900 //
2901 // Bad channels
2902 //
2903 if (p_FiffInfoBase.bads.size() > 0) {
2905 this->write_name_list(FIFF_MNE_CH_NAME_LIST, p_FiffInfoBase.bads);
2907 }
2908
2910
2911 return pos;
2912}
2913
2914//=============================================================================================================
2915
2917{
2918 fiff_long_t pos = this->device()->pos();
2919
2920 fiff_int_t datasize = nel * 4;
2921
2922 *this << static_cast<qint32>(kind);
2923 *this << static_cast<qint32>(FIFFT_INT);
2924 *this << static_cast<qint32>(datasize);
2925 *this << static_cast<qint32>(next);
2926
2927 for (qint32 i = 0; i < nel; ++i)
2928 *this << data[i];
2929
2930 return pos;
2931}
2932
2933//=============================================================================================================
2934
2936{
2937 fiff_long_t pos = this->device()->pos();
2938
2939 // qint32 FIFFT_MATRIX = 1 << 30;
2940 // qint32 FIFFT_MATRIX_INT = FIFFT_INT | FIFFT_MATRIX;
2941
2942 qint32 numel = mat.rows() * mat.cols();
2943
2944 fiff_int_t datasize = 4 * numel + 4 * 3;
2945
2946 *this << static_cast<qint32>(kind);
2947 *this << static_cast<qint32> FIFFT_MATRIX_INT;
2948 *this << static_cast<qint32>(datasize);
2949 *this << static_cast<qint32>(FIFFV_NEXT_SEQ);
2950
2951 qint32 i, j;
2952 // Storage order: row-major
2953 for (i = 0; i < mat.rows(); ++i)
2954 for (j = 0; j < mat.cols(); ++j)
2955 *this << mat(i, j);
2956
2957 qint32 dims[3];
2958 dims[0] = mat.cols();
2959 dims[1] = mat.rows();
2960 dims[2] = 2;
2961
2962 for (i = 0; i < 3; ++i)
2963 *this << dims[i];
2964
2965 return pos;
2966}
2967
2968//=============================================================================================================
2969
2971{
2972 QString all = data.join(":");
2973 return this->write_string(kind, all);
2974}
2975
2976//=============================================================================================================
2977
2979{
2980 fiff_long_t pos = this->device()->pos();
2981
2983 this->write_int(FIFF_MNE_NROW, &mat.nrow);
2984 this->write_int(FIFF_MNE_NCOL, &mat.ncol);
2985 if (mat.row_names.size() > 0)
2987 if (mat.col_names.size() > 0)
2989 this->write_float_matrix(kind, mat.data.cast<float>());
2991
2992 return pos;
2993}
2994
2995//=============================================================================================================
2996
2997fiff_long_t FiffStream::write_proj(const QList<FiffProj>& projs)
2998{
2999 fiff_long_t pos = this->device()->pos();
3000
3001 if (projs.size() <= 0)
3002 return -1;
3003
3004 this->start_block(FIFFB_PROJ);
3005
3006 for (qint32 k = 0; k < projs.size(); ++k) {
3008 this->write_string(FIFF_NAME, projs[k].desc);
3009 this->write_int(FIFF_PROJ_ITEM_KIND, &projs[k].kind);
3010 if (projs[k].kind == FIFFV_PROJ_ITEM_FIELD) {
3011 float fValue = 0.0f;
3012 this->write_float(FIFF_PROJ_ITEM_TIME, &fValue);
3013 }
3014
3015 this->write_int(FIFF_NCHAN, &projs[k].data->ncol);
3016 this->write_int(FIFF_PROJ_ITEM_NVEC, &projs[k].data->nrow);
3017 qint32 bValue = static_cast<qint32>(projs[k].active);
3018 this->write_int(FIFF_MNE_PROJ_ITEM_ACTIVE, &bValue);
3019 this->write_name_list(FIFF_PROJ_ITEM_CH_NAME_LIST, projs[k].data->col_names);
3020 this->write_float_matrix(FIFF_PROJ_ITEM_VECTORS, projs[k].data->data.cast<float>()); //rows == length(names)
3022 }
3023 this->end_block(FIFFB_PROJ);
3024
3025 return pos;
3026}
3027
3028//=============================================================================================================
3029
3031{
3032 fiff_long_t pos = this->device()->pos();
3033
3034 if (p_FiffEvokedSet.evoked.isEmpty())
3035 return -1;
3036
3037 this->start_block(FIFFB_MEAS);
3038 this->write_id(FIFF_BLOCK_ID);
3039
3040 if (p_FiffEvokedSet.info.meas_id.version != -1)
3041 this->write_id(FIFF_PARENT_BLOCK_ID, p_FiffEvokedSet.info.meas_id);
3042
3043 //
3044 // Write measurement info so that the file can be read back
3045 //
3047
3048 this->write_int(FIFF_NCHAN, &p_FiffEvokedSet.info.nchan);
3049
3050 float sfreq = p_FiffEvokedSet.info.sfreq;
3051 this->write_float(FIFF_SFREQ, &sfreq);
3052
3053 for (int k = 0; k < p_FiffEvokedSet.info.nchan; ++k) {
3054 FiffChInfo ch = p_FiffEvokedSet.info.chs[k];
3055 ch.scanNo = k + 1;
3056 this->write_ch_info(ch);
3057 }
3058
3059 if (!p_FiffEvokedSet.info.dev_head_t.isEmpty())
3060 this->write_coord_trans(p_FiffEvokedSet.info.dev_head_t);
3061
3062 if (!p_FiffEvokedSet.info.projs.isEmpty())
3063 this->write_proj(p_FiffEvokedSet.info.projs);
3064
3065 if (!p_FiffEvokedSet.info.bads.isEmpty())
3066 this->write_bad_channels(p_FiffEvokedSet.info.bads);
3067
3069
3070 for (int j = 0; j < p_FiffEvokedSet.evoked.size(); ++j) {
3071 const FiffEvoked& evoked = p_FiffEvokedSet.evoked[j];
3072
3075
3076 this->write_string(FIFF_COMMENT, evoked.comment);
3077
3078 int first = evoked.first;
3079 this->write_int(FIFF_FIRST_SAMPLE, &first);
3080
3081 int last = evoked.last;
3082 this->write_int(FIFF_LAST_SAMPLE, &last);
3083
3085
3086 int aspectKind = FIFFV_ASPECT_AVERAGE;
3087 this->write_int(FIFF_ASPECT_KIND, &aspectKind);
3088
3089 int nave = evoked.nave;
3090 this->write_int(FIFF_NAVE, &nave);
3091
3092 // Readers multiply FIFF_EPOCH by each channel's cal, so store uncalibrated values.
3093 Eigen::VectorXd decal(evoked.data.rows());
3094 for (int k = 0; k < decal.size(); ++k) {
3095 const double cal = k < p_FiffEvokedSet.info.chs.size() ? p_FiffEvokedSet.info.chs[k].cal : 1.0;
3096 decal[k] = cal != 0.0 ? 1.0 / cal : 1.0;
3097 }
3098 Eigen::MatrixXf floatData = (decal.asDiagonal() * evoked.data).cast<float>();
3099 this->write_float_matrix(FIFF_EPOCH, floatData);
3100
3101 this->end_block(FIFFB_ASPECT);
3102 this->end_block(FIFFB_EVOKED);
3104 }
3105
3106 this->end_block(FIFFB_MEAS);
3107
3108 return pos;
3109}
3110
3111//=============================================================================================================
3112
3113bool FiffStream::write_raw_buffer(const MatrixXd& buf,
3114 const RowVectorXd& cals)
3115{
3116 if (buf.rows() != cals.cols()) {
3117 qWarning("buffer and calibration sizes do not match\n");
3118 return false;
3119 }
3120
3121 using T = Eigen::Triplet<double>;
3122 std::vector<T> tripletList;
3123 tripletList.reserve(cals.cols());
3124 for (qint32 i = 0; i < cals.cols(); ++i)
3125 tripletList.push_back(T(i, i, 1.0 / cals[i]));
3126
3127 SparseMatrix<double> inv_calsMat(cals.cols(), cals.cols());
3128 inv_calsMat.setFromTriplets(tripletList.begin(), tripletList.end());
3129
3130 MatrixXf tmp = (inv_calsMat * buf).cast<float>();
3131 this->write_float(FIFF_DATA_BUFFER, tmp.data(), tmp.rows() * tmp.cols());
3132 return true;
3133}
3134
3135//=============================================================================================================
3136
3137bool FiffStream::write_raw_buffer(const MatrixXd& buf,
3138 const SparseMatrix<double>& mult)
3139{
3140 if (buf.rows() != mult.cols()) {
3141 qWarning("buffer and mult sizes do not match\n");
3142 return false;
3143 }
3144
3145 SparseMatrix<double> inv_mult(mult.rows(), mult.cols());
3146 for (int k = 0; k < inv_mult.outerSize(); ++k)
3147 for (SparseMatrix<double>::InnerIterator it(mult, k); it; ++it)
3148 inv_mult.coeffRef(it.row(), it.col()) = 1 / it.value();
3149
3150 MatrixXf tmp = (inv_mult * buf).cast<float>();
3151 this->write_float(FIFF_DATA_BUFFER, tmp.data(), tmp.rows() * tmp.cols());
3152 return true;
3153}
3154
3155//=============================================================================================================
3156
3157bool FiffStream::write_raw_buffer(const MatrixXd& buf)
3158{
3159 MatrixXf tmp = buf.cast<float>();
3160 this->write_float(FIFF_DATA_BUFFER, tmp.data(), tmp.rows() * tmp.cols());
3161 return true;
3162}
3163
3164//=============================================================================================================
3165
3167 const QString& data)
3168{
3169 fiff_long_t pos = this->device()->pos();
3170
3171 const QByteArray bytes = data.toUtf8();
3172 const fiff_int_t datasize = static_cast<fiff_int_t>(bytes.size());
3173 *this << static_cast<qint32>(kind);
3174 *this << static_cast<qint32>(FIFFT_STRING);
3175 *this << static_cast<qint32>(datasize);
3176 *this << static_cast<qint32>(FIFFV_NEXT_SEQ);
3177
3178 this->writeRawData(bytes.constData(), datasize);
3179
3180 return pos;
3181}
3182
3183//=============================================================================================================
3184
3185void FiffStream::write_rt_command(fiff_int_t command, const QString& data)
3186{
3187 const QByteArray bytes = data.toUtf8();
3188 const fiff_int_t datasize = static_cast<fiff_int_t>(bytes.size());
3189 *this << static_cast<qint32>(FIFF_MNE_RT_COMMAND);
3190 *this << static_cast<qint32>(FIFFT_VOID);
3191 *this << 4 + static_cast<qint32>(datasize);
3192 *this << static_cast<qint32>(FIFFV_NEXT_SEQ);
3193 *this << command;
3194
3195 this->writeRawData(bytes.constData(), datasize);
3196}
3197
3198//=============================================================================================================
3199
3200QList<FiffDirEntry::SPtr> FiffStream::make_dir(bool* ok)
3201{
3202 FiffTag::UPtr t_pTag;
3203 QList<FiffDirEntry::SPtr> dir;
3204 FiffDirEntry::SPtr t_pFiffDirEntry;
3205 fiff_long_t pos;
3206 if (ok)
3207 *ok = false;
3208 /*
3209 * Start from the very beginning...
3210 */
3211 if (!this->device()->seek(SEEK_SET))
3212 return dir;
3213 while ((pos = this->read_tag_info(t_pTag)) != -1) {
3214 /*
3215 * Guard against reading past EOF. When QDataStream reaches the
3216 * end of the device every subsequent read silently returns zero,
3217 * so read_tag_info never returns -1. Detect this by checking
3218 * whether the stream is still healthy after the header read.
3219 */
3220 if (this->status() != QDataStream::Ok) {
3221 this->resetStatus();
3222 break;
3223 }
3224 /*
3225 * Check that we haven't run into the directory
3226 */
3227 if (t_pTag->kind == FIFF_DIR)
3228 break;
3229 /*
3230 * Put in the new entry
3231 */
3232 t_pFiffDirEntry = FiffDirEntry::SPtr(new FiffDirEntry);
3233 t_pFiffDirEntry->kind = t_pTag->kind;
3234 t_pFiffDirEntry->type = t_pTag->type;
3235 t_pFiffDirEntry->size = t_pTag->size();
3236 t_pFiffDirEntry->pos = pos;
3237
3238 dir.append(t_pFiffDirEntry);
3239 if (t_pTag->next < 0)
3240 break;
3241 }
3242 /*
3243 * Put in the new the terminating entry
3244 */
3245 t_pFiffDirEntry = FiffDirEntry::SPtr(new FiffDirEntry);
3246 t_pFiffDirEntry->kind = -1;
3247 t_pFiffDirEntry->type = -1;
3248 t_pFiffDirEntry->size = -1;
3249 t_pFiffDirEntry->pos = -1;
3250 dir.append(t_pFiffDirEntry);
3251
3252 if (ok)
3253 *ok = true;
3254 return dir;
3255}
3256
3257//=============================================================================================================
3258
3259bool FiffStream::copyProcessingHistory(const QString& fromPath, const QString& toPath)
3260{
3261 // FiffStream::open() opens the device itself
3262 QFile srcFile(fromPath);
3263 FiffStream srcStream(&srcFile);
3264 if (!srcStream.open()) {
3265 qWarning("FiffStream::copyProcessingHistory - Cannot parse source FIFF file %s",
3266 fromPath.toUtf8().constData());
3267 return false;
3268 }
3269
3270 // Find the FIFFB_PROCESSING_HISTORY block in the directory tree
3271 QList<FiffDirNode::SPtr> histNodes = srcStream.dirtree()->dir_tree_find(FIFFB_PROCESSING_HISTORY);
3272 if (histNodes.isEmpty()) {
3273 qWarning("FiffStream::copyProcessingHistory - No processing history block found in %s",
3274 fromPath.toUtf8().constData());
3275 srcStream.close();
3276 return false;
3277 }
3278
3279 // Read the whole block, including the processing records nested inside it
3280 struct Item
3281 {
3282 int blockStart = 0; // block kind to open, 0 for a tag
3283 int blockEnd = 0; // block kind to close, 0 for a tag
3284 FiffTag::UPtr tag;
3285 };
3286 std::vector<Item> items;
3287 std::function<void(const FiffDirNode::SPtr&)> collect = [&](const FiffDirNode::SPtr& node) {
3288 items.push_back({node->type, 0, nullptr});
3289 for (int i = 0; i < node->nent(); ++i) {
3290 const int kind = node->dir[i]->kind;
3291 if (kind == FIFF_BLOCK_START || kind == FIFF_BLOCK_END)
3292 continue;
3293 FiffTag::UPtr tag;
3294 if (srcStream.read_tag(tag, node->dir[i]->pos))
3295 items.push_back({0, 0, std::move(tag)});
3296 }
3297 for (int c = 0; c < node->nchild(); ++c)
3298 collect(node->children[c]);
3299 items.push_back({0, node->type, nullptr});
3300 };
3301 collect(histNodes[0]);
3302 srcStream.close();
3303
3304 // Open destination file for update
3305 QFile dstFile(toPath);
3306 FiffStream::SPtr dstStream = FiffStream::open_update(dstFile);
3307 if (!dstStream) {
3308 qWarning("FiffStream::copyProcessingHistory - Cannot open destination file %s for update",
3309 toPath.toUtf8().constData());
3310 return false;
3311 }
3312
3313 // open_update marks the last tag as the end of the file; chain it to the appended block
3314 const fiff_long_t lastPos = dstStream->dir()[dstStream->nent() - 2]->pos;
3315 FiffTag::UPtr lastTag;
3316 if (!dstStream->read_tag(lastTag, lastPos)) {
3317 dstStream->close();
3318 return false;
3319 }
3320 lastTag->next = FIFFV_NEXT_SEQ;
3321 dstStream->write_tag(lastTag, lastPos);
3322 dstStream->device()->seek(dstStream->device()->size());
3323
3324 for (const Item& item : items) {
3325 if (item.blockStart)
3326 dstStream->start_block(item.blockStart);
3327 else if (item.blockEnd)
3328 dstStream->end_block(item.blockEnd);
3329 else
3330 dstStream->write_tag(item.tag);
3331 }
3332 // open_update left the file without its terminating tag
3333 dstStream->end_file();
3334
3335 dstStream->close();
3336 return true;
3337}
3338
3339//=============================================================================================================
3340
3341bool FiffStream::check_beginning(FiffTag::UPtr& p_pTag)
3342{
3343 this->read_tag(p_pTag);
3344
3345 if (p_pTag->kind != FIFF_FILE_ID) {
3346 qWarning("Fiff::open: file does not start with a file id tag\n"); //consider throw
3347 return false;
3348 }
3349
3350 if (p_pTag->type != FIFFT_ID_STRUCT) {
3351 qWarning("Fiff::open: file does not start with a file id tag\n"); //consider throw
3352 return false;
3353 }
3354 if (p_pTag->size() != 20) {
3355 qWarning("Fiff::open: file does not start with a file id tag\n"); //consider throw
3356 return false;
3357 }
3358 //do not rewind since the data is contained in the returned tag; -> done for TCP IP reasosn, no rewind possible there
3359 return true;
3360}
FIFF channel descriptor record (FIFF_CH_INFO): per-channel logical/scanner numbers,...
constexpr auto FIFFB_MNE_PARENT_MEAS_FILE
constexpr auto FIFFV_COORD_HEAD
constexpr auto FIFF_MNE_FILE_NAME
constexpr auto FIFF_MNE_ROW_NAMES
constexpr auto FIFFB_MNE_CTF_COMP
constexpr auto FIFF_MNE_CTF_COMP_KIND
constexpr auto FIFFV_MNE_COORD_CTF_HEAD
constexpr auto FIFFV_NEXT_NONE
constexpr auto FIFFB_MNE
constexpr auto FIFF_MNE_ENV_COMMAND_LINE
constexpr auto FIFF_MNE_COORD_FRAME
constexpr auto FIFF_MNE_NCOL
constexpr auto FIFF_MNE_COV_EIGENVALUES
constexpr auto FIFFB_MNE_NAMED_MATRIX
constexpr auto FIFFV_NEXT_SEQ
constexpr auto FIFFV_COORD_DEVICE
constexpr auto FIFF_MNE_NROW
constexpr auto FIFF_MNE_CH_NAME_LIST
constexpr auto FIFFB_MNE_COV
constexpr auto FIFF_MNE_COV_EIGENVECTORS
constexpr auto FIFF_MNE_COV_DIAG
constexpr auto FIFF_MNE_COV_DIM
constexpr auto FIFFV_COORD_UNKNOWN
constexpr auto FIFF_MNE_PROJ_ITEM_ACTIVE
constexpr auto FIFF_MNE_COV_NFREE
constexpr auto FIFF_MNE_ENV_WORKING_DIR
constexpr auto FIFF_MNE_COV
constexpr auto FIFFV_COORD_MRI
constexpr auto FIFF_MNE_CTF_COMP_CALIBRATED
constexpr auto FIFF_MNE_COV_KIND
constexpr auto FIFF_MNE_CTF_COMP_DATA
constexpr auto FIFF_MNE_COL_NAMES
constexpr auto FIFFB_MNE_ENV
constexpr auto FIFFB_MNE_BAD_CHANNELS
constexpr auto FIFF_MNE_RT_COMMAND
constexpr auto FIFFB_MNE_CTF_COMP_DATA
FIFF tag: the 16-byte tag header (kind, type, size, next) plus its decoded payload.
Set of averaged evoked responses sharing a FiffInfo, plus the ave-style category / rejection descript...
FIFF binary tag-stream layer: wraps a QIODevice to read and write FIFF tags, directories,...
Full FIFF measurement metadata: everything from FIFFB_MEAS / FIFFB_MEAS_INFO needed to interpret a re...
4x4 affine FIFF coordinate transform (FIFF_COORD_TRANS) annotated with source/destination coordinate-...
constexpr auto FIFF_DATA_SKIP
Definition fiff_file.h:548
constexpr auto FIFF_PROJ_ITEM_NVEC
Definition fiff_file.h:795
constexpr auto FIFF_BLOCK_END
Definition fiff_file.h:319
constexpr auto FIFFB_PROCESSED_DATA
Definition fiff_file.h:356
#define FIFFB_PROJ
Definition fiff_file.h:400
constexpr auto FIFFB_DACQ_PARS
Definition fiff_file.h:370
constexpr auto FIFFB_ROOT
Definition fiff_file.h:352
constexpr auto FIFF_PROJ_NAME
Definition fiff_file.h:567
constexpr auto FIFF_PROJ_ITEM_KIND
Definition fiff_file.h:791
constexpr auto FIFFV_NATIVE_ENDIAN
Definition fiff_file.h:888
constexpr auto FIFFV_BIG_ENDIAN
Definition fiff_file.h:890
constexpr auto FIFFB_SUBJECT
Definition fiff_file.h:360
constexpr auto FIFFT_CH_INFO_STRUCT
Definition fiff_file.h:238
constexpr auto FIFF_NOP
Definition fiff_file.h:322
constexpr auto FIFF_PROJ_ITEM_CH_NAME_LIST
Definition fiff_file.h:800
constexpr auto FIFFT_DIG_POINT_STRUCT
Definition fiff_file.h:241
constexpr auto FIFFB_CONTINUOUS_DATA
Definition fiff_file.h:366
constexpr auto FIFFB_BEM
Definition fiff_file.h:394
constexpr auto FIFFB_SMSH_RAW_DATA
Definition fiff_file.h:373
constexpr auto FIFF_DACQ_STIM
Definition fiff_file.h:342
constexpr auto FIFF_EPOCH
Definition fiff_file.h:549
#define FIFFT_MATRIX_FLOAT
Definition fiff_file.h:268
constexpr auto FIFF_GANTRY_ANGLE
Definition fiff_file.h:546
constexpr auto FIFF_FILE_ID
Definition fiff_file.h:314
constexpr auto FIFF_COMMENT
Definition fiff_file.h:450
#define FIFFT_RCS_MATRIX_FLOAT
Definition fiff_file.h:271
constexpr auto FIFF_DIR
Definition fiff_file.h:316
constexpr auto FIFF_EXPERIMENTER
Definition fiff_file.h:456
constexpr auto FIFF_BLOCK_START
Definition fiff_file.h:318
constexpr auto FIFF_UTC_OFFSET
Definition fiff_file.h:442
constexpr auto FIFF_DATA_BUFFER
Definition fiff_file.h:547
constexpr auto FIFFT_ID_STRUCT
Definition fiff_file.h:239
constexpr auto FIFF_LINE_FREQ
Definition fiff_file.h:480
constexpr auto FIFFT_COORD_TRANS_STRUCT
Definition fiff_file.h:243
constexpr auto FIFFB_ASPECT
Definition fiff_file.h:359
#define FIFFT_CCS_MATRIX_FLOAT
Definition fiff_file.h:270
constexpr auto FIFF_HIGHPASS
Definition fiff_file.h:467
constexpr auto FIFFB_RAW_DATA
Definition fiff_file.h:355
constexpr auto FIFFT_DOUBLE
Definition fiff_file.h:224
constexpr auto FIFF_LAST_SAMPLE
Definition fiff_file.h:453
constexpr auto FIFF_DATA_PACK
Definition fiff_file.h:446
#define FIFF_DESCRIPTION
Definition fiff_file.h:477
constexpr auto FIFF_NAVE
Definition fiff_file.h:451
constexpr auto FIFF_DACQ_PARS
Definition fiff_file.h:341
constexpr auto FIFF_HPI_COIL_FREQ
Definition fiff_file.h:481
constexpr auto FIFFV_LITTLE_ENDIAN
Definition fiff_file.h:889
constexpr auto FIFFT_STRING
Definition fiff_file.h:229
constexpr auto FIFF_SFREQ
Definition fiff_file.h:445
constexpr auto FIFF_DIR_POINTER
Definition fiff_file.h:315
constexpr auto FIFFB_MRI_SET
Definition fiff_file.h:382
constexpr auto FIFFT_VOID
Definition fiff_file.h:219
constexpr auto FIFFT_DAU_PACK16
Definition fiff_file.h:234
constexpr auto FIFFB_ISOTRAK
Definition fiff_file.h:361
constexpr auto FIFFV_PROJ_ITEM_FIELD
Definition fiff_file.h:814
constexpr auto FIFF_NCHAN
Definition fiff_file.h:444
constexpr auto FIFF_COORD_TRANS
Definition fiff_file.h:466
constexpr auto FIFFB_HPI_SUBSYSTEM
Definition fiff_file.h:375
constexpr auto FIFF_FIRST_SAMPLE
Definition fiff_file.h:452
#define FIFFB_PROJ_ITEM
Definition fiff_file.h:401
constexpr auto FIFF_LOWPASS
Definition fiff_file.h:463
constexpr auto FIFF_PARENT_BLOCK_ID
Definition fiff_file.h:324
constexpr auto FIFF_PROJ_ID
Definition fiff_file.h:566
constexpr auto FIFF_XPLOTTER_LAYOUT
Definition fiff_file.h:828
constexpr auto FIFF_NAME
Definition fiff_file.h:476
#define FIFFT_MATRIX_INT
Definition fiff_file.h:267
constexpr auto FIFFV_ASPECT_AVERAGE
Definition fiff_file.h:429
constexpr auto FIFFB_EVOKED
Definition fiff_file.h:357
constexpr auto FIFFT_SHORT
Definition fiff_file.h:221
constexpr auto FIFF_ASPECT_KIND
Definition fiff_file.h:454
constexpr auto FIFFT_FLOAT
Definition fiff_file.h:223
constexpr auto FIFFB_HPI_COIL
Definition fiff_file.h:364
constexpr auto FIFF_PROJ_ITEM_TIME
Definition fiff_file.h:792
constexpr auto FIFFT_DIR_ENTRY_STRUCT
Definition fiff_file.h:240
constexpr auto FIFFV_ASPECT_STD_ERR
Definition fiff_file.h:430
constexpr auto FIFF_DIG_POINT
Definition fiff_file.h:457
constexpr auto FIFF_PROJ_ITEM_VECTORS
Definition fiff_file.h:796
constexpr auto FIFFB_MRI
Definition fiff_file.h:381
constexpr auto FIFFB_MEAS_INFO
Definition fiff_file.h:354
constexpr auto FIFFT_INT
Definition fiff_file.h:222
constexpr auto FIFFB_MEAS
Definition fiff_file.h:353
constexpr auto FIFFB_HPI_MEAS
Definition fiff_file.h:362
constexpr auto FIFFB_PROCESSING_HISTORY
Definition fiff_file.h:618
constexpr auto FIFFB_HPI_RESULT
Definition fiff_file.h:363
constexpr auto FIFFB_EVENTS
Definition fiff_file.h:368
constexpr auto FIFF_BLOCK_ID
Definition fiff_file.h:317
constexpr auto FIFF_CH_INFO
Definition fiff_file.h:447
constexpr auto FIFF_FREE_LIST
Definition fiff_file.h:320
constexpr auto FIFF_MEAS_DATE
Definition fiff_file.h:448
return FiffCoordTrans(from_frame, to_frame, R, moveVec)
Coil-frame position record embedded inside FIFF_CH_INFO: coil location and 3x3 EX/EY/EZ orientation t...
Recursive node of the parsed FIFF block tree (FIFFB_* hierarchy with directory entries and children).
Single digitization point (FIFF_DIG_POINT) with kind (cardinal/HPI/EEG/extra), identifier and 3D coor...
FIFF continuous raw recording: FiffInfo plus a directory of FIFF_DATA_BUFFER tags for random-access s...
High-level digitization data: dig points plus the device→head transform and fitting metadata that tog...
128-bit FIFF identifier record (machine ID + creation time) used to stamp files, blocks and parent re...
CTF / 4D Neuroimaging software gradient-compensation matrix block (FIFFB_MNE_CTF_COMP_DATA).
Noise / data covariance matrix as stored under FIFFB_MNE_COV, with channel names, kind,...
Minimal measurement-info subset (channel list, sampling rate, basic transforms) shared by FIFF reader...
Header-only Eigen matrix text I/O — round-trips dense matrices to whitespace-separated ASCII for cros...
General numerical helpers: GCD, log2, histogram binning, baseline rescaling, sparsity tests.
Static linear-algebra helpers: SVD-based conditioning, block-diagonal assembly, sorted index pairs.
FIFF file I/O, in-memory data structures and high-level readers/writers.
qint32 fiff_int_t
Definition fiff_types.h:86
qint64 fiff_long_t
Definition fiff_types.h:88
Shared utilities (I/O helpers, spectral analysis, layout management, warp algorithms).
Per-channel FIFF descriptor: identifiers, kind, calibration, coil type, channel-frame coil position a...
Channel coil-frame placement: origin r0 (m) and orthonormal axes ex / ey / ez in FIFFV_COORD_DEVICE.
Definition fiff_ch_pos.h:65
Eigen::Vector3f r0
fiff_int_t coil_type
Eigen::Vector3f ey
Eigen::Vector3f ex
Eigen::Vector3f ez
Labelled 4x4 FIFF affine: source frame, destination frame, rotation, translation and cached inverse.
Eigen::Matrix< float, 4, 4, Eigen::DontAlign > invtrans
Eigen::Matrix< float, 4, 4, Eigen::DontAlign > trans
FIFF noise / data covariance: matrix, channel names, kind, applied projectors, bads,...
Definition fiff_cov.h:82
QList< FiffProj > projs
Definition fiff_cov.h:279
fiff_int_t nfree
Definition fiff_cov.h:281
fiff_int_t dim
Definition fiff_cov.h:276
Eigen::MatrixXd eigvec
Definition fiff_cov.h:283
fiff_int_t kind
Definition fiff_cov.h:273
QStringList bads
Definition fiff_cov.h:280
QStringList names
Definition fiff_cov.h:277
Eigen::VectorXd eig
Definition fiff_cov.h:282
Eigen::MatrixXd data
Definition fiff_cov.h:278
One CTF software-gradient compensation matrix: grade kind, calibration flag and the gradiometer × ref...
bool calibrate(const QList< FiffChInfo > &chs)
Eigen::MatrixXd rowcals
Eigen::MatrixXd colcals
FiffNamedMatrix::SDPtr data
One digitizer point: kind (cardinal/HPI/EEG/extra), ident, 3D position in FIFFV_COORD_HEAD.
Registration-ready digitization data: dig points, device→head transform and HPI fit metadata.
QList< FIFFLIB::FiffDigPoint > points
Directory entry: tag kind + on-disk type + byte size + absolute file offset (16-byte record).
QSharedPointer< FiffDirEntry > SPtr
Recursive FIFF block-tree node: block kind, block ID, directly contained directory entries and child ...
QSharedPointer< FiffDirNode > SPtr
static bool copy_tree(QSharedPointer< FiffStream > &p_pStreamIn, const FiffId &in_id, const QList< QSharedPointer< FiffDirNode > > &p_Nodes, QSharedPointer< FiffStream > &p_pStreamOut)
Single averaged evoked response: time axis, data, baseline, channel info and averaging metadata.
Definition fiff_evoked.h:77
Eigen::MatrixXd data
Set of FiffEvoked instances sharing one FiffInfo, plus channel-picking and compensation helpers.
QList< FiffEvoked > evoked
128-bit FIFF identifier: hardware machine ID plus creation time, stamped on every file and block.
Definition fiff_id.h:69
fiff_int_t machid[2]
Definition fiff_id.h:193
bool isEmpty() const
Definition fiff_id.h:201
FiffTime time
Definition fiff_id.h:194
static FiffId new_file_id()
Definition fiff_id.cpp:73
fiff_int_t version
Definition fiff_id.h:192
Full FIFF measurement info: per-channel descriptors, sampling and filter setup, projectors,...
Definition fiff_info.h:90
QString description
Definition fiff_info.h:286
FiffCoordTrans dev_ctf_t
Definition fiff_info.h:289
QList< float > hpi_coil_freqs
Definition fiff_info.h:296
fiff_int_t gantry_angle
Definition fiff_info.h:288
FiffCoordTrans dig_trans
Definition fiff_info.h:291
QList< FiffCtfComp > comps
Definition fiff_info.h:293
QString xplotter_layout
Definition fiff_info.h:284
fiff_int_t meas_date[2]
Definition fiff_info.h:277
QList< FiffDigPoint > dig
Definition fiff_info.h:290
QString experimenter
Definition fiff_info.h:285
QList< FiffProj > projs
Definition fiff_info.h:292
Stripped FIFF measurement info: channel list, sampling rate, device→head transform and bad-channel li...
QList< FiffCoordTrans > all_coord_trans
QList< FiffChInfo > chs
FiffCoordTrans ctf_head_t
FiffCoordTrans dev_head_t
FIFF named matrix: dense / sparse Eigen matrix plus row-name and column-name string lists.
QSharedDataPointer< FiffNamedMatrix > SDPtr
Single SSP projection item: kind, active flag, desired flag and the named projection vector matrix.
Definition fiff_proj.h:82
Continuous FIFF raw recording: FiffInfo plus a random-access directory of FIFF_DATA_BUFFER tags.
Eigen::RowVectorXd cals
FiffStream::SPtr file
QList< FiffRawDir > rawdir
Per-buffer raw-data directory entry: data kind, first sample, sample count, on-disk tag position.
FiffDirEntry::SPtr ent
bool write_raw_buffer(const Eigen::MatrixXd &buf, const Eigen::RowVectorXd &cals)
fiff_long_t write_cov(const FiffCov &p_FiffCov)
bool read_cov(const FiffDirNode::SPtr &p_Node, fiff_int_t cov_kind, FiffCov &p_covData)
fiff_long_t write_dir_entries(const QList< FiffDirEntry::SPtr > &dir, fiff_long_t pos=-1)
fiff_long_t start_block(fiff_int_t kind)
fiff_long_t write_float_matrix(fiff_int_t kind, const Eigen::MatrixXf &mat)
fiff_long_t write_proj(const QList< FiffProj > &projs)
fiff_long_t write_int_matrix(fiff_int_t kind, const Eigen::MatrixXi &mat)
QSharedPointer< FiffStream > SPtr
bool read_rt_tag(std::unique_ptr< FiffTag > &p_pTag)
bool read_tag_data(std::unique_ptr< FiffTag > &p_pTag, fiff_long_t pos=-1)
bool read_meas_info_base(const FiffDirNode::SPtr &p_Node, FiffInfoBase &p_InfoForward)
fiff_long_t write_tag(const std::unique_ptr< FiffTag > &p_pTag, fiff_long_t pos=-1)
static bool copyProcessingHistory(const QString &fromPath, const QString &toPath)
void write_bad_channels(const QStringList &bads)
fiff_long_t write_dig_point(const FiffDigPoint &dig)
fiff_long_t write_int(fiff_int_t kind, const fiff_int_t *data, fiff_int_t nel=1, fiff_int_t next=FIFFV_NEXT_SEQ)
static bool setup_read_raw(QIODevice &p_IODevice, FiffRawData &data, bool allow_maxshield=true, bool is_littleEndian=false)
QList< FiffCtfComp > read_ctf_comp(const FiffDirNode::SPtr &p_Node, const QList< FiffChInfo > &p_Chs)
fiff_long_t write_float(fiff_int_t kind, const float *data, fiff_int_t nel=1)
fiff_long_t write_id(fiff_int_t kind, const FiffId &id=FiffId::getDefault())
fiff_long_t write_float_sparse_rcs(fiff_int_t kind, const Eigen::SparseMatrix< float > &mat)
fiff_long_t write_ch_pos(const FiffChPos &chpos)
void write_rt_command(fiff_int_t command, const QString &data)
fiff_long_t write_coord_trans(const FiffCoordTrans &trans)
bool get_evoked_entries(const QList< FiffDirNode::SPtr > &evoked_node, QStringList &comments, QList< fiff_int_t > &aspect_kinds, QString &t)
fiff_long_t write_name_list(fiff_int_t kind, const QStringList &data)
bool read_meas_info(const FiffDirNode::SPtr &p_Node, FiffInfo &p_Info, FiffDirNode::SPtr &p_NodeInfo)
bool open(QIODevice::OpenModeFlag mode=QIODevice::ReadOnly)
fiff_long_t read_tag_info(std::unique_ptr< FiffTag > &p_pTag, bool p_bDoSkip=true)
fiff_long_t write_named_matrix(fiff_int_t kind, const FiffNamedMatrix &mat)
FiffStream(QIODevice *p_pIODevice)
FiffId id() const
static QStringList split_name_list(QString p_sNameList)
fiff_long_t write_string(fiff_int_t kind, const QString &data)
QStringList read_bad_channels(const FiffDirNode::SPtr &p_Node)
fiff_long_t write_evoked_set(const FiffEvokedSet &p_FiffEvokedSet)
const FiffDirNode::SPtr & dirtree() const
bool read_digitizer_data(const FiffDirNode::SPtr &p_Node, FiffDigitizerData &p_digData)
static FiffStream::SPtr start_writing_raw(QIODevice &p_IODevice, const FiffInfo &info, Eigen::RowVectorXd &cals, Eigen::MatrixXi sel=defaultMatrixXi, bool bResetRange=true)
fiff_long_t write_dir_pointer(fiff_int_t dirpos, fiff_long_t pos=-1, fiff_int_t next=FIFFV_NEXT_SEQ)
static FiffStream::SPtr start_file(QIODevice &p_IODevice)
fiff_long_t write_info_base(const FiffInfoBase &p_FiffInfoBase)
fiff_long_t end_block(fiff_int_t kind, fiff_int_t next=FIFFV_NEXT_SEQ)
fiff_long_t write_float_sparse_ccs(fiff_int_t kind, const Eigen::SparseMatrix< float > &mat)
fiff_long_t write_ch_info(const FiffChInfo &ch)
fiff_long_t write_ctf_comp(const QList< FiffCtfComp > &comps)
bool read_tag(std::unique_ptr< FiffTag > &p_pTag, fiff_long_t pos=-1)
fiff_long_t write_double(fiff_int_t kind, const double *data, fiff_int_t nel=1)
bool attach_env(const QString &workingDir, const QString &command)
QList< FiffProj > read_proj(const FiffDirNode::SPtr &p_Node)
static FiffStream::SPtr open_update(QIODevice &p_IODevice)
FiffDirNode::SPtr make_subtree(QList< FiffDirEntry::SPtr > &dentry)
bool read_named_matrix(const FiffDirNode::SPtr &p_Node, fiff_int_t matkind, FiffNamedMatrix &mat)
QList< FiffDirEntry::SPtr > & dir()
std::unique_ptr< FiffTag > UPtr
Definition fiff_tag.h:165
static void convert_tag_data(const FiffTag::UPtr &tag, int from_endian, int to_endian)
Definition fiff_tag.cpp:443
static std::vector< Eigen::Triplet< T > > sortrows(const std::vector< Eigen::Triplet< T > > &A, qint32 column=0)
Definition linalg.h:344
static bool issparse(Eigen::VectorXd &v)
Definition numerics.cpp:68