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