This is an automated email from the git hooks/post-receive script. tille pushed a commit to branch master in repository edfbrowser.
commit 98c02ce47d3d58205c9389007b947eba556ea4d5 Author: Andreas Tille <[email protected]> Date: Mon Nov 13 12:51:49 2017 +0100 New upstream version 1.61 --- README.txt | 12 +- annotations_dock.cpp | 102 ++- annotations_dock.h | 8 +- annotlist_filter_dialog.cpp | 373 ++++++++ averager_dialog.h => annotlist_filter_dialog.h | 75 +- averager_curve_wnd.cpp | 4 +- averager_curve_wnd.h | 8 +- averager_dialog.cpp | 61 +- averager_dialog.h | 9 +- doc/manual.html | 34 +- edf_annot_list.c | 45 + edf_annot_list.h | 2 + edfbrowser.pro | 4 + reduce_signals.cpp => export_filtered_signals.cpp | 1004 +++++++++++---------- export_filtered_signals.h | 140 +++ filteredblockread.cpp | 10 +- global.h | 10 +- images/splash.png | Bin 9306 -> 9150 bytes mainwindow.cpp | 7 + mainwindow.h | 8 +- mainwindow_constr.cpp | 10 +- options_dialog.cpp | 234 ++--- options_dialog.h | 7 +- print_to_bdf.cpp | 2 - print_to_edf.cpp | 2 - read_write_settings.cpp | 100 +- reduce_signals.cpp | 130 ++- statistics_dialog.cpp | 119 ++- statistics_dialog.h | 6 +- version.txt | 18 +- viewcurve.cpp | 62 +- 31 files changed, 1856 insertions(+), 750 deletions(-) diff --git a/README.txt b/README.txt index 2a72c23..9e36472 100644 --- a/README.txt +++ b/README.txt @@ -95,7 +95,7 @@ openSUSE: sudo zypper install -t pattern devel_basis # # # This will not mess with your system libraries. The new compiled libraries will be stored # # # -# in a new and separate directory: /usr/local/Qt-5.9.1 # +# in a new and separate directory: /usr/local/Qt-5.9.2 # # # # It will not interfere with other Qt programs. # # # @@ -105,12 +105,14 @@ mkdir Qt5-source cd Qt5-source -wget http://ftp1.nluug.nl/languages/qt/official_releases/qt/5.9/5.9.1/single/qt-everywhere-opensource-src-5.9.1.tar.xz +wget http://ftp1.nluug.nl/languages/qt/official_releases/qt/5.9/5.9.2/single/qt-everywhere-opensource-src-5.9.2.tar.xz here is a list of download mirrors: https://download.qt.io/static/mirrorlist/ -The Qt source package you are going to need is: qt-everywhere-opensource-src-5.9.1.tar.xz +The Qt source package you are going to need is: qt-everywhere-opensource-src-5.9.2.tar.xz -tar -xvf qt-everywhere-opensource-src-5.9.1.tar.xz +tar -xvf qt-everywhere-opensource-src-5.9.2.tar.xz + +cd qt-everywhere-opensource-src-5.9.2 ./configure -v -release -opensource -confirm-license -c++std c++11 -static -accessibility -fontconfig -skip qtdeclarative -skip qtconnectivity -skip qtmultimedia -no-qml-debug -qt-zlib -no-mtdev -no-journald -qt-libpng -qt-libjpeg -system-freetype -qt-harfbuzz -no-openssl -no-libproxy -no-glib -nomake examples -nomake tests -no-compile-examples -cups -no-evdev -no-dbus -no-eglfs -qreal double -no-opengl -skip qtlocation -skip qtsensors -skip qtwayland -skip qtgamepad -skip qtserialbus @@ -124,7 +126,7 @@ sudo make install Now go to the directory that contains the EDFbrowser sourcecode and enter the following commands: -/usr/local/Qt-5.9.1/bin/qmake +/usr/local/Qt-5.9.2/bin/qmake make -j8 diff --git a/annotations_dock.cpp b/annotations_dock.cpp index 2439f3e..cfd8dd2 100644 --- a/annotations_dock.cpp +++ b/annotations_dock.cpp @@ -100,6 +100,8 @@ UI_Annotationswindow::UI_Annotationswindow(int file_number, QWidget *w_parent) hide_all_BS_triggers_act = new QAction("Hide all Biosemi triggers", list); unhide_all_NK_triggers_act = new QAction("Unhide all Nihon Kohden triggers", list); unhide_all_BS_triggers_act = new QAction("Unhide all Biosemi triggers", list); + filt_ival_time_act = new QAction("Filter Interval Time", list); + show_stats_act = new QAction("Heart Rate Variability", list); list->setContextMenuPolicy(Qt::ActionsContextMenu); list->insertAction(NULL, show_between_act); @@ -113,6 +115,8 @@ UI_Annotationswindow::UI_Annotationswindow(int file_number, QWidget *w_parent) list->insertAction(NULL, unhide_all_NK_triggers_act); list->insertAction(NULL, hide_all_BS_triggers_act); list->insertAction(NULL, unhide_all_BS_triggers_act); + list->insertAction(NULL, filt_ival_time_act); + list->insertAction(NULL, show_stats_act); h_layout = new QHBoxLayout; h_layout->addWidget(checkbox1); @@ -144,10 +148,76 @@ UI_Annotationswindow::UI_Annotationswindow(int file_number, QWidget *w_parent) QObject::connect(hide_all_BS_triggers_act, SIGNAL(triggered(bool)), this, SLOT(hide_all_BS_triggers(bool))); QObject::connect(unhide_all_NK_triggers_act, SIGNAL(triggered(bool)), this, SLOT(unhide_all_NK_triggers(bool))); QObject::connect(unhide_all_BS_triggers_act, SIGNAL(triggered(bool)), this, SLOT(unhide_all_BS_triggers(bool))); + QObject::connect(filt_ival_time_act, SIGNAL(triggered(bool)), this, SLOT(filt_ival_time(bool))); + QObject::connect(show_stats_act, SIGNAL(triggered(bool)), this, SLOT(show_stats(bool))); QObject::connect(lineedit1, SIGNAL(textEdited(const QString)), this, SLOT(filter_edited(const QString))); } +void UI_Annotationswindow::show_stats(bool) +{ + struct annotation_list *annot_list; + + struct annotationblock *annot; + + if(mainwindow->files_open < 1) + { + return; + } + + if(mainwindow->annot_editor_active) + { + QMessageBox messagewindow(QMessageBox::Critical, "Error", "Close the annotation editor and try again."); + messagewindow.exec(); + + return; + } + + if(list->count() < 1) + { + return; + } + + annot_list = &mainwindow->edfheaderlist[file_num]->annot_list; + + annot = edfplus_annotation_get_item_visible_only(annot_list, list->currentRow()); + + UI_StatisticWindow stats_wndw(NULL, 0LL, annot_list, annot); +} + + +void UI_Annotationswindow::filt_ival_time(bool) +{ + struct annotation_list *annot_list; + + struct annotationblock *annot; + + if(mainwindow->files_open < 1) + { + return; + } + + if(mainwindow->annot_editor_active) + { + QMessageBox messagewindow(QMessageBox::Critical, "Error", "Close the annotation editor and try again."); + messagewindow.exec(); + + return; + } + + if(list->count() < 1) + { + return; + } + + annot_list = &mainwindow->edfheaderlist[file_num]->annot_list; + + annot = edfplus_annotation_get_item_visible_only(annot_list, list->currentRow()); + + UI_AnnotFilterWindow filter_wndw(mainwindow, annot, mainwindow->annot_filter, file_num); +} + + void UI_Annotationswindow::hide_all_NK_triggers(bool) { int i, sz; @@ -270,7 +340,7 @@ void UI_Annotationswindow::unhide_all_BS_triggers(bool) void UI_Annotationswindow::filter_edited(const QString text) { - int i, n, len, sz; + int i, j, n, len, sz; char filter_str[32]; @@ -308,7 +378,7 @@ void UI_Annotationswindow::filter_edited(const QString text) len = strlen(filter_str); - if(invert_filter == 0) + if(invert_filter == 0) { for(i=0; i<sz; i++) { @@ -321,9 +391,9 @@ void UI_Annotationswindow::filter_edited(const QString text) n = strlen(annot->annotation) - len + 1; - for(i=0; i<n; i++) + for(j=0; j<n; j++) { - if(!(strncmp(filter_str, annot->annotation + i, len))) + if(!(strncmp(filter_str, annot->annotation + j, len))) { annot->hided_in_list = 0; @@ -348,9 +418,9 @@ void UI_Annotationswindow::filter_edited(const QString text) n = strlen(annot->annotation) - len + 1; - for(i=0; i<n; i++) + for(j=0; j<n; j++) { - if(!(strncmp(filter_str, annot->annotation + i, len))) + if(!(strncmp(filter_str, annot->annotation + j, len))) { annot->hided_in_list = 1; @@ -468,12 +538,14 @@ void UI_Annotationswindow::hide_annot(bool) if(n >= sz) return; - annot = edfplus_annotation_get_item(annot_list, n); + annot = edfplus_annotation_get_item_visible_only(annot_list, n); annot->hided_in_list = 1; annot->hided = 1; + updateList(); + mainwindow->maincurve->update(); } @@ -503,6 +575,8 @@ void UI_Annotationswindow::unhide_annot(bool) annot->hided = 0; + updateList(); + mainwindow->maincurve->update(); } @@ -530,7 +604,7 @@ void UI_Annotationswindow::hide_same_annots(bool) if(n >= sz) return; - annot = edfplus_annotation_get_item(annot_list, n); + annot = edfplus_annotation_get_item_visible_only(annot_list, n); strcpy(str1, annot->annotation); @@ -556,6 +630,8 @@ void UI_Annotationswindow::hide_same_annots(bool) } } + updateList(); + mainwindow->maincurve->update(); } @@ -579,7 +655,7 @@ void UI_Annotationswindow::unhide_same_annots(bool) if(n >= sz) return; - annot = edfplus_annotation_get_item(annot_list, n); + annot = edfplus_annotation_get_item_visible_only(annot_list, n); strcpy(str1, annot->annotation); @@ -605,6 +681,8 @@ void UI_Annotationswindow::unhide_same_annots(bool) } } + updateList(); + mainwindow->maincurve->update(); } @@ -628,13 +706,15 @@ void UI_Annotationswindow::unhide_all_annots(bool) annot->hided_in_list = 0; } + updateList(); + mainwindow->maincurve->update(); } void UI_Annotationswindow::average_annot(bool) { - if(mainwindow->files_open != 1) + if(mainwindow->files_open < 1) { return; } @@ -660,7 +740,7 @@ void UI_Annotationswindow::average_annot(bool) return; } - UI_AveragerWindow average_wndw(mainwindow, list->currentRow()); + UI_AveragerWindow average_wndw(mainwindow, list->currentRow(), file_num); } diff --git a/annotations_dock.h b/annotations_dock.h index 3954332..d72d09a 100644 --- a/annotations_dock.h +++ b/annotations_dock.h @@ -62,6 +62,8 @@ #include "utils.h" #include "averager_dialog.h" #include "edf_annot_list.h" +#include "annotlist_filter_dialog.h" +#include "statistics_dialog.h" class UI_Mainwindow; @@ -116,7 +118,9 @@ private: *hide_all_NK_triggers_act, *hide_all_BS_triggers_act, *unhide_all_NK_triggers_act, - *unhide_all_BS_triggers_act; + *unhide_all_BS_triggers_act, + *filt_ival_time_act, + *show_stats_act; private slots: @@ -136,6 +140,8 @@ private slots: void hide_all_BS_triggers(bool); void unhide_all_NK_triggers(bool); void unhide_all_BS_triggers(bool); + void filt_ival_time(bool); + void show_stats(bool); }; diff --git a/annotlist_filter_dialog.cpp b/annotlist_filter_dialog.cpp new file mode 100644 index 0000000..00eaecf --- /dev/null +++ b/annotlist_filter_dialog.cpp @@ -0,0 +1,373 @@ +/* +*************************************************************************** +* +* Author: Teunis van Beelen +* +* Copyright (C) 2017 Teunis van Beelen +* +* Email: [email protected] +* +*************************************************************************** +* +* This program is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see <http://www.gnu.org/licenses/>. +* +*************************************************************************** +*/ + + + + +#include "annotlist_filter_dialog.h" + + + +UI_AnnotFilterWindow::UI_AnnotFilterWindow(QWidget *w_parent, struct annotationblock *annot, struct annot_filter_struct *filter_p, int file_n) +{ + mainwindow = (UI_Mainwindow *)w_parent; + + annot_filter_dialog = new QDialog(w_parent); + + file_num = file_n; + + annot_list = &mainwindow->edfheaderlist[file_num]->annot_list; + + filter_params = filter_p; + + annots_dock = mainwindow->annotations_dock[file_num]; + + annot_filter_dialog->setMinimumSize(430, 400); + annot_filter_dialog->setMaximumSize(430, 400); + annot_filter_dialog->setWindowTitle("Filter annotations"); + annot_filter_dialog->setModal(true); + annot_filter_dialog->setAttribute(Qt::WA_DeleteOnClose, true); + + annotLabel = new QLabel(annot_filter_dialog); + annotLabel->setGeometry(20, 20, 100, 25); + annotLabel->setText("Filter annotation:"); + annotLabel->setToolTip("Label of the annotation to be filtered"); + + annotNameLabel = new QLabel(annot_filter_dialog); + annotNameLabel->setGeometry(160, 20, 200, 25); + annotNameLabel->setToolTip("Label of the annotation to be filtered"); + + t1Label = new QLabel(annot_filter_dialog); + t1Label->setGeometry(20, 65, 120, 25); + t1Label->setText("Minimum interval:"); + t1Label->setToolTip("Minimum interval between two consegutive annotations"); + + t1_spinbox = new QSpinBox(annot_filter_dialog); + t1_spinbox->setGeometry(160, 65, 100, 25); + t1_spinbox->setRange(1, 500000); + t1_spinbox->setSuffix(" mSec"); + t1_spinbox->setValue(filter_params->tmin); + t1_spinbox->setToolTip("Minimum interval between two consegutive annotations"); + + t2Label = new QLabel(annot_filter_dialog); + t2Label->setGeometry(20, 110, 120, 25); + t2Label->setText("Maximum interval:"); + t2Label->setToolTip("Maximum interval between two consegutive annotations"); + + t2_spinbox = new QSpinBox(annot_filter_dialog); + t2_spinbox->setGeometry(160, 110, 100, 25); + t2_spinbox->setRange(1, 500000); + t2_spinbox->setSuffix(" mSec"); + t2_spinbox->setValue(filter_params->tmax); + t2_spinbox->setToolTip("Maximum interval between two consegutive annotations"); + + invert_checkbox = new QCheckBox("Invert ", annot_filter_dialog); + invert_checkbox->setGeometry(20, 155, 200, 25); + invert_checkbox->setTristate(false); + invert_checkbox->setToolTip("Invert the filter result"); + if(filter_params->invert) + { + invert_checkbox->setCheckState(Qt::Checked); + } + else + { + invert_checkbox->setCheckState(Qt::Unchecked); + } + + hide_other_checkbox = new QCheckBox("Hide other annotations ", annot_filter_dialog); + hide_other_checkbox->setGeometry(20, 200, 200, 25); + hide_other_checkbox->setTristate(false); + hide_other_checkbox->setToolTip("Hide annotations with a different label"); + if(filter_params->hide_other) + { + hide_other_checkbox->setCheckState(Qt::Checked); + } + else + { + hide_other_checkbox->setCheckState(Qt::Unchecked); + } + + hide_in_list_checkbox = new QCheckBox("Filter list only ", annot_filter_dialog); + hide_in_list_checkbox->setGeometry(20, 245, 200, 25); + hide_in_list_checkbox->setTristate(false); + hide_in_list_checkbox->setToolTip("Filter affects the annotationlist only, not the annotation markers in the signal window"); + if(filter_params->hide_in_list_only) + { + hide_in_list_checkbox->setCheckState(Qt::Checked); + } + else + { + hide_in_list_checkbox->setCheckState(Qt::Unchecked); + } + + ApplyButton = new QPushButton(annot_filter_dialog); + ApplyButton->setGeometry(20, 355, 100, 25); + ApplyButton->setText("Apply"); + + UndoButton = new QPushButton(annot_filter_dialog); + UndoButton->setGeometry(165, 355, 100, 25); + UndoButton->setText("Undo"); + + CloseButton = new QPushButton(annot_filter_dialog); + CloseButton->setGeometry(310, 355, 100, 25); + CloseButton->setText("Close"); + + sel_annot_ptr = annot; + strcpy(sel_annot_str, sel_annot_ptr->annotation); + remove_leading_spaces(sel_annot_str); + remove_trailing_spaces(sel_annot_str); + + annotNameLabel->setText(sel_annot_str); + + QObject::connect(CloseButton, SIGNAL(clicked()), annot_filter_dialog, SLOT(close())); + QObject::connect(ApplyButton, SIGNAL(clicked()), this, SLOT(apply_filter())); + QObject::connect(UndoButton, SIGNAL(clicked()), this, SLOT(undo_filter())); + + annot_filter_dialog->exec(); +} + + +void UI_AnnotFilterWindow::undo_filter() +{ + int i, sz; + + struct annotationblock *annot; + + sz = edfplus_annotation_size(annot_list); + + for(i=0; i<sz; i++) + { + annot = edfplus_annotation_get_item(annot_list, i); + + annot->hided_in_list = 0; + + annot->hided = 0; + } + + annots_dock->updateList(); + + mainwindow->maincurve->update(); +} + + +void UI_AnnotFilterWindow::apply_filter() +{ + int i, + sz, + is_set=0, + t1_val, + t2_val; + + long long t1, + t_diff, + t_min, + t_max; + + char annot_str[MAX_ANNOTATION_LEN + 1]; + + struct annotationblock *annot, *annot_before; + + if(invert_checkbox->checkState() == Qt::Checked) + { + filter_params->invert = 1; + } + else + { + filter_params->invert = 0; + } + + if(hide_in_list_checkbox->checkState() == Qt::Checked) + { + filter_params->hide_in_list_only = 1; + } + else + { + filter_params->hide_in_list_only = 0; + } + + if(hide_other_checkbox->checkState() == Qt::Checked) + { + filter_params->hide_other = 1; + } + else + { + filter_params->hide_other = 0; + } + + t1_val = t1_spinbox->value(); + + t2_val = t2_spinbox->value(); + + if(t1_val >= t2_val) + { + QMessageBox messagewindow(QMessageBox::Critical, "Error", "Minimum interval must be less than\n" + "maximum interval"); + messagewindow.exec(); + return; + } + + filter_params->tmin = t1_val; + + filter_params->tmax = t2_val; + + t_min = filter_params->tmin * (TIME_DIMENSION / 1000LL); + + t_max = filter_params->tmax * (TIME_DIMENSION / 1000LL); + + sz = edfplus_annotation_size(annot_list); + + for(i=0; i<sz; i++) + { + annot = edfplus_annotation_get_item(annot_list, i); + + strcpy(annot_str, annot->annotation); + remove_leading_spaces(sel_annot_str); + remove_trailing_spaces(annot_str); + + if(strcmp(annot_str, sel_annot_str)) + { + if(filter_params->hide_other) + { + annot->hided_in_list = 1; + + if(filter_params->hide_in_list_only) + { + annot->hided = 0; + } + else + { + annot->hided = 1; + } + } + else + { + annot->hided_in_list = 0; + + annot->hided = 0; + } + + continue; + } + + if(is_set == 0) + { + is_set = 1; + + t1 = annot->onset; + + annot->hided_in_list = 1; + + if(filter_params->hide_in_list_only) + { + annot->hided = 0; + } + else + { + annot->hided = 1; + } + + annot_before = annot; + + continue; + } + + t_diff = annot->onset - t1; + + t1 = annot->onset; + + if(filter_params->invert) + { + if((t_diff < t_min) || (t_diff > t_max)) + { + annot->hided_in_list = 1; + + if(filter_params->hide_in_list_only) + { + annot->hided = 0; + } + else + { + annot->hided = 1; + } + } + else + { + annot->hided_in_list = 0; + + annot->hided = 0; + + annot_before->hided_in_list = 0; + + annot_before->hided = 0; + } + } + else + { + if((t_diff >= t_min) && (t_diff <= t_max)) + { + annot->hided_in_list = 1; + + if(filter_params->hide_in_list_only) + { + annot->hided = 0; + } + else + { + annot->hided = 1; + } + } + else + { + annot->hided_in_list = 0; + + annot->hided = 0; + + annot_before->hided_in_list = 0; + + annot_before->hided = 0; + } + } + + annot_before = annot; + } + + annots_dock->updateList(); + + mainwindow->maincurve->update(); +} + + + + + + + + + + + + diff --git a/averager_dialog.h b/annotlist_filter_dialog.h similarity index 60% copy from averager_dialog.h copy to annotlist_filter_dialog.h index 6f6a4fe..726a9ae 100644 --- a/averager_dialog.h +++ b/annotlist_filter_dialog.h @@ -3,7 +3,7 @@ * * Author: Teunis van Beelen * -* Copyright (C) 2011, 2012, 2013, 2014, 2015, 2016, 2017 Teunis van Beelen +* Copyright (C) 2017 Teunis van Beelen * * Email: [email protected] * @@ -28,25 +28,21 @@ -#ifndef AVERAGER_FORM1_H -#define AVERAGER_FORM1_H +#ifndef ANNOTFILTER_FORM1_H +#define ANNOTFILTER_FORM1_H #include <QtGlobal> #include <QApplication> #include <QObject> -#include <QListWidget> -#include <QListWidgetItem> #include <QDialog> #include <QPushButton> #include <QLabel> -#include <QProgressDialog> -#include <QComboBox> -#include <QList> -#include <QTime> -#include <QTimeEdit> -#include <QDoubleSpinBox> +#include <QMessageBox> +#include <QSpinBox> +#include <QCheckBox> +#include <QToolTip> #include <stdio.h> #include <stdlib.h> @@ -55,71 +51,78 @@ #include "global.h" #include "mainwindow.h" #include "edf_annot_list.h" -#include "averager_curve_wnd.h" #include "utils.h" +#include "annotations_dock.h" class UI_Mainwindow; +class UI_Annotationswindow; -class UI_AveragerWindow : public QObject + +class UI_AnnotFilterWindow : public QObject { Q_OBJECT public: - UI_AveragerWindow(QWidget *, int); - - ~UI_AveragerWindow(); + UI_AnnotFilterWindow(QWidget *, struct annotationblock *, struct annot_filter_struct *, int); UI_Mainwindow *mainwindow; private: -QDialog *averager_dialog; +QDialog *annot_filter_dialog; QLabel *annotLabel, *annotNameLabel, - *signalLabel, - *ratioLabel, - *bufsizeLabel, - *time1Label, - *time2Label; + *t1Label, + *t2Label; QPushButton *CloseButton, - *StartButton; + *ApplyButton, + *UndoButton; QListWidget *list; -QComboBox *ratioBox; - -QTimeEdit *timeEdit1, - *timeEdit2; +QSpinBox *t1_spinbox, + *t2_spinbox; -QTime time1, - time2; +QCheckBox *hide_in_list_checkbox, + *hide_other_checkbox, + *invert_checkbox; -QDoubleSpinBox *avg_periodspinbox; +int file_num; -char annot_str[MAX_ANNOTATION_LEN + 1]; +char sel_annot_str[MAX_ANNOTATION_LEN + 1]; -int signal_nr; +struct annotation_list *annot_list; -double *avgbuf; +struct annotationblock *sel_annot_ptr; +struct annot_filter_struct *filter_params; -void process_avg(struct signalcompblock *); +UI_Annotationswindow *annots_dock; private slots: -void startButtonClicked(); +void apply_filter(); +void undo_filter(); }; -#endif // AVERAGER_FORM1_H +#endif // ANNOTFILTER_FORM1_H + + + + + + + + diff --git a/averager_curve_wnd.cpp b/averager_curve_wnd.cpp index d5db6b3..76f9ef0 100644 --- a/averager_curve_wnd.cpp +++ b/averager_curve_wnd.cpp @@ -41,7 +41,7 @@ UI_AverageCurveWindow::UI_AverageCurveWindow(struct signalcompblock *signal_comp int acnt, int trigger_position, char *annotation, - double avg__period) + int avg__period) { char str[1024]; @@ -464,7 +464,7 @@ void UI_AverageCurveWindow::export_edf(void) } edfwrite_annotation_latin1(edf_hdl, - (avg_period * 10000.0) / (double)avg_trigger_position_ratio, + (avg_period * 10) / avg_trigger_position_ratio, -1, avg_annotation); diff --git a/averager_curve_wnd.h b/averager_curve_wnd.h index e2c01b7..dbd57cd 100644 --- a/averager_curve_wnd.h +++ b/averager_curve_wnd.h @@ -78,7 +78,7 @@ public: int, int, char *, - double); + int); ~UI_AverageCurveWindow(); @@ -95,13 +95,13 @@ private: averagecurvedialognumber, avg_cnt, avg_trigger_position_ratio, - flywheel_value; + flywheel_value, + avg_period; double pagetime, *avgbuf, avg_max_value, - avg_min_value, - avg_period; + avg_min_value; long long avg_samples_on_screen; diff --git a/averager_dialog.cpp b/averager_dialog.cpp index 14febea..8757b71 100644 --- a/averager_dialog.cpp +++ b/averager_dialog.cpp @@ -32,7 +32,7 @@ -UI_AveragerWindow::UI_AveragerWindow(QWidget *w_parent, int annot_nr) +UI_AveragerWindow::UI_AveragerWindow(QWidget *w_parent, int annot_nr, int file_n) { int i; @@ -42,6 +42,8 @@ UI_AveragerWindow::UI_AveragerWindow(QWidget *w_parent, int annot_nr) mainwindow = (UI_Mainwindow *)w_parent; + file_num = file_n; + averager_dialog = new QDialog(w_parent); averager_dialog->setMinimumSize(600, 400); @@ -68,7 +70,7 @@ UI_AveragerWindow::UI_AveragerWindow(QWidget *w_parent, int annot_nr) time1.setHMS(0, 0, 0, 0); - recording_duration = (mainwindow->edfheaderlist[0]->datarecords * mainwindow->edfheaderlist[0]->long_data_record_duration) / TIME_DIMENSION; + recording_duration = (mainwindow->edfheaderlist[file_num]->datarecords * mainwindow->edfheaderlist[file_num]->long_data_record_duration) / TIME_DIMENSION; time2.setHMS((recording_duration / 3600) % 24, (recording_duration % 3600) / 60, recording_duration % 60, 0); @@ -110,11 +112,10 @@ UI_AveragerWindow::UI_AveragerWindow(QWidget *w_parent, int annot_nr) bufsizeLabel->setGeometry(20, 250, 100, 25); bufsizeLabel->setText("Average period:"); - avg_periodspinbox = new QDoubleSpinBox(averager_dialog); + avg_periodspinbox = new QSpinBox(averager_dialog); avg_periodspinbox->setGeometry(130, 250, 100, 25); - avg_periodspinbox->setDecimals(3); - avg_periodspinbox->setRange(0.01, 300.0); - avg_periodspinbox->setSuffix(" sec"); + avg_periodspinbox->setRange(10, 300000); + avg_periodspinbox->setSuffix(" mSec"); avg_periodspinbox->setValue(mainwindow->average_period); CloseButton = new QPushButton(averager_dialog); @@ -139,9 +140,10 @@ UI_AveragerWindow::UI_AveragerWindow(QWidget *w_parent, int annot_nr) list->setCurrentRow(0, QItemSelectionModel::Select); - annot_ptr = edfplus_annotation_get_item(&mainwindow->edfheaderlist[0]->annot_list, annot_nr); + annot_ptr = edfplus_annotation_get_item_visible_only(&mainwindow->edfheaderlist[file_num]->annot_list, annot_nr); strcpy(annot_str, annot_ptr->annotation); + remove_leading_spaces(annot_str); remove_trailing_spaces(annot_str); annotNameLabel->setText(annot_str); @@ -227,29 +229,30 @@ void UI_AveragerWindow::startButtonClicked() break; } - backup_viewtime = mainwindow->edfheaderlist[0]->viewtime; + backup_viewtime = mainwindow->edfheaderlist[file_num]->viewtime; backup_timescale = mainwindow->pagetime; - mainwindow->pagetime = avg_periodspinbox->value() * TIME_DIMENSION; + mainwindow->pagetime = avg_periodspinbox->value() * (TIME_DIMENSION / 1000LL); mainwindow->setup_viewbuf(); mainwindow->signal_averaging_active = 1; - n = edfplus_annotation_size(&mainwindow->edfheaderlist[0]->annot_list); + n = edfplus_annotation_size(&mainwindow->edfheaderlist[file_num]->annot_list); avg_cnt = 0; for(i=0; i<n; i++) { - annot_ptr = edfplus_annotation_get_item(&mainwindow->edfheaderlist[0]->annot_list, i); + annot_ptr = edfplus_annotation_get_item(&mainwindow->edfheaderlist[file_num]->annot_list, i); - if(((annot_ptr->onset - mainwindow->edfheaderlist[0]->starttime_offset) >= l_time1) - && ((annot_ptr->onset - mainwindow->edfheaderlist[0]->starttime_offset) <= l_time2)) + if(((annot_ptr->onset - mainwindow->edfheaderlist[file_num]->starttime_offset) >= l_time1) + && ((annot_ptr->onset - mainwindow->edfheaderlist[file_num]->starttime_offset) <= l_time2)) { strcpy(str, annot_ptr->annotation); + remove_leading_spaces(str); remove_trailing_spaces(str); if(!strcmp(str, annot_str)) @@ -287,7 +290,7 @@ void UI_AveragerWindow::startButtonClicked() QMessageBox messagewindow(QMessageBox::Critical, "Error", "Too many \"Average\" windows are open.\nClose some first."); messagewindow.exec(); - mainwindow->edfheaderlist[0]->viewtime = backup_viewtime; + mainwindow->edfheaderlist[file_num]->viewtime = backup_viewtime; mainwindow->pagetime = backup_timescale; mainwindow->signal_averaging_active = 0; mainwindow->setup_viewbuf(); @@ -302,7 +305,7 @@ void UI_AveragerWindow::startButtonClicked() QMessageBox messagewindow(QMessageBox::Critical, "Error", "Too many samples in buf."); messagewindow.exec(); - mainwindow->edfheaderlist[0]->viewtime = backup_viewtime; + mainwindow->edfheaderlist[file_num]->viewtime = backup_viewtime; mainwindow->pagetime = backup_timescale; mainwindow->signal_averaging_active = 0; mainwindow->setup_viewbuf(); @@ -318,7 +321,7 @@ void UI_AveragerWindow::startButtonClicked() QMessageBox messagewindow(QMessageBox::Critical, "Error", "The system was not able to provide enough resources (memory) to perform the requested action."); messagewindow.exec(); - mainwindow->edfheaderlist[0]->viewtime = backup_viewtime; + mainwindow->edfheaderlist[file_num]->viewtime = backup_viewtime; mainwindow->pagetime = backup_timescale; mainwindow->signal_averaging_active = 0; mainwindow->setup_viewbuf(); @@ -326,19 +329,25 @@ void UI_AveragerWindow::startButtonClicked() return; } - n = edfplus_annotation_size(&mainwindow->edfheaderlist[0]->annot_list); + n = edfplus_annotation_size(&mainwindow->edfheaderlist[file_num]->annot_list); avg_cnt = 0; for(i=0; i<n; i++) { - annot_ptr = edfplus_annotation_get_item(&mainwindow->edfheaderlist[0]->annot_list, i); + annot_ptr = edfplus_annotation_get_item(&mainwindow->edfheaderlist[file_num]->annot_list, i); + + if(annot_ptr->hided_in_list) + { + continue; + } - if(((annot_ptr->onset - mainwindow->edfheaderlist[0]->starttime_offset) >= l_time1) - && ((annot_ptr->onset - mainwindow->edfheaderlist[0]->starttime_offset) <= l_time2)) + if(((annot_ptr->onset - mainwindow->edfheaderlist[file_num]->starttime_offset) >= l_time1) + && ((annot_ptr->onset - mainwindow->edfheaderlist[file_num]->starttime_offset) <= l_time2)) { strcpy(str, annot_ptr->annotation); + remove_leading_spaces(str); remove_trailing_spaces(str); if(!strcmp(str, annot_str)) @@ -353,7 +362,7 @@ void UI_AveragerWindow::startButtonClicked() { free(avgbuf); - mainwindow->edfheaderlist[0]->viewtime = backup_viewtime; + mainwindow->edfheaderlist[file_num]->viewtime = backup_viewtime; mainwindow->pagetime = backup_timescale; @@ -365,11 +374,11 @@ void UI_AveragerWindow::startButtonClicked() } } - mainwindow->edfheaderlist[0]->viewtime = annot_ptr->onset; + mainwindow->edfheaderlist[file_num]->viewtime = annot_ptr->onset; - mainwindow->edfheaderlist[0]->viewtime -= mainwindow->edfheaderlist[0]->starttime_offset; + mainwindow->edfheaderlist[file_num]->viewtime -= mainwindow->edfheaderlist[file_num]->starttime_offset; - mainwindow->edfheaderlist[0]->viewtime -= (mainwindow->pagetime / trigger_position_ratio); + mainwindow->edfheaderlist[file_num]->viewtime -= (mainwindow->pagetime / trigger_position_ratio); mainwindow->setup_viewbuf(); @@ -395,7 +404,7 @@ void UI_AveragerWindow::startButtonClicked() free(avgbuf); - mainwindow->edfheaderlist[0]->viewtime = backup_viewtime; + mainwindow->edfheaderlist[file_num]->viewtime = backup_viewtime; mainwindow->pagetime = backup_timescale; @@ -446,7 +455,7 @@ void UI_AveragerWindow::startButtonClicked() } } - mainwindow->edfheaderlist[0]->viewtime = backup_viewtime; + mainwindow->edfheaderlist[file_num]->viewtime = backup_viewtime; mainwindow->pagetime = backup_timescale; diff --git a/averager_dialog.h b/averager_dialog.h index 6f6a4fe..c2cbfbd 100644 --- a/averager_dialog.h +++ b/averager_dialog.h @@ -46,7 +46,7 @@ #include <QList> #include <QTime> #include <QTimeEdit> -#include <QDoubleSpinBox> +#include <QSpinBox> #include <stdio.h> #include <stdlib.h> @@ -69,7 +69,7 @@ class UI_AveragerWindow : public QObject Q_OBJECT public: - UI_AveragerWindow(QWidget *, int); + UI_AveragerWindow(QWidget *, int, int); ~UI_AveragerWindow(); @@ -101,11 +101,12 @@ QTimeEdit *timeEdit1, QTime time1, time2; -QDoubleSpinBox *avg_periodspinbox; +QSpinBox *avg_periodspinbox; char annot_str[MAX_ANNOTATION_LEN + 1]; -int signal_nr; +int signal_nr, + file_num; double *avgbuf; diff --git a/doc/manual.html b/doc/manual.html index 86bf9a0..f0583c3 100644 --- a/doc/manual.html +++ b/doc/manual.html @@ -7,7 +7,7 @@ <meta name="description" content="EDFbrowser manual"> </head><body> -<h1>EDFbrowser 1.60 manual</h1> +<h1>EDFbrowser 1.61 manual</h1> <p><br></p> @@ -28,6 +28,7 @@ <li><a href="#Organize_signals">Organize signals</a></li> <li><a href="#Navigation">Navigation</a></li> <li><a href="#Annotations">Annotations</a></li> + <li><a href="#Annotations_Filter">Annotations Filter</a></li> <li><a href="#Filters">Filters</a></li> <li><a href="#Adjust_filters">Adjust filters</a></li> <li><a href="#Powerspectrum">Powerspectrum</a></li> @@ -49,6 +50,7 @@ <li><a href="#Header_editor">Header editor</a></li> <li><a href="#EDFBDF_to_ASCII_format_converter">EDF(+)/BDF(+) to ASCII format converter</a></li> <li><a href="#Reduce_signals">Reduce signals, duration and/or samplerate</a></li> + <li><a href="#Export_filtered_signals">Export filtered signals</a></li> <li><a href="#Export_annotations">Export annotations/events</a></li> <li><a href="#Import_annotations">Import annotations/events</a></li> <li><a href="#Z_EEG">Z-EEG</a></li> @@ -343,6 +345,21 @@ <p><br><br></p> +<h3><a name="Annotations_Filter">Annotations Filter</a></h3> + +<p> + The annotations list can be filtered based on the maximum and minimum interval time<br> + between two consegutive annotations with the same name/label.<br> + Right-click on the annotations list and select "Filter Interval Time".<br> + A dialog will appear where you can set the filter parameters.<br> +</p> + +<p><br></p> + +<p><a href="#Table_of_Contents">Table of Contents</a></p> + +<p><br><br></p> + <h3><a name="Filters">Filters</a></h3> <p> @@ -531,6 +548,8 @@ - Mean, the average of the RR-intervals.<br> - SDNN, the standard deviation of RR-intervals.<br> - RMSSD, the square root of the mean squared difference of successive RR's.<br> + - NN20, the number of pairs of successive RR's that differ by more than 20 ms.<br> + - pNN20, the proportion of NN20 divided by total number of RR's as a percentage.<br> - NN50, the number of pairs of successive RR's that differ by more than 50 ms.<br> - pNN50, the proportion of NN50 divided by total number of RR's as a percentage.<br> <br> @@ -877,6 +896,19 @@ <p><br><br></p> +<h3><a name="Export_filtered_signals">Export filtered signals</a></h3> + +<p> + This tool can be used to export the signals which are visible on the screen to a new EDF/BDF file<br> + including any applied filters and or derivations. +</p> + +<p><br></p> + +<p><a href="#Table_of_Contents">Table of Contents</a></p> + +<p><br><br></p> + <h3><a name="Export_annotations">Export annotations/events</a></h3> <p> diff --git a/edf_annot_list.c b/edf_annot_list.c index 73bbaf6..6768a31 100644 --- a/edf_annot_list.c +++ b/edf_annot_list.c @@ -102,6 +102,26 @@ int edfplus_annotation_size(struct annotation_list *list) } +int edfplus_annotation_cnt(struct annotation_list *list, struct annotationblock *annot) +{ + int i, n=0; + + struct annotationblock *tmp_annot; + + for(i=0; i<list->sz; i++) + { + tmp_annot = &list->items[list->idx[i]]; + + if(!strcmp(tmp_annot->annotation, annot->annotation)) + { + if(!tmp_annot->hided_in_list) n++; + } + } + + return n; +} + + void edfplus_annotation_empty_list(struct annotation_list *list) { if(list == NULL) return; @@ -144,6 +164,31 @@ struct annotationblock * edfplus_annotation_get_item(struct annotation_list *lis } +struct annotationblock * edfplus_annotation_get_item_visible_only(struct annotation_list *list, int n) +{ + int i, j=0; + + if(list == NULL) return NULL; + + if((n >= list->sz) || (n < 0)) return NULL; + + for(i=0; i<list->sz; i++) + { + if(list->items[list->idx[i]].hided_in_list) + { + continue; + } + + if(n == j++) + { + return &list->items[list->idx[i]]; + } + } + + return NULL; +} + + int edfplus_annotation_get_index_at(struct annotation_list *list, long long onset, int start) { int i; diff --git a/edf_annot_list.h b/edf_annot_list.h index 68bed2b..aeff32f 100644 --- a/edf_annot_list.h +++ b/edf_annot_list.h @@ -67,9 +67,11 @@ struct annotation_list{ int edfplus_annotation_add_item(struct annotation_list *, struct annotationblock); int edfplus_annotation_size(struct annotation_list *); +int edfplus_annotation_cnt(struct annotation_list *, struct annotationblock *); void edfplus_annotation_empty_list(struct annotation_list *); void edfplus_annotation_remove_item(struct annotation_list *, int); struct annotationblock * edfplus_annotation_get_item(struct annotation_list *, int); +struct annotationblock * edfplus_annotation_get_item_visible_only(struct annotation_list *, int); int edfplus_annotation_get_index(struct annotation_list *, struct annotationblock *); void edfplus_annotation_sort(struct annotation_list *, void (*)(void)); struct annotation_list * edfplus_annotation_create_list_copy(struct annotation_list *); diff --git a/edfbrowser.pro b/edfbrowser.pro index 47e8737..d14b78a 100644 --- a/edfbrowser.pro +++ b/edfbrowser.pro @@ -127,6 +127,8 @@ HEADERS += biox2edf.h HEADERS += edf_helper.h HEADERS += plif_ecg_subtract_filter.h HEADERS += plif_ecg_subtract_filter_dialog.h +HEADERS += annotlist_filter_dialog.h +HEADERS += export_filtered_signals.h HEADERS += third_party/fidlib/fidlib.h HEADERS += third_party/fidlib/fidmkf.h @@ -219,6 +221,8 @@ SOURCES += biox2edf.cpp SOURCES += edf_helper.c SOURCES += plif_ecg_subtract_filter.c SOURCES += plif_ecg_subtract_filter_dialog.cpp +SOURCES += annotlist_filter_dialog.cpp +SOURCES += export_filtered_signals.cpp SOURCES += third_party/fidlib/fidlib.c diff --git a/reduce_signals.cpp b/export_filtered_signals.cpp similarity index 58% copy from reduce_signals.cpp copy to export_filtered_signals.cpp index e9c0de0..dbe924c 100644 --- a/reduce_signals.cpp +++ b/export_filtered_signals.cpp @@ -3,7 +3,7 @@ * * Author: Teunis van Beelen * -* Copyright (C) 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017 Teunis van Beelen +* Copyright (C) 2017 Teunis van Beelen * * Email: [email protected] * @@ -27,11 +27,11 @@ -#include "reduce_signals.h" +#include "export_filtered_signals.h" -UI_ReduceSignalsWindow::UI_ReduceSignalsWindow(QWidget *w_parent) +UI_ExportFilteredSignalsWindow::UI_ExportFilteredSignalsWindow(QWidget *w_parent) { mainwindow = (UI_Mainwindow *)w_parent; @@ -41,10 +41,21 @@ UI_ReduceSignalsWindow::UI_ReduceSignalsWindow(QWidget *w_parent) myobjectDialog->setMinimumSize(715, 578); myobjectDialog->setMaximumSize(715, 578); - myobjectDialog->setWindowTitle("Reduce signals and/or duration"); + myobjectDialog->setWindowTitle("Export Filtered Signals"); myobjectDialog->setModal(true); myobjectDialog->setAttribute(Qt::WA_DeleteOnClose, true); + tree = new QTreeView(myobjectDialog); + tree->setGeometry(20, 66, 405, 432); + tree->setHeaderHidden(true); + tree->setIndentation(30); + tree->setSelectionMode(QAbstractItemView::NoSelection); + tree->setEditTriggers(QAbstractItemView::NoEditTriggers); + tree->setSortingEnabled(false); + tree->setDragDropMode(QAbstractItemView::NoDragDrop); + + t_model = new QStandardItemModel(this); + label1 = new QLabel(myobjectDialog); label1->setGeometry(20, 20, 685, 25); @@ -66,10 +77,6 @@ UI_ReduceSignalsWindow::UI_ReduceSignalsWindow(QWidget *w_parent) label5->setGeometry(605, 447, 100, 25); label5->setEnabled(false); - label6 = new QLabel(myobjectDialog); - label6->setGeometry(445, 232, 140, 25); - label6->setText("Anti-aliasing filter order"); - radioButton1 = new QRadioButton("whole duration", myobjectDialog); radioButton1->setGeometry(485, 299, 120, 25); radioButton1->setChecked(true); @@ -91,33 +98,13 @@ UI_ReduceSignalsWindow::UI_ReduceSignalsWindow(QWidget *w_parent) spinBox2->setValue(2147483647); spinBox2->setEnabled(false); - spinBox3 = new QSpinBox(myobjectDialog); - spinBox3->setGeometry(595, 170, 100, 25); - spinBox3->setRange(1, 100000); - spinBox3->setValue(1); - spinBox3->setEnabled(false); - - spinBox4 = new QSpinBox(myobjectDialog); - spinBox4->setGeometry(595, 232, 100, 25); - spinBox4->setRange(1, REDUCER_MAX_AA_FILTERS + 1); - spinBox4->setValue(REDUCER_MAX_AA_FILTERS); - spinBox4->setEnabled(false); - - SignalsTablewidget = new QTableWidget(myobjectDialog); - SignalsTablewidget->setGeometry(20, 66, 405, 432); - SignalsTablewidget->setSelectionMode(QAbstractItemView::NoSelection); - SignalsTablewidget->setColumnCount(2); - SignalsTablewidget->setColumnWidth(0, 180); - SignalsTablewidget->setColumnWidth(1, 180); - - QStringList horizontallabels; - horizontallabels += "Label"; - horizontallabels += "Samplerate divider"; - SignalsTablewidget->setHorizontalHeaderLabels(horizontallabels); - pushButton1 = new QPushButton(myobjectDialog); pushButton1->setGeometry(20, 528, 100, 25); pushButton1->setText("Select File"); + if(mainwindow->files_open < 2) + { + pushButton1->setEnabled(false); + } pushButton2 = new QPushButton(myobjectDialog); pushButton2->setGeometry(575, 528, 100, 25); @@ -125,39 +112,16 @@ UI_ReduceSignalsWindow::UI_ReduceSignalsWindow(QWidget *w_parent) pushButton3 = new QPushButton(myobjectDialog); pushButton3->setGeometry(200, 528, 100, 25); - pushButton3->setText("Reduce"); + pushButton3->setText("Export"); pushButton3->setEnabled(false); - pushButton4 = new QPushButton(myobjectDialog); - pushButton4->setGeometry(445, 66, 140, 25); - pushButton4->setText("Select all signals"); - pushButton4->setEnabled(false); - - pushButton5 = new QPushButton(myobjectDialog); - pushButton5->setGeometry(445, 118, 140, 25); - pushButton5->setText("Deselect all signals"); - pushButton5->setEnabled(false); - - pushButton6 = new QPushButton(myobjectDialog); - pushButton6->setGeometry(445, 170, 140, 25); - pushButton6->setText("Set samplerate divider:"); - pushButton6->setEnabled(false); - - helpButton = new QPushButton(myobjectDialog); - helpButton->setGeometry(400, 528, 100, 25); - helpButton->setText("Help"); - - QObject::connect(pushButton1, SIGNAL(clicked()), this, SLOT(SelectFileButton())); - QObject::connect(pushButton2, SIGNAL(clicked()), myobjectDialog, SLOT(close())); - QObject::connect(pushButton3, SIGNAL(clicked()), this, SLOT(StartConversion())); - QObject::connect(pushButton4, SIGNAL(clicked()), this, SLOT(Select_all_signals())); - QObject::connect(pushButton5, SIGNAL(clicked()), this, SLOT(Deselect_all_signals())); - QObject::connect(pushButton6, SIGNAL(clicked()), this, SLOT(Set_SRdivider_all_signals())); - QObject::connect(spinBox1, SIGNAL(valueChanged(int)), this, SLOT(spinBox1changed(int))); - QObject::connect(spinBox2, SIGNAL(valueChanged(int)), this, SLOT(spinBox2changed(int))); - QObject::connect(radioButton1, SIGNAL(toggled(bool)), this, SLOT(radioButton1Toggled(bool))); - QObject::connect(radioButton2, SIGNAL(toggled(bool)), this, SLOT(radioButton2Toggled(bool))); - QObject::connect(helpButton, SIGNAL(clicked()), this, SLOT(helpbuttonpressed())); + QObject::connect(pushButton1, SIGNAL(clicked()), this, SLOT(SelectFileButton())); + QObject::connect(pushButton2, SIGNAL(clicked()), myobjectDialog, SLOT(close())); + QObject::connect(pushButton3, SIGNAL(clicked()), this, SLOT(StartExport())); + QObject::connect(spinBox1, SIGNAL(valueChanged(int)), this, SLOT(spinBox1changed(int))); + QObject::connect(spinBox2, SIGNAL(valueChanged(int)), this, SLOT(spinBox2changed(int))); + QObject::connect(radioButton1, SIGNAL(toggled(bool)), this, SLOT(radioButton1Toggled(bool))); + QObject::connect(radioButton2, SIGNAL(toggled(bool)), this, SLOT(radioButton2Toggled(bool))); edfhdr = NULL; inputfile = NULL; @@ -166,11 +130,16 @@ UI_ReduceSignalsWindow::UI_ReduceSignalsWindow(QWidget *w_parent) inputpath[0] = 0; + if(mainwindow->files_open == 1) + { + SelectFileButton(); + } + myobjectDialog->exec(); } -void UI_ReduceSignalsWindow::spinBox1changed(int value) +void UI_ExportFilteredSignalsWindow::spinBox1changed(int value) { long long seconds, milliSec; @@ -179,9 +148,9 @@ void UI_ReduceSignalsWindow::spinBox1changed(int value) char scratchpad[256]; - QObject::disconnect(spinBox2, SIGNAL(valueChanged(int)), this, SLOT(spinBox2changed(int))); + QObject::disconnect(spinBox2, SIGNAL(valueChanged(int)), this, SLOT(spinBox2changed(int))); spinBox2->setMinimum(value); - QObject::connect(spinBox2, SIGNAL(valueChanged(int)), this, SLOT(spinBox2changed(int))); + QObject::connect(spinBox2, SIGNAL(valueChanged(int)), this, SLOT(spinBox2changed(int))); if(edfhdr == NULL) { @@ -208,7 +177,7 @@ void UI_ReduceSignalsWindow::spinBox1changed(int value) } -void UI_ReduceSignalsWindow::spinBox2changed(int value) +void UI_ExportFilteredSignalsWindow::spinBox2changed(int value) { long long seconds, milliSec; @@ -217,9 +186,9 @@ void UI_ReduceSignalsWindow::spinBox2changed(int value) char scratchpad[256]; - QObject::disconnect(spinBox1, SIGNAL(valueChanged(int)), this, SLOT(spinBox1changed(int))); + QObject::disconnect(spinBox1, SIGNAL(valueChanged(int)), this, SLOT(spinBox1changed(int))); spinBox1->setMaximum(value); - QObject::connect(spinBox1, SIGNAL(valueChanged(int)), this, SLOT(spinBox1changed(int))); + QObject::connect(spinBox1, SIGNAL(valueChanged(int)), this, SLOT(spinBox1changed(int))); if(edfhdr == NULL) { @@ -242,7 +211,7 @@ void UI_ReduceSignalsWindow::spinBox2changed(int value) } -void UI_ReduceSignalsWindow::radioButton1Toggled(bool checked) +void UI_ExportFilteredSignalsWindow::radioButton1Toggled(bool checked) { long long seconds, milliSec; @@ -293,7 +262,7 @@ void UI_ReduceSignalsWindow::radioButton1Toggled(bool checked) } -void UI_ReduceSignalsWindow::radioButton2Toggled(bool checked) +void UI_ExportFilteredSignalsWindow::radioButton2Toggled(bool checked) { if(checked == true) { @@ -307,100 +276,19 @@ void UI_ReduceSignalsWindow::radioButton2Toggled(bool checked) } -void UI_ReduceSignalsWindow::Select_all_signals() -{ - int i; - - if(edfhdr==NULL) - { - return; - } - - for(i=0; i<edfhdr->edfsignals; i++) - { - if(!edfhdr->edfparam[i].annotation) - { - ((QCheckBox *)(SignalsTablewidget->cellWidget(i, 0)))->setCheckState(Qt::Checked); - } - } -} - - - -void UI_ReduceSignalsWindow::Deselect_all_signals() +void UI_ExportFilteredSignalsWindow::SelectFileButton() { - int i; - - if(edfhdr==NULL) - { - return; - } - - for(i=0; i<edfhdr->edfsignals; i++) - { - if(!edfhdr->edfparam[i].annotation) - { - ((QCheckBox *)(SignalsTablewidget->cellWidget(i, 0)))->setCheckState(Qt::Unchecked); - } - } -} - - - -void UI_ReduceSignalsWindow::Set_SRdivider_all_signals() -{ - int i, j, sr, idx; - - sr = spinBox3->value(); - - for(i=0; i<edfhdr->edfsignals; i++) - { - if(edfhdr->edfparam[i].annotation) - { - continue; - } - - idx = 0; - - for(j=1; j<=edfhdr->edfparam[i].smp_per_record; j++) - { - if(!(edfhdr->edfparam[i].smp_per_record % j)) - { - if(j == sr) - { - if(idx < ((QComboBox *)(SignalsTablewidget->cellWidget(i, 1)))->count()) - { - ((QComboBox *)(SignalsTablewidget->cellWidget(i, 1)))->setCurrentIndex(idx); - } - - break; - } - - idx++; - } - } - } -} - - - -void UI_ReduceSignalsWindow::SelectFileButton() -{ - int i, j, - days; + int days; long long seconds, milliSec; - char txt_string[2048], - str[256]; + char txt_string[2048]; label1->clear(); label4->clear(); label5->clear(); - SignalsTablewidget->setRowCount(0); - inputfile = NULL; outputfile = NULL; @@ -411,13 +299,8 @@ void UI_ReduceSignalsWindow::SelectFileButton() file_num = -1; pushButton3->setEnabled(false); - pushButton4->setEnabled(false); - pushButton5->setEnabled(false); - pushButton6->setEnabled(false); spinBox1->setEnabled(false); spinBox2->setEnabled(false); - spinBox3->setEnabled(false); - spinBox4->setEnabled(false); radioButton1->setChecked(true); radioButton1->setEnabled(false); radioButton2->setEnabled(false); @@ -426,11 +309,20 @@ void UI_ReduceSignalsWindow::SelectFileButton() label4->setEnabled(false); label5->setEnabled(false); - UI_activeFileChooserWindow afchooser(&file_num, mainwindow); + t_model->clear(); - if(file_num < 0) + if(mainwindow->files_open > 1) { - return; + UI_activeFileChooserWindow afchooser(&file_num, mainwindow); + + if(file_num < 0) + { + return; + } + } + else + { + file_num = 0; } edfhdr = mainwindow->edfheaderlist[file_num]; @@ -474,54 +366,12 @@ void UI_ReduceSignalsWindow::SelectFileButton() label1->setText(inputpath); - SignalsTablewidget->setRowCount(edfhdr->edfsignals); - - for(i=0; i<edfhdr->edfsignals; i++) - { - SignalsTablewidget->setRowHeight(i, 25); - - SignalsTablewidget->setCellWidget(i, 0, new QCheckBox(edfhdr->edfparam[i].label)); - ((QCheckBox *)(SignalsTablewidget->cellWidget(i, 0)))->setTristate(false); - ((QCheckBox *)(SignalsTablewidget->cellWidget(i, 0)))->setCheckState(Qt::Checked); - - if(edfhdr->edfparam[i].annotation) - { - ((QCheckBox *)(SignalsTablewidget->cellWidget(i, 0)))->setEnabled(false); - } - - if(!(edfhdr->edfparam[i].annotation)) - { - SignalsTablewidget->setCellWidget(i, 1, new QComboBox); - ((QComboBox *)(SignalsTablewidget->cellWidget(i, 1)))->setEditable(false); - - for(j=1; j<=edfhdr->edfparam[i].smp_per_record; j++) - { - if(!(edfhdr->edfparam[i].smp_per_record % j)) - { -// snprintf(str, 256, "%i (%f", j, ((double)(edfhdr->edfparam[i].smp_per_record / j)) / edfhdr->data_record_duration); - snprintf(str, 256, "%i (", j); - convert_to_metric_suffix(str + strlen(str), - ((double)(edfhdr->edfparam[i].smp_per_record / j)) / edfhdr->data_record_duration, - 3); - remove_trailing_zeros(str); - strcat(str, "Hz)"); - ((QComboBox *)(SignalsTablewidget->cellWidget(i, 1)))->addItem(str, QVariant(j)); - } - } - } - } - pushButton3->setEnabled(true); - pushButton4->setEnabled(true); - pushButton5->setEnabled(true); - pushButton6->setEnabled(true); spinBox1->setValue(1); spinBox2->setMaximum(edfhdr->datarecords); spinBox2->setValue(edfhdr->datarecords); spinBox1->setMaximum(edfhdr->datarecords); - spinBox3->setEnabled(true); - spinBox4->setEnabled(true); radioButton1->setEnabled(true); radioButton2->setEnabled(true); @@ -541,15 +391,18 @@ void UI_ReduceSignalsWindow::SelectFileButton() sprintf(txt_string, "%i:%02i:%02i.%03i", (int)(seconds / 3600), (int)((seconds % 3600) / 60), (int)(seconds % 60), (int)milliSec); } label5->setText(txt_string); -} + populate_tree_view(); +} -void UI_ReduceSignalsWindow::StartConversion() +void UI_ExportFilteredSignalsWindow::StartExport() { - int i, j, k, n, + int i, j, k, p, + type, new_edfsignals, datarecords=0, + start_datarecord=0, annot_smp_per_record, annot_recordsize, timestamp_digits=0, @@ -560,22 +413,29 @@ void UI_ReduceSignalsWindow::StartConversion() len, annots_per_datrec=0, smplrt, - tmp, - val, progress_steps, datrecs_processed, - annot_list_sz=0; + annot_list_sz=0, + smp_per_record[MAXSIGNALS], + signalslist[MAXSIGNALS], + digmin, + digmax, + value; - char *readbuf=NULL, - scratchpad[256]; + char scratchpad[4096]; + + double *filtered_blockread_buf[MAXSIGNALS], + bitvalue, + phys_offset, + frequency, + frequency2; long long new_starttime, time_diff, onset_diff, taltime, l_temp, - endtime=0, - l_tmp; + endtime=0; struct date_time_struct dts; @@ -584,13 +444,14 @@ void UI_ReduceSignalsWindow::StartConversion() struct annotationblock *annot_ptr=NULL; - union { - unsigned int one; - signed int one_signed; - unsigned short two[2]; - signed short two_signed[2]; - unsigned char four[4]; - } var; + FilteredBlockReadClass *block_reader[MAXSIGNALS]; + + struct signalcompblock *signalcomp[MAXSIGNALS]; + + for(i=0; i<MAXSIGNALS; i++) + { + block_reader[i] = NULL; + } memset(&new_annot_list, 0, sizeof(struct annotation_list)); @@ -600,13 +461,8 @@ void UI_ReduceSignalsWindow::StartConversion() progress.reset(); pushButton3->setEnabled(false); - pushButton4->setEnabled(false); - pushButton5->setEnabled(false); - pushButton6->setEnabled(false); spinBox1->setEnabled(false); spinBox2->setEnabled(false); - spinBox3->setEnabled(false); - spinBox4->setEnabled(false); radioButton1->setEnabled(false); radioButton2->setEnabled(false); label2->setEnabled(false); @@ -622,48 +478,54 @@ void UI_ReduceSignalsWindow::StartConversion() return; } - new_edfsignals = 0; - annot_smp_per_record = 0; - aa_filter_order = spinBox4->value() - 1; - time_diff = (long long)(spinBox1->value() - 1) * edfhdr->long_data_record_duration; taltime = (time_diff + edfhdr->starttime_offset) % TIME_DIMENSION; endtime = (long long)(spinBox2->value() - (spinBox1->value() - 1)) * edfhdr->long_data_record_duration + taltime; - for(i=0; i<edfhdr->edfsignals; i++) + for(i=0, new_edfsignals=0; i<mainwindow->signalcomps; i++) { - if(!edfhdr->edfparam[i].annotation) - { - if(((QCheckBox *)(SignalsTablewidget->cellWidget(i, 0)))->checkState()==Qt::Checked) - { - signalslist[new_edfsignals] = i; + if(mainwindow->signalcomp[i]->filenum != file_num) continue; - dividerlist[new_edfsignals] = ((QComboBox *)(SignalsTablewidget->cellWidget(i, 1)))->itemData(((QComboBox *)(SignalsTablewidget->cellWidget(i, 1)))->currentIndex()).toInt(); + signalcomp[new_edfsignals] = mainwindow->signalcomp[i]; - new_edfsignals++; - } - } + signalslist[new_edfsignals] = signalcomp[new_edfsignals]->edfsignal[0]; + + block_reader[new_edfsignals] = new FilteredBlockReadClass; + + filtered_blockread_buf[new_edfsignals] = block_reader[new_edfsignals]->init_signalcomp(signalcomp[new_edfsignals], 1, 0); + + smp_per_record[new_edfsignals] = block_reader[new_edfsignals]->samples_in_buf(); + + new_edfsignals++; } - datarecords = spinBox2->value() - spinBox1->value() + 1; + if(!new_edfsignals) + { + showpopupmessage("Error", "No signals present on screen for selected file."); + goto END_1; + } + + start_datarecord = spinBox1->value() - 1; + + datarecords = spinBox2->value() - start_datarecord; if(edfhdr->edfplus || edfhdr->bdfplus) { timestamp_decimals = edfplus_annotation_get_tal_timestamp_decimal_cnt(edfhdr); if(timestamp_decimals < 0) { - showpopupmessage("Error", "Internal error, get_tal_timestamp_decimal_cnt("); + showpopupmessage("Error", "Internal error, get_tal_timestamp_decimal_cnt()"); goto END_1; } timestamp_digits = edfplus_annotation_get_tal_timestamp_digit_cnt(edfhdr); if(timestamp_digits < 0) { - showpopupmessage("Error", "Internal error, get_tal_timestamp_digit_cnt("); + showpopupmessage("Error", "Internal error, get_tal_timestamp_digit_cnt()"); goto END_1; } @@ -751,31 +613,6 @@ void UI_ReduceSignalsWindow::StartConversion() annot_recordsize = 0; } - readbuf = (char *)malloc(edfhdr->recordsize); - if(readbuf==NULL) - { - showpopupmessage("Error", "Malloc error, (readbuf)."); - goto END_2; - } -/////////////////////////////////////////////////////////////////// - - for(i=0; i<new_edfsignals; i++) - { - if(dividerlist[i] > 1) - { - for(j=0; j<aa_filter_order; j++) - { - filterlist[i][j] = create_ravg_filter(1, dividerlist[i]); - - if(filterlist[i][j] == NULL) - { - showpopupmessage("Error", "Malloc error, (create_ravg_filter())."); - - goto END_3; - } - } - } - } /////////////////////////////////////////////////////////////////// outputpath[0] = 0; @@ -789,13 +626,13 @@ void UI_ReduceSignalsWindow::StartConversion() remove_extension_from_filename(outputpath); if(edfhdr->edf) { - strcat(outputpath, "_reduced.edf"); + strcat(outputpath, "_filtered.edf"); strcpy(outputpath, QFileDialog::getSaveFileName(0, "Save file", QString::fromLocal8Bit(outputpath), "EDF files (*.edf *.EDF)").toLocal8Bit().data()); } else { - strcat(outputpath, "_reduced.bdf"); + strcat(outputpath, "_filtered.bdf"); strcpy(outputpath, QFileDialog::getSaveFileName(0, "Save file", QString::fromLocal8Bit(outputpath), "BDF files (*.bdf *.BDF)").toLocal8Bit().data()); } @@ -809,7 +646,7 @@ void UI_ReduceSignalsWindow::StartConversion() if(mainwindow->file_is_opened(outputpath)) { - showpopupmessage("Reduce signals", "Error, selected file is in use."); + showpopupmessage("Error", "Selected file is in use."); goto END_3; } @@ -907,7 +744,10 @@ void UI_ReduceSignalsWindow::StartConversion() for(i=0; i<new_edfsignals; i++) { - fprintf(outputfile, "%s", edfhdr->edfparam[signalslist[i]].label); + snprintf(scratchpad, 16, "%s", signalcomp[i]->signallabel); + strcat(scratchpad, " "); + scratchpad[16] = 0; + fprintf(outputfile, "%s", scratchpad); } if(edfhdr->edfplus) { @@ -995,7 +835,144 @@ void UI_ReduceSignalsWindow::StartConversion() } for(i=0; i<new_edfsignals; i++) { - fprintf(outputfile, "%s", edfhdr->edfparam[signalslist[i]].prefilter); +// fprintf(outputfile, "%s", edfhdr->edfparam[signalslist[i]].prefilter); + + strcpy(scratchpad, edfhdr->edfparam[signalslist[i]].prefilter); + strcat(scratchpad, " "); + for(p = strlen(scratchpad) - 1; p>=0; p--) + { + if(scratchpad[p]!=' ') break; + } + p++; + if(p) p++; + + for(j=0; j<signalcomp[i]->filter_cnt; j++) + { + if(signalcomp[i]->filter[j]->is_LPF == 1) + { + p += sprintf(scratchpad + p, "LP:%f", signalcomp[i]->filter[j]->cutoff_frequency); + } + + if(signalcomp[i]->filter[j]->is_LPF == 0) + { + p += sprintf(scratchpad + p, "HP:%f", signalcomp[i]->filter[j]->cutoff_frequency); + } + + for(k=(p-1); k>0; k--) + { + if(scratchpad[k]!='0') break; + } + + if(scratchpad[k]=='.') scratchpad[k] = 0; + else scratchpad[k+1] = 0; + + strcat(scratchpad, "Hz "); + + p = strlen(scratchpad); + + if(p>80) break; + } + + for(j=0; j<signalcomp[i]->fidfilter_cnt; j++) + { + type = signalcomp[i]->fidfilter_type[j]; + + frequency = signalcomp[i]->fidfilter_freq[j]; + + frequency2 = signalcomp[i]->fidfilter_freq2[j]; + + if(type == 0) + { + p += sprintf(scratchpad + p, "HP:%f", frequency); + } + + if(type == 1) + { + p += sprintf(scratchpad + p, "LP:%f", frequency); + } + + if(type == 2) + { + p += sprintf(scratchpad + p, "N:%f", frequency); + } + + if(type == 3) + { + p += sprintf(scratchpad + p, "BP:%f", frequency); + } + + if(type == 4) + { + p += sprintf(scratchpad + p, "BS:%f", frequency); + } + + for(k=(p-1); k>0; k--) + { + if(scratchpad[k]!='0') break; + } + + if(scratchpad[k]=='.') scratchpad[k] = 0; + else scratchpad[k+1] = 0; + + p = strlen(scratchpad); + + if((type == 3) || (type == 4)) + { + p += sprintf(scratchpad + p, "-%f", frequency2); + + for(k=(p-1); k>0; k--) + { + if(scratchpad[k]!='0') break; + } + + if(scratchpad[k]=='.') scratchpad[k] = 0; + else scratchpad[k+1] = 0; + } + + strcat(scratchpad, "Hz "); + + p = strlen(scratchpad); + + if(p>80) break; + } + + for(j=0; j<signalcomp[i]->ravg_filter_cnt; j++) + { + if(signalcomp[i]->ravg_filter_type[j] == 0) + { + p += sprintf(scratchpad + p, "HP:%iSmpls ", signalcomp[i]->ravg_filter[j]->size); + } + + if(signalcomp[i]->ravg_filter_type[j] == 1) + { + p += sprintf(scratchpad + p, "LP:%iSmpls ", signalcomp[i]->ravg_filter[j]->size); + } + + p = strlen(scratchpad); + + if(p>80) break; + } + + if(signalcomp[i]->ecg_filter != NULL) + { + p += sprintf(scratchpad + p, "ECG:HR "); + } + + if(signalcomp[i]->zratio_filter != NULL) + { + p += sprintf(scratchpad + p, "Z-ratio "); + } + + for(;p<81; p++) + { + scratchpad[p] = ' '; + } + + if(fwrite(scratchpad, 80, 1, outputfile)!=1) + { + showpopupmessage("Error", "Write error (2)."); + goto END_4; + } } if(edfhdr->edfplus || edfhdr->bdfplus) { @@ -1006,7 +983,7 @@ void UI_ReduceSignalsWindow::StartConversion() } for(i=0; i<new_edfsignals; i++) { - fprintf(outputfile, "%-8i", edfhdr->edfparam[signalslist[i]].smp_per_record / dividerlist[i]); + fprintf(outputfile, "%-8i", edfhdr->edfparam[signalslist[i]].smp_per_record); } if(edfhdr->edfplus || edfhdr->bdfplus) { @@ -1034,8 +1011,6 @@ void UI_ReduceSignalsWindow::StartConversion() progress_steps = 1; } - fseeko(inputfile, (long long)edfhdr->hdrsize + ((long long)(spinBox1->value() - 1) * (long long)edfhdr->recordsize), SEEK_SET); - for(datrecs_processed=0; datrecs_processed<datarecords; datrecs_processed++) { if(!(datrecs_processed % progress_steps)) @@ -1050,126 +1025,56 @@ void UI_ReduceSignalsWindow::StartConversion() } } - if(fread(readbuf, edfhdr->recordsize, 1, inputfile) != 1) + for(i=0; i<new_edfsignals; i++) { - progress.reset(); - showpopupmessage("Error", "Read error (2)."); - goto END_4; + if(block_reader[i]->process_signalcomp(start_datarecord)) + { + progress.reset(); + showpopupmessage("Error", "Read error (2)."); + goto END_4; + } } - if(edfhdr->edf) - { - for(i=0; i<new_edfsignals; i++) - { - if(dividerlist[i] == 1) - { - smplrt = edfhdr->edfparam[signalslist[i]].smp_per_record; + start_datarecord++; - for(j=0; j<smplrt; j++) - { - fputc(readbuf[edfhdr->edfparam[signalslist[i]].buf_offset + (j * 2)], outputfile); - if(fputc(readbuf[edfhdr->edfparam[signalslist[i]].buf_offset + (j * 2) + 1], outputfile)==EOF) - { - progress.reset(); - showpopupmessage("Error", "Write error (4)."); - goto END_4; - } - } - } - else - { - smplrt = edfhdr->edfparam[signalslist[i]].smp_per_record / dividerlist[i]; - - for(j=0; j<smplrt; j++) - { - tmp = 0; + for(i=0; i<new_edfsignals; i++) + { + digmax = edfhdr->edfparam[signalslist[i]].dig_max; - for(k=0; k<dividerlist[i]; k++) - { - val = *(((signed short *)(readbuf + edfhdr->edfparam[signalslist[i]].buf_offset)) + (dividerlist[i] * j) + k); + digmin = edfhdr->edfparam[signalslist[i]].dig_min; - for(n=0; n<aa_filter_order; n++) - { - val = run_ravg_filter(val, filterlist[i][n]); - } + bitvalue = edfhdr->edfparam[signalslist[i]].bitvalue; - tmp += val; - } + phys_offset = edfhdr->edfparam[signalslist[i]].offset; - tmp /= dividerlist[i]; + smplrt = smp_per_record[i]; - fputc(tmp & 0xff, outputfile); - if(fputc((tmp >> 8) & 0xff, outputfile)==EOF) - { - progress.reset(); - showpopupmessage("Error", "Write error (4)."); - goto END_4; - } - } - } - } - } - else - { - for(i=0; i<new_edfsignals; i++) + for(j=0; j<smplrt; j++) { - if(dividerlist[i] == 1) - { - smplrt = edfhdr->edfparam[signalslist[i]].smp_per_record; + value = (filtered_blockread_buf[i][j] / bitvalue) - phys_offset; - for(j=0; j<smplrt; j++) - { - fputc(readbuf[edfhdr->edfparam[signalslist[i]].buf_offset + (j * 3)], outputfile); - fputc(readbuf[edfhdr->edfparam[signalslist[i]].buf_offset + (j * 3) + 1], outputfile); - if(fputc(readbuf[edfhdr->edfparam[signalslist[i]].buf_offset + (j * 3) + 2], outputfile)==EOF) - { - progress.reset(); - showpopupmessage("Error", "Write error (4)."); - goto END_4; - } - } - } - else + if(value>digmax) { - smplrt = edfhdr->edfparam[signalslist[i]].smp_per_record / dividerlist[i]; + value = digmax; + } - for(j=0; j<smplrt; j++) - { - l_tmp = 0LL; + if(value<digmin) + { + value = digmin; + } - for(k=0; k<dividerlist[i]; k++) - { - var.two[0] = *((unsigned short *)(readbuf + edfhdr->edfparam[signalslist[i]].buf_offset + (dividerlist[i] * j * 3) + (k * 3))); - var.four[2] = *((unsigned char *)(readbuf + edfhdr->edfparam[signalslist[i]].buf_offset + (dividerlist[i] * j * 3) + (k * 3) + 2)); - - if(var.four[2]&0x80) - { - var.four[3] = 0xff; - } - else - { - var.four[3] = 0x00; - } - - for(n=0; n<aa_filter_order; n++) - { - var.one_signed = run_ravg_filter(var.one_signed, filterlist[i][n]); - } - - l_tmp += var.one_signed; - } + fputc(value&0xff, outputfile); - l_tmp /= dividerlist[i]; + if(fputc((value>>8)&0xff, outputfile)==EOF) + { + progress.reset(); + showpopupmessage("Error", "Write error (4)."); + goto END_4; + } - fputc(l_tmp & 0xff, outputfile); - fputc((l_tmp >> 8) & 0xff, outputfile); - if(fputc((l_tmp >> 16) & 0xff, outputfile)==EOF) - { - progress.reset(); - showpopupmessage("Error", "Write error (4)."); - goto END_4; - } - } + if(edfhdr->bdf) + { + fputc((value>>16)&0xff, outputfile); } } } @@ -1206,60 +1111,57 @@ void UI_ReduceSignalsWindow::StartConversion() { for(i=0; i<annots_per_datrec; i++) { - if(annot_cnt < annot_list_sz) - { - annot_ptr = edfplus_annotation_get_item(&new_annot_list, annot_cnt); + if(annot_cnt >= annot_list_sz) break; - len = snprintf(scratchpad, 256, "%+i.%07i", - (int)(annot_ptr->onset / TIME_DIMENSION), - (int)(annot_ptr->onset % TIME_DIMENSION)); + annot_ptr = edfplus_annotation_get_item(&new_annot_list, annot_cnt++); - for(j=0; j<7; j++) - { - if(scratchpad[len - j - 1] != '0') - { - break; - } - } + len = snprintf(scratchpad, 256, "%+i.%07i", + (int)(annot_ptr->onset / TIME_DIMENSION), + (int)(annot_ptr->onset % TIME_DIMENSION)); - if(j) + for(j=0; j<7; j++) + { + if(scratchpad[len - j - 1] != '0') { - len -= j; - - if(j == 7) - { - len--; - } + break; } + } - if(fwrite(scratchpad, len, 1, outputfile) != 1) + if(j) + { + len -= j; + + if(j == 7) { - progress.reset(); - showpopupmessage("Error", "Write error (5)."); - goto END_4; + len--; } + } - tallen += len; - - if(annot_ptr->duration[0]!=0) - { - fputc(21, outputfile); - tallen++; + if(fwrite(scratchpad, len, 1, outputfile) != 1) + { + progress.reset(); + showpopupmessage("Error", "Write error (5)."); + goto END_4; + } - tallen += fprintf(outputfile, "%s", annot_ptr->duration); - } + tallen += len; - fputc(20, outputfile); + if(annot_ptr->duration[0]!=0) + { + fputc(21, outputfile); tallen++; - tallen += fprintf(outputfile, "%s", annot_ptr->annotation); + tallen += fprintf(outputfile, "%s", annot_ptr->duration); + } - fputc(20, outputfile); - fputc(0, outputfile); - tallen += 2; + fputc(20, outputfile); + tallen++; - annot_cnt--; - } + tallen += fprintf(outputfile, "%s", annot_ptr->annotation); + + fputc(20, outputfile); + fputc(0, outputfile); + tallen += 2; } } @@ -1282,24 +1184,7 @@ END_4: END_3: - for(i=0; i<new_edfsignals; i++) - { - if(dividerlist[i] > 1) - { - for(j=0; j<aa_filter_order; j++) - { - free_ravg_filter(filterlist[i][j]); - } - } - } - -END_2: - - if(readbuf != NULL) - { - free(readbuf); - readbuf = NULL; - } +//END_2: END_1: @@ -1317,11 +1202,17 @@ END_1: edfplus_annotation_empty_list(&new_annot_list); - SignalsTablewidget->setRowCount(0); + for(i=0; i<MAXSIGNALS; i++) + { + if(block_reader[i] != NULL) + { + delete block_reader[i]; + } + } } -void UI_ReduceSignalsWindow::showpopupmessage(const char *str1, const char *str2) +void UI_ExportFilteredSignalsWindow::showpopupmessage(const char *str1, const char *str2) { QMessageBox messagewindow(QMessageBox::NoIcon, str1, str2); @@ -1329,20 +1220,226 @@ void UI_ReduceSignalsWindow::showpopupmessage(const char *str1, const char *str2 } -void UI_ReduceSignalsWindow::helpbuttonpressed() +void UI_ExportFilteredSignalsWindow::populate_tree_view() { -#ifdef Q_OS_LINUX - QDesktopServices::openUrl(QUrl("file:///usr/share/doc/edfbrowser/manual.html#Reduce_signals")); -#endif - -#ifdef Q_OS_WIN32 - char p_path[MAX_PATH_LENGTH]; - - strcpy(p_path, "file:///"); - strcat(p_path, mainwindow->specialFolder(CSIDL_PROGRAM_FILES).toLocal8Bit().data()); - strcat(p_path, "\\EDFbrowser\\manual.html#Reduce_signals"); - QDesktopServices::openUrl(QUrl(p_path)); -#endif + int i, j, + type, + model, + order; + + char txtbuf[2048]; + + double frequency, + frequency2, + ripple; + + QStandardItem *parentItem, + *signalItem, + *filterItem; + + t_model->clear(); + + parentItem = t_model->invisibleRootItem(); + + for(i=0; i<mainwindow->signalcomps; i++) + { + if(mainwindow->signalcomp[i]->filenum != file_num) continue; + + txtbuf[0] = 0; + + if(mainwindow->signalcomp[i]->alias[0] != 0) + { + strcpy(txtbuf, "alias: "); + strcat(txtbuf, mainwindow->signalcomp[i]->alias); + strcat(txtbuf, " "); + } + + for(j=0; j<mainwindow->signalcomp[i]->num_of_signals; j++) + { + sprintf(txtbuf + strlen(txtbuf), "%+ix %s", + mainwindow->signalcomp[i]->factor[j], + mainwindow->signalcomp[i]->edfhdr->edfparam[mainwindow->signalcomp[i]->edfsignal[j]].label); + + remove_trailing_spaces(txtbuf); + + strcat(txtbuf, " "); + } + + signalItem = new QStandardItem(txtbuf); + + parentItem->appendRow(signalItem); + + filterItem = new QStandardItem("Filters"); + + signalItem->appendRow(filterItem); + + if(mainwindow->signalcomp[i]->spike_filter) + { + sprintf(txtbuf, "Spike: %.8f", mainwindow->signalcomp[i]->spike_filter_velocity); + + remove_trailing_zeros(txtbuf); + + sprintf(txtbuf + strlen(txtbuf), " %s/0.5mSec. Hold-off: %i mSec.", + mainwindow->signalcomp[i]->physdimension, + mainwindow->signalcomp[i]->spike_filter_holdoff); + + filterItem->appendRow(new QStandardItem(txtbuf)); + } + + for(j=0; j<mainwindow->signalcomp[i]->filter_cnt; j++) + { + if(mainwindow->signalcomp[i]->filter[j]->is_LPF == 1) + { + sprintf(txtbuf, "LPF: %fHz", mainwindow->signalcomp[i]->filter[j]->cutoff_frequency); + } + + if(mainwindow->signalcomp[i]->filter[j]->is_LPF == 0) + { + sprintf(txtbuf, "HPF: %fHz", mainwindow->signalcomp[i]->filter[j]->cutoff_frequency); + } + + remove_trailing_zeros(txtbuf); + + filterItem->appendRow(new QStandardItem(txtbuf)); + } + + for(j=0; j<mainwindow->signalcomp[i]->ravg_filter_cnt; j++) + { + if(mainwindow->signalcomp[i]->ravg_filter_type[j] == 0) + { + sprintf(txtbuf, "highpass moving average %i smpls", mainwindow->signalcomp[i]->ravg_filter[j]->size); + } + + if(mainwindow->signalcomp[i]->ravg_filter_type[j] == 1) + { + sprintf(txtbuf, "lowpass moving average %i smpls", mainwindow->signalcomp[i]->ravg_filter[j]->size); + } + + filterItem->appendRow(new QStandardItem(txtbuf)); + } + + for(j=0; j<mainwindow->signalcomp[i]->fidfilter_cnt; j++) + { + type = mainwindow->signalcomp[i]->fidfilter_type[j]; + + model = mainwindow->signalcomp[i]->fidfilter_model[j]; + + frequency = mainwindow->signalcomp[i]->fidfilter_freq[j]; + + frequency2 = mainwindow->signalcomp[i]->fidfilter_freq2[j]; + + order = mainwindow->signalcomp[i]->fidfilter_order[j]; + + ripple = mainwindow->signalcomp[i]->fidfilter_ripple[j]; + + if(type == 0) + { + if(model == 0) + { + sprintf(txtbuf, "highpass Butterworth %fHz %ith order", frequency, order); + } + + if(model == 1) + { + sprintf(txtbuf, "highpass Chebyshev %fHz %ith order %fdB ripple", frequency, order, ripple); + } + + if(model == 2) + { + sprintf(txtbuf, "highpass Bessel %fHz %ith order", frequency, order); + } + } + + if(type == 1) + { + if(model == 0) + { + sprintf(txtbuf, "lowpass Butterworth %fHz %ith order", frequency, order); + } + + if(model == 1) + { + sprintf(txtbuf, "lowpass Chebyshev %fHz %ith order %fdB ripple", frequency, order, ripple); + } + + if(model == 2) + { + sprintf(txtbuf, "lowpass Bessel %fHz %ith order", frequency, order); + } + } + + if(type == 2) + { + sprintf(txtbuf, "notch %fHz Q-factor %i", frequency, order); + } + + if(type == 3) + { + if(model == 0) + { + sprintf(txtbuf, "bandpass Butterworth %f-%fHz %ith order", frequency, frequency2, order); + } + + if(model == 1) + { + sprintf(txtbuf, "bandpass Chebyshev %f-%fHz %ith order %fdB ripple", frequency, frequency2, order, ripple); + } + + if(model == 2) + { + sprintf(txtbuf, "bandpass Bessel %f-%fHz %ith order", frequency, frequency2, order); + } + } + + if(type == 4) + { + if(model == 0) + { + sprintf(txtbuf, "bandstop Butterworth %f-%fHz %ith order", frequency, frequency2, order); + } + + if(model == 1) + { + sprintf(txtbuf, "bandstop Chebyshev %f-%fHz %ith order %fdB ripple", frequency, frequency2, order, ripple); + } + + if(model == 2) + { + sprintf(txtbuf, "bandstop Bessel %f-%fHz %ith order", frequency, frequency2, order); + } + } + + remove_trailing_zeros(txtbuf); + + filterItem->appendRow(new QStandardItem(txtbuf)); + } + + if(mainwindow->signalcomp[i]->ecg_filter != NULL) + { + sprintf(txtbuf, "ECG heartrate detection"); + + filterItem->appendRow(new QStandardItem(txtbuf)); + } + + if(mainwindow->signalcomp[i]->plif_ecg_filter != NULL) + { + sprintf(txtbuf, "Powerline interference removal: %iHz", + (mainwindow->signalcomp[i]->plif_ecg_subtract_filter_plf * 10) + 50); + + filterItem->appendRow(new QStandardItem(txtbuf)); + } + + if(mainwindow->signalcomp[i]->zratio_filter != NULL) + { + sprintf(txtbuf, "Z-ratio cross-over frequency is %.1f Hz", mainwindow->signalcomp[i]->zratio_crossoverfreq); + + filterItem->appendRow(new QStandardItem(txtbuf)); + } + } + + tree->setModel(t_model); + + tree->expandAll(); } @@ -1361,3 +1458,4 @@ void UI_ReduceSignalsWindow::helpbuttonpressed() + diff --git a/export_filtered_signals.h b/export_filtered_signals.h new file mode 100644 index 0000000..5aec060 --- /dev/null +++ b/export_filtered_signals.h @@ -0,0 +1,140 @@ +/* +*************************************************************************** +* +* Author: Teunis van Beelen +* +* Copyright (C) 2017 Teunis van Beelen +* +* Email: [email protected] +* +*************************************************************************** +* +* This program is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see <http://www.gnu.org/licenses/>. +* +*************************************************************************** +*/ + + +#ifndef UI_EXPORTFILTSIGNALSFORM_H +#define UI_EXPORTFILTSIGNALSFORM_H + + +#include <QtGlobal> +#include <QApplication> +#include <QDialog> +#include <QLabel> +#include <QPushButton> +#include <QCheckBox> +#include <QObject> +#include <QTableWidget> +#include <QFileDialog> +#include <QCursor> +#include <QString> +#include <QSpinBox> +#include <QRadioButton> +#include <QMessageBox> +#include <QComboBox> +#include <QVariant> +#include <QProgressDialog> +#include <QDesktopServices> +#include <QUrl> +#include <QTreeView> +#include <QStandardItemModel> +#include <QStandardItem> + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "global.h" +#include "mainwindow.h" +#include "check_edf_file.h" +#include "utils.h" +#include "utc_date_time.h" +#include "active_file_chooser.h" +#include "edf_annot_list.h" +#include "edf_helper.h" +#include "filteredblockread.h" + + + +class UI_Mainwindow; + + + +class UI_ExportFilteredSignalsWindow : public QObject +{ + Q_OBJECT + +public: + + UI_ExportFilteredSignalsWindow(QWidget *parent); + + UI_Mainwindow *mainwindow; + +private: + +QLabel *label1, + *label2, + *label3, + *label4, + *label5; + +QPushButton *pushButton1, + *pushButton2, + *pushButton3; + +QSpinBox *spinBox1, + *spinBox2; + +QRadioButton *radioButton1, + *radioButton2; + +QDialog *myobjectDialog; + +QTreeView *tree; + +QStandardItemModel *t_model; + +int file_num; + +char inputpath[MAX_PATH_LENGTH], + outputpath[MAX_PATH_LENGTH], + *recent_savedir; + +FILE *inputfile, + *outputfile; + +struct edfhdrblock *edfhdr; + +void showpopupmessage(const char *, const char *); + +private slots: + +void SelectFileButton(); +void StartExport(); +void spinBox1changed(int); +void spinBox2changed(int); +void radioButton1Toggled(bool); +void radioButton2Toggled(bool); +void populate_tree_view(); + +}; + + + + +#endif + + diff --git a/filteredblockread.cpp b/filteredblockread.cpp index 9e76575..aa9b8a9 100644 --- a/filteredblockread.cpp +++ b/filteredblockread.cpp @@ -165,27 +165,27 @@ int FilteredBlockReadClass::process_signalcomp(int datarecord_start) if((datarecord_start < 0) || (datarecord_start >= hdr->datarecords)) { - return(-1); + return(-2); } if(datarecord_cnt > (hdr->datarecords - datarecord_start)) { - return(-1); + return(-3); } if(fseeko(inputfile, ((long long)hdr->hdrsize) + (((long long)datarecord_start) * ((long long) hdr->recordsize)), SEEK_SET) == -1LL) { - return(-1); + return(-4); } if(fread(readbuf, hdr->recordsize * datarecord_cnt, 1, inputfile) != 1) { - return(-1); + return(-5); } if((readbuf == NULL) || (processed_samples_buf == NULL)) { - return(-1); + return(-6); } for(s=0; s<total_samples; s++) diff --git a/global.h b/global.h index 51d48b0..2d7c6c9 100644 --- a/global.h +++ b/global.h @@ -44,7 +44,7 @@ #endif #define PROGRAM_NAME "EDFbrowser" -#define PROGRAM_VERSION "1.60" +#define PROGRAM_VERSION "1.61" #define MINIMUM_QT4_VERSION 0x040701 #define MINIMUM_QT5_VERSION 0x050901 #define MAXFILES 32 @@ -288,6 +288,14 @@ struct video_player_struct{ int fpos; }; +struct annot_filter_struct{ + int tmin; + int tmax; + int invert; + int hide_other; + int hide_in_list_only; + }; + #endif diff --git a/images/splash.png b/images/splash.png index 5eee368..6045572 100644 Binary files a/images/splash.png and b/images/splash.png differ diff --git a/mainwindow.cpp b/mainwindow.cpp index f37d4ae..64e2689 100644 --- a/mainwindow.cpp +++ b/mainwindow.cpp @@ -120,6 +120,7 @@ void UI_Mainwindow::closeEvent(QCloseEvent *cl_event) free(import_annotations_var); free(export_annotations_var); free(video_player); + free(annot_filter); cl_event->accept(); } @@ -3216,6 +3217,12 @@ void UI_Mainwindow::export_ecg_rr_interval_to_ascii() } +void UI_Mainwindow::export_filtered_signals() +{ + UI_ExportFilteredSignalsWindow filt_signalswdw(this); +} + + void UI_Mainwindow::export_annotations() { if(!files_open) diff --git a/mainwindow.h b/mainwindow.h index 1177fe9..e596a6c 100644 --- a/mainwindow.h +++ b/mainwindow.h @@ -160,6 +160,7 @@ #include "biox2edf.h" #include "plif_ecg_subtract_filter.h" #include "plif_ecg_subtract_filter_dialog.h" +#include "export_filtered_signals.h" #include "third_party/fidlib/fidlib.h" @@ -224,7 +225,8 @@ public: timescale_doubler, viewtime_indicator_type, mainwindow_title_type, - linear_interpol; + linear_interpol, + average_period; long long pagetime, maxfilesize_to_readin_annotations; @@ -242,7 +244,6 @@ public: double pixelsizefactor, x_pixelsizefactor, - average_period, default_amplitude; struct{ @@ -271,6 +272,8 @@ public: struct video_player_struct *video_player; + struct annot_filter_struct *annot_filter; + UI_Annotationswindow *annotations_dock[MAXFILES]; UI_AnnotationEditwindow *annotationEditDock; @@ -565,6 +568,7 @@ private slots: void convert_mit_to_edf(); void convert_biox_to_edf(); void video_process_error(QProcess::ProcessError); + void export_filtered_signals(); // void search_pattern(); protected: diff --git a/mainwindow_constr.cpp b/mainwindow_constr.cpp index 71480e6..156ca1d 100644 --- a/mainwindow_constr.cpp +++ b/mainwindow_constr.cpp @@ -177,7 +177,7 @@ UI_Mainwindow::UI_Mainwindow() export_annotations_var->format = 1; export_annotations_var->duration = 0; - average_period = 0.3; + average_period = 300; average_ratio = 0; @@ -212,6 +212,13 @@ UI_Mainwindow::UI_Mainwindow() raw2edf_var.skipbytes = 1; strcpy(raw2edf_var.phys_dim, "uV"); + annot_filter = (struct annot_filter_struct *)calloc(1, sizeof(struct annot_filter_struct)); + annot_filter->tmin = 1000; + annot_filter->tmax = 2000; + annot_filter->invert = 0; + annot_filter->hide_other = 1; + annot_filter->hide_in_list_only = 1; + read_general_settings(); maincurve = new ViewCurve(this); @@ -686,6 +693,7 @@ UI_Mainwindow::UI_Mainwindow() toolsmenu->addAction("Export annotations/events", this, SLOT(export_annotations())); toolsmenu->addAction("Export EDF/BDF to ASCII", this, SLOT(export_to_ascii())); toolsmenu->addAction("Export/Import ECG RR-interval", this, SLOT(export_ecg_rr_interval_to_ascii())); + toolsmenu->addAction("Export Filtered Signals", this, SLOT(export_filtered_signals())); toolsmenu->addSeparator(); toolsmenu->addAction("Convert Nihon Kohden to EDF+", this, SLOT(nk2edf_converter())); toolsmenu->addAction("Convert ASCII to EDF/BDF", this, SLOT(convert_ascii_to_edf())); diff --git a/options_dialog.cpp b/options_dialog.cpp index 9901115..a01730b 100644 --- a/options_dialog.cpp +++ b/options_dialog.cpp @@ -85,51 +85,51 @@ UI_OptionsDialog::UI_OptionsDialog(QWidget *w_parent) BgColorButton->setColor(mainwindow->maincurve->backgroundcolor); label2 = new QLabel(tab1); - label2->setGeometry(20, 55, 200, 25); + label2->setGeometry(20, 45, 200, 25); label2->setText("Small ruler color"); SrColorButton = new SpecialButton(tab1); - SrColorButton->setGeometry(240, 60, 60, 15); + SrColorButton->setGeometry(240, 50, 60, 15); SrColorButton->setColor(mainwindow->maincurve->small_ruler_color); label3 = new QLabel(tab1); - label3->setGeometry(20, 95, 200, 25); + label3->setGeometry(20, 75, 200, 25); label3->setText("Big ruler color"); BrColorButton = new SpecialButton(tab1); - BrColorButton->setGeometry(240, 100, 60, 15); + BrColorButton->setGeometry(240, 80, 60, 15); BrColorButton->setColor(mainwindow->maincurve->big_ruler_color); label4 = new QLabel(tab1); - label4->setGeometry(20, 135, 200, 25); + label4->setGeometry(20, 105, 200, 25); label4->setText("Mouse rectangle color"); MrColorButton = new SpecialButton(tab1); - MrColorButton->setGeometry(240, 140, 60, 15); + MrColorButton->setGeometry(240, 110, 60, 15); MrColorButton->setColor(mainwindow->maincurve->mouse_rect_color); label5 = new QLabel(tab1); - label5->setGeometry(20, 175, 200, 25); + label5->setGeometry(20, 135, 200, 25); label5->setText("Text color"); TxtColorButton = new SpecialButton(tab1); - TxtColorButton->setGeometry(240, 180, 60, 15); + TxtColorButton->setGeometry(240, 140, 60, 15); TxtColorButton->setColor(mainwindow->maincurve->text_color); label6 = new QLabel(tab1); - label6->setGeometry(20, 215, 200, 25); + label6->setGeometry(20, 165, 200, 25); label6->setText("Signals color"); SigColorButton = new SpecialButton(tab1); - SigColorButton->setGeometry(240, 220, 60, 15); + SigColorButton->setGeometry(240, 170, 60, 15); SigColorButton->setColor((Qt::GlobalColor)mainwindow->maincurve->signal_color); label7 = new QLabel(tab1); - label7->setGeometry(20, 255, 200, 25); + label7->setGeometry(20, 195, 200, 25); label7->setText("Baseline color"); checkbox3 = new QCheckBox(tab1); - checkbox3->setGeometry(200, 258, 20, 20); + checkbox3->setGeometry(200, 198, 20, 20); checkbox3->setTristate(false); if(mainwindow->show_baselines) { @@ -141,39 +141,39 @@ UI_OptionsDialog::UI_OptionsDialog(QWidget *w_parent) } BaseColorButton = new SpecialButton(tab1); - BaseColorButton->setGeometry(240, 260, 60, 15); + BaseColorButton->setGeometry(240, 200, 60, 15); BaseColorButton->setColor(mainwindow->maincurve->baseline_color); label8 = new QLabel(tab1); - label8->setGeometry(20, 295, 200, 25); + label8->setGeometry(20, 225, 200, 25); label8->setText("Crosshair color"); Crh1ColorButton = new SpecialButton(tab1); - Crh1ColorButton->setGeometry(240, 300, 60, 15); + Crh1ColorButton->setGeometry(240, 230, 60, 15); Crh1ColorButton->setColor((Qt::GlobalColor)mainwindow->maincurve->crosshair_1.color); label9 = new QLabel(tab1); - label9->setGeometry(20, 335, 200, 25); + label9->setGeometry(20, 255, 200, 25); label9->setText("2th Crosshair color"); Crh2ColorButton = new SpecialButton(tab1); - Crh2ColorButton->setGeometry(240, 340, 60, 15); + Crh2ColorButton->setGeometry(240, 260, 60, 15); Crh2ColorButton->setColor((Qt::GlobalColor)mainwindow->maincurve->crosshair_2.color); label10 = new QLabel(tab1); - label10->setGeometry(20, 375, 200, 25); + label10->setGeometry(20, 285, 200, 25); label10->setText("Floating ruler color"); FrColorButton = new SpecialButton(tab1); - FrColorButton->setGeometry(240, 380, 60, 15); + FrColorButton->setGeometry(240, 290, 60, 15); FrColorButton->setColor((Qt::GlobalColor)mainwindow->maincurve->floating_ruler_color); label12 = new QLabel(tab1); - label12->setGeometry(20, 415, 200, 25); + label12->setGeometry(20, 315, 200, 25); label12->setText("Annotation marker"); checkbox2 = new QCheckBox(tab1); - checkbox2->setGeometry(200, 418, 20, 20); + checkbox2->setGeometry(200, 318, 20, 20); checkbox2->setTristate(false); if(mainwindow->show_annot_markers) { @@ -185,23 +185,23 @@ UI_OptionsDialog::UI_OptionsDialog(QWidget *w_parent) } AnnotMkrButton = new SpecialButton(tab1); - AnnotMkrButton->setGeometry(240, 420, 60, 15); + AnnotMkrButton->setGeometry(240, 320, 60, 15); AnnotMkrButton->setColor(mainwindow->maincurve->annot_marker_color); label12_1 = new QLabel(tab1); - label12_1->setGeometry(20, 455, 200, 25); + label12_1->setGeometry(20, 345, 200, 25); label12_1->setText("Annotation duration background"); AnnotDurationButton = new SpecialButton(tab1); - AnnotDurationButton->setGeometry(240, 460, 60, 15); + AnnotDurationButton->setGeometry(240, 350, 60, 15); AnnotDurationButton->setColor(mainwindow->maincurve->annot_duration_color); label11 = new QLabel(tab1); - label11->setGeometry(20, 495, 200, 25); + label11->setGeometry(20, 375, 200, 25); label11->setText("Print in grayscale"); checkbox1 = new QCheckBox(tab1); - checkbox1->setGeometry(200, 498, 20, 20); + checkbox1->setGeometry(200, 378, 20, 20); checkbox1->setTristate(false); if(mainwindow->maincurve->blackwhite_printing) { @@ -213,11 +213,11 @@ UI_OptionsDialog::UI_OptionsDialog(QWidget *w_parent) } label13 = new QLabel(tab1); - label13->setGeometry(20, 535, 200, 25); + label13->setGeometry(20, 405, 200, 25); label13->setText("Clip signals to pane"); checkbox4 = new QCheckBox(tab1); - checkbox4->setGeometry(200, 538, 20, 20); + checkbox4->setGeometry(200, 408, 20, 20); checkbox4->setTristate(false); if(mainwindow->clip_to_pane) { @@ -228,25 +228,28 @@ UI_OptionsDialog::UI_OptionsDialog(QWidget *w_parent) checkbox4->setCheckState(Qt::Unchecked); } + groupbox1 = new QGroupBox("Colorschema", tab1); + groupbox1->setGeometry(120, 490, 180, 195); + colorSchema_Dark_Button = new QPushButton(tab1); - colorSchema_Dark_Button->setGeometry(140, 580, 140, 20); - colorSchema_Dark_Button->setText("Colorschema \"Dark\""); + colorSchema_Dark_Button->setGeometry(150, 520, 120, 20); + colorSchema_Dark_Button->setText("\"Dark\""); colorSchema_NK_Button = new QPushButton(tab1); - colorSchema_NK_Button->setGeometry(140, 610, 140, 20); - colorSchema_NK_Button->setText("Colorschema \"NK\""); + colorSchema_NK_Button->setGeometry(150, 550, 120, 20); + colorSchema_NK_Button->setText("\"NK\""); - DefaultButton = new QPushButton(tab1); - DefaultButton->setGeometry(140, 640, 140, 20); - DefaultButton->setText("Default colorschema"); + colorSchema_Blue_on_Gray_Button = new QPushButton(tab1); + colorSchema_Blue_on_Gray_Button->setGeometry(150, 580, 120, 20); + colorSchema_Blue_on_Gray_Button->setText("\"Blue on gray\""); saveColorSchemaButton = new QPushButton(tab1); - saveColorSchemaButton->setGeometry(140, 670, 140, 20); - saveColorSchemaButton->setText("Save colorschema"); + saveColorSchemaButton->setGeometry(150, 610, 120, 20); + saveColorSchemaButton->setText("Save"); loadColorSchemaButton = new QPushButton(tab1); - loadColorSchemaButton->setGeometry(140, 700, 140, 20); - loadColorSchemaButton->setText("Load colorschema"); + loadColorSchemaButton->setGeometry(150, 640, 120, 20); + loadColorSchemaButton->setText("Load"); QObject::connect(BgColorButton, SIGNAL(clicked(SpecialButton *)), this, SLOT(BgColorButtonClicked(SpecialButton *))); QObject::connect(SrColorButton, SIGNAL(clicked(SpecialButton *)), this, SLOT(SrColorButtonClicked(SpecialButton *))); @@ -266,7 +269,7 @@ UI_OptionsDialog::UI_OptionsDialog(QWidget *w_parent) QObject::connect(checkbox4, SIGNAL(stateChanged(int)), this, SLOT(checkbox4Clicked(int))); QObject::connect(saveColorSchemaButton, SIGNAL(clicked()), this, SLOT(saveColorSchemaButtonClicked())); QObject::connect(loadColorSchemaButton, SIGNAL(clicked()), this, SLOT(loadColorSchemaButtonClicked())); - QObject::connect(DefaultButton, SIGNAL(clicked()), this, SLOT(DefaultButtonClicked())); + QObject::connect(colorSchema_Blue_on_Gray_Button, SIGNAL(clicked()), this, SLOT(loadColorSchema_blue_gray())); QObject::connect(colorSchema_NK_Button, SIGNAL(clicked()), this, SLOT(loadColorSchema_NK())); QObject::connect(colorSchema_Dark_Button, SIGNAL(clicked()), this, SLOT(loadColorSchema_Dark())); @@ -1222,82 +1225,6 @@ void UI_OptionsDialog::checkbox4_6Clicked(int state) } -void UI_OptionsDialog::DefaultButtonClicked() -{ - int i; - - QPalette palette; - - mainwindow->maincurve->backgroundcolor = Qt::gray; - BgColorButton->setColor(mainwindow->maincurve->backgroundcolor); - - mainwindow->maincurve->small_ruler_color = Qt::black; - SrColorButton->setColor(mainwindow->maincurve->small_ruler_color); - - mainwindow->maincurve->big_ruler_color = Qt::darkGray; - BrColorButton->setColor(mainwindow->maincurve->big_ruler_color); - - mainwindow->maincurve->mouse_rect_color = Qt::black; - MrColorButton->setColor(mainwindow->maincurve->mouse_rect_color); - - mainwindow->maincurve->text_color = Qt::black; - TxtColorButton->setColor(mainwindow->maincurve->text_color); - - mainwindow->maincurve->signal_color = Qt::blue; - SigColorButton->setColor(Qt::blue); - - mainwindow->maincurve->baseline_color = Qt::darkGray; - BaseColorButton->setColor(Qt::darkGray); - mainwindow->show_baselines = 1; - checkbox3->setCheckState(Qt::Checked); - - mainwindow->maincurve->crosshair_1.color = Qt::red; - Crh1ColorButton->setColor(Qt::red); - - mainwindow->maincurve->crosshair_2.color = Qt::cyan; - Crh2ColorButton->setColor(Qt::cyan); - - mainwindow->maincurve->floating_ruler_color = Qt::red; - FrColorButton->setColor(Qt::red); - - mainwindow->maincurve->annot_marker_color = Qt::white; - AnnotMkrButton->setColor(Qt::white); - mainwindow->show_annot_markers = 1; - checkbox2->setCheckState(Qt::Checked); - - mainwindow->maincurve->annot_duration_color.setRed(0); - mainwindow->maincurve->annot_duration_color.setGreen(127); - mainwindow->maincurve->annot_duration_color.setBlue(127); - mainwindow->maincurve->annot_duration_color.setAlpha(32); - AnnotDurationButton->setColor(mainwindow->maincurve->annot_duration_color); - - palette.setColor(QPalette::Text, mainwindow->maincurve->text_color); - palette.setColor(QPalette::Base, mainwindow->maincurve->backgroundcolor); - - for(i=0; i<mainwindow->files_open; i++) - { - if(mainwindow->annotations_dock[i]) - { - mainwindow->annotations_dock[i]->list->setPalette(palette); - } - } - - for(i=0; i<mainwindow->signalcomps; i++) - { - mainwindow->signalcomp[i]->color = mainwindow->maincurve->signal_color; - } - - mainwindow->maincurve->blackwhite_printing = 1; - - checkbox1->setCheckState(Qt::Checked); - - checkbox4->setCheckState(Qt::Unchecked); - - mainwindow->maincurve->update(); -} - - - void UI_OptionsDialog::BgColorButtonClicked(SpecialButton *) { int i; @@ -2055,6 +1982,81 @@ void UI_OptionsDialog::loadColorSchema_Dark() } +void UI_OptionsDialog::loadColorSchema_blue_gray() +{ + int i; + + QPalette palette; + + mainwindow->maincurve->backgroundcolor = Qt::gray; + BgColorButton->setColor(mainwindow->maincurve->backgroundcolor); + + mainwindow->maincurve->small_ruler_color = Qt::black; + SrColorButton->setColor(mainwindow->maincurve->small_ruler_color); + + mainwindow->maincurve->big_ruler_color = Qt::darkGray; + BrColorButton->setColor(mainwindow->maincurve->big_ruler_color); + + mainwindow->maincurve->mouse_rect_color = Qt::black; + MrColorButton->setColor(mainwindow->maincurve->mouse_rect_color); + + mainwindow->maincurve->text_color = Qt::black; + TxtColorButton->setColor(mainwindow->maincurve->text_color); + + mainwindow->maincurve->signal_color = Qt::blue; + SigColorButton->setColor(Qt::blue); + + mainwindow->maincurve->baseline_color = Qt::darkGray; + BaseColorButton->setColor(Qt::darkGray); + mainwindow->show_baselines = 1; + checkbox3->setCheckState(Qt::Checked); + + mainwindow->maincurve->crosshair_1.color = Qt::red; + Crh1ColorButton->setColor(Qt::red); + + mainwindow->maincurve->crosshair_2.color = Qt::cyan; + Crh2ColorButton->setColor(Qt::cyan); + + mainwindow->maincurve->floating_ruler_color = Qt::red; + FrColorButton->setColor(Qt::red); + + mainwindow->maincurve->annot_marker_color = Qt::white; + AnnotMkrButton->setColor(Qt::white); + mainwindow->show_annot_markers = 1; + checkbox2->setCheckState(Qt::Checked); + + mainwindow->maincurve->annot_duration_color.setRed(0); + mainwindow->maincurve->annot_duration_color.setGreen(127); + mainwindow->maincurve->annot_duration_color.setBlue(127); + mainwindow->maincurve->annot_duration_color.setAlpha(32); + AnnotDurationButton->setColor(mainwindow->maincurve->annot_duration_color); + + palette.setColor(QPalette::Text, mainwindow->maincurve->text_color); + palette.setColor(QPalette::Base, mainwindow->maincurve->backgroundcolor); + + for(i=0; i<mainwindow->files_open; i++) + { + if(mainwindow->annotations_dock[i]) + { + mainwindow->annotations_dock[i]->list->setPalette(palette); + } + } + + for(i=0; i<mainwindow->signalcomps; i++) + { + mainwindow->signalcomp[i]->color = mainwindow->maincurve->signal_color; + } + + mainwindow->maincurve->blackwhite_printing = 1; + + checkbox1->setCheckState(Qt::Checked); + + checkbox4->setCheckState(Qt::Unchecked); + + mainwindow->maincurve->update(); +} + + diff --git a/options_dialog.h b/options_dialog.h index 44ea74f..827e400 100644 --- a/options_dialog.h +++ b/options_dialog.h @@ -61,6 +61,7 @@ #include <QGridLayout> #include <QDesktopWidget> #include <QFileDialog> +#include <QGroupBox> #include "global.h" #include "mainwindow.h" @@ -106,7 +107,7 @@ QVBoxLayout *mainLayout; QHBoxLayout *horLayout; QPushButton *CloseButton, - *DefaultButton, + *colorSchema_Blue_on_Gray_Button, *colorSchema_NK_Button, *colorSchema_Dark_Button, *ApplyButton, @@ -199,6 +200,8 @@ QRadioButton *radiobutton1, QLineEdit *lineEdit3_1; +QGroupBox *groupbox1; + void update_interface(void); private slots: @@ -226,7 +229,6 @@ void checkbox4_3Clicked(int); void checkbox4_4Clicked(int); void checkbox4_5Clicked(int); void checkbox4_6Clicked(int); -void DefaultButtonClicked(); void ApplyButtonClicked(); void colorBarButtonClicked(SpecialButton *); void DefaultButton2Clicked(); @@ -248,6 +250,7 @@ void saveColorSchemaButtonClicked(); void loadColorSchemaButtonClicked(); void loadColorSchema_NK(); void loadColorSchema_Dark(); +void loadColorSchema_blue_gray(); void dspinbox4_4ValueChanged(double); }; diff --git a/print_to_bdf.cpp b/print_to_bdf.cpp index af9363f..cd132c5 100644 --- a/print_to_bdf.cpp +++ b/print_to_bdf.cpp @@ -694,8 +694,6 @@ void print_screen_to_bdf(UI_Mainwindow *mainwindow) else scratchpad[k+1] = 0; p = strlen(scratchpad); - - if(p>80) break; } for(j=0; j<signalcomp[i]->filter_cnt; j++) diff --git a/print_to_edf.cpp b/print_to_edf.cpp index ce7fa35..ce2d8c2 100644 --- a/print_to_edf.cpp +++ b/print_to_edf.cpp @@ -691,8 +691,6 @@ void print_screen_to_edf(UI_Mainwindow *mainwindow) else scratchpad[k+1] = 0; p = strlen(scratchpad); - - if(p>80) break; } for(j=0; j<signalcomp[i]->filter_cnt; j++) diff --git a/read_write_settings.cpp b/read_write_settings.cpp index a3f5737..e514ba0 100644 --- a/read_write_settings.cpp +++ b/read_write_settings.cpp @@ -1213,7 +1213,9 @@ void UI_Mainwindow::read_general_settings() return; } - average_period = atof(result); + average_period = atoi(result); + + if(average_period < 1) average_period = 300; xml_go_up(xml_hdl); } @@ -1622,6 +1624,86 @@ void UI_Mainwindow::read_general_settings() xml_go_up(xml_hdl); } + if(!(xml_goto_nth_element_inside(xml_hdl, "annotfilter_var", 0))) + { + if(!(xml_goto_nth_element_inside(xml_hdl, "tmin", 0))) + { + if(xml_get_content_of_element(xml_hdl, result, XML_STRBUFLEN)) + { + xml_close(xml_hdl); + return; + } + + annot_filter->tmin = atoi(result); + if(annot_filter->tmin < 1) annot_filter->tmin = 1; + if(annot_filter->tmin > 500000) annot_filter->tmin = 500000; + + xml_go_up(xml_hdl); + } + + if(!(xml_goto_nth_element_inside(xml_hdl, "tmax", 0))) + { + if(xml_get_content_of_element(xml_hdl, result, XML_STRBUFLEN)) + { + xml_close(xml_hdl); + return; + } + + annot_filter->tmax = atoi(result); + if(annot_filter->tmax < 1) annot_filter->tmax = 1; + if(annot_filter->tmax > 500000) annot_filter->tmax = 500000; + + xml_go_up(xml_hdl); + } + + if(!(xml_goto_nth_element_inside(xml_hdl, "invert", 0))) + { + if(xml_get_content_of_element(xml_hdl, result, XML_STRBUFLEN)) + { + xml_close(xml_hdl); + return; + } + + annot_filter->invert = atoi(result); + if(annot_filter->invert < 0) annot_filter->invert = 0; + if(annot_filter->invert > 1) annot_filter->invert = 1; + + xml_go_up(xml_hdl); + } + + if(!(xml_goto_nth_element_inside(xml_hdl, "hide_other", 0))) + { + if(xml_get_content_of_element(xml_hdl, result, XML_STRBUFLEN)) + { + xml_close(xml_hdl); + return; + } + + annot_filter->hide_other = atoi(result); + if(annot_filter->hide_other < 0) annot_filter->hide_other = 0; + if(annot_filter->hide_other > 1) annot_filter->hide_other = 1; + + xml_go_up(xml_hdl); + } + + if(!(xml_goto_nth_element_inside(xml_hdl, "hide_in_list_only", 0))) + { + if(xml_get_content_of_element(xml_hdl, result, XML_STRBUFLEN)) + { + xml_close(xml_hdl); + return; + } + + annot_filter->hide_in_list_only = atoi(result); + if(annot_filter->hide_in_list_only < 0) annot_filter->hide_in_list_only = 0; + if(annot_filter->hide_in_list_only > 1) annot_filter->hide_in_list_only = 1; + + xml_go_up(xml_hdl); + } + + xml_go_up(xml_hdl); + } + if(!(xml_goto_nth_element_inside(xml_hdl, "check_for_updates", 0))) { if(xml_get_content_of_element(xml_hdl, result, XML_STRBUFLEN)) @@ -1994,7 +2076,7 @@ void UI_Mainwindow::write_settings() fprintf(cfgfile, " <mousewheelsens>%i</mousewheelsens>\n", mousewheelsens); - fprintf(cfgfile, " <average_period>%f</average_period>\n", average_period); + fprintf(cfgfile, " <average_period>%i</average_period>\n", average_period); fprintf(cfgfile, " <average_ratio>%i</average_ratio>\n", average_ratio); @@ -2048,6 +2130,20 @@ void UI_Mainwindow::write_settings() fprintf(cfgfile, " </raw2edf_var>\n"); + fprintf(cfgfile, " <annotfilter_var>\n"); + + fprintf(cfgfile, " <tmin>%i</tmin>\n", annot_filter->tmin); + + fprintf(cfgfile, " <tmax>%i</tmax>\n", annot_filter->tmax); + + fprintf(cfgfile, " <invert>%i</invert>\n", annot_filter->invert); + + fprintf(cfgfile, " <hide_other>%i</hide_other>\n", annot_filter->hide_other); + + fprintf(cfgfile, " <hide_in_list_only>%i</hide_in_list_only>\n", annot_filter->hide_in_list_only); + + fprintf(cfgfile, " </annotfilter_var>\n"); + fprintf(cfgfile, " <check_for_updates>%i</check_for_updates>\n", check_for_updates); fprintf(cfgfile, " <viewtime_indicator_type>%i</viewtime_indicator_type>\n", viewtime_indicator_type); diff --git a/reduce_signals.cpp b/reduce_signals.cpp index e9c0de0..e040c10 100644 --- a/reduce_signals.cpp +++ b/reduce_signals.cpp @@ -118,6 +118,10 @@ UI_ReduceSignalsWindow::UI_ReduceSignalsWindow(QWidget *w_parent) pushButton1 = new QPushButton(myobjectDialog); pushButton1->setGeometry(20, 528, 100, 25); pushButton1->setText("Select File"); + if(mainwindow->files_open < 2) + { + pushButton1->setEnabled(false); + } pushButton2 = new QPushButton(myobjectDialog); pushButton2->setGeometry(575, 528, 100, 25); @@ -166,6 +170,11 @@ UI_ReduceSignalsWindow::UI_ReduceSignalsWindow(QWidget *w_parent) inputpath[0] = 0; + if(mainwindow->files_open == 1) + { + SelectFileButton(); + } + myobjectDialog->exec(); } @@ -386,8 +395,7 @@ void UI_ReduceSignalsWindow::Set_SRdivider_all_signals() void UI_ReduceSignalsWindow::SelectFileButton() { - int i, j, - days; + int i, j, k, days, found; long long seconds, milliSec; @@ -426,11 +434,18 @@ void UI_ReduceSignalsWindow::SelectFileButton() label4->setEnabled(false); label5->setEnabled(false); - UI_activeFileChooserWindow afchooser(&file_num, mainwindow); + if(mainwindow->files_open > 1) + { + UI_activeFileChooserWindow afchooser(&file_num, mainwindow); - if(file_num < 0) + if(file_num < 0) + { + return; + } + } + else { - return; + file_num = 0; } edfhdr = mainwindow->edfheaderlist[file_num]; @@ -498,7 +513,6 @@ void UI_ReduceSignalsWindow::SelectFileButton() { if(!(edfhdr->edfparam[i].smp_per_record % j)) { -// snprintf(str, 256, "%i (%f", j, ((double)(edfhdr->edfparam[i].smp_per_record / j)) / edfhdr->data_record_duration); snprintf(str, 256, "%i (", j); convert_to_metric_suffix(str + strlen(str), ((double)(edfhdr->edfparam[i].smp_per_record / j)) / edfhdr->data_record_duration, @@ -511,6 +525,35 @@ void UI_ReduceSignalsWindow::SelectFileButton() } } + for(i=0, found=0; i<edfhdr->edfsignals; i++) + { + if(edfhdr->edfparam[i].annotation) continue; + + for(j=0; j<mainwindow->signalcomps; j++) + { + for(k=0; k<mainwindow->signalcomp[j]->num_of_signals; k++) + { + if(mainwindow->signalcomp[j]->edfsignal[k] == i) + { + found = 1; + + break; + } + } + + if(found) break; + } + + if(found) + { + found = 0; + } + else + { + ((QCheckBox *)(SignalsTablewidget->cellWidget(i, 0)))->setCheckState(Qt::Unchecked); + } + } + pushButton3->setEnabled(true); pushButton4->setEnabled(true); pushButton5->setEnabled(true); @@ -1206,60 +1249,57 @@ void UI_ReduceSignalsWindow::StartConversion() { for(i=0; i<annots_per_datrec; i++) { - if(annot_cnt < annot_list_sz) - { - annot_ptr = edfplus_annotation_get_item(&new_annot_list, annot_cnt); + if(annot_cnt >= annot_list_sz) break; - len = snprintf(scratchpad, 256, "%+i.%07i", - (int)(annot_ptr->onset / TIME_DIMENSION), - (int)(annot_ptr->onset % TIME_DIMENSION)); + annot_ptr = edfplus_annotation_get_item(&new_annot_list, annot_cnt++); - for(j=0; j<7; j++) - { - if(scratchpad[len - j - 1] != '0') - { - break; - } - } + len = snprintf(scratchpad, 256, "%+i.%07i", + (int)(annot_ptr->onset / TIME_DIMENSION), + (int)(annot_ptr->onset % TIME_DIMENSION)); - if(j) + for(j=0; j<7; j++) + { + if(scratchpad[len - j - 1] != '0') { - len -= j; - - if(j == 7) - { - len--; - } + break; } + } - if(fwrite(scratchpad, len, 1, outputfile) != 1) + if(j) + { + len -= j; + + if(j == 7) { - progress.reset(); - showpopupmessage("Error", "Write error (5)."); - goto END_4; + len--; } + } - tallen += len; - - if(annot_ptr->duration[0]!=0) - { - fputc(21, outputfile); - tallen++; + if(fwrite(scratchpad, len, 1, outputfile) != 1) + { + progress.reset(); + showpopupmessage("Error", "Write error (5)."); + goto END_4; + } - tallen += fprintf(outputfile, "%s", annot_ptr->duration); - } + tallen += len; - fputc(20, outputfile); + if(annot_ptr->duration[0]!=0) + { + fputc(21, outputfile); tallen++; - tallen += fprintf(outputfile, "%s", annot_ptr->annotation); + tallen += fprintf(outputfile, "%s", annot_ptr->duration); + } - fputc(20, outputfile); - fputc(0, outputfile); - tallen += 2; + fputc(20, outputfile); + tallen++; - annot_cnt--; - } + tallen += fprintf(outputfile, "%s", annot_ptr->annotation); + + fputc(20, outputfile); + fputc(0, outputfile); + tallen += 2; } } diff --git a/statistics_dialog.cpp b/statistics_dialog.cpp index bb74ecd..4b8f473 100644 --- a/statistics_dialog.cpp +++ b/statistics_dialog.cpp @@ -31,15 +31,29 @@ #include "statistics_dialog.h" +#define STAT_JOB_SRC_SIGNAL 0 +#define STAT_JOB_SRC_ECG 1 +#define STAT_JOB_SRC_ANNOT 2 -UI_StatisticWindow::UI_StatisticWindow(struct signalcompblock *signalcomp, long long pagetime) +#define BEAT_IVAL_SIZE 262144 + + + + +UI_StatisticWindow::UI_StatisticWindow(struct signalcompblock *signalcomp, + long long pagetime, + struct annotation_list *annot_list, + struct annotationblock *annot) { int i, tmp, + NN20, + pNN20, NN50, - pNN50; + pNN50, + job_src=0; - char stat_str[2048]; + char stat_str[2048]={""}; double d_tmp, average_bpm, @@ -48,7 +62,11 @@ UI_StatisticWindow::UI_StatisticWindow(struct signalcompblock *signalcomp, long sdnn_rr, *buf_bpm, rmssd_rr, - *beat_interval_list; + *beat_interval_list=NULL; + + long long l_tmp=0; + + struct annotationblock *tmp_annot; StatDialog = new QDialog; StatDialog->setWindowTitle("Statistics"); @@ -57,7 +75,25 @@ UI_StatisticWindow::UI_StatisticWindow(struct signalcompblock *signalcomp, long StatDialog->setWindowFlags(Qt::Window | Qt::WindowMinMaxButtonsHint | Qt::WindowCloseButtonHint); StatDialog->setWindowIcon(QIcon(":/images/edf.png")); - if(signalcomp->ecg_filter != NULL) + if(signalcomp != NULL) + { + if(signalcomp->ecg_filter != NULL) + { + job_src = STAT_JOB_SRC_ECG; + } + else + { + job_src = STAT_JOB_SRC_SIGNAL; + } + } + else + { + job_src = STAT_JOB_SRC_ANNOT; + + beat_interval_list = (double *)malloc(sizeof(double) * BEAT_IVAL_SIZE); + } + + if((job_src == STAT_JOB_SRC_ECG) || (job_src == STAT_JOB_SRC_ANNOT)) { StatDialog->setMinimumSize(600, 400); StatDialog->setSizeGripEnabled(true); @@ -79,10 +115,22 @@ UI_StatisticWindow::UI_StatisticWindow(struct signalcompblock *signalcomp, long curve1->setBackgroundColor(Qt::black); curve1->setRasterColor(Qt::gray); curve1->setTraceWidth(0); - curve1->setH_label(signalcomp->physdimension); + if(job_src == STAT_JOB_SRC_ECG) + { + curve1->setH_label(signalcomp->physdimension); + } curve1->setLowerLabel("HR (beats/min)"); curve1->setDashBoardEnabled(false); - curve1->setUpperLabel1("Distribution"); + if(job_src == STAT_JOB_SRC_ANNOT) + { + strcpy(stat_str, "Distribution "); + strcat(stat_str, annot->annotation); + curve1->setUpperLabel1(stat_str); + } + else + { + curve1->setUpperLabel1("Distribution"); + } curve1->setFillSurfaceEnabled(true); vlayout2_1 = new QVBoxLayout; @@ -91,7 +139,8 @@ UI_StatisticWindow::UI_StatisticWindow(struct signalcompblock *signalcomp, long vlayout2_1->addWidget(startSlider); vlayout2_1->addWidget(stopSlider); } - else + + if(job_src == STAT_JOB_SRC_SIGNAL) { StatDialog->setMinimumSize(300, 400); StatDialog->setMaximumSize(300, 400); @@ -116,7 +165,7 @@ UI_StatisticWindow::UI_StatisticWindow(struct signalcompblock *signalcomp, long hlayout1 = new QHBoxLayout; hlayout1->addLayout(vlayout1_1, 1); - if(signalcomp->ecg_filter != NULL) + if((job_src == STAT_JOB_SRC_ECG) || (job_src == STAT_JOB_SRC_ANNOT)) { hlayout1->addLayout(vlayout2_1, 100); } @@ -130,7 +179,7 @@ UI_StatisticWindow::UI_StatisticWindow(struct signalcompblock *signalcomp, long bpm_distribution[i] = 0; } - if(signalcomp->ecg_filter == NULL) + if(job_src == STAT_JOB_SRC_SIGNAL) { if((signalcomp->stat_cnt < 1) || (pagetime < 10LL)) { @@ -191,11 +240,39 @@ UI_StatisticWindow::UI_StatisticWindow(struct signalcompblock *signalcomp, long } } } - else + + if((job_src == STAT_JOB_SRC_ECG) || (job_src == STAT_JOB_SRC_ANNOT)) { - beat_cnt = ecg_filter_get_beat_cnt(signalcomp->ecg_filter); + if(job_src == STAT_JOB_SRC_ECG) + { + beat_cnt = ecg_filter_get_beat_cnt(signalcomp->ecg_filter); - beat_interval_list = ecg_filter_get_interval_beatlist(signalcomp->ecg_filter); + beat_interval_list = ecg_filter_get_interval_beatlist(signalcomp->ecg_filter); + } + + if(job_src == STAT_JOB_SRC_ANNOT) + { + for(i=0, beat_cnt=0; beat_cnt<BEAT_IVAL_SIZE; i++) + { + tmp_annot = edfplus_annotation_get_item_visible_only(annot_list, i); + + if(tmp_annot == NULL) break; + + if(!strcmp(tmp_annot->annotation, annot->annotation)) + { + if(beat_cnt) + { + beat_interval_list[beat_cnt - 1] = ((double)(tmp_annot->onset - l_tmp)) / (double)TIME_DIMENSION; + } + + l_tmp = tmp_annot->onset; + + beat_cnt++; + } + } + + if(beat_cnt) beat_cnt--; + } if(beat_cnt < 3) { @@ -208,6 +285,7 @@ UI_StatisticWindow::UI_StatisticWindow(struct signalcompblock *signalcomp, long sdnn_bpm = 0.0; sdnn_rr = 0.0; rmssd_rr = 0.0; + NN20 = 0; NN50 = 0; buf_bpm = (double *)malloc(sizeof(double) * beat_cnt); @@ -231,6 +309,11 @@ UI_StatisticWindow::UI_StatisticWindow(struct signalcompblock *signalcomp, long rmssd_rr += (d_tmp * d_tmp); + if(((beat_interval_list[i] - beat_interval_list[i + 1]) > 0.02 ) || ((beat_interval_list[i + 1] - beat_interval_list[i]) > 0.02 )) + { + NN20++; + } + if(((beat_interval_list[i] - beat_interval_list[i + 1]) > 0.05 ) || ((beat_interval_list[i + 1] - beat_interval_list[i]) > 0.05 )) { NN50++; @@ -243,6 +326,7 @@ UI_StatisticWindow::UI_StatisticWindow(struct signalcompblock *signalcomp, long rmssd_rr /= beat_cnt; rmssd_rr = sqrt(rmssd_rr); + pNN20 = (NN20 * 100) / (beat_cnt - 1); pNN50 = (NN50 * 100) / (beat_cnt - 1); for(i=0; i<beat_cnt; i++) @@ -262,6 +346,8 @@ UI_StatisticWindow::UI_StatisticWindow(struct signalcompblock *signalcomp, long "RMSSD RR: %3i ms\n\n" "Mean HR: %3.3f bpm\n\n" "SDNN HR: %3.3f bpm\n\n" + "NN20: %3i\n\n" + "pNN20: %3i %%\n\n" "NN50: %3i\n\n" "pNN50: %3i %%\n\n", beat_cnt, @@ -270,6 +356,8 @@ UI_StatisticWindow::UI_StatisticWindow(struct signalcompblock *signalcomp, long (int)rmssd_rr, average_bpm, sdnn_bpm, + NN20, + pNN20, NN50, pNN50); @@ -339,6 +427,11 @@ UI_StatisticWindow::UI_StatisticWindow(struct signalcompblock *signalcomp, long } } + if(job_src == STAT_JOB_SRC_ANNOT) + { + free(beat_interval_list); + } + Label1->setText(stat_str); StatDialog->exec(); diff --git a/statistics_dialog.h b/statistics_dialog.h index 01f6883..d03c667 100644 --- a/statistics_dialog.h +++ b/statistics_dialog.h @@ -51,6 +51,7 @@ #include "global.h" #include "ecg_filter.h" #include "signalcurve.h" +#include "edf_annot_list.h" @@ -61,7 +62,10 @@ class UI_StatisticWindow : public QObject public: -UI_StatisticWindow(struct signalcompblock *, long long); +UI_StatisticWindow(struct signalcompblock *, + long long, + struct annotation_list *annot_list=NULL, + struct annotationblock *annot=NULL); private: diff --git a/version.txt b/version.txt index bb4337e..0ea6393 100644 --- a/version.txt +++ b/version.txt @@ -1,5 +1,21 @@ - version 1.60 to be defined + version 1.61 November 1, 2017 + -------------- + + - Fixed a bug that caused a freeze/lockup when using the annotationlist filter. + + - Added the possibility to filter annotations based on minimum and maximum interval time. + + - Fixed a regression bug that could cause a crash when using the "reduce signals" tool + with an EDF+ file. + + - Added a tool to export filtered and or derived signals to a new file. + + - Added the possibility to view the Heart Rate Variability using the annotation list. + + + + version 1.60 September 16, 2017 -------------- - Improve parameter checking for signal composition when loading a montage file. diff --git a/viewcurve.cpp b/viewcurve.cpp index 1bd0bec..cc8a8e9 100644 --- a/viewcurve.cpp +++ b/viewcurve.cpp @@ -63,18 +63,52 @@ ViewCurve::ViewCurve(QWidget *w_parent) : QWidget(w_parent) original_sensitivity = (double *)calloc(1, sizeof(double[MAXSIGNALS])); - backgroundcolor = Qt::gray; - small_ruler_color = Qt::black; - big_ruler_color = Qt::darkGray; - mouse_rect_color = Qt::black; - text_color = Qt::black; - signal_color = Qt::blue; - baseline_color = Qt::darkGray; - crosshair_1.color = Qt::red; - crosshair_2.color = Qt::cyan; - floating_ruler_color = Qt::red; - annot_marker_color = Qt::white; - annot_duration_color = QColor(0, 127, 127, 32); +//////////////////////////////////////////////////////// + + backgroundcolor.setRed(64); + backgroundcolor.setGreen(64); + backgroundcolor.setBlue(64); + + small_ruler_color.setRed(255); + small_ruler_color.setGreen(255); + small_ruler_color.setBlue(255); + + big_ruler_color.setRed(128); + big_ruler_color.setGreen(128); + big_ruler_color.setBlue(128); + + mouse_rect_color.setRed(255); + mouse_rect_color.setGreen(255); + mouse_rect_color.setBlue(255); + + text_color.setRed(255); + text_color.setGreen(255); + text_color.setBlue(255); + + baseline_color.setRed(128); + baseline_color.setGreen(128); + baseline_color.setBlue(128); + + annot_marker_color.setRed(255); + annot_marker_color.setGreen(255); + annot_marker_color.setBlue(255); + + annot_duration_color.setRed(0); + annot_duration_color.setGreen(127); + annot_duration_color.setBlue(127); + annot_duration_color.setAlpha(32); + + signal_color = 12; + + floating_ruler_color = 10; + + blackwhite_printing = 1; + + crosshair_1.color = 7; + + crosshair_2.color = 10; + +///////////////////////////////////////////////////////// crosshair_1.active = 0; crosshair_2.active = 0; @@ -1490,7 +1524,7 @@ void ViewCurve::drawCurve_stage_2(QPainter *painter, int w_width, int w_height, { l_tmp = annot->onset - mainwindow->edfheaderlist[i]->starttime_offset; - if(((l_tmp + annot->long_duration) > (mainwindow->edfheaderlist[i]->viewtime - TIME_DIMENSION)) && (!annot->hided) && (!annot->hided_in_list)) + if(((l_tmp + annot->long_duration) > (mainwindow->edfheaderlist[i]->viewtime - TIME_DIMENSION)) && (!annot->hided)) { if(l_tmp > (mainwindow->edfheaderlist[i]->viewtime + mainwindow->pagetime)) { @@ -1934,7 +1968,7 @@ void ViewCurve::drawCurve_stage_2(QPainter *painter, int w_width, int w_height, l_tmp = annot->onset - mainwindow->edfheaderlist[i]->starttime_offset; - if((l_tmp > (mainwindow->edfheaderlist[i]->viewtime - TIME_DIMENSION)) && (!annot->hided) && (!annot->hided_in_list)) + if((l_tmp > (mainwindow->edfheaderlist[i]->viewtime - TIME_DIMENSION)) && (!annot->hided)) { if(l_tmp > (mainwindow->edfheaderlist[i]->viewtime + mainwindow->pagetime)) { -- Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/debian-med/edfbrowser.git _______________________________________________ debian-med-commit mailing list [email protected] http://lists.alioth.debian.org/cgi-bin/mailman/listinfo/debian-med-commit
