Skip to content
Commits on Source (6)
......@@ -13,7 +13,7 @@ The GCC compiler on Linux or Mingw-w64 on windows. <http://mingw-w64.sourceforge
http://sourceforge.net/projects/mingw-w64/files/Toolchains%20targetting%20Win32/Personal%20Builds/mingw-builds/4.8.2/threads-posix/dwarf/i686-4.8.2-release-posix-dwarf-rt_v3-rev3.7z/download
Please, do not use any microsoft tools or compilers. Don't waste your time, it's not going to work!
Do not use microsoft tools or compilers.
......@@ -47,13 +47,14 @@ sudo make install
How to compile (step by step)
=============================
How to compile
==============
- Install Git, the GCC compiler and the Qt4 development package:
Linux Mint 18: sudo apt-get install git-core libqt4-dev libqt4-core g++
openSuse Leap 42.2: sudo zypper in git-core libqt4-devel
Fedora 25: sudo dnf install git-core qt-devel gcc-c++
Ubuntu 18.04: sudo apt-get install g++ make git-core qtbase5-dev-tools qtbase5-dev qt5-default
- Download the source code:
mkdir EDFbrowser_git
......@@ -65,9 +66,10 @@ How to compile (step by step)
Linux Mint 18: qmake
openSuse Leap 42.2: qmake
Fedora 25: qmake-qt4
Ubuntu: qmake
- Compile the source code and install it:
make -j16
make -j8
sudo make install
Now you can run the program by typing: edfbrowser
......@@ -95,7 +97,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.4 #
# in a new and separate directory: /usr/local/Qt-5.9.5 #
# #
# It will not interfere with other Qt programs. #
# #
......@@ -105,14 +107,14 @@ mkdir Qt5-source
cd Qt5-source
wget http://ftp1.nluug.nl/languages/qt/official_releases/qt/5.9/5.9.4/single/qt-everywhere-opensource-src-5.9.4.tar.xz
wget http://ftp1.nluug.nl/languages/qt/official_releases/qt/5.9/5.9.5/single/qt-everywhere-opensource-src-5.9.5.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.4.tar.xz
The Qt source package you are going to need is: qt-everywhere-opensource-src-5.9.5.tar.xz
tar -xvf qt-everywhere-opensource-src-5.9.4.tar.xz
tar -xvf qt-everywhere-opensource-src-5.9.5.tar.xz
cd qt-everywhere-opensource-src-5.9.4
cd qt-everywhere-opensource-src-5.9.5
./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
......@@ -126,7 +128,7 @@ sudo make install
Now go to the directory that contains the EDFbrowser sourcecode and enter the following commands:
/usr/local/Qt-5.9.4/bin/qmake
/usr/local/Qt-5.9.5/bin/qmake
make -j8
......
......@@ -791,8 +791,6 @@ void UI_Annotationswindow::updateList(void)
QString string;
QByteArray ba;
struct annotationblock *annot;
struct annotation_list *annot_list;
......@@ -842,8 +840,7 @@ void UI_Annotationswindow::updateList(void)
string = QString::fromUtf8(annot->annotation);
ba = string.toUtf8();
str_tmp = ba.data();
str_tmp = string.toUtf8().data();
len = 0;
for(i=0; ; i++)
......@@ -1014,14 +1011,14 @@ void UI_Annotationswindow::annotation_selected(QListWidgetItem * item, int cente
if(mainwindow->video_player->status == VIDEO_STATUS_PLAYING)
{
mainwindow->video_player_seek((int)((annot->onset - (mainwindow->pagetime / 2) - mainwindow->edfheaderlist[file_num]->starttime_offset) / TIME_DIMENSION));
mainwindow->video_player_seek((int)((annot->onset - mainwindow->edfheaderlist[file_num]->starttime_offset) / TIME_DIMENSION));
return;
}
if(mainwindow->video_player->status == VIDEO_STATUS_PAUSED)
{
mainwindow->video_player_seek((int)((annot->onset - (mainwindow->pagetime / 2) - mainwindow->edfheaderlist[file_num]->starttime_offset) / TIME_DIMENSION));
mainwindow->video_player_seek((int)((annot->onset - mainwindow->edfheaderlist[file_num]->starttime_offset) / TIME_DIMENSION));
}
if(mainwindow->viewtime_sync==VIEWTIME_SYNCED_OFFSET)
......
......@@ -516,7 +516,7 @@ void UI_AveragerWindow::process_avg(struct signalcompblock *signalcomp)
for(s=signalcomp->sample_start; s<signalcomp->samples_on_screen; s++)
{
if(s>signalcomp->sample_stop) break;
if(s>=signalcomp->sample_stop) break;
dig_value = 0.0;
s2 = s + signalcomp->sample_timeoffset - signalcomp->sample_start;
......
......@@ -778,7 +778,8 @@ struct edfhdrblock * EDFfileCheck::check_edf_file(FILE *inputfile, char *txt_str
if(is_number(scratchpad))
{
sprintf(txt_string, "Error, physical minimum field of signal %i is invalid: \"%s\".",
sprintf(txt_string, "Error, physical minimum field of signal %i is invalid: \"%s\".\n"
"You can try to fix it with the header editor, check the manual for the procedure.",
i + 1,
scratchpad);
free(edf_hdr);
......@@ -813,7 +814,8 @@ struct edfhdrblock * EDFfileCheck::check_edf_file(FILE *inputfile, char *txt_str
if(is_number(scratchpad))
{
sprintf(txt_string, "Error, physical maximum field of signal %i is invalid: \"%s\".",
sprintf(txt_string, "Error, physical maximum field of signal %i is invalid: \"%s\".\n"
"You can try to fix it with the header editor, check the manual for the procedure.",
i + 1,
scratchpad);
free(edf_hdr);
......
edfbrowser (1.64+dfsg-1) unstable; urgency=medium
* New upstream version
* Point Vcs fields to salsa.debian.org
* Standards-Version: 4.1.4
-- Andreas Tille <tille@debian.org> Wed, 06 Jun 2018 09:17:58 +0200
edfbrowser (1.63+dfsg-1) unstable; urgency=medium
* New upstream version
......
......@@ -11,9 +11,9 @@ Build-Depends: debhelper (>= 11~),
libqt5opengl5-dev,
qttools5-dev-tools,
libedf-dev
Standards-Version: 4.1.3
Vcs-Browser: https://anonscm.debian.org/cgit/debian-med/edfbrowser.git
Vcs-Git: https://anonscm.debian.org/git/debian-med/edfbrowser.git
Standards-Version: 4.1.4
Vcs-Browser: https://salsa.debian.org/med-team/edfbrowser
Vcs-Git: https://salsa.debian.org/med-team/edfbrowser.git
Homepage: http://www.teuniz.net/edfbrowser/
Package: edfbrowser
......
......@@ -7,7 +7,7 @@
<meta name="description" content="EDFbrowser manual">
</head><body>
<h1>EDFbrowser 1.63 manual</h1>
<h1>EDFbrowser 1.64 manual</h1>
<p><br></p>
......@@ -115,14 +115,16 @@
<h3><a name="Video"></a>Video</h3>
<p>
(Linux version only)<br>
Use the Filemenu to start (or stop) a video. After the video has been started, you can use the slider<br>
on the bottom to change the file position or use page-up/page-down.<br><br>
In order for EDFbrowser to be able to start a video, the <a href="https://www.videolan.org/">VLC mediaplayer</a> must be installed on your system.<br>
On windows: make sure VLC is installed in: C:\Program Files\VideoLAN\VLC\ or C:\Program Files (x86)\VideoLAN\VLC\<br><br>
In order for EDFbrowser to be able to start a video, the VLC mediaplayer needs to be installed on your system.<br><br>
Open an EDF or BDF file and select/setup your montage as usual. Then press Ctrl-Shift-v (or go to File -> Start video)<br>
to select a video. After the video has started, you can use the slider on the bottom to change the file position or<br>
use page-up/page-down.<br><br>
Also, the startdate and starttime needs to be set in the filename of the video (for synchronization).<br>
The following text is copied from <a href="http://www.edfplus.info/specs/video.html">http://www.edfplus.info/specs/video.html</a> :<br><br>
<i>
Video filenames of the same patient must start with the same patient identification,<br>
followed by the start-date and -time of the video, as follows:<br>
NL_012348168_03-MAY-2013_14h45m49.013s_Video.ogv<br>
......@@ -134,7 +136,16 @@
so midnight is coded as 00h00m00s. The decimal fraction of a second (noted here by .XXXX) can have any lenght and can also be omitted<br>
(for example in 06h37m12s). The addition _Video is not obligatory and neither do we standardize any video format such as ogv.<br>
So, a perfectly OK video filename would also be:<br>
NL_012348168_03-MAY-2013_14h45m49.013s.mpeg
NL_012348168_03-MAY-2013_14h45m49.013s.mpeg<br><br>
</i>
Note: EDFbrowser will ignore the part of the filename directly before the startdate and directly after the starttime.<br><br>
If the filename of the video does not contain the startdate and starttime, you can still continue to use the video but<br>
in that case EDFbrowser will assume that the starttime of the video coincides with the starttime of the EDF file.<br><br>
You can resize the video window by dragging the bottom-right corner with the mouse.<br>
All other operations like stop, pause, etc. must be done by using the videoplayer controls (buttons) in EDFbrowser.<br>
Do not use the control interface of VLC, it will interfere with EDFbrowser.
</p>
<p><br></p>
......@@ -406,7 +417,7 @@
The Power Spectral Density of the corresponding signal will be shown (uV)<sup>2</sup>/FFT-resolution.<br>
The amount of datasamples used to perform the FFT equals the data which is<br>
shown on the screen. Increasing or decreasing the FFT blocksize affects the FFT resolution.<br>
The FFT blocksize can be set in Settings menu.<br>
The default FFT blocksize can be set in Settings menu.<br>
So, if the samplefrequency of the selected signal is 256Hz, the timescale is set to 10 seconds and<br>
the FFT-blocksize is 512, the number of FFT's performed is (10 seconds x 256 Hz) / 512 = 5.<br>
The output of the five FFT's are averaged.<br>
......@@ -484,7 +495,7 @@
- Dynamic powerline interference subtraction from biosignals<br>
Ivaylo I. Christov<br>
<br>
The subtraction method extracts the powerline interference noise during a<br>
The subtraction method extracts the powerline interference noise (50/60Hz and harmonics) during a<br>
a linear region between two consecutive QRS complexes and stores it in a buffer.<br>
The reference noise from the buffer is used to subtract it from the signal outside<br>
the linear region i.e. during the QRS complex.<br>
......@@ -492,7 +503,7 @@
integer multiple of the powerline frequency.<br>
In case they are synchronized, this method will remove also the harmonics of the<br>
powerline frequency. In that case extra notch-filters for the harmonics are<br>
not necessary. The advantage of this method is that it will not cause ringing<br>
not necessary. The advantage of this method is that it will not cause ringing or other distortion<br>
in the waveform of the QRS complex (like notch-filters do).<br>
<br>
The following rules apply:<br>
......@@ -502,7 +513,7 @@
<br>
Note: Good results will be achieved when the accuracy of the recording sampleclock is &lt=100ppm.<br>
A nearly perfect result will achieved when the recording sampleclock is synchronized with the<br>
powerlinefrequency in hardware (e.g. using a PLL).
powerlinefrequency in hardware (e.g. using a Phase Locked Loop).
</p>
<p><br></p>
......@@ -847,7 +858,7 @@
<br>
filename_data.txt contains a separate line for each sampletime that occurs.<br>
Note to windows-users: these lines are separated by a linefeed only,<br>
so the file does NOT look OK in Notepad, use Wordpad instead.<br>
so the file does NOT look OK in Notepad, use a real editor instead.<br>
<br>
Each line contains the comma-separated values of the sampletime and of all<br>
samples that were taken at that time.<br>
......@@ -1081,7 +1092,7 @@
<br>
- the data in the ASCII-file must be presented in their physical dimension (i.e. uV, bpm, mmHg, etc.)<br>
- the data in the ASCII-file must be organised in columns and rows<br>
- a row must contain values from different signals/channels aquired at the same sampletime<br>
- a row must contain values from different signals/channels acquired at the same sampletime<br>
- a column must represent a continuous sampled signal/channel<br>
- all signals/channels must have the same samplefrequency<br>
- the timeinterval between two consecutive samples of the same signal/channel must have a stable value (fixed samplerate)<br>
......@@ -1109,17 +1120,17 @@
<br>
- label (name of the signal/channel i.e. FP1, SaO2, Heartrate, etc.)<br>
- physical maximum (the maximum physical value that can occur, i.e. the maximum inputlevel<br>
of the aquisition equipment. A common value in EEG applications is 3000 uV)<br>
physical minimum will be equal to physical maximum. for example, if you enter 3000, the<br>
of the acquisition equipment. A common value in EEG applications is 3000 uV)<br>
Physical minimum will be equal to physical maximum. For example, if you enter 3000, the<br>
range will be from +3000 to -3000<br>
- physical dimension (i.e. uV, %, mmHg, bpm)<br>
- physical dimension (units, e.g. uV, mV, %, mmHg, bpm)<br>
- multiplier is normally 1.0. Some programs exports their ascii-data expressed in Volts while<br>
the signal is in the microVolt range. By changing the multiplier you can add gain to the signal before converting.<br>
For example, if the ascii-data is expressed in Volts and the signal is in the microVolt range (EEG),<br>
set the physical maximum to 3000, set the physical dimension to "uV" and set the multiplier to 1000000.<br>
<br>
It is possible to exclude columns, by unchecking the corresponding row in the signals-table,<br>
this can be useful when a column contains a time/datestamp or when you don't want to include<br>
It is possible to exclude columns, by unchecking the corresponding row in the signals-table.<br>
This can be useful when a column contains a time/datestamp or when you don't want to include<br>
a particular signal in the EDF/BDF-file.<br>
<br>
Click on the startbutton to start the conversion.<br>
......@@ -1127,7 +1138,7 @@
Click on the loadbutton to load parameters from a template.<br>
<br>
Note: It is important to enter the right value in the "physical maximum" field.<br>
If you to choose this value too small, the top of the signal will be cut off.<br>
If you to choose this value too small, the top of the signal will clip at the peaks.<br>
If you choose this value too big, small values of the signal will not be visible<br>
and the signal will look coarse.<br>
The ideal value for the "physical maximum" is just above (or equal to) the maximum value that can occur,<br>
......@@ -1608,23 +1619,24 @@
<h3><a name="Annotation_editor">Annotation editor</a></h3>
<p>
The annotation editor can be used to add, remove or edit annotations.<br>
The annotation editor can be used to create, edit or delete annotations.<br>
Start the editor via menu -&gt; Window -&gt; Annotation editor.<br>
To create a new annotation, write the text of the annotation in the description window and set<br>
the onset time. You can set the duration time as well. If the duration time is unknown or not<br>
applicable, set it to the value -1. Now click on the create button.<br><br>
applicable, set it to -1. Now click on the create button.<br><br>
Instead of manually entering the onset time, you can use a <a href="#Crosshairs">crosshair</a>.<br>
Drag and drop the crosshair and the onset time will be automatically adjusted.<br>
You can use a second <a href="#Crosshairs">crosshair</a> to adjust the duration time.<br><br>
You can use a second <a href="#Crosshairs">crosshair</a> to adjust the duration of the event.<br><br>
To modify an existent annotation, click on the annotation in the annotation window.<br>
Adjust the text and or time, manually or drag and drop the annotation marker.<br><br>
Adjust the text and/or time, manually or drag and drop the annotation marker with the mouse.<br><br>
To delete an annotation, click on the annotation in the annotation window and click<br>
on the delete button.<br><br>
on the delete button (or hit Del on your keyboard.<br>
Pay attention, there's no undo.<br><br>
When you are finished editing annotations, save the file in menu -&gt; File -&gt; Save.<br>
When you have finished editing annotations, save the file in menu -&gt; File -&gt; Save.<br>
Your file will not be altered, instead a copy of your file with the edited annotations<br>
will be made.<br><br>
......
......@@ -130,6 +130,7 @@ HEADERS += plif_ecg_subtract_filter.h
HEADERS += plif_ecg_subtract_filter_dialog.h
HEADERS += annotlist_filter_dialog.h
HEADERS += export_filtered_signals.h
HEADERS += fft_wrap.h
HEADERS += third_party/fidlib/fidlib.h
HEADERS += third_party/fidlib/fidmkf.h
......@@ -225,6 +226,7 @@ SOURCES += plif_ecg_subtract_filter.c
SOURCES += plif_ecg_subtract_filter_dialog.cpp
SOURCES += annotlist_filter_dialog.cpp
SOURCES += export_filtered_signals.cpp
SOURCES += fft_wrap.c
SOURCES += third_party/fidlib/fidlib.c
......
......@@ -94,6 +94,7 @@ UI_AnnotationEditwindow::UI_AnnotationEditwindow(QWidget *w_parent)
deletebutton = new QPushButton(annot_edit_dialog);
deletebutton->setGeometry(840, 10, 100, 25);
deletebutton->setText("Delete");
deletebutton->setShortcut(QKeySequence::Delete);
deletebutton->setEnabled(false);
createbutton = new QPushButton(annot_edit_dialog);
......@@ -107,7 +108,6 @@ UI_AnnotationEditwindow::UI_AnnotationEditwindow(QWidget *w_parent)
}
void UI_AnnotationEditwindow::open_close_dock(bool visible)
{
if(mainwindow->files_open != 1)
......
......@@ -108,7 +108,7 @@ void UI_EMSA2EDFwindow::SelectFileButton()
char path[MAX_PATH_LENGTH],
scratchpad[256],
*buf,
*buf=NULL,
date[9],
time[9],
month[4],
......@@ -127,6 +127,7 @@ void UI_EMSA2EDFwindow::SelectFileButton()
char str[4];
} var;
logbuf = NULL;
pushButton1->setEnabled(false);
......@@ -774,7 +775,7 @@ void UI_EMSA2EDFwindow::SelectFileButton()
scratchpad[j] = ' ';
}
latin1_to_ascii(scratchpad, 16);
scratchpad[len] = 0;
scratchpad[16] = 0;
fseeko(inputfile, (long long)(1025 + (i * 512)), SEEK_SET);
if((fgetc(inputfile)=='E')&&(len<13))
{
......
......@@ -53,6 +53,7 @@ UI_ExportFilteredSignalsWindow::UI_ExportFilteredSignalsWindow(QWidget *w_parent
tree->setEditTriggers(QAbstractItemView::NoEditTriggers);
tree->setSortingEnabled(false);
tree->setDragDropMode(QAbstractItemView::NoDragDrop);
tree->setAlternatingRowColors(true);
t_model = new QStandardItemModel(this);
......@@ -1267,10 +1268,50 @@ void UI_ExportFilteredSignalsWindow::populate_tree_view()
signalItem = new QStandardItem(txtbuf);
switch(mainwindow->signalcomp[i]->color)
{
case Qt::white : signalItem->setIcon(QIcon(":/images/white_icon_16x16"));
break;
case Qt::black : signalItem->setIcon(QIcon(":/images/black_icon_16x16"));
break;
case Qt::red : signalItem->setIcon(QIcon(":/images/red_icon_16x16"));
break;
case Qt::darkRed : signalItem->setIcon(QIcon(":/images/darkred_icon_16x16"));
break;
case Qt::green : signalItem->setIcon(QIcon(":/images/green_icon_16x16"));
break;
case Qt::darkGreen : signalItem->setIcon(QIcon(":/images/darkgreen_icon_16x16"));
break;
case Qt::blue : signalItem->setIcon(QIcon(":/images/blue_icon_16x16"));
break;
case Qt::darkBlue : signalItem->setIcon(QIcon(":/images/darkblue_icon_16x16"));
break;
case Qt::cyan : signalItem->setIcon(QIcon(":/images/cyan_icon_16x16"));
break;
case Qt::darkCyan : signalItem->setIcon(QIcon(":/images/darkcyan_icon_16x16"));
break;
case Qt::magenta : signalItem->setIcon(QIcon(":/images/magenta_icon_16x16"));
break;
case Qt::darkMagenta : signalItem->setIcon(QIcon(":/images/darkmagenta_icon_16x16"));
break;
case Qt::yellow : signalItem->setIcon(QIcon(":/images/yellow_icon_16x16"));
break;
case Qt::darkYellow : signalItem->setIcon(QIcon(":/images/darkyellow_icon_16x16"));
break;
case Qt::gray : signalItem->setIcon(QIcon(":/images/gray_icon_16x16"));
break;
case Qt::darkGray : signalItem->setIcon(QIcon(":/images/darkgray_icon_16x16"));
break;
case Qt::lightGray : signalItem->setIcon(QIcon(":/images/lightgray_icon_16x16"));
break;
}
parentItem->appendRow(signalItem);
filterItem = new QStandardItem("Filters");
filterItem->setIcon(QIcon(":/images/filter_lowpass_small.png"));
signalItem->appendRow(filterItem);
if(mainwindow->signalcomp[i]->spike_filter)
......
......@@ -52,6 +52,9 @@
#include <QTreeView>
#include <QStandardItemModel>
#include <QStandardItem>
#include <QPixmap>
#include <QIcon>
#include <QColor>
#include <stdio.h>
#include <stdlib.h>
......
/*
***************************************************************************
*
* Author: Teunis van Beelen
*
* Copyright (C) 2018 Teunis van Beelen
*
* Email: teuniz@gmail.com
*
***************************************************************************
*
* 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 "fft_wrap.h"
static void hamming_window_func(const double *, double *, int);
static void blackman_window_func(const double *, double *, int);
struct fft_wrap_settings_struct * fft_wrap_create(double *buf, int buf_size, int dft_size, int window_type)
{
struct fft_wrap_settings_struct *st;
if(buf == NULL) return NULL;
if(buf_size < 2) return NULL;
if(dft_size < 2) return NULL;
if(dft_size & 1) dft_size--;
if((window_type < 0) || (window_type > 2)) return NULL;
st = (struct fft_wrap_settings_struct *)calloc(1, sizeof(struct fft_wrap_settings_struct));
if(st == NULL) return NULL;
st->sz_in = buf_size;
st->dft_sz = dft_size;
st->wndw_type = window_type;
st->blocks = 1;
if(st->dft_sz < st->sz_in)
{
st->blocks = st->sz_in / st->dft_sz;
}
else
{
st->dft_sz = st->sz_in;
}
if(st->dft_sz & 1) st->dft_sz--;
st->smpls_left = st->sz_in % st->dft_sz;
if(st->smpls_left & 1) st->smpls_left--;
st->sz_out = st->dft_sz / 2;
st->buf_in = buf;
if(st->wndw_type)
{
st->buf_wndw = (double *)malloc(sizeof(double) * (st->dft_sz + 2));
if(st->buf_wndw == NULL)
{
free(st);
return NULL;
}
}
st->buf_out = (double *)malloc(sizeof(double) * (st->sz_out + 2));
if(st->buf_out == NULL)
{
free(st->buf_wndw);
free(st);
return NULL;
}
st->kiss_fftbuf = (kiss_fft_cpx *)malloc((st->sz_out + 1) * sizeof(kiss_fft_cpx));
if(st->kiss_fftbuf == NULL)
{
free(st->buf_wndw);
free(st->buf_out);
free(st);
return NULL;
}
st->cfg = kiss_fftr_alloc(st->dft_sz, 0, NULL, NULL);
return st;
}
void fft_wrap_run(struct fft_wrap_settings_struct *st)
{
int i, j;
if(st == NULL) return;
if(st->sz_in < 2) return;
if(st->dft_sz < 2) return;
if(st->sz_out < 1) return;
if(st->buf_in == NULL) return;
if(st->buf_out == NULL) return;
if(st->kiss_fftbuf == NULL) return;
if(st->wndw_type)
{
if(st->buf_wndw == NULL) return;
if(st->wndw_type == 1)
{
hamming_window_func(st->buf_in, st->buf_wndw, st->dft_sz);
}
else if(st->wndw_type == 2)
{
blackman_window_func(st->buf_in, st->buf_wndw, st->dft_sz);
}
else
{
return;
}
kiss_fftr(st->cfg, st->buf_wndw, st->kiss_fftbuf);
}
else
{
kiss_fftr(st->cfg, st->buf_in, st->kiss_fftbuf);
}
for(i=0; i<st->sz_out; i++)
{
st->buf_out[i] = ((st->kiss_fftbuf[i].r * st->kiss_fftbuf[i].r) + (st->kiss_fftbuf[i].i * st->kiss_fftbuf[i].i)) / st->sz_out;
}
for(j=1; j<st->blocks; j++)
{
if(st->wndw_type == 1)
{
hamming_window_func(st->buf_in + (j * st->dft_sz), st->buf_wndw, st->dft_sz);
}
else if(st->wndw_type == 2)
{
blackman_window_func(st->buf_in + (j * st->dft_sz), st->buf_wndw, st->dft_sz);
}
if(st->wndw_type)
{
kiss_fftr(st->cfg, st->buf_wndw, st->kiss_fftbuf);
}
else
{
kiss_fftr(st->cfg, st->buf_in + (j * st->dft_sz), st->kiss_fftbuf);
}
for(i=0; i<st->sz_out; i++)
{
st->buf_out[i] += ((st->kiss_fftbuf[i].r * st->kiss_fftbuf[i].r) + (st->kiss_fftbuf[i].i * st->kiss_fftbuf[i].i)) / st->sz_out;
}
}
if(st->smpls_left)
{
if(st->wndw_type == 1)
{
hamming_window_func(st->buf_in + ((j-1) * st->dft_sz) + st->smpls_left, st->buf_wndw, st->dft_sz);
}
else if(st->wndw_type == 2)
{
blackman_window_func(st->buf_in + ((j-1) * st->dft_sz) + st->smpls_left, st->buf_wndw, st->dft_sz);
}
if(st->wndw_type)
{
kiss_fftr(st->cfg, st->buf_wndw, st->kiss_fftbuf);
}
else
{
kiss_fftr(st->cfg, st->buf_in + ((j-1) * st->dft_sz) + st->smpls_left, st->kiss_fftbuf);
}
for(i=0; i<st->sz_out; i++)
{
st->buf_out[i] += ((st->kiss_fftbuf[i].r * st->kiss_fftbuf[i].r) + (st->kiss_fftbuf[i].i * st->kiss_fftbuf[i].i)) / st->sz_out;
st->buf_out[i] /= (st->blocks + 1);
}
}
else
{
if(st->blocks > 1)
{
for(i=0; i<st->sz_out; i++)
{
st->buf_out[i] /= st->blocks;
}
}
}
}
void free_fft_wrap(struct fft_wrap_settings_struct *st)
{
if(st == NULL) return;
free(st->cfg);
free(st->kiss_fftbuf);
free(st->buf_out);
free(st->buf_wndw);
memset(st, 0, sizeof(struct fft_wrap_settings_struct));
free(st);
}
static void hamming_window_func(const double *src, double *dest, int sz)
{
int i;
for(i=0; i<sz; i++)
{
dest[i] = (0.53836 - (0.46164 * cos((2.0 * M_PI * i) / (sz - 1)))) * src[i];
}
}
static void blackman_window_func(const double *src, double *dest, int sz)
{
int i;
for(i=0; i<sz; i++)
{
dest[i] = (0.42 - (0.5 * cos((2.0 * M_PI * i) / (sz - 1))) + (0.08 * cos((4.0 * M_PI * i) / (sz - 1)))) * src[i];
}
}
/*
***************************************************************************
*
* Author: Teunis van Beelen
*
* Copyright (C) 2018 Teunis van Beelen
*
* Email: teuniz@gmail.com
*
***************************************************************************
*
* 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 fft_wrap_INCLUDED
#define fft_wrap_INCLUDED
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <math.h>
#include "third_party/kiss_fft/kiss_fftr.h"
#ifdef __cplusplus
extern "C" {
#endif
struct fft_wrap_settings_struct{
int sz_in;
int dft_sz;
int sz_out;
int blocks;
int smpls_left;
int wndw_type;
double *buf_in;
double *buf_wndw;
double *buf_out;
kiss_fftr_cfg cfg;
kiss_fft_cpx *kiss_fftbuf;
};
struct fft_wrap_settings_struct * fft_wrap_create(double *, int, int, int);
void fft_wrap_run(struct fft_wrap_settings_struct *);
void free_fft_wrap(struct fft_wrap_settings_struct *);
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif
......@@ -263,11 +263,16 @@ int FilteredBlockReadClass::process_signalcomp(int datarecord_start)
dig_value = plif_run_subtract_filter(dig_value, signalcomp->plif_ecg_filter);
}
if(signalcomp->ecg_filter != NULL)
if(signalcomp->ecg_filter)
{
dig_value = run_ecg_filter(dig_value, signalcomp->ecg_filter);
}
if(signalcomp->zratio_filter)
{
dig_value = run_zratio_filter(dig_value, signalcomp->zratio_filter);
}
dig_value *= signalcomp->polarity;
}
......
......@@ -44,7 +44,7 @@
#endif
#define PROGRAM_NAME "EDFbrowser"
#define PROGRAM_VERSION "1.63"
#define PROGRAM_VERSION "1.64"
#define MINIMUM_QT4_VERSION 0x040701
#define MINIMUM_QT5_VERSION 0x050901
#define MAXFILES 32
......@@ -75,6 +75,7 @@
#define VIDEO_STATUS_STARTUP_3 3
#define VIDEO_STATUS_STARTUP_4 4
#define VIDEO_STATUS_STARTUP_5 5
#define VIDEO_STATUS_STARTUP_6 6
#define VIDEO_STATUS_PLAYING 16
#define VIDEO_STATUS_PAUSED 17
#define VIDEO_STATUS_ENDED 18
......@@ -286,6 +287,7 @@ struct video_player_struct{
int starttime_diff;
int stop_det_counter;
int fpos;
int speed;
};
struct annot_filter_struct{
......
......@@ -900,7 +900,7 @@ void UI_headerEditorWindow::read_header()
void UI_headerEditorWindow::save_hdr()
{
int i, j, p, len, hassign, digmin=0, digmax=0, dig_ok;
int i, j, p, len, hassign, digmin=0, digmax=0, dig_ok, dots, commas;
char scratchpad[256],
scratchpad2[256],
......@@ -1447,6 +1447,25 @@ void UI_headerEditorWindow::save_hdr()
}
}
scratchpad[8] = 0;
for(p=0, dots=0, commas=0; p<8; p++)
{
if(scratchpad[p] == ',') commas++;
if(scratchpad[p] == '.') dots++;
}
if((commas == 1) && (dots == 0))
{
for(p=0; p<8; p++)
{
if(scratchpad[p] == ',')
{
scratchpad[p] = '.';
break;
}
}
}
fseeko(file, (long long)(256 + (edfsignals * 104) + (i * 8)), SEEK_SET);
fprintf(file, "%s", scratchpad);
......@@ -1463,6 +1482,25 @@ void UI_headerEditorWindow::save_hdr()
}
}
scratchpad2[8] = 0;
for(p=0, dots=0, commas=0; p<8; p++)
{
if(scratchpad2[p] == ',') commas++;
if(scratchpad2[p] == '.') dots++;
}
if((commas == 1) && (dots == 0))
{
for(p=0; p<8; p++)
{
if(scratchpad2[p] == ',')
{
scratchpad2[p] = '.';
break;
}
}
}
fseeko(file, (long long)(256 + (edfsignals * 112) + (i * 8)), SEEK_SET);
fprintf(file, "%s", scratchpad2);
......
......@@ -14,5 +14,25 @@
<file>images/go-first-symbolic-rtl.symbolic.png</file>
<file>images/zoom-in-symbolic.symbolic.png</file>
<file>images/zoom-out-symbolic.symbolic.png</file>
<file>images/filter_lowpass_small.png</file>
<file>images/black_icon_16x16.png</file>
<file>images/darkcyan_icon_16x16.png</file>
<file>images/darkred_icon_16x16.png</file>
<file>images/lightgray_icon_16x16.png</file>
<file>images/yellow_icon_16x16.png</file>
<file>images/blue_icon_16x16.png</file>
<file>images/darkgray_icon_16x16.png</file>
<file>images/darkyellow_icon_16x16.png</file>
<file>images/magenta_icon_16x16.png</file>
<file>images/cyan_icon_16x16.png</file>
<file>images/darkgreen_icon_16x16.png</file>
<file>images/gray_icon_16x16.png</file>
<file>images/red_icon_16x16.png</file>
<file>images/darkblue_icon_16x16.png</file>
<file>images/darkmagenta_icon_16x16.png</file>
<file>images/green_icon_16x16.png</file>
<file>images/white_icon_16x16.png</file>
<file>images/media-seek-forward.png</file>
<file>images/media-seek-backward.png</file>
</qresource>
</RCC>