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