[med-svn] [Git][med-team/edfbrowser][upstream] New upstream version 1.71+dfsg

Andreas Tille gitlab at salsa.debian.org
Sun Jan 5 12:13:00 GMT 2020



Andreas Tille pushed to branch upstream at Debian Med / edfbrowser


Commits:
4ac48100 by Andreas Tille at 2020-01-05T12:38:45+01:00
New upstream version 1.71+dfsg
- - - - -


22 changed files:

- README.txt
- doc/manual.html
- edfbrowser.pro
- fft_wrap.c
- fft_wrap.h
- global.h
- import_annotations.cpp
- + ishne2edf.cpp
- + ishne2edf.h
- mainwindow.cpp
- mainwindow.h
- mainwindow_constr.cpp
- options_dialog.cpp
- options_dialog.h
- read_write_settings.cpp
- signalcurve.cpp
- signals_dialog.cpp
- signals_dialog.h
- spectrum_dock.cpp
- spectrumanalyzer.cpp
- version.txt
- videoplayer.cpp


Changes:

=====================================
README.txt
=====================================
@@ -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)
 


=====================================
doc/manual.html
=====================================
@@ -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>
 


=====================================
edfbrowser.pro
=====================================
@@ -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
 


=====================================
fft_wrap.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,13 +291,21 @@ 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
-                {
-                  for(i=0; i<sz2; i++)
+                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
                   {
-                    coef[i] = 0;
+                    for(i=0; i<sz2; i++)
+                    {
+                      coef[i] = 0;
+                    }
                   }
-                }
 
     set_gain_unity(coef, sz2);
   }


=====================================
fft_wrap.h
=====================================
@@ -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


=====================================
global.h
=====================================
@@ -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


=====================================
import_annotations.cpp
=====================================
@@ -1244,7 +1244,14 @@ int UI_ImportAnnotationswindow::import_from_ascii(void)
 
   startline = DatastartSpinbox->value();
 
-  descr_column = DescriptionColumnSpinBox->value() - 1;
+  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))
       {


=====================================
ishne2edf.cpp
=====================================
@@ -0,0 +1,682 @@
+/*
+***************************************************************************
+*
+* Author: Teunis van Beelen
+*
+* Copyright (C) 2019 Teunis van Beelen
+*
+* Email: teuniz at 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. */
+  }
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+


