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