Skip to content
Commits on Source (5)
......@@ -91,7 +91,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.12.3-static #
# in a new and separate directory: /usr/local/Qt-5.12.6-static #
# #
# It will not interfere with other Qt programs. #
# #
......@@ -101,28 +101,28 @@ mkdir Qt5-source
cd Qt5-source
wget http://ftp1.nluug.nl/languages/qt/official_releases/qt/5.12/5.12.3/single/qt-everywhere-src-5.12.3.tar.xz
wget http://ftp1.nluug.nl/languages/qt/official_releases/qt/5.12/5.12.6/single/qt-everywhere-src-5.12.6.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-src-5.12.3.tar.xz
The Qt source package you are going to need is: qt-everywhere-src-5.12.6.tar.xz
tar -xvf qt-everywhere-src-5.12.3.tar.xz
tar -xvf qt-everywhere-src-5.12.6.tar.xz
cd qt-everywhere-src-5.12.3
cd qt-everywhere-src-5.12.6
./configure -v -prefix /usr/local/Qt-5.12.3-static -release -opensource -confirm-license -c++std c++11 -static -accessibility -fontconfig -skip qtdeclarative -skip qtconnectivity -skip qtmultimedia -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 -skip qt3d -skip qtpurchasing -skip qtquickcontrols -skip qtquickcontrols2 -skip qtspeech -skip qtwebengine
./configure -v -prefix /usr/local/Qt-5.12.6-static -release -opensource -confirm-license -c++std c++11 -static -accessibility -fontconfig -skip qtdeclarative -skip qtconnectivity -skip qtmultimedia -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 -skip qt3d -skip qtpurchasing -skip qtquickcontrols -skip qtquickcontrols2 -skip qtspeech -skip qtwebengine
(takes about 2 minutes)
make -j6 (change option -j according to number of available cpu cores e.g -j4 or -j8)
(takes about 11 minutes)
(takes about 12 minutes)
sudo make install
Now go to the directory that contains the EDFbrowser sourcecode and enter the following commands:
/usr/local/Qt-5.12.3-static/bin/qmake
/usr/local/Qt-5.12.6-static/bin/qmake
make -j6 (change option -j according to number of available cpu cores e.g -j4 or -j8)
......
edfbrowser (1.71+dfsg-1) unstable; urgency=medium
* New upstream version
* Standards-Version: 4.4.1
-- Andreas Tille <tille@debian.org> Sun, 05 Jan 2020 12:38:57 +0100
edfbrowser (1.70+dfsg-1) unstable; urgency=medium
* New upstream version
......
......@@ -10,7 +10,7 @@ Build-Depends: debhelper-compat (= 12),
libqt5opengl5-dev,
qttools5-dev-tools,
libedf-dev
Standards-Version: 4.4.0
Standards-Version: 4.4.1
Vcs-Browser: https://salsa.debian.org/med-team/edfbrowser
Vcs-Git: https://salsa.debian.org/med-team/edfbrowser.git
Homepage: https://www.teuniz.net/edfbrowser/
......
......@@ -7,7 +7,7 @@
<meta name="description" content="EDFbrowser manual">
</head><body>
<h1>EDFbrowser 1.70 manual</h1>
<h1>EDFbrowser 1.71 manual</h1>
<p><br></p>
......
......@@ -134,6 +134,7 @@ HEADERS += fft_wrap.h
HEADERS += ecg_statistics.h
HEADERS += fir_filter.h
HEADERS += fir_filter_dialog.h
HEADERS += ishne2edf.h
HEADERS += third_party/fidlib/fidlib.h
HEADERS += third_party/fidlib/fidmkf.h
......@@ -240,6 +241,7 @@ SOURCES += fft_wrap.c
SOURCES += ecg_statistics.c
SOURCES += fir_filter.c
SOURCES += fir_filter_dialog.cpp
SOURCES += ishne2edf.cpp
SOURCES += third_party/fidlib/fidlib.c
......
......@@ -41,7 +41,7 @@ struct fft_wrap_settings_struct * fft_wrap_create(double *buf, int buf_size, int
if(buf_size < 4) return NULL;
if(dft_size < 4) return NULL;
if(dft_size & 1) dft_size--;
if((window_type < 0) || (window_type > 7)) return NULL;
if((window_type < 0) || (window_type > 8)) return NULL;
if((overlap < 1) || (overlap > 5)) return NULL;
st = (struct fft_wrap_settings_struct *)calloc(1, sizeof(struct fft_wrap_settings_struct));
......@@ -291,6 +291,14 @@ static void window_func(const double *src, double *dest, double *coef, int sz, i
- (0.324954578e-2 * cos((14.0 * M_PI * i) / (sz - 1))) + (0.13801040e-3 * cos((16.0 * M_PI * i) / (sz - 1))) - (0.132725e-5 * cos((18.0 * M_PI * i) / (sz - 1))); /* 9-term HFT223D */
}
}
else if(type == FFT_WNDW_TYPE_HFT95)
{ /* Spectrum and spectral density estimation by the Discrete Fourier transform (DFT), including a comprehensive list of window functions and some new at-top windows Max Planck Institute */
for(i=0; i<sz2; i++)
{
coef[i] = 1.0 - (1.9383379 * cos((2.0 * M_PI * i) / (sz - 1))) + (1.3045202 * cos((4.0 * M_PI * i) / (sz - 1)))
- (0.4028270 * cos((6.0 * M_PI * i) / (sz - 1))) + (0.0350665 * cos((8.0 * M_PI * i) / (sz - 1)));
}
}
else
{
for(i=0; i<sz2; i++)
......
......@@ -47,6 +47,7 @@
#define FFT_WNDW_TYPE_NUTTALL4C 5
#define FFT_WNDW_TYPE_HANN 6
#define FFT_WNDW_TYPE_HFT223D 7
#define FFT_WNDW_TYPE_HFT95 8
#ifdef __cplusplus
......
......@@ -58,7 +58,7 @@
#endif
#define PROGRAM_NAME "EDFbrowser"
#define PROGRAM_VERSION "1.70"
#define PROGRAM_VERSION "1.71"
#define PROGRAM_BETA_SUFFIX ""
#define MINIMUM_QT4_VERSION 0x040701
#define MINIMUM_QT5_VERSION 0x050901
......
......@@ -1244,7 +1244,14 @@ int UI_ImportAnnotationswindow::import_from_ascii(void)
startline = DatastartSpinbox->value();
if(manualdescription)
{
descr_column = -1;
}
else
{
descr_column = DescriptionColumnSpinBox->value() - 1;
}
onset_column = OnsetColumnSpinBox->value() - 1;
......@@ -1422,7 +1429,7 @@ int UI_ImportAnnotationswindow::import_from_ascii(void)
#ifdef IMPORT_ANNOTS_DEBUG
printf(" line %i\n", line_nr);
#endif
if(onset_is_set && descr_is_set)
if(onset_is_set && (descr_is_set || manualdescription))
{
if((!ignore_consecutive) || strcmp(description, last_description))
{
......
/*
***************************************************************************
*
* Author: Teunis van Beelen
*
* Copyright (C) 2019 Teunis van Beelen
*
* Email: teuniz@protonmail.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 "ishne2edf.h"
#define ISHNE_MAX_CHNS (12)
UI_IshneEDFwindow::UI_IshneEDFwindow(QWidget *w_parent, char *recent_dir, char *save_dir)
{
mainwindow = (UI_Mainwindow *)w_parent;
recent_opendir = recent_dir;
recent_savedir = save_dir;
myobjectDialog = new QDialog;
myobjectDialog->setMinimumSize(600, 480);
myobjectDialog->setMaximumSize(600, 480);
myobjectDialog->setWindowTitle("ISHNE ECG to EDF converter");
myobjectDialog->setModal(true);
myobjectDialog->setAttribute(Qt::WA_DeleteOnClose, true);
textEdit1 = new QTextEdit(myobjectDialog);
textEdit1->setGeometry(20, 20, 560, 380);
textEdit1->setFrameStyle(QFrame::Panel | QFrame::Sunken);
textEdit1->setReadOnly(true);
textEdit1->setLineWrapMode(QTextEdit::NoWrap);
textEdit1->append("ISHNE ECG to EDF converter\n");
pushButton1 = new QPushButton(myobjectDialog);
pushButton1->setGeometry(20, 430, 100, 25);
pushButton1->setText("Select File");
pushButton2 = new QPushButton(myobjectDialog);
pushButton2->setGeometry(480, 430, 100, 25);
pushButton2->setText("Close");
crc_ccitt_init();
QObject::connect(pushButton1, SIGNAL(clicked()), this, SLOT(SelectFileButton()));
QObject::connect(pushButton2, SIGNAL(clicked()), myobjectDialog, SLOT(close()));
myobjectDialog->exec();
}
void UI_IshneEDFwindow::SelectFileButton()
{
int i, j,
var_block_sz,
ecg_smpl_sz,
var_block_offset,
ecg_block_offset,
chns,
sf,
lead_spec[ISHNE_MAX_CHNS],
amp_resolution[ISHNE_MAX_CHNS],
sex,
edf_hdl=-99,
birthdate_valid=0,
total_blocks=0,
blocks_written=0;
unsigned long long int file_sz=0;
short *inbuf=NULL,
*outbuf=NULL;
char path[MAX_PATH_LENGTH]={""},
hdr[4096]={""},
scratchpad[4096]={""},
tmp_str[128]={""};
const char *lead_label[20]={"Unknown","Generic bipolar","X bipolar","Y bipolar","Z bipolar","I","II","III","aVR","aVL",
"aVF","V1","V2","V3","V4","V5","V6","ES","AS","AI"};
FILE *inputfile=NULL;
QProgressDialog progress("Converting ECG data ...", "Abort", 0, 0, myobjectDialog);
progress.reset();
struct
{
int day;
int month;
int year;
int hour;
int minute;
int second;
} start_dt;
struct
{
int day;
int month;
int year;
} birth_d;
///////////////////////////////////////// OPEN THE ECG FILE ///////////////////////
strlcpy(path, QFileDialog::getOpenFileName(0, "Select inputfile", QString::fromLocal8Bit(recent_opendir), "ECG files (*.ecg *.ECG)").toLocal8Bit().data(), MAX_PATH_LENGTH);
if(!strcmp(path, ""))
{
return;
}
get_directory_from_path(recent_opendir, path, MAX_PATH_LENGTH);
inputfile = fopen(path, "rb");
if(inputfile == NULL)
{
snprintf(scratchpad, 4096, "Error, can not open file:\n%s\n", path);
textEdit1->append(QString::fromLocal8Bit(scratchpad));
return;
}
snprintf(scratchpad, 4096, "Processing file:\n%s", path);
textEdit1->append(QString::fromLocal8Bit(scratchpad));
fseek(inputfile, 0, SEEK_END);
file_sz = ftell(inputfile);
if(file_sz < 522)
{
textEdit1->append("Error, file is too small.");
goto OUT_EXIT;
}
rewind(inputfile);
if(fread(hdr, 522, 1, inputfile) != 1)
{
textEdit1->append("A read error occurred when trying to read the header.");
goto OUT_EXIT;
}
if(strncmp(hdr, "ISHNE1.0", 8))
{
textEdit1->append("Error, wrong magic string in header.");
goto OUT_EXIT;
}
////////////////////////////////// GET THE HEADER DATA ////////////////////////
var_block_sz = *((int *)(hdr + 10));
if(var_block_sz < 0)
{
textEdit1->append("Error, parameter size of variable length block in header is lower than zero.");
goto OUT_EXIT;
}
ecg_smpl_sz = *((int *)(hdr + 14));
if(ecg_smpl_sz < 0)
{
textEdit1->append("Error, parameter ECG sample size in header is lower than zero.");
goto OUT_EXIT;
}
var_block_offset = *((int *)(hdr + 18));
if(var_block_offset != 522)
{
textEdit1->append("Error, parameter offset of variable length block in header differs from 522");
goto OUT_EXIT;
}
ecg_block_offset = *((int *)(hdr + 22));
if(ecg_block_offset != (var_block_sz + 522))
{
textEdit1->append("Error, parameter offset of ECG block in header differs from 522 + variable length block");
goto OUT_EXIT;
}
if((unsigned long)ecg_block_offset > file_sz)
{
textEdit1->append("Error, start of ECG block is after end of file.");
goto OUT_EXIT;
}
chns = *((short *)(hdr + 156));
if(chns < 1)
{
textEdit1->append("Error, number of leads is less than 1.");
goto OUT_EXIT;
}
if(chns > ISHNE_MAX_CHNS)
{
textEdit1->append("Error, number of leads is more than 12.");
goto OUT_EXIT;
}
sf = *((short *)(hdr + 272));
if(sf < 1)
{
textEdit1->append("Error, sampling rate is less than 1Hz.");
goto OUT_EXIT;
}
sex = *((short *)(hdr + 128));
if((sex < 0) || (sex > 2))
{
textEdit1->append("Error, subject sex is out of range.");
goto OUT_EXIT;
}
total_blocks = ecg_smpl_sz / sf;
if(total_blocks < 1)
{
textEdit1->append("Error, not enough samples in file (recording duration is less than one second).");
goto OUT_EXIT;
}
if(file_sz < (unsigned int)(ecg_block_offset + (ecg_smpl_sz * chns * 2)))
{
textEdit1->append("Error, file size is less than file size based on header parameters.");
goto OUT_EXIT;
}
if(check_crc(inputfile, var_block_offset + var_block_sz))
{
textEdit1->append("CRC error, file header is corrupt.");
goto OUT_EXIT;
}
////////////////////////////// GET THE LEAD DATA ////////////////////////////////////
for(i=0; i<chns; i++)
{
lead_spec[i] = *((short *)(hdr + 158 + (i * 2)));
if((lead_spec[i] < 0) || (lead_spec[i] > 19))
{
snprintf(scratchpad, 4096, "Error, lead specification of lead %i is out of range.", i + 1);
textEdit1->append(scratchpad);
goto OUT_EXIT;
}
amp_resolution[i] = *((short *)(hdr + 206 + (i * 2)));
if(amp_resolution[i] < 1)
{
snprintf(scratchpad, 4096, "Error, amplitude resolution of lead %i is less than 1nV.", i + 1);
textEdit1->append(scratchpad);
goto OUT_EXIT;
}
}
/////////////////////////////////////// GET THE START DATE AND TIME /////////////////////
start_dt.day = *((short *)(hdr + 138));
if((start_dt.day < 1) || (start_dt.day > 31))
{
textEdit1->append("Error, illegal start date.");
goto OUT_EXIT;
}
start_dt.month = *((short *)(hdr + 140));
if((start_dt.month < 1) || (start_dt.month > 12))
{
textEdit1->append("Error, illegal start date.");
goto OUT_EXIT;
}
start_dt.year = *((short *)(hdr + 142));
if((start_dt.year < 1000) || (start_dt.year > 3000))
{
textEdit1->append("Error, illegal start date.");
goto OUT_EXIT;
}
start_dt.hour = *((short *)(hdr + 150));
if((start_dt.hour < 0) || (start_dt.hour > 23))
{
textEdit1->append("Error, illegal start time.");
goto OUT_EXIT;
}
start_dt.minute = *((short *)(hdr + 152));
if((start_dt.minute < 0) || (start_dt.minute > 59))
{
textEdit1->append("Error, illegal start time.");
goto OUT_EXIT;
}
start_dt.second = *((short *)(hdr + 154));
if((start_dt.second < 0) || (start_dt.second > 59))
{
textEdit1->append("Error, illegal start time.");
goto OUT_EXIT;
}
birthdate_valid = 1;
birth_d.year = *((short *)(hdr + 136));
if((birth_d.year < 1000) || (birth_d.year > 3000))
{
birthdate_valid = 0;
}
birth_d.month = *((short *)(hdr + 134));
if((birth_d.month < 1) || (birth_d.month > 12))
{
birthdate_valid = 0;
}
birth_d.day = *((short *)(hdr + 132));
if((birth_d.day < 1) || (birth_d.day > 31))
{
birthdate_valid = 0;
}
// if(!birthdate_valid)
// {
// snprintf(scratchpad, 4096, "Skipping illegal date of birth: %04i-%02i-%02i", birth_d.year, birth_d.month, birth_d.day);
// textEdit1->append(scratchpad);
// }
/////////////////////////////////////// STORE TO EDF ///////////////////////////////
remove_extension_from_filename(path);
strlcat(path, ".edf", MAX_PATH_LENGTH);
strlcpy(path, QFileDialog::getSaveFileName(0, "Select outputfile", QString::fromLocal8Bit(path), "EDF files (*.edf *.EDF)").toLocal8Bit().data(), MAX_PATH_LENGTH);
if(!strcmp(path, ""))
{
goto OUT_EXIT;
}
get_directory_from_path(recent_savedir, path, MAX_PATH_LENGTH);
edf_hdl = edfopen_file_writeonly(path, EDFLIB_FILETYPE_EDFPLUS, chns);
if(edf_hdl < 0)
{
textEdit1->append("Error, can not open EDF file for writing\n");
goto OUT_EXIT;
}
for(i=0; i<chns; i++)
{
if(edf_set_samplefrequency(edf_hdl, i, sf))
{
textEdit1->append("Error, edf_set_samplefrequency()\n");
goto OUT_EXIT;
}
if(edf_set_digital_maximum(edf_hdl, i, 32767))
{
textEdit1->append("Error, edf_set_digital_maximum()\n");
goto OUT_EXIT;
}
if(edf_set_digital_minimum(edf_hdl, i, -32768))
{
textEdit1->append("Error, edf_set_digital_minimum()\n");
goto OUT_EXIT;
}
if(edf_set_physical_dimension(edf_hdl, i, "uV"))
{
textEdit1->append("Error, edf_set_physical_dimension()\n");
goto OUT_EXIT;
}
if(edf_set_physical_maximum(edf_hdl, i, 32.767 * amp_resolution[i]))
{
textEdit1->append("Error, edf_set_physical_maximum()\n");
goto OUT_EXIT;
}
if(edf_set_physical_minimum(edf_hdl, i, -32.768 * amp_resolution[i]))
{
textEdit1->append("Error, edf_set_physical_minimum()\n");
goto OUT_EXIT;
}
if(edf_set_label(edf_hdl, i, lead_label[lead_spec[i]]))
{
textEdit1->append("Error, edf_set_label()\n");
goto OUT_EXIT;
}
}
if(edf_set_startdatetime(edf_hdl, start_dt.year, start_dt.month, start_dt.day, start_dt.hour, start_dt.minute, start_dt.second))
{
textEdit1->append("Error, edf_set_startdatetime()\n");
goto OUT_EXIT;
}
strncpy(tmp_str, hdr + 28, 40);
tmp_str[40] = 0;
remove_leading_spaces(tmp_str);
remove_trailing_spaces(tmp_str);
strlcat(tmp_str, " ", 128);
strncpy(scratchpad, hdr + 68, 40);
scratchpad[40] = 0;
remove_leading_spaces(scratchpad);
remove_trailing_spaces(scratchpad);
strlcat(tmp_str, scratchpad, 128);
remove_trailing_spaces(tmp_str);
if(strlen(tmp_str))
{
if(edf_set_patientname(edf_hdl, tmp_str))
{
textEdit1->append("Error, edf_set_patientname()\n");
goto OUT_EXIT;
}
}
strncpy(tmp_str, hdr + 108, 20);
tmp_str[20] = 0;
remove_leading_spaces(tmp_str);
remove_trailing_spaces(tmp_str);
if(strlen(tmp_str))
{
if(edf_set_patientcode(edf_hdl, tmp_str))
{
textEdit1->append("Error, edf_set_patientcode()\n");
goto OUT_EXIT;
}
}
if(sex == 1)
{
if(edf_set_gender(edf_hdl, 1))
{
textEdit1->append("Error, edf_set_gender()\n");
goto OUT_EXIT;
}
}
else if(sex == 2)
{
if(edf_set_gender(edf_hdl, 0))
{
textEdit1->append("Error, edf_set_gender()\n");
goto OUT_EXIT;
}
}
if(birthdate_valid)
{
if(edf_set_birthdate(edf_hdl, birth_d.year, birth_d.month, birth_d.day))
{
textEdit1->append("Error, edf_set_birthdate()\n");
goto OUT_EXIT;
}
}
strncpy(tmp_str, hdr + 232, 40);
tmp_str[40] = 0;
remove_leading_spaces(tmp_str);
remove_trailing_spaces(tmp_str);
if(strlen(tmp_str))
{
if(edf_set_equipment(edf_hdl, tmp_str))
{
textEdit1->append("Error, edf_set_equipment()\n");
goto OUT_EXIT;
}
}
/////////////////// Start conversion //////////////////////////////////////////
// printf("sf: %i chns: %i var_block_offset: %i var_block_sz: %i ecg_block_offset: %i ecg_smpl_sz: %i total_blocks: %i\n",
// sf, chns, var_block_offset, var_block_sz, ecg_block_offset, ecg_smpl_sz, total_blocks);
inbuf = (short *)malloc(sf * chns * sizeof(short));
if(inbuf == NULL)
{
textEdit1->append("Malloc() error\n");
goto OUT_EXIT;
}
outbuf = (short *)malloc(sf * chns * sizeof(short));
if(outbuf == NULL)
{
textEdit1->append("Malloc() error\n");
goto OUT_EXIT;
}
fseek(inputfile, ecg_block_offset, SEEK_SET);
progress.setMaximum(total_blocks);
progress.setWindowModality(Qt::WindowModal);
progress.setMinimumDuration(200);
for(blocks_written=0; blocks_written<total_blocks; blocks_written++)
{
if(!(blocks_written % 10))
{
progress.setValue(blocks_written);
qApp->processEvents();
if(progress.wasCanceled() == true)
{
textEdit1->append("Conversion aborted by user.\n");
break;
}
}
if(fread(inbuf, sf * chns * 2, 1, inputfile) != 1)
{
textEdit1->append("Error, could not read from input file.");
goto OUT_EXIT;
}
for(i=0; i<chns; i++)
{
for(j=0; j<sf; j++)
{
*(outbuf + (i * sf) + j) = *(inbuf + (j * chns) + i);
}
}
if(edf_blockwrite_digital_short_samples(edf_hdl, outbuf))
{
textEdit1->append("Error, edf_blockwrite_digital_short_samples()\n");
goto OUT_EXIT;
}
}
textEdit1->append("Done\n");
OUT_EXIT:
progress.reset();
if(edf_hdl >= 0) edfclose_file(edf_hdl);
if(inputfile != NULL) fclose(inputfile);
free(inbuf);
free(outbuf);
}
int UI_IshneEDFwindow::check_crc(FILE *inputfile, int len)
{
unsigned short crc=0xFFFF, crc2=0x0000;
unsigned char *buf=NULL;
buf = (unsigned char *)malloc(len);
if(buf == NULL)
{
return -99;
}
rewind(inputfile);
if(fread(buf, len, 1, inputfile) != 1)
{
free(buf);
return -88;
}
crc2 = *((unsigned short *)(buf + 8));
crc = crc_ccitt(buf + 10, len - 10, crc);
// printf("crc: %04X crc2: %04X\n", crc, crc2);
if(crc != crc2)
{
free(buf);
return -1;
}
free(buf);
return 0;
}
unsigned short UI_IshneEDFwindow::crc_ccitt(const unsigned char *message, int nbytes, unsigned short remainder)
{
int byte;
unsigned char data;
for(byte=0; byte<nbytes; byte++) /* Divide the message by the polynomial, a byte at a time. */
{
data = message[byte] ^ (remainder >> 8);
remainder = crc_ccitt_table[data] ^ (remainder << 8);
}
return remainder; /* The final remainder is the CRC. */
}
void UI_IshneEDFwindow::crc_ccitt_init(void)
{
int dividend;
unsigned short remainder;
unsigned char bit;
for(dividend=0; dividend<256; dividend++) /* Compute the remainder of each possible dividend. */
{
remainder = dividend << 8; /* Start with the dividend followed by zeros. */
for(bit=8; bit>0; bit--) /* Perform modulo-2 division, a bit at a time. */
{
if(remainder & 32768) /* Try to divide the current data bit. */
{
remainder = (remainder << 1) ^ 0x1021; /* polynomial */
}
else
{
remainder = (remainder << 1);
}
}
crc_ccitt_table[dividend] = remainder; /* Store the result into the table. */
}
}
/*
***************************************************************************
*
* Author: Teunis van Beelen
*
* Copyright (C) 2019 Teunis van Beelen
*
* Email: teuniz@protonmail.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 UI_ISHNE2EDFFORM_H
#define UI_ISHNE2EDFFORM_H
#include <QtGlobal>
#include <QApplication>
#include <QDialog>
#include <QLabel>
#include <QLineEdit>
#include <QDateTimeEdit>
#include <QPushButton>
#include <QObject>
#include <QFileDialog>
#include <QCheckBox>
#include <QCursor>
#include <QDoubleSpinBox>
#include <QProgressDialog>
#include <QMessageBox>
#include <QString>
#include <QPixmap>
#include <QDesktopServices>
#include <QUrl>
#include <QTextEdit>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "global.h"
#include "mainwindow.h"
#include "utils.h"
#include "edflib.h"
class UI_Mainwindow;
class UI_IshneEDFwindow : public QObject
{
Q_OBJECT
public:
UI_IshneEDFwindow(QWidget *, char *recent_dir=NULL, char *save_dir=NULL);
UI_Mainwindow *mainwindow;
private:
QDialog *myobjectDialog;
QTextEdit *textEdit1;
QPushButton *pushButton1,
*pushButton2;
char *recent_opendir,
*recent_savedir;
unsigned short crc_ccitt_table[256];
void crc_ccitt_init(void);
unsigned short crc_ccitt(const unsigned char *, int, unsigned short);
int check_crc(FILE *, int);
private slots:
void SelectFileButton();
};
#endif
......@@ -625,6 +625,12 @@ void UI_Mainwindow::convert_mortara_to_edf()
}
void UI_Mainwindow::convert_ishne_to_edf()
{
UI_IshneEDFwindow ishne2edf(this, recent_opendir, recent_savedir);
}
void UI_Mainwindow::convert_nexfin_to_edf()
{
UI_NEXFIN2EDFwindow nexfin2edf(recent_opendir, recent_savedir);
......
......@@ -172,6 +172,7 @@
#include "plif_ecg_subtract_filter_dialog.h"
#include "export_filtered_signals.h"
#include "fir_filter_dialog.h"
#include "ishne2edf.h"
#include "third_party/fidlib/fidlib.h"
......@@ -230,8 +231,17 @@ public:
spectrum_bw,
spectrum_sqrt,
spectrum_vlog,
spectrum_window,
spectrum_blocksize_predefined,
spectrum_blocksize_userdefined,
spectrum_overlap,
spectrumdock_bw,
spectrumdock_sqrt,
spectrumdock_vlog,
spectrumdock_window,
spectrumdock_blocksize_predefined,
spectrumdock_blocksize_userdefined,
spectrumdock_overlap,
spectrumdock_colorbars,
use_threads,
check_for_updates,
......@@ -242,7 +252,8 @@ public:
linear_interpol,
auto_update_annot_onset,
average_period,
font_size;
font_size,
use_diverse_signal_colors;
unsigned long long pagetime,
maxfilesize_to_readin_annotations;
......@@ -567,6 +578,7 @@ private slots:
void convert_wave_to_edf();
void convert_fm_audio_to_edf();
void convert_mortara_to_edf();
void convert_ishne_to_edf();
void convert_nexfin_to_edf();
void edfd_converter();
void slider_moved(int);
......
......@@ -144,6 +144,8 @@ UI_Mainwindow::UI_Mainwindow()
auto_update_annot_onset = 0;
use_diverse_signal_colors = 0;
toolbar_stats.sz = 0;
toolbar_stats.active = 0;
toolbar_stats.annot_label[0] = 0;
......@@ -228,12 +230,32 @@ UI_Mainwindow::UI_Mainwindow()
spectrum_vlog = 0;
spectrum_window = 0;
spectrum_blocksize_predefined = 0;
spectrum_blocksize_userdefined = 200;
spectrum_overlap = 0;
spectrumdock_bw = 0;
spectrumdock_sqrt = 0;
spectrumdock_vlog = 0;
spectrum_window = 0;
spectrumdock_blocksize_predefined = 0;
spectrumdock_blocksize_userdefined = 200;
spectrumdock_overlap = 0;
spectrumdock_colorbars = 0;
spectrumdock_window = 0;
z_score_var.crossoverfreq = 7.5;
z_score_var.z_threshold = 0.0;
z_score_var.zscore_page_len = 30;
......@@ -754,6 +776,7 @@ UI_Mainwindow::UI_Mainwindow()
toolsmenu->addAction("Convert Biox CB-1305-C to EDF", this, SLOT(convert_biox_to_edf()));
toolsmenu->addAction("Convert FM Audio ECG to EDF", this, SLOT(convert_fm_audio_to_edf()));
toolsmenu->addAction("Convert Mortara ECG XML to EDF", this, SLOT(convert_mortara_to_edf()));
toolsmenu->addAction("Convert ISHNE ECG to EDF", this, SLOT(convert_ishne_to_edf()));
toolsmenu->addAction("Convert Binary/raw data to EDF", this, SLOT(convert_binary_to_edf()));
toolsmenu->addSeparator();
toolsmenu->addAction("Options", this, SLOT(show_options_dialog()));
......
......@@ -41,7 +41,7 @@ UI_OptionsDialog::UI_OptionsDialog(QWidget *w_parent)
optionsdialog = new QDialog(w_parent);
if(QApplication::desktop()->screenGeometry().height() < 900)
if(QApplication::desktop()->screenGeometry().height() < 940)
{
showminimized = 1;
}
......@@ -60,8 +60,8 @@ UI_OptionsDialog::UI_OptionsDialog(QWidget *w_parent)
}
else
{
optionsdialog->setMinimumSize(440, 820);
optionsdialog->setMaximumSize(440, 820);
optionsdialog->setMinimumSize(440, 860);
optionsdialog->setMaximumSize(440, 860);
}
optionsdialog->setWindowTitle("Settings");
optionsdialog->setModal(true);
......@@ -124,12 +124,30 @@ UI_OptionsDialog::UI_OptionsDialog(QWidget *w_parent)
SigColorButton->setGeometry(240, 170, 60, 15);
SigColorButton->setColor((Qt::GlobalColor)mainwindow->maincurve->signal_color);
label16 = new QLabel(tab1);
label16->setGeometry(20, 195, 200, 25);
label16->setText("Vary signal colors");
label16->setToolTip("When adding signals to the screen, vary the traces' color");
checkbox16 = new QCheckBox(tab1);
checkbox16->setGeometry(200, 198, 20, 20);
checkbox16->setTristate(false);
checkbox16->setToolTip("When adding signals to the screen, vary the traces' color");
if(mainwindow->use_diverse_signal_colors)
{
checkbox16->setCheckState(Qt::Checked);
}
else
{
checkbox16->setCheckState(Qt::Unchecked);
}
label7 = new QLabel(tab1);
label7->setGeometry(20, 195, 200, 25);
label7->setGeometry(20, 225, 200, 25);
label7->setText("Baseline color");
checkbox3 = new QCheckBox(tab1);
checkbox3->setGeometry(200, 198, 20, 20);
checkbox3->setGeometry(200, 228, 20, 20);
checkbox3->setTristate(false);
if(mainwindow->show_baselines)
{
......@@ -141,39 +159,39 @@ UI_OptionsDialog::UI_OptionsDialog(QWidget *w_parent)
}
BaseColorButton = new SpecialButton(tab1);
BaseColorButton->setGeometry(240, 200, 60, 15);
BaseColorButton->setGeometry(240, 230, 60, 15);
BaseColorButton->setColor(mainwindow->maincurve->baseline_color);
label8 = new QLabel(tab1);
label8->setGeometry(20, 225, 200, 25);
label8->setGeometry(20, 255, 200, 25);
label8->setText("Crosshair color");
Crh1ColorButton = new SpecialButton(tab1);
Crh1ColorButton->setGeometry(240, 230, 60, 15);
Crh1ColorButton->setGeometry(240, 260, 60, 15);
Crh1ColorButton->setColor((Qt::GlobalColor)mainwindow->maincurve->crosshair_1.color);
label9 = new QLabel(tab1);
label9->setGeometry(20, 255, 200, 25);
label9->setGeometry(20, 285, 200, 25);
label9->setText("2th Crosshair color");
Crh2ColorButton = new SpecialButton(tab1);
Crh2ColorButton->setGeometry(240, 260, 60, 15);
Crh2ColorButton->setGeometry(240, 290, 60, 15);
Crh2ColorButton->setColor((Qt::GlobalColor)mainwindow->maincurve->crosshair_2.color);
label10 = new QLabel(tab1);
label10->setGeometry(20, 285, 200, 25);
label10->setGeometry(20, 315, 200, 25);
label10->setText("Floating ruler color");
FrColorButton = new SpecialButton(tab1);
FrColorButton->setGeometry(240, 290, 60, 15);
FrColorButton->setGeometry(240, 320, 60, 15);
FrColorButton->setColor((Qt::GlobalColor)mainwindow->maincurve->floating_ruler_color);
label12 = new QLabel(tab1);
label12->setGeometry(20, 315, 200, 25);
label12->setGeometry(20, 345, 200, 25);
label12->setText("Annotation marker");
checkbox2 = new QCheckBox(tab1);
checkbox2->setGeometry(200, 318, 20, 20);
checkbox2->setGeometry(200, 348, 20, 20);
checkbox2->setTristate(false);
if(mainwindow->show_annot_markers)
{
......@@ -185,15 +203,15 @@ UI_OptionsDialog::UI_OptionsDialog(QWidget *w_parent)
}
AnnotMkrButton = new SpecialButton(tab1);
AnnotMkrButton->setGeometry(240, 320, 60, 15);
AnnotMkrButton->setGeometry(240, 350, 60, 15);
AnnotMkrButton->setColor(mainwindow->maincurve->annot_marker_color);
label12_2 = new QLabel(tab1);
label12_2->setGeometry(20, 345, 200, 25);
label12_2->setGeometry(20, 375, 200, 25);
label12_2->setText("Show duration at marker");
checkbox2_1 = new QCheckBox(tab1);
checkbox2_1->setGeometry(200, 348, 20, 20);
checkbox2_1->setGeometry(200, 378, 20, 20);
checkbox2_1->setTristate(false);
if(mainwindow->annotations_show_duration)
{
......@@ -205,19 +223,19 @@ UI_OptionsDialog::UI_OptionsDialog(QWidget *w_parent)
}
label12_1 = new QLabel(tab1);
label12_1->setGeometry(20, 375, 200, 25);
label12_1->setGeometry(20, 405, 200, 25);
label12_1->setText("Annotation duration background");
AnnotDurationButton = new SpecialButton(tab1);
AnnotDurationButton->setGeometry(240, 380, 60, 15);
AnnotDurationButton->setGeometry(240, 410, 60, 15);
AnnotDurationButton->setColor(mainwindow->maincurve->annot_duration_color);
label12_3 = new QLabel(tab1);
label12_3->setGeometry(20, 405, 200, 25);
label12_3->setGeometry(20, 435, 200, 25);
label12_3->setText("Show only at screen bottom");
checkbox2_2 = new QCheckBox(tab1);
checkbox2_2->setGeometry(200, 408, 20, 20);
checkbox2_2->setGeometry(200, 438, 20, 20);
checkbox2_2->setTristate(false);
if(mainwindow->annotations_duration_background_type)
{
......@@ -229,11 +247,11 @@ UI_OptionsDialog::UI_OptionsDialog(QWidget *w_parent)
}
label14 = new QLabel(tab1);
label14->setGeometry(20, 435, 200, 25);
label14->setGeometry(20, 465, 200, 25);
label14->setText("Annotations: filter list only");
checkbox5 = new QCheckBox(tab1);
checkbox5->setGeometry(200, 438, 20, 20);
checkbox5->setGeometry(200, 468, 20, 20);
checkbox5->setTristate(false);
checkbox5->setToolTip("Annotation filter affects the annotationlist only, not the annotation markers in the signal window");
if(mainwindow->annot_filter->hide_in_list_only)
......@@ -246,11 +264,11 @@ UI_OptionsDialog::UI_OptionsDialog(QWidget *w_parent)
}
label11 = new QLabel(tab1);
label11->setGeometry(20, 465, 200, 25);
label11->setGeometry(20, 495, 200, 25);
label11->setText("Print in grayscale");
checkbox1 = new QCheckBox(tab1);
checkbox1->setGeometry(200, 468, 20, 20);
checkbox1->setGeometry(200, 498, 20, 20);
checkbox1->setTristate(false);
if(mainwindow->maincurve->blackwhite_printing)
{
......@@ -262,11 +280,11 @@ UI_OptionsDialog::UI_OptionsDialog(QWidget *w_parent)
}
label13 = new QLabel(tab1);
label13->setGeometry(20, 495, 200, 25);
label13->setGeometry(20, 525, 200, 25);
label13->setText("Clip signals to pane");
checkbox4 = new QCheckBox(tab1);
checkbox4->setGeometry(200, 498, 20, 20);
checkbox4->setGeometry(200, 528, 20, 20);
checkbox4->setTristate(false);
if(mainwindow->clip_to_pane)
{
......@@ -278,26 +296,26 @@ UI_OptionsDialog::UI_OptionsDialog(QWidget *w_parent)
}
groupbox1 = new QGroupBox("Colorschema", tab1);
groupbox1->setGeometry(120, 540, 180, 195);
groupbox1->setGeometry(120, 570, 180, 195);
colorSchema_Dark_Button = new QPushButton(tab1);
colorSchema_Dark_Button->setGeometry(150, 570, 120, 20);
colorSchema_Dark_Button->setGeometry(150, 600, 120, 20);
colorSchema_Dark_Button->setText("\"Dark\"");
colorSchema_NK_Button = new QPushButton(tab1);
colorSchema_NK_Button->setGeometry(150, 600, 120, 20);
colorSchema_NK_Button->setGeometry(150, 630, 120, 20);
colorSchema_NK_Button->setText("\"NK\"");
colorSchema_Blue_on_Gray_Button = new QPushButton(tab1);
colorSchema_Blue_on_Gray_Button->setGeometry(150, 630, 120, 20);
colorSchema_Blue_on_Gray_Button->setGeometry(150, 660, 120, 20);
colorSchema_Blue_on_Gray_Button->setText("\"Blue on gray\"");
saveColorSchemaButton = new QPushButton(tab1);
saveColorSchemaButton->setGeometry(150, 660, 120, 20);
saveColorSchemaButton->setGeometry(150, 690, 120, 20);
saveColorSchemaButton->setText("Save");
loadColorSchemaButton = new QPushButton(tab1);
loadColorSchemaButton->setGeometry(150, 690, 120, 20);
loadColorSchemaButton->setGeometry(150, 720, 120, 20);
loadColorSchemaButton->setText("Load");
QObject::connect(BgColorButton, SIGNAL(clicked(SpecialButton *)), this, SLOT(BgColorButtonClicked(SpecialButton *)));
......@@ -319,6 +337,7 @@ UI_OptionsDialog::UI_OptionsDialog(QWidget *w_parent)
QObject::connect(checkbox3, SIGNAL(stateChanged(int)), this, SLOT(checkbox3Clicked(int)));
QObject::connect(checkbox4, SIGNAL(stateChanged(int)), this, SLOT(checkbox4Clicked(int)));
QObject::connect(checkbox5, SIGNAL(stateChanged(int)), this, SLOT(checkbox5Clicked(int)));
QObject::connect(checkbox16, SIGNAL(stateChanged(int)), this, SLOT(checkbox16Clicked(int)));
QObject::connect(saveColorSchemaButton, SIGNAL(clicked()), this, SLOT(saveColorSchemaButtonClicked()));
QObject::connect(loadColorSchemaButton, SIGNAL(clicked()), this, SLOT(loadColorSchemaButtonClicked()));
QObject::connect(colorSchema_Blue_on_Gray_Button, SIGNAL(clicked()), this, SLOT(loadColorSchema_blue_gray()));
......@@ -1241,6 +1260,20 @@ void UI_OptionsDialog::checkbox5Clicked(int state)
}
void UI_OptionsDialog::checkbox16Clicked(int state)
{
if(state==Qt::Checked)
{
mainwindow->use_diverse_signal_colors = 1;
}
if(state==Qt::Unchecked)
{
mainwindow->use_diverse_signal_colors = 0;
}
}
void UI_OptionsDialog::checkbox3_1Clicked(int state)
{
if(state==Qt::Checked)
......
......@@ -150,6 +150,7 @@ QLabel *label1,
*label12_3,
*label13,
*label14,
*label16,
*label4_1,
*label4_2,
*label4_3,
......@@ -191,6 +192,7 @@ QCheckBox *checkbox1,
*checkbox3_1,
*checkbox4,
*checkbox5,
*checkbox16,
*checkbox4_1,
*checkbox4_2,
*checkbox4_3,
......@@ -234,6 +236,7 @@ void checkbox2_2Clicked(int);
void checkbox3Clicked(int);
void checkbox4Clicked(int);
void checkbox5Clicked(int);
void checkbox16Clicked(int);
void checkbox3_1Clicked(int);
void checkbox4_1Clicked(int);
void checkbox4_2Clicked(int);
......
......@@ -1838,6 +1838,23 @@ void UI_Mainwindow::read_general_settings()
xml_go_up(xml_hdl);
}
if(!(xml_goto_nth_element_inside(xml_hdl, "use_diverse_signal_colors", 0)))
{
if(xml_get_content_of_element(xml_hdl, result, XML_STRBUFLEN))
{
xml_close(xml_hdl);
return;
}
use_diverse_signal_colors = atoi(result);
if(use_diverse_signal_colors != 1)
{
use_diverse_signal_colors = 0;
}
xml_go_up(xml_hdl);
}
xml_close(xml_hdl);
}
......@@ -2225,6 +2242,8 @@ void UI_Mainwindow::write_settings()
fprintf(cfgfile, " <auto_update_annot_onset>%i</auto_update_annot_onset>\n", auto_update_annot_onset);
fprintf(cfgfile, " <use_diverse_signal_colors>%i</use_diverse_signal_colors>\n", use_diverse_signal_colors);
fprintf(cfgfile, " </UI>\n</config>\n");
fclose(cfgfile);
......
......@@ -1031,7 +1031,14 @@ void SignalCurve::drawWidget_to_printer(QPainter *painter, int curve_w, int curv
continue;
}
if((precision == 0) && (max_value > 1000.0))
{
q_str.setNum((double)i / (double)p2_multiplier, 'e', precision);
}
else
{
q_str.setNum((double)i / (double)p2_multiplier, 'f', precision);
}
p2_tmp = (double)(i - p2_ruler_startvalue) * p2_pixels_per_unit;
......@@ -1594,7 +1601,14 @@ void SignalCurve::drawWidget(QPainter *painter, int curve_w, int curve_h)
continue;
}
if((precision == 0) && (max_value > 1000.0))
{
q_str.setNum((double)lk / (double)p2_multiplier, 'e', precision);
}
else
{
q_str.setNum((double)lk / (double)p2_multiplier, 'f', precision);
}
p2_tmp = (double)(lk - p2_ruler_startvalue) * p2_pixels_per_unit;
......
......@@ -37,6 +37,17 @@ UI_Signalswindow::UI_Signalswindow(QWidget *w_parent)
mainwindow = (UI_Mainwindow *)w_parent;
smp_per_record = 0;
last_default_color = 0;
default_color_list[0] = Qt::yellow;
default_color_list[1] = Qt::green;
default_color_list[2] = Qt::red;
default_color_list[3] = Qt::cyan;
default_color_list[4] = Qt::magenta;
default_color_list[5] = Qt::blue;
SignalsDialog = new QDialog;
SignalsDialog->setMinimumSize(800, 500);
......@@ -124,8 +135,6 @@ UI_Signalswindow::UI_Signalswindow(QWidget *w_parent)
compositionlist->setSelectionBehavior(QAbstractItemView::SelectRows);
compositionlist->setSelectionMode(QAbstractItemView::ExtendedSelection);
smp_per_record = 0;
QObject::connect(CloseButton, SIGNAL(clicked()), SignalsDialog, SLOT(close()));
QObject::connect(SelectAllButton, SIGNAL(clicked()), this, SLOT(SelectAllButtonClicked()));
QObject::connect(HelpButton, SIGNAL(clicked()), this, SLOT(HelpButtonClicked()));
......@@ -195,7 +204,15 @@ void UI_Signalswindow::DisplayCompButtonClicked()
newsignalcomp->edfhdr = mainwindow->edfheaderlist[newsignalcomp->filenum];
newsignalcomp->file_duration = newsignalcomp->edfhdr->long_data_record_duration * newsignalcomp->edfhdr->datarecords;
newsignalcomp->voltpercm = mainwindow->default_amplitude;
if(mainwindow->use_diverse_signal_colors)
{
newsignalcomp->color = default_color_list[last_default_color++];
last_default_color %= 6;
}
else
{
newsignalcomp->color = curve_color;
}
newsignalcomp->hasruler = 0;
newsignalcomp->polarity = 1;
......@@ -297,7 +314,15 @@ void UI_Signalswindow::DisplayButtonClicked()
newsignalcomp->edfhdr = mainwindow->edfheaderlist[newsignalcomp->filenum];
newsignalcomp->file_duration = newsignalcomp->edfhdr->long_data_record_duration * newsignalcomp->edfhdr->datarecords;
newsignalcomp->voltpercm = mainwindow->default_amplitude;
if(mainwindow->use_diverse_signal_colors)
{
newsignalcomp->color = default_color_list[last_default_color++];
last_default_color %= 6;
}
else
{
newsignalcomp->color = curve_color;
}
newsignalcomp->hasruler = 0;
newsignalcomp->polarity = 1;
......
......@@ -102,7 +102,9 @@ private:
SpecialButton *ColorButton;
int smp_per_record,
curve_color;
curve_color,
default_color_list[32],
last_default_color;
char physdimension[64];
......