=====================================
ishne2edf.h
=====================================
@@ -0,0 +1,107 @@
+/*
+***************************************************************************
+*
+* Author: Teunis van Beelen
+*
+* Copyright (C) 2019 Teunis van Beelen
+*
+* Email: teuniz at 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
+
+


=====================================
mainwindow.cpp
=====================================
@@ -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);


=====================================
mainwindow.h
=====================================
@@ -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);


=====================================
mainwindow_constr.cpp
=====================================
@@ -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()));


=====================================
options_dialog.cpp
=====================================
@@ -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)


=====================================
options_dialog.h
=====================================
@@ -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);


=====================================
read_write_settings.cpp
=====================================
@@ -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);


=====================================
signalcurve.cpp
=====================================
@@ -1031,7 +1031,14 @@ void SignalCurve::drawWidget_to_printer(QPainter *painter, int curve_w, int curv
         continue;
       }
 
-      q_str.setNum((double)i / (double)p2_multiplier, 'f', precision);
+      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;
       }
 
-      q_str.setNum((double)lk / (double)p2_multiplier, 'f', precision);
+      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;
 


=====================================
signals_dialog.cpp
=====================================
@@ -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;
-  newsignalcomp->color = curve_color;
+  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;
-    newsignalcomp->color = curve_color;
+    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;
 


=====================================
signals_dialog.h
=====================================
@@ -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];
 


=====================================
spectrum_dock.cpp
=====================================
@@ -224,8 +224,12 @@ UI_SpectrumDockWindow::UI_SpectrumDockWindow(QWidget *w_parent)
   windowBox->addItem("Nuttall4c");
   windowBox->addItem("Hann");
   windowBox->addItem("HFT223D");
+  windowBox->addItem("HFT95");
   windowBox->setCurrentIndex(window_type);
   windowBox->setToolTip("Window");
+  windowBox->setCurrentIndex(mainwindow->spectrumdock_window);
+
+  window_type = mainwindow->spectrumdock_window;
 
   overlap_box = new QComboBox;
   overlap_box->setMinimumSize(70, 25);
@@ -234,6 +238,9 @@ UI_SpectrumDockWindow::UI_SpectrumDockWindow(QWidget *w_parent)
   overlap_box->addItem("Overlap: 67%");
   overlap_box->addItem("Overlap: 75%");
   overlap_box->addItem("Overlap: 80%");
+  overlap_box->setCurrentIndex(mainwindow->spectrumdock_overlap);
+
+  overlap = mainwindow->spectrumdock_overlap + 1;
 
   dftsz_label = new QLabel;
   dftsz_label->setText("Blocksize:");
@@ -356,6 +363,8 @@ void UI_SpectrumDockWindow::windowBox_changed(int idx)
 
   window_type = idx;
 
+  mainwindow->spectrumdock_window = idx;
+
   init_maxvalue = 1;
 
   update_curve();
@@ -382,6 +391,8 @@ void UI_SpectrumDockWindow::overlap_box_changed(int idx)
 
   if(overlap == (idx + 1))  return;
 
+  mainwindow->spectrumdock_overlap = idx;
+
   overlap = idx + 1;
 
   init_maxvalue = 1;
@@ -390,14 +401,87 @@ void UI_SpectrumDockWindow::overlap_box_changed(int idx)
 }
 
 
-void UI_SpectrumDockWindow::open_close_dock(bool)
+void UI_SpectrumDockWindow::open_close_dock(bool visible)
 {
+  char str[512]={""};
+
   if(mainwindow->files_open != 1 || signal_nr < 0)
   {
     dock->hide();
 
     return;
   }
+
+  if(visible)
+  {
+    overlap_box->setCurrentIndex(mainwindow->spectrumdock_overlap);
+
+    overlap = mainwindow->spectrumdock_overlap + 1;
+
+    windowBox->setCurrentIndex(mainwindow->spectrumdock_window);
+
+    window_type = mainwindow->spectrumdock_window;
+
+    if(mainwindow->spectrumdock_sqrt)
+    {
+      sqrtButton->setChecked(true);
+
+      snprintf(str, 512, "Amplitude Spectrum %.64s", signallabel);
+
+      dock->setWindowTitle(str);
+
+      if(mainwindow->spectrumdock_vlog)
+      {
+        snprintf(str, 512, "log10(%s)", physdimension);
+        curve1->setV_label(str);
+      }
+      else
+      {
+        curve1->setV_label(physdimension);
+      }
+    }
+    else
+    {
+      sqrtButton->setChecked(false);
+
+      snprintf(str, 512, "Power Spectrum %.64s", signallabel);
+
+      dock->setWindowTitle(str);
+
+      if(mainwindow->spectrumdock_vlog)
+      {
+        snprintf(str, 512, "log((%s)^2/Hz)", physdimension);
+      }
+      else
+      {
+        snprintf(str, 512, "(%s)^2/Hz", physdimension);
+      }
+
+      curve1->setV_label(str);
+    }
+
+    if(mainwindow->spectrumdock_vlog)
+    {
+      vlogButton->setChecked(true);
+
+      log_minslider->setVisible(true);
+    }
+    else
+    {
+      vlogButton->setChecked(false);
+
+      log_minslider->setVisible(false);
+    }
+
+    if(mainwindow->spectrumdock_colorbars)
+    {
+      colorBarButton->setCheckState(Qt::Checked);
+    }
+    else
+    {
+      colorBarButton->setCheckState(Qt::Unchecked);
+    }
+  }
 }
 
 


=====================================
spectrumanalyzer.cpp
=====================================
@@ -289,6 +289,7 @@ UI_FreqSpectrumWindow::UI_FreqSpectrumWindow(struct signalcompblock *signal_comp
   dftsz_box->addItem("Blocksize: 5000000");
   dftsz_box->addItem("Blocksize: 8388608");
   dftsz_box->addItem("Blocksize: 10000000");
+  dftsz_box->setCurrentIndex(mainwindow->spectrum_blocksize_predefined);
 
   windowBox = new QComboBox;
   windowBox->setMinimumSize(70, 25);
@@ -300,15 +301,35 @@ UI_FreqSpectrumWindow::UI_FreqSpectrumWindow(struct signalcompblock *signal_comp
   windowBox->addItem("Nuttall4c");
   windowBox->addItem("Hann");
   windowBox->addItem("HFT223D");
+  windowBox->addItem("HFT95");
   windowBox->setCurrentIndex(window_type);
   windowBox->setToolTip("Window");
+  windowBox->setCurrentIndex(mainwindow->spectrum_window);
+
+  window_type = mainwindow->spectrum_window;
 
   dftsz_spinbox = new QSpinBox;
   dftsz_spinbox->setMinimumSize(70, 25);
   dftsz_spinbox->setMinimum(10);
-  dftsz_spinbox->setMaximum(1000);
   dftsz_spinbox->setSingleStep(2);
-  dftsz_spinbox->setValue(dftblocksize);
+  if(mainwindow->spectrum_blocksize_predefined)
+  {
+    dftsz_spinbox->setMaximum(10000000);
+
+    dftsz_spinbox->setValue(dftsz_range[mainwindow->spectrum_blocksize_predefined]);
+
+    dftblocksize = dftsz_range[mainwindow->spectrum_blocksize_predefined];
+
+    dftsz_spinbox->setEnabled(false);
+  }
+  else
+  {
+    dftsz_spinbox->setMaximum(1000);
+
+    dftsz_spinbox->setValue(mainwindow->spectrum_blocksize_userdefined);
+
+    dftblocksize = mainwindow->spectrum_blocksize_userdefined;
+  }
 
   overlap_box = new QComboBox;
   overlap_box->setMinimumSize(70, 25);
@@ -317,6 +338,9 @@ UI_FreqSpectrumWindow::UI_FreqSpectrumWindow(struct signalcompblock *signal_comp
   overlap_box->addItem("Overlap: 67%");
   overlap_box->addItem("Overlap: 75%");
   overlap_box->addItem("Overlap: 80%");
+  overlap_box->setCurrentIndex(mainwindow->spectrum_overlap);
+
+  overlap = mainwindow->spectrum_overlap + 1;
 
   vlayout3 = new QVBoxLayout;
   vlayout3->addStretch(100);
@@ -428,6 +452,8 @@ void UI_FreqSpectrumWindow::windowBox_changed(int idx)
 
   if(window_type == idx)  return;
 
+  mainwindow->spectrum_window = idx;
+
   window_type = idx;
 
   busy = 1;
@@ -464,6 +490,8 @@ void UI_FreqSpectrumWindow::dftsz_value_changed(int new_val)
 
 void UI_FreqSpectrumWindow::dftsz_box_changed(int idx)
 {
+  mainwindow->spectrum_blocksize_predefined = idx;
+
   if(idx)
   {
     if(dftsz_range[idx] > samples)
@@ -503,6 +531,8 @@ void UI_FreqSpectrumWindow::overlap_box_changed(int idx)
 
   if(overlap == (idx + 1))  return;
 
+  mainwindow->spectrum_overlap = idx;
+
   overlap = idx + 1;
 
   busy = 1;
@@ -600,6 +630,8 @@ void UI_FreqSpectrumWindow::print_to_txt()
             break;
     case FFT_WNDW_TYPE_HFT223D               : fprintf(outputfile, "FFT window function: HFT223D\n");
             break;
+    case FFT_WNDW_TYPE_HFT95                 : fprintf(outputfile, "FFT window function: HFT95\n");
+            break;
   }
   switch(overlap)
   {


=====================================
version.txt
=====================================
@@ -1,5 +1,24 @@
 
 
+ version 1.71      December 21, 2019
+ --------------
+
+ - Added an option in the settings dialog to enable to assign varying colors to traces
+   when adding traces to the screen.
+
+ - Spectrumanalyzer: switch to exponential notation in case of big numbers.
+
+ - Spectrum Analyzer: added window type "HFT95".
+
+ - Converters: added a ISHNE Holter ECG to EDF converter.
+
+ - Videoplayer: fixed a bug that could cause a wrong synchronization between the video and the EDF file.
+
+ - Import annotations: solved a bug that prevented to import annotations stored in an ASCII file when
+   the option "Manual description" was enabled.
+
+
+
  version 1.70      September 7, 2019
  --------------
 


=====================================
videoplayer.cpp
=====================================
@@ -496,7 +496,7 @@ void UI_Mainwindow::video_poll_timer_func()
 
         if(video_player->fpos != vpos)
         {
-          jump_to_time_millisec(video_player->utc_starttime - edfheaderlist[sel_viewtime]->utc_starttime + (vpos * 1000LL) - (pagetime / 20000));
+          jump_to_time_millisec(((video_player->utc_starttime - edfheaderlist[sel_viewtime]->utc_starttime + vpos) * 1000LL) - (pagetime / 20000LL));
 
           video_player->fpos = vpos;
 



View it on GitLab: https://salsa.debian.org/med-team/edfbrowser/commit/4ac4810027b859d7f08c3c9ae1633c97e005b54e

-- 
View it on GitLab: https://salsa.debian.org/med-team/edfbrowser/commit/4ac4810027b859d7f08c3c9ae1633c97e005b54e
You're receiving this email because of your account on salsa.debian.org.


-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://alioth-lists.debian.net/pipermail/debian-med-commit/attachments/20200105/9cbaf8ea/attachment-0001.html>


More information about the debian-med-commit mailing list