From 4e81fd8885276600d4028ac28001e6e0cfef93c0 Mon Sep 17 00:00:00 2001 From: Dimitri Papadopoulos <3234522+DimitriPapadopoulos@users.noreply.github.com> Date: Tue, 21 Jan 2025 20:27:00 +0100 Subject: [PATCH 1/4] Update to EDFlib v1.26 This is a pristine copy from EDFlib v1.26. --- pyedflib/_extensions/c/edflib.c | 3510 +++++++++++++------------------ pyedflib/_extensions/c/edflib.h | 1696 ++++++++++----- 2 files changed, 2595 insertions(+), 2611 deletions(-) diff --git a/pyedflib/_extensions/c/edflib.c b/pyedflib/_extensions/c/edflib.c index ce4fef76..097e32dd 100644 --- a/pyedflib/_extensions/c/edflib.c +++ b/pyedflib/_extensions/c/edflib.c @@ -1,7 +1,7 @@ /* ***************************************************************************** * -* Copyright (c) 2009 - 2020 Teunis van Beelen +* Copyright (c) 2009 - 2024 Teunis van Beelen * All rights reserved. * * Email: teuniz@protonmail.com @@ -31,22 +31,14 @@ ***************************************************************************** */ - - - /* compile with options "-D_LARGEFILE64_SOURCE -D_LARGEFILE_SOURCE" */ -#pragma warning( disable : 4996 ) // ignore unsafe strncpy -#pragma warning( disable : 4244 ) // ignore precision loss - #include "edflib.h" - -#define EDFLIB_VERSION (117) +#define EDFLIB_VERSION (126) #define EDFLIB_MAXFILES (64) - -#if defined(__APPLE__) || defined(__MACH__) || defined(__APPLE_CC__) || defined(__HAIKU__) +#if defined(__APPLE__) || defined(__MACH__) || defined(__APPLE_CC__) || defined(__HAIKU__) || defined(__ANDROID__) #define fopeno fopen @@ -58,7 +50,6 @@ #endif - #ifdef _WIN32 #ifndef __MINGW32__ @@ -76,117 +67,131 @@ #endif - - -/* max size of annotationtext */ +/* max length of annotation's description in bytes + * you may modify this number in order to create more space for longer description strings + */ #define EDFLIB_WRITE_MAX_ANNOTATION_LEN (40) -/* bytes in datarecord for EDF annotations, must be an integer multiple of three and two */ -#define EDFLIB_ANNOTATION_BYTES (114) +/* number of bytes in datarecord for the annotations track, must be a multiple of six + * do not modify this macro + */ +#if ((EDFLIB_WRITE_MAX_ANNOTATION_LEN + 80) % 6) +#define EDFLIB_ANNOTATION_BYTES ((((EDFLIB_WRITE_MAX_ANNOTATION_LEN + 80) / 6) + 1) * 6) +#else +#define EDFLIB_ANNOTATION_BYTES (EDFLIB_WRITE_MAX_ANNOTATION_LEN + 80) +#endif /* for writing only */ #define EDFLIB_MAX_ANNOTATION_CHANNELS (64) #define EDFLIB_ANNOT_MEMBLOCKSZ (1000) +typedef struct +{ + char label[17]; + char transducer[81]; + char physdimension[9]; + double phys_min; + double phys_max; + int dig_min; + int dig_max; + char prefilter[81]; + int smp_per_record; + char reserved[33]; + double offset; + int buf_offset; + double bitvalue; + int annotation; + long long sample_pntr; +} edfparamblock_t; + +typedef struct +{ + FILE *file_hdl; + char path[1024]; + int writemode; + char version[32]; + char patient[81]; + char recording[81]; + char plus_patientcode[81]; + char plus_sex[16]; + char plus_birthdate[16]; + int plus_birthdate_day; + int plus_birthdate_month; + int plus_birthdate_year; + char plus_patient_name[81]; + char plus_patient_additional[81]; + char plus_startdate[16]; + char plus_admincode[81]; + char plus_technician[81]; + char plus_equipment[81]; + char plus_recording_additional[81]; + long long l_starttime; + int startdate_day; + int startdate_month; + int startdate_year; + int starttime_second; + int starttime_minute; + int starttime_hour; + char reserved[45]; + int hdrsize; + int edfsignals; + long long datarecords; + int recordsize; + int annot_ch[EDFLIB_MAXSIGNALS]; + int nr_annot_chns; + int mapped_signals[EDFLIB_MAXSIGNALS]; + int edf; + int edfplus; + int bdf; + int bdfplus; + int discontinuous; + int signal_write_sequence_pos; + long long starttime_offset; + double data_record_duration; + long long long_data_record_duration; + int annots_in_file; + int annotlist_sz; + int total_annot_bytes; + int eq_sf; + char *wrbuf; + int wrbufsize; + int annot_chan_idx_pos; + edfparamblock_t *edfparam; +} edfhdrblock_t; + +typedef struct +{ + long long onset; + long long duration_l; + char duration[20]; + char annotation[EDFLIB_MAX_ANNOTATION_LEN + 1]; +} edf_read_annotationblock_t; -struct edfparamblock{ - char label[17]; - char transducer[81]; - char physdimension[9]; - double phys_min; - double phys_max; - int dig_min; - int dig_max; - char prefilter[81]; - int smp_per_record; - char reserved[33]; - double offset; - int buf_offset; - double bitvalue; - int annotation; - long long sample_pntr; - }; - -struct edfhdrblock{ - FILE *file_hdl; - char path[1024]; - int writemode; - char version[32]; - char patient[81]; - char recording[81]; - char plus_patientcode[81]; - char plus_gender[16]; - char plus_birthdate[16]; - char plus_patient_name[81]; - char plus_patient_additional[81]; - char plus_startdate[16]; - char plus_admincode[81]; - char plus_technician[81]; - char plus_equipment[81]; - char plus_recording_additional[81]; - long long l_starttime; - int startdate_day; - int startdate_month; - int startdate_year; - int starttime_second; - int starttime_minute; - int starttime_hour; - char reserved[45]; - int hdrsize; - int edfsignals; - long long datarecords; - int recordsize; - int annot_ch[EDFLIB_MAXSIGNALS]; - int nr_annot_chns; - int mapped_signals[EDFLIB_MAXSIGNALS]; - int edf; - int edfplus; - int bdf; - int bdfplus; - int discontinuous; - int signal_write_sequence_pos; - long long starttime_offset; - double data_record_duration; - long long long_data_record_duration; - int annots_in_file; - int annotlist_sz; - int total_annot_bytes; - int eq_sf; - char *wrbuf; - int wrbufsize; - struct edfparamblock *edfparam; - }; - - -static struct edf_annotationblock{ - long long onset; - char duration[16]; - char annotation[EDFLIB_MAX_ANNOTATION_LEN + 1]; - } *annotationslist[EDFLIB_MAXFILES]; - - -static struct edf_write_annotationblock{ - long long onset; - long long duration; - char annotation[EDFLIB_WRITE_MAX_ANNOTATION_LEN + 1]; - } *write_annotationslist[EDFLIB_MAXFILES]; +static edf_read_annotationblock_t *annotationslist[EDFLIB_MAXFILES]; -static int edf_files_open=0; +typedef struct +{ + long long onset; + long long duration; + char annotation[EDFLIB_WRITE_MAX_ANNOTATION_LEN + 1]; +} edf_write_annotationblock_t; -static struct edfhdrblock *hdrlist[EDFLIB_MAXFILES]; +static edf_write_annotationblock_t *write_annotationslist[EDFLIB_MAXFILES]; +static int edf_files_open=0; + +static edfhdrblock_t *hdrlist[EDFLIB_MAXFILES]; -static struct edfhdrblock * edflib_check_edf_file(FILE *, int *, int); -static int edflib_repair_file_size(const char *path, struct edfhdrblock *edfhdr); +static edfhdrblock_t * edflib_check_edf_file(FILE *, int *); static int edflib_is_integer_number(char *); static int edflib_is_number(char *); static long long edflib_get_long_duration(char *); -static int edflib_get_annotations(struct edfhdrblock *, int, int); +static int edflib_get_annotations(edfhdrblock_t *, int, int); static int edflib_is_duration_number(char *); static int edflib_is_onset_number(char *); static long long edflib_get_long_time(char *); -static int edflib_write_edf_header(struct edfhdrblock *); +static int edflib_write_edf_header(edfhdrblock_t *); static void edflib_latin1_to_ascii(char *, int); static void edflib_latin12utf8(char *, int); static void edflib_remove_padding_trailing_spaces(char *); @@ -199,41 +204,34 @@ static int edflib_sprint_int_number_nonlocalized(char *, int, int, int); static int edflib_snprint_ll_number_nonlocalized(char *, long long, int, int, int); static int edflib_fprint_int_number_nonlocalized(FILE *, int, int, int); static int edflib_fprint_ll_number_nonlocalized(FILE *, long long, int, int); -static int edflib_write_tal(struct edfhdrblock *, FILE *); +static int edflib_write_tal(edfhdrblock_t *, FILE *); static int edflib_strlcpy(char *, const char *, int); static int edflib_strlcat(char *, const char *, int); - - -int edflib_is_file_used(const char *path) +EDFLIB_API int edflib_is_file_used(const char *path) { - int i, file_used=0; + int i; for(i=0; ipath))) - { - file_used= 1; - - break; - } + if(!(strcmp(path, hdrlist[i]->path))) return 1; } } - return file_used ; + return 0; } -int edflib_get_number_of_open_files() +EDFLIB_API int edflib_get_number_of_open_files() { return edf_files_open; } -int edflib_get_handle(int file_number) +EDFLIB_API int edflib_get_handle(int file_number) { int i, file_count=0; @@ -241,10 +239,7 @@ int edflib_get_handle(int file_number) { if(hdrlist[i]!=NULL) { - if(file_count++ == file_number) - { - return i; - } + if(file_count++ == file_number) return i; } } @@ -252,7 +247,7 @@ int edflib_get_handle(int file_number) } -int edfopen_file_readonly(const char *path, struct edf_hdr_struct *edfhdr, int read_annotations, int check_file_size) +EDFLIB_API int edfopen_file_readonly(const char *path, edflib_hdr_t *edfhdr, int read_annotations_mode) { int i, j, channel, @@ -260,40 +255,50 @@ int edfopen_file_readonly(const char *path, struct edf_hdr_struct *edfhdr, int r FILE *file; - struct edfhdrblock *hdr; - + edfhdrblock_t *hdr; - if(read_annotations<0) + union { - edfhdr->filetype = EDFLIB_INVALID_READ_ANNOTS_VALUE; + char four[4]; + int one; + } byte_order_test_var; - return -1; - } + memset(edfhdr, 0, sizeof(edflib_hdr_t)); + + edfhdr->handle = -1; - if(read_annotations>2) + /* avoid surprises! */ + if((sizeof(char) != 1) || + (sizeof(short) != 2) || + (sizeof(int) != 4) || + (sizeof(long long) != 8) || + (sizeof(float) != 4) || + (sizeof(double) != 8)) { - edfhdr->filetype = EDFLIB_INVALID_READ_ANNOTS_VALUE; + edfhdr->filetype = EDFLIB_ARCH_ERROR; return -1; } - if(check_file_size<0) + /* check endianness! */ + byte_order_test_var.one = 0x03020100; + if((byte_order_test_var.four[0] != 0) || + (byte_order_test_var.four[1] != 1) || + (byte_order_test_var.four[2] != 2) || + (byte_order_test_var.four[3] != 3)) { - edfhdr->filetype = EDFLIB_INVALID_CHECK_SIZE_VALUE; - + edfhdr->filetype = EDFLIB_ARCH_ERROR; return -1; } - if(check_file_size>2) + if((read_annotations_mode<0)||(read_annotations_mode>2)) { - edfhdr->filetype = EDFLIB_INVALID_CHECK_SIZE_VALUE; + edfhdr->filetype = EDFLIB_INVALID_READ_ANNOTS_VALUE; return -1; } - memset(edfhdr, 0, sizeof(struct edf_hdr_struct)); - if(edf_files_open>=EDFLIB_MAXFILES) { edfhdr->filetype = EDFLIB_MAXFILES_REACHED; @@ -322,18 +327,7 @@ int edfopen_file_readonly(const char *path, struct edf_hdr_struct *edfhdr, int r return -1; } - hdr = edflib_check_edf_file(file, &edf_error,check_file_size); - if (hdr==NULL && edf_error == EDFLIB_FILE_CONTAINS_FORMAT_ERRORS && check_file_size == EDFLIB_REPAIR_FILE_SIZE_IF_WRONG) - { - hdr = edflib_check_edf_file(file, &edf_error, EDFLIB_DO_NOT_CHECK_FILE_SIZE); - fclose(file); - edflib_repair_file_size(path, hdr); - free(hdr->edfparam); - free(hdr); - file = fopeno(path, "rb"); - hdr = edflib_check_edf_file(file, &edf_error, EDFLIB_CHECK_FILE_SIZE); - } - + hdr = edflib_check_edf_file(file, &edf_error); if(hdr==NULL) { edfhdr->filetype = edf_error; @@ -355,8 +349,6 @@ int edfopen_file_readonly(const char *path, struct edf_hdr_struct *edfhdr, int r return -1; } - hdr->writemode = 0; - for(i=0; ipatient, hdr->patient, 81); edflib_strlcpy(edfhdr->recording, hdr->recording, 81); - edfhdr->patientcode[0] = 0; - edfhdr->gender[0] = 0; - edfhdr->birthdate[0] = 0; - edfhdr->patient_name[0] = 0; - edfhdr->patient_additional[0] = 0; - edfhdr->admincode[0] = 0; - edfhdr->technician[0] = 0; - edfhdr->equipment[0] = 0; - edfhdr->recording_additional[0] = 0; } else { - edfhdr->patient[0] = 0; - edfhdr->recording[0] = 0; edflib_strlcpy(edfhdr->patientcode, hdr->plus_patientcode, 81); - edflib_strlcpy(edfhdr->gender, hdr->plus_gender, 16); + edflib_strlcpy(edfhdr->sex, hdr->plus_sex, 16); +#if defined(__GNUC__) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wdeprecated-declarations" +#endif + edflib_strlcpy(edfhdr->gender, hdr->plus_sex, 16); +#if defined(__GNUC__) +#pragma GCC diagnostic pop +#endif edflib_strlcpy(edfhdr->birthdate, hdr->plus_birthdate, 16); + edfhdr->birthdate_day = hdr->plus_birthdate_day; + edfhdr->birthdate_month = hdr->plus_birthdate_month; + edfhdr->birthdate_year = hdr->plus_birthdate_year; edflib_strlcpy(edfhdr->patient_name, hdr->plus_patient_name, 81); edflib_strlcpy(edfhdr->patient_additional, hdr->plus_patient_additional, 81); edflib_strlcpy(edfhdr->admincode, hdr->plus_admincode, 81); @@ -437,28 +429,25 @@ int edfopen_file_readonly(const char *path, struct edf_hdr_struct *edfhdr, int r edflib_strlcpy(edfhdr->equipment, hdr->plus_equipment, 81); edflib_strlcpy(edfhdr->recording_additional, hdr->plus_recording_additional, 81); - if((read_annotations==EDFLIB_READ_ANNOTATIONS)||(read_annotations==EDFLIB_READ_ALL_ANNOTATIONS)) + if(edflib_get_annotations(hdr, edfhdr->handle, read_annotations_mode)) { - if(edflib_get_annotations(hdr, edfhdr->handle, read_annotations)) - { - edfhdr->filetype = EDFLIB_FILE_CONTAINS_FORMAT_ERRORS; + edfhdr->filetype = EDFLIB_FILE_CONTAINS_FORMAT_ERRORS; - fclose(file); + fclose(file); - free(hdr->edfparam); - hdr->edfparam = NULL; - free(hdr); - hdr = NULL; - hdrlist[edfhdr->handle] = NULL; - free(annotationslist[edfhdr->handle]); - annotationslist[edfhdr->handle] = NULL; - - return -1; - } + free(hdr->edfparam); + hdr->edfparam = NULL; + free(hdr); + hdr = NULL; + hdrlist[edfhdr->handle] = NULL; + free(annotationslist[edfhdr->handle]); + annotationslist[edfhdr->handle] = NULL; - edfhdr->starttime_subsecond = hdr->starttime_offset; + return -1; } + edfhdr->starttime_subsecond = hdr->starttime_offset; + edfhdr->annotations_in_file = hdr->annots_in_file; } @@ -496,9 +485,9 @@ int edfopen_file_readonly(const char *path, struct edf_hdr_struct *edfhdr, int r } -int edfclose_file(int handle) +EDFLIB_API int edfclose_file(int handle) { - struct edf_write_annotationblock *annot2; + edf_write_annotationblock_t *annot2; int i, j, k, n, p, err, datrecsize, @@ -509,23 +498,12 @@ int edfclose_file(int handle) char str[EDFLIB_ANNOTATION_BYTES * 2]; - struct edfhdrblock *hdr; - + edfhdrblock_t *hdr; - if(handle<0) - { - return -1; - } - if(handle>=EDFLIB_MAXFILES) - { - return -1; - } + if((handle<0)||(handle>=EDFLIB_MAXFILES)) return -1; - if(hdrlist[handle]==NULL) - { - return -1; - } + if(hdrlist[handle]==NULL) return -1; hdr = hdrlist[handle]; @@ -553,13 +531,10 @@ int edfclose_file(int handle) edf_files_open--; return err; - } for(k=0; kannots_in_file; k++) { - annot2 = write_annotationslist[handle] + k; - p = edflib_fprint_ll_number_nonlocalized(hdr->file_hdl, (hdr->datarecords * hdr->long_data_record_duration + hdr->starttime_offset) / EDFLIB_TIME_DIMENSION, 0, 1); if((hdr->long_data_record_duration % EDFLIB_TIME_DIMENSION) || (hdr->starttime_offset)) @@ -600,13 +575,33 @@ int edfclose_file(int handle) { if(hdr->edf) { - offset += (long long)(hdr->edfparam[i].smp_per_record * 2); + if(hdr->annot_chan_idx_pos == EDF_ANNOT_IDX_POS_END) + { + offset += (long long)(hdr->edfparam[i].smp_per_record * 2); + } + else if(hdr->annot_chan_idx_pos == EDF_ANNOT_IDX_POS_MIDDLE) + { + if(i < (hdr->edfsignals / 2)) + { + offset += (long long)(hdr->edfparam[i].smp_per_record * 2); + } + } datrecsize += (hdr->edfparam[i].smp_per_record * 2); } else { - offset += (long long)(hdr->edfparam[i].smp_per_record * 3); + if(hdr->annot_chan_idx_pos == EDF_ANNOT_IDX_POS_END) + { + offset += (long long)(hdr->edfparam[i].smp_per_record * 3); + } + else if(hdr->annot_chan_idx_pos == EDF_ANNOT_IDX_POS_MIDDLE) + { + if(i < (hdr->edfsignals / 2)) + { + offset += (long long)(hdr->edfparam[i].smp_per_record * 3); + } + } datrecsize += (hdr->edfparam[i].smp_per_record * 3); } @@ -618,7 +613,7 @@ int edfclose_file(int handle) { annot2 = write_annotationslist[handle] + k; - annot2->onset += hdr->starttime_offset / 1000LL; + annot2->onset += hdr->starttime_offset / 10LL; p = 0; @@ -642,23 +637,23 @@ int edfclose_file(int handle) str[p++] = 0; } - n = edflib_snprint_ll_number_nonlocalized(str + p, annot2->onset / 10000LL, 0, 1, (EDFLIB_ANNOTATION_BYTES * 2) - p); + n = edflib_snprint_ll_number_nonlocalized(str + p, annot2->onset / 1000000LL, 0, 1, (EDFLIB_ANNOTATION_BYTES * 2) - p); p += n; - if(annot2->onset % 10000LL) + if(annot2->onset % 1000000LL) { str[p++] = '.'; - n = edflib_snprint_ll_number_nonlocalized(str + p, annot2->onset % 10000LL, 4, 0, (EDFLIB_ANNOTATION_BYTES * 2) - p); + n = edflib_snprint_ll_number_nonlocalized(str + p, annot2->onset % 1000000LL, 6, 0, (EDFLIB_ANNOTATION_BYTES * 2) - p); p += n; } if(annot2->duration>=0LL) { str[p++] = 21; - n = edflib_snprint_ll_number_nonlocalized(str + p, annot2->duration / 10000LL, 0, 0, (EDFLIB_ANNOTATION_BYTES * 2) - p); + n = edflib_snprint_ll_number_nonlocalized(str + p, annot2->duration / 1000000LL, 0, 0, (EDFLIB_ANNOTATION_BYTES * 2) - p); p += n; - if(annot2->duration % 10000LL) + if(annot2->duration % 1000000LL) { str[p++] = '.'; - n = edflib_snprint_ll_number_nonlocalized(str + p, annot2->duration % 10000LL, 4, 0, (EDFLIB_ANNOTATION_BYTES * 2) - p); + n = edflib_snprint_ll_number_nonlocalized(str + p, annot2->duration % 1000000LL, 6, 0, (EDFLIB_ANNOTATION_BYTES * 2) - p); p += n; } } @@ -726,42 +721,21 @@ int edfclose_file(int handle) } -long long edfseek(int handle, int edfsignal, long long offset, int whence) +EDFLIB_API long long edfseek(int handle, int edfsignal, long long offset, int whence) { long long smp_in_file; int channel; + if((handle<0)||(handle>=EDFLIB_MAXFILES)) return -1; - if(handle<0) - { - return -1; - } - - if(handle>=EDFLIB_MAXFILES) - { - return -1; - } + if(hdrlist[handle]==NULL) return -1; - if(hdrlist[handle]==NULL) - { - return -1; - } - - if(edfsignal<0) - { - return -1; - } + if(edfsignal<0) return -1; - if(hdrlist[handle]->writemode) - { - return -1; - } + if(hdrlist[handle]->writemode) return -1; - if(edfsignal>=(hdrlist[handle]->edfsignals - hdrlist[handle]->nr_annot_chns)) - { - return -1; - } + if(edfsignal>=(hdrlist[handle]->edfsignals - hdrlist[handle]->nr_annot_chns)) return -1; channel = hdrlist[handle]->mapped_signals[edfsignal]; @@ -797,40 +771,19 @@ long long edfseek(int handle, int edfsignal, long long offset, int whence) } -long long edftell(int handle, int edfsignal) +EDFLIB_API long long edftell(int handle, int edfsignal) { int channel; + if((handle<0)||(handle>=EDFLIB_MAXFILES)) return -1; - if(handle<0) - { - return -1; - } - - if(handle>=EDFLIB_MAXFILES) - { - return -1; - } - - if(hdrlist[handle]==NULL) - { - return -1; - } + if(hdrlist[handle]==NULL) return -1; - if(edfsignal<0) - { - return -1; - } + if(edfsignal<0) return -1; - if(hdrlist[handle]->writemode) - { - return -1; - } + if(hdrlist[handle]->writemode) return -1; - if(edfsignal>=(hdrlist[handle]->edfsignals - hdrlist[handle]->nr_annot_chns)) - { - return -1; - } + if(edfsignal>=(hdrlist[handle]->edfsignals - hdrlist[handle]->nr_annot_chns)) return -1; channel = hdrlist[handle]->mapped_signals[edfsignal]; @@ -838,48 +791,29 @@ long long edftell(int handle, int edfsignal) } -void edfrewind(int handle, int edfsignal) +EDFLIB_API int edfrewind(int handle, int edfsignal) { int channel; + if((handle<0)||(handle>=EDFLIB_MAXFILES)) return -1; - if(handle<0) - { - return; - } - - if(handle>=EDFLIB_MAXFILES) - { - return; - } - - if(hdrlist[handle]==NULL) - { - return; - } + if(hdrlist[handle]==NULL) return -1; - if(edfsignal<0) - { - return; - } + if(edfsignal<0) return -1; - if(hdrlist[handle]->writemode) - { - return; - } + if(hdrlist[handle]->writemode) return -1; - if(edfsignal>=(hdrlist[handle]->edfsignals - hdrlist[handle]->nr_annot_chns)) - { - return; - } + if(edfsignal>=(hdrlist[handle]->edfsignals - hdrlist[handle]->nr_annot_chns)) return -1; channel = hdrlist[handle]->mapped_signals[edfsignal]; hdrlist[handle]->edfparam[channel].sample_pntr = 0LL; + + return 0; } -int edfread_physical_samples(int handle, int edfsignal, int n, double *buf) +EDFLIB_API int edfread_physical_samples(int handle, int edfsignal, int n, double *buf) { int bytes_per_smpl=2, tmp, @@ -895,7 +829,7 @@ int edfread_physical_samples(int handle, int edfsignal, int n, double *buf) smp_per_record, jump; - struct edfhdrblock *hdr; + edfhdrblock_t *hdr; union { unsigned int one; @@ -907,48 +841,21 @@ int edfread_physical_samples(int handle, int edfsignal, int n, double *buf) FILE *file; + if((handle<0)||(handle>=EDFLIB_MAXFILES)) return -1; - if(handle<0) - { - return -1; - } - - if(handle>=EDFLIB_MAXFILES) - { - return -1; - } - - if(hdrlist[handle]==NULL) - { - return -1; - } + if(hdrlist[handle]==NULL) return -1; - if(edfsignal<0) - { - return -1; - } + if(edfsignal<0) return -1; - if(hdrlist[handle]->writemode) - { - return -1; - } + if(hdrlist[handle]->writemode) return -1; - if(edfsignal>=(hdrlist[handle]->edfsignals - hdrlist[handle]->nr_annot_chns)) - { - return -1; - } + if(edfsignal>=(hdrlist[handle]->edfsignals - hdrlist[handle]->nr_annot_chns)) return -1; channel = hdrlist[handle]->mapped_signals[edfsignal]; - if(n<0LL) - { - return -1; - } + if(n<0LL) return -1; - if(n==0LL) - { - return 0LL; - } + if(n==0LL) return 0LL; hdr = hdrlist[handle]; @@ -968,15 +875,9 @@ int edfread_physical_samples(int handle, int edfsignal, int n, double *buf) { n = smp_in_file - hdr->edfparam[channel].sample_pntr; - if(n==0) - { - return 0LL; - } + if(n==0) return 0LL; - if(n<0) - { - return -1; - } + if(n<0) return -1; } file = hdr->file_hdl; @@ -1018,6 +919,15 @@ int edfread_physical_samples(int handle, int edfsignal, int n, double *buf) } var.four[1] = tmp; + if(var.two_signed[0] > hdr->edfparam[channel].dig_max) + { + var.two_signed[0] = hdr->edfparam[channel].dig_max; + } + else if(var.two_signed[0] < hdr->edfparam[channel].dig_min) + { + var.two_signed[0] = hdr->edfparam[channel].dig_min; + } + buf[i] = phys_bitvalue * (phys_offset + (double)var.two_signed[0]); sample_pntr++; @@ -1039,10 +949,7 @@ int edfread_physical_samples(int handle, int edfsignal, int n, double *buf) var.four[0] = fgetc(file); var.four[1] = fgetc(file); tmp = fgetc(file); - if(tmp==EOF) - { - return -1; - } + if(tmp==EOF) return -1; var.four[2] = tmp; if(var.four[2]&0x80) @@ -1054,6 +961,15 @@ int edfread_physical_samples(int handle, int edfsignal, int n, double *buf) var.four[3] = 0x00; } + if(var.one_signed > hdr->edfparam[channel].dig_max) + { + var.one_signed = hdr->edfparam[channel].dig_max; + } + else if(var.one_signed < hdr->edfparam[channel].dig_min) + { + var.one_signed = hdr->edfparam[channel].dig_min; + } + buf[i] = phys_bitvalue * (phys_offset + (double)var.one_signed); sample_pntr++; @@ -1066,7 +982,7 @@ int edfread_physical_samples(int handle, int edfsignal, int n, double *buf) } -int edfread_digital_samples(int handle, int edfsignal, int n, int *buf) +EDFLIB_API int edfread_digital_samples(int handle, int edfsignal, int n, int *buf) { int bytes_per_smpl=2, tmp, @@ -1079,7 +995,7 @@ int edfread_digital_samples(int handle, int edfsignal, int n, int *buf) smp_per_record, jump; - struct edfhdrblock *hdr; + edfhdrblock_t *hdr; union { unsigned int one; @@ -1091,48 +1007,21 @@ int edfread_digital_samples(int handle, int edfsignal, int n, int *buf) FILE *file; + if((handle<0)||(handle>=EDFLIB_MAXFILES)) return -1; - if(handle<0) - { - return -1; - } - - if(handle>=EDFLIB_MAXFILES) - { - return -1; - } - - if(hdrlist[handle]==NULL) - { - return -1; - } + if(hdrlist[handle]==NULL) return -1; - if(edfsignal<0) - { - return -1; - } + if(edfsignal<0) return -1; - if(hdrlist[handle]->writemode) - { - return -1; - } + if(hdrlist[handle]->writemode) return -1; - if(edfsignal>=(hdrlist[handle]->edfsignals - hdrlist[handle]->nr_annot_chns)) - { - return -1; - } + if(edfsignal>=(hdrlist[handle]->edfsignals - hdrlist[handle]->nr_annot_chns)) return -1; channel = hdrlist[handle]->mapped_signals[edfsignal]; - if(n<0LL) - { - return -1; - } + if(n<0LL) return -1; - if(n==0LL) - { - return 0LL; - } + if(n==0LL) return 0LL; hdr = hdrlist[handle]; @@ -1192,11 +1081,17 @@ int edfread_digital_samples(int handle, int edfsignal, int n, int *buf) var.four[0] = fgetc(file); tmp = fgetc(file); - if(tmp==EOF) + if(tmp==EOF) return -1; + var.four[1] = tmp; + + if(var.two_signed[0] > hdr->edfparam[channel].dig_max) { - return -1; + var.two_signed[0] = hdr->edfparam[channel].dig_max; } - var.four[1] = tmp; + else if(var.two_signed[0] < hdr->edfparam[channel].dig_min) + { + var.two_signed[0] = hdr->edfparam[channel].dig_min; + } buf[i] = var.two_signed[0]; @@ -1219,10 +1114,7 @@ int edfread_digital_samples(int handle, int edfsignal, int n, int *buf) var.four[0] = fgetc(file); var.four[1] = fgetc(file); tmp = fgetc(file); - if(tmp==EOF) - { - return -1; - } + if(tmp==EOF) return -1; var.four[2] = tmp; if(var.four[2]&0x80) @@ -1234,6 +1126,15 @@ int edfread_digital_samples(int handle, int edfsignal, int n, int *buf) var.four[3] = 0x00; } + if(var.one_signed > hdr->edfparam[channel].dig_max) + { + var.one_signed = hdr->edfparam[channel].dig_max; + } + else if(var.one_signed < hdr->edfparam[channel].dig_min) + { + var.one_signed = hdr->edfparam[channel].dig_min; + } + buf[i] = var.one_signed; sample_pntr++; @@ -1246,49 +1147,30 @@ int edfread_digital_samples(int handle, int edfsignal, int n, int *buf) } -int edf_get_annotation(int handle, int n, struct edf_annotation_struct *annot) +EDFLIB_API int edf_get_annotation(int handle, int n, edflib_annotation_t *annot) { - memset(annot, 0, sizeof(struct edf_annotation_struct)); - - if(handle<0) - { - return -1; - } + memset(annot, 0, sizeof(edflib_annotation_t)); - if(handle>=EDFLIB_MAXFILES) - { - return -1; - } + if((handle<0)||(handle>=EDFLIB_MAXFILES)) return -1; - if(hdrlist[handle]==NULL) - { - return -1; - } + if(hdrlist[handle]==NULL) return -1; - if(hdrlist[handle]->writemode) - { - return -1; - } + if(hdrlist[handle]->writemode) return -1; - if(n<0) - { - return -1; - } + if(n<0) return -1; - if(n>=hdrlist[handle]->annots_in_file) - { - return -1; - } + if(n>=hdrlist[handle]->annots_in_file) return -1; annot->onset = (annotationslist[handle] + n)->onset; - edflib_strlcpy(annot->duration, (annotationslist[handle] + n)->duration, 16); + annot->duration_l = (annotationslist[handle] + n)->duration_l; + edflib_strlcpy(annot->duration, (annotationslist[handle] + n)->duration, 20); edflib_strlcpy(annot->annotation, (annotationslist[handle] + n)->annotation, EDFLIB_MAX_ANNOTATION_LEN + 1); return 0; } -static struct edfhdrblock * edflib_check_edf_file(FILE *inputfile, int *edf_error, int check_file_size) +static edfhdrblock_t * edflib_check_edf_file(FILE *inputfile, int *edf_error) { int i, j, p, r=0, n, dotposition, @@ -1298,7 +1180,7 @@ static struct edfhdrblock * edflib_check_edf_file(FILE *inputfile, int *edf_erro scratchpad[128], scratchpad2[64]; - struct edfhdrblock *edfhdr; + edfhdrblock_t *edfhdr; /***************** check header ******************************/ @@ -1309,7 +1191,7 @@ static struct edfhdrblock * edflib_check_edf_file(FILE *inputfile, int *edf_erro return NULL; } - edfhdr = (struct edfhdrblock *)calloc(1, sizeof(struct edfhdrblock)); + edfhdr = (edfhdrblock_t *)calloc(1, sizeof(edfhdrblock_t)); if(edfhdr==NULL) { free(edf_hdr); @@ -1426,7 +1308,7 @@ static struct edfhdrblock * edflib_check_edf_file(FILE *inputfile, int *edf_erro { if((scratchpad[i]<32)||(scratchpad[i]>126)) { - *edf_error = EDFLIB_FILE_ERRORS_STARTDATE; + *edf_error = EDFLIB_FILE_CONTAINS_FORMAT_ERRORS; free(edf_hdr); free(edfhdr); return NULL; @@ -1447,7 +1329,7 @@ static struct edfhdrblock * edflib_check_edf_file(FILE *inputfile, int *edf_erro if(error) { scratchpad[8] = 0; - *edf_error = EDFLIB_FILE_ERRORS_STARTDATE; + *edf_error = EDFLIB_FILE_CONTAINS_FORMAT_ERRORS; free(edf_hdr); free(edfhdr); return NULL; @@ -1457,29 +1339,29 @@ static struct edfhdrblock * edflib_check_edf_file(FILE *inputfile, int *edf_erro scratchpad[5] = 0; scratchpad[8] = 0; - if((edflib_atof_nonlocalized(scratchpad)<1)||(edflib_atof_nonlocalized(scratchpad)>31)) + if((edflib_atoi_nonlocalized(scratchpad)<1)||(edflib_atoi_nonlocalized(scratchpad)>31)) { strncpy(scratchpad, edf_hdr + 168, 8); scratchpad[8] = 0; - *edf_error = EDFLIB_FILE_ERRORS_STARTDATE; + *edf_error = EDFLIB_FILE_CONTAINS_FORMAT_ERRORS; free(edf_hdr); free(edfhdr); return NULL; } - if((edflib_atof_nonlocalized(scratchpad+3)<1)||(edflib_atof_nonlocalized(scratchpad+3)>12)) + if((edflib_atoi_nonlocalized(scratchpad+3)<1)||(edflib_atoi_nonlocalized(scratchpad+3)>12)) { strncpy(scratchpad, edf_hdr + 168, 8); scratchpad[8] = 0; - *edf_error = EDFLIB_FILE_ERRORS_STARTDATE; + *edf_error = EDFLIB_FILE_CONTAINS_FORMAT_ERRORS; free(edf_hdr); free(edfhdr); return NULL; } - edfhdr->startdate_day = edflib_atof_nonlocalized(scratchpad); - edfhdr->startdate_month = edflib_atof_nonlocalized(scratchpad + 3); - edfhdr->startdate_year = edflib_atof_nonlocalized(scratchpad + 6); + edfhdr->startdate_day = edflib_atoi_nonlocalized(scratchpad); + edfhdr->startdate_month = edflib_atoi_nonlocalized(scratchpad + 3); + edfhdr->startdate_year = edflib_atoi_nonlocalized(scratchpad + 6); if(edfhdr->startdate_year>84) { edfhdr->startdate_year += 1900; @@ -1497,7 +1379,7 @@ static struct edfhdrblock * edflib_check_edf_file(FILE *inputfile, int *edf_erro { if((scratchpad[i]<32)||(scratchpad[i]>126)) { - *edf_error = EDFLIB_FILE_ERRORS_STARTTIME; + *edf_error = EDFLIB_FILE_CONTAINS_FORMAT_ERRORS; free(edf_hdr); free(edfhdr); return NULL; @@ -1520,7 +1402,7 @@ static struct edfhdrblock * edflib_check_edf_file(FILE *inputfile, int *edf_erro { strncpy(scratchpad, edf_hdr + 176, 8); scratchpad[8] = 0; - *edf_error = EDFLIB_FILE_ERRORS_STARTTIME; + *edf_error = EDFLIB_FILE_CONTAINS_FORMAT_ERRORS; free(edf_hdr); free(edfhdr); return NULL; @@ -1530,43 +1412,43 @@ static struct edfhdrblock * edflib_check_edf_file(FILE *inputfile, int *edf_erro scratchpad[5] = 0; scratchpad[8] = 0; - if(edflib_atof_nonlocalized(scratchpad)>23) + if(edflib_atoi_nonlocalized(scratchpad)>23) { strncpy(scratchpad, edf_hdr + 176, 8); scratchpad[8] = 0; - *edf_error = EDFLIB_FILE_ERRORS_STARTTIME; + *edf_error = EDFLIB_FILE_CONTAINS_FORMAT_ERRORS; free(edf_hdr); free(edfhdr); return NULL; } - if(edflib_atof_nonlocalized(scratchpad+3)>59) + if(edflib_atoi_nonlocalized(scratchpad+3)>59) { strncpy(scratchpad, edf_hdr + 176, 8); scratchpad[8] = 0; - *edf_error = EDFLIB_FILE_ERRORS_STARTTIME; + *edf_error = EDFLIB_FILE_CONTAINS_FORMAT_ERRORS; free(edf_hdr); free(edfhdr); return NULL; } - if(edflib_atof_nonlocalized(scratchpad+6)>59) + if(edflib_atoi_nonlocalized(scratchpad+6)>59) { strncpy(scratchpad, edf_hdr + 176, 8); scratchpad[8] = 0; - *edf_error = EDFLIB_FILE_ERRORS_STARTTIME; + *edf_error = EDFLIB_FILE_CONTAINS_FORMAT_ERRORS; free(edf_hdr); free(edfhdr); return NULL; } - edfhdr->starttime_hour = edflib_atof_nonlocalized(scratchpad); - edfhdr->starttime_minute = edflib_atof_nonlocalized(scratchpad + 3); - edfhdr->starttime_second = edflib_atof_nonlocalized(scratchpad + 6); + edfhdr->starttime_hour = edflib_atoi_nonlocalized(scratchpad); + edfhdr->starttime_minute = edflib_atoi_nonlocalized(scratchpad + 3); + edfhdr->starttime_second = edflib_atoi_nonlocalized(scratchpad + 6); - edfhdr->l_starttime = 3600 * edflib_atof_nonlocalized(scratchpad); - edfhdr->l_starttime += 60 * edflib_atof_nonlocalized(scratchpad + 3); - edfhdr->l_starttime += edflib_atof_nonlocalized(scratchpad + 6); + edfhdr->l_starttime = 3600 * edflib_atoi_nonlocalized(scratchpad); + edfhdr->l_starttime += 60 * edflib_atoi_nonlocalized(scratchpad + 3); + edfhdr->l_starttime += edflib_atoi_nonlocalized(scratchpad + 6); edfhdr->l_starttime *= EDFLIB_TIME_DIMENSION; @@ -1578,7 +1460,7 @@ static struct edfhdrblock * edflib_check_edf_file(FILE *inputfile, int *edf_erro { if((scratchpad[i]<32)||(scratchpad[i]>126)) { - *edf_error = EDFLIB_FILE_ERRORS_NUMBER_SIGNALS; + *edf_error = EDFLIB_FILE_CONTAINS_FORMAT_ERRORS; free(edf_hdr); free(edfhdr); return NULL; @@ -1587,15 +1469,15 @@ static struct edfhdrblock * edflib_check_edf_file(FILE *inputfile, int *edf_erro if(edflib_is_integer_number(scratchpad)) { - *edf_error = EDFLIB_FILE_ERRORS_NUMBER_SIGNALS; + *edf_error = EDFLIB_FILE_CONTAINS_FORMAT_ERRORS; free(edf_hdr); free(edfhdr); return NULL; } - edfhdr->edfsignals = edflib_atof_nonlocalized(scratchpad); + edfhdr->edfsignals = edflib_atoi_nonlocalized(scratchpad); if(edfhdr->edfsignals<1) { - *edf_error = EDFLIB_FILE_ERRORS_NUMBER_SIGNALS; + *edf_error = EDFLIB_FILE_CONTAINS_FORMAT_ERRORS; free(edf_hdr); free(edfhdr); return NULL; @@ -1603,7 +1485,7 @@ static struct edfhdrblock * edflib_check_edf_file(FILE *inputfile, int *edf_erro if(edfhdr->edfsignals>EDFLIB_MAXSIGNALS) { - *edf_error = EDFLIB_FILE_ERRORS_NUMBER_SIGNALS; + *edf_error = EDFLIB_FILE_CONTAINS_FORMAT_ERRORS; free(edf_hdr); free(edfhdr); return NULL; @@ -1618,7 +1500,7 @@ static struct edfhdrblock * edflib_check_edf_file(FILE *inputfile, int *edf_erro { if((scratchpad[i]<32)||(scratchpad[i]>126)) { - *edf_error = EDFLIB_FILE_ERRORS_BYTES_HEADER; + *edf_error = EDFLIB_FILE_CONTAINS_FORMAT_ERRORS; free(edf_hdr); free(edfhdr); return NULL; @@ -1627,16 +1509,16 @@ static struct edfhdrblock * edflib_check_edf_file(FILE *inputfile, int *edf_erro if(edflib_is_integer_number(scratchpad)) { - *edf_error = EDFLIB_FILE_ERRORS_BYTES_HEADER; + *edf_error = EDFLIB_FILE_CONTAINS_FORMAT_ERRORS; free(edf_hdr); free(edfhdr); return NULL; } - n = edflib_atof_nonlocalized(scratchpad); + n = edflib_atoi_nonlocalized(scratchpad); if((edfhdr->edfsignals * 256 + 256)!=n) { - *edf_error = EDFLIB_FILE_ERRORS_BYTES_HEADER; + *edf_error = EDFLIB_FILE_CONTAINS_FORMAT_ERRORS; free(edf_hdr); free(edfhdr); return NULL; @@ -1653,7 +1535,7 @@ static struct edfhdrblock * edflib_check_edf_file(FILE *inputfile, int *edf_erro { if((scratchpad[i]<32)||(scratchpad[i]>126)) { - *edf_error = EDFLIB_FILE_ERRORS_RESERVED_FIELD; + *edf_error = EDFLIB_FILE_CONTAINS_FORMAT_ERRORS; free(edf_hdr); free(edfhdr); return NULL; @@ -1662,26 +1544,34 @@ static struct edfhdrblock * edflib_check_edf_file(FILE *inputfile, int *edf_erro if(edfhdr->edf) { - if(!strncmp(scratchpad, "EDF+C", 5)) + if(!strncmp(scratchpad, "EDF+C ", 44)) { edfhdr->edfplus = 1; + edfhdr->discontinuous = 0; } - - if(!strncmp(scratchpad, "EDF+D", 5)) - { - edfhdr->edfplus = 1; - edfhdr->discontinuous = 1; - } + else if(!strncmp(scratchpad, "EDF+D ", 44)) + { + edfhdr->edfplus = 1; + edfhdr->discontinuous = 1; + } + else if(strncmp(scratchpad, " ", 44)) + { + *edf_error = EDFLIB_FILE_CONTAINS_FORMAT_ERRORS; + free(edf_hdr); + free(edfhdr); + return NULL; + } } if(edfhdr->bdf) { - if(!strncmp(scratchpad, "BDF+C", 5)) + if(!strncmp(scratchpad, "BDF+C ", 44)) { edfhdr->bdfplus = 1; + edfhdr->discontinuous = 0; } - if(!strncmp(scratchpad, "BDF+D", 5)) + if(!strncmp(scratchpad, "BDF+D ", 44)) { edfhdr->bdfplus = 1; edfhdr->discontinuous = 1; @@ -1700,7 +1590,7 @@ static struct edfhdrblock * edflib_check_edf_file(FILE *inputfile, int *edf_erro { if((scratchpad[i]<32)||(scratchpad[i]>126)) { - *edf_error = EDFLIB_FILE_ERRORS_NUMBER_DATARECORDS; + *edf_error = EDFLIB_FILE_CONTAINS_FORMAT_ERRORS; free(edf_hdr); free(edfhdr); return NULL; @@ -1709,16 +1599,16 @@ static struct edfhdrblock * edflib_check_edf_file(FILE *inputfile, int *edf_erro if(edflib_is_integer_number(scratchpad)) { - *edf_error = EDFLIB_FILE_ERRORS_NUMBER_DATARECORDS; + *edf_error = EDFLIB_FILE_CONTAINS_FORMAT_ERRORS; free(edf_hdr); free(edfhdr); return NULL; } - edfhdr->datarecords = edflib_atof_nonlocalized(scratchpad); + edfhdr->datarecords = edflib_atoi_nonlocalized(scratchpad); if(edfhdr->datarecords<1) { - *edf_error = EDFLIB_FILE_ERRORS_NUMBER_DATARECORDS; + *edf_error = EDFLIB_FILE_CONTAINS_FORMAT_ERRORS; free(edf_hdr); free(edfhdr); return NULL; @@ -1733,7 +1623,7 @@ static struct edfhdrblock * edflib_check_edf_file(FILE *inputfile, int *edf_erro { if((scratchpad[i]<32)||(scratchpad[i]>126)) { - *edf_error = EDFLIB_FILE_ERRORS_DURATION; + *edf_error = EDFLIB_FILE_CONTAINS_FORMAT_ERRORS; free(edf_hdr); free(edfhdr); return NULL; @@ -1742,7 +1632,7 @@ static struct edfhdrblock * edflib_check_edf_file(FILE *inputfile, int *edf_erro if(edflib_is_number(scratchpad)) { - *edf_error = EDFLIB_FILE_ERRORS_DURATION; + *edf_error = EDFLIB_FILE_CONTAINS_FORMAT_ERRORS; free(edf_hdr); free(edfhdr); return NULL; @@ -1751,7 +1641,7 @@ static struct edfhdrblock * edflib_check_edf_file(FILE *inputfile, int *edf_erro edfhdr->data_record_duration = edflib_atof_nonlocalized(scratchpad); if(edfhdr->data_record_duration < -0.000001) { - *edf_error = EDFLIB_FILE_ERRORS_DURATION; + *edf_error = EDFLIB_FILE_CONTAINS_FORMAT_ERRORS; free(edf_hdr); free(edfhdr); return NULL; @@ -1780,7 +1670,7 @@ static struct edfhdrblock * edflib_check_edf_file(FILE *inputfile, int *edf_erro return NULL; } - edfhdr->edfparam = (struct edfparamblock *)calloc(1, sizeof(struct edfparamblock) * edfhdr->edfsignals); + edfhdr->edfparam = (edfparamblock_t *)calloc(1, sizeof(edfparamblock_t) * edfhdr->edfsignals); if(edfhdr->edfparam==NULL) { *edf_error = EDFLIB_MALLOC_ERROR; @@ -1799,37 +1689,45 @@ static struct edfhdrblock * edflib_check_edf_file(FILE *inputfile, int *edf_erro { if((scratchpad[j]<32)||(scratchpad[j]>126)) { - *edf_error = EDFLIB_FILE_ERRORS_LABEL; + *edf_error = EDFLIB_FILE_CONTAINS_FORMAT_ERRORS; free(edf_hdr); free(edfhdr->edfparam); free(edfhdr); return NULL; } } - if(edfhdr->edfplus) + if(!strncmp(scratchpad, "EDF Annotations ", 16)) { - if(!strncmp(scratchpad, "EDF Annotations ", 16)) + if(edfhdr->edfplus) { edfhdr->annot_ch[edfhdr->nr_annot_chns] = i; edfhdr->nr_annot_chns++; edfhdr->edfparam[i].annotation = 1; } + else + { + scratchpad[3] = '_'; + } } - if(edfhdr->bdfplus) + if(!strncmp(scratchpad, "BDF Annotations ", 16)) { - if(!strncmp(scratchpad, "BDF Annotations ", 16)) + if(edfhdr->bdfplus) { edfhdr->annot_ch[edfhdr->nr_annot_chns] = i; edfhdr->nr_annot_chns++; edfhdr->edfparam[i].annotation = 1; } + else + { + scratchpad[3] = '_'; + } } - strncpy(edfhdr->edfparam[i].label, edf_hdr + 256 + (i * 16), 16); + memcpy(edfhdr->edfparam[i].label, scratchpad, 16); edfhdr->edfparam[i].label[16] = 0; } if(edfhdr->edfplus&&(!edfhdr->nr_annot_chns)) { - *edf_error = EDFLIB_FILE_ERRORS_LABEL; + *edf_error = EDFLIB_FILE_CONTAINS_FORMAT_ERRORS; free(edf_hdr); free(edfhdr->edfparam); free(edfhdr); @@ -1837,7 +1735,7 @@ static struct edfhdrblock * edflib_check_edf_file(FILE *inputfile, int *edf_erro } if(edfhdr->bdfplus&&(!edfhdr->nr_annot_chns)) { - *edf_error = EDFLIB_FILE_ERRORS_LABEL; + *edf_error = EDFLIB_FILE_CONTAINS_FORMAT_ERRORS; free(edf_hdr); free(edfhdr->edfparam); free(edfhdr); @@ -1845,10 +1743,9 @@ static struct edfhdrblock * edflib_check_edf_file(FILE *inputfile, int *edf_erro } if((edfhdr->edfsignals!=edfhdr->nr_annot_chns)||((!edfhdr->edfplus)&&(!edfhdr->bdfplus))) { - //if(edfhdr->data_record_duration<0.0000001) - if(edfhdr->data_record_duration<0) + if(edfhdr->data_record_duration<0.0000001) { - *edf_error = EDFLIB_FILE_ERRORS_LABEL; + *edf_error = EDFLIB_FILE_CONTAINS_FORMAT_ERRORS; free(edf_hdr); free(edfhdr->edfparam); free(edfhdr); @@ -1865,7 +1762,7 @@ static struct edfhdrblock * edflib_check_edf_file(FILE *inputfile, int *edf_erro { if((scratchpad[j]<32)||(scratchpad[j]>126)) { - *edf_error = EDFLIB_FILE_ERRORS_TRANSDUCER; + *edf_error = EDFLIB_FILE_CONTAINS_FORMAT_ERRORS; free(edf_hdr); free(edfhdr->edfparam); free(edfhdr); @@ -1883,7 +1780,7 @@ static struct edfhdrblock * edflib_check_edf_file(FILE *inputfile, int *edf_erro { if(edfhdr->edfparam[i].transducer[j]!=' ') { - *edf_error = EDFLIB_FILE_ERRORS_TRANSDUCER; + *edf_error = EDFLIB_FILE_CONTAINS_FORMAT_ERRORS; free(edf_hdr); free(edfhdr->edfparam); free(edfhdr); @@ -1903,7 +1800,7 @@ static struct edfhdrblock * edflib_check_edf_file(FILE *inputfile, int *edf_erro { if((scratchpad[j]<32)||(scratchpad[j]>126)) { - *edf_error = EDFLIB_FILE_ERRORS_PHYS_DIMENSION; + *edf_error = EDFLIB_FILE_CONTAINS_FORMAT_ERRORS; free(edf_hdr); free(edfhdr->edfparam); free(edfhdr); @@ -1925,7 +1822,7 @@ static struct edfhdrblock * edflib_check_edf_file(FILE *inputfile, int *edf_erro { if((scratchpad[j]<32)||(scratchpad[j]>126)) { - *edf_error = EDFLIB_FILE_ERRORS_PHYS_MIN; + *edf_error = EDFLIB_FILE_CONTAINS_FORMAT_ERRORS; free(edf_hdr); free(edfhdr->edfparam); free(edfhdr); @@ -1935,7 +1832,7 @@ static struct edfhdrblock * edflib_check_edf_file(FILE *inputfile, int *edf_erro if(edflib_is_number(scratchpad)) { - *edf_error = EDFLIB_FILE_ERRORS_PHYS_MIN; + *edf_error = EDFLIB_FILE_CONTAINS_FORMAT_ERRORS; free(edf_hdr); free(edfhdr->edfparam); free(edfhdr); @@ -1956,7 +1853,7 @@ static struct edfhdrblock * edflib_check_edf_file(FILE *inputfile, int *edf_erro { if((scratchpad[j]<32)||(scratchpad[j]>126)) { - *edf_error = EDFLIB_FILE_ERRORS_PHYS_MAX; + *edf_error = EDFLIB_FILE_CONTAINS_FORMAT_ERRORS; free(edf_hdr); free(edfhdr->edfparam); free(edfhdr); @@ -1966,7 +1863,7 @@ static struct edfhdrblock * edflib_check_edf_file(FILE *inputfile, int *edf_erro if(edflib_is_number(scratchpad)) { - *edf_error = EDFLIB_FILE_ERRORS_PHYS_MAX; + *edf_error = EDFLIB_FILE_CONTAINS_FORMAT_ERRORS; free(edf_hdr); free(edfhdr->edfparam); free(edfhdr); @@ -1976,7 +1873,7 @@ static struct edfhdrblock * edflib_check_edf_file(FILE *inputfile, int *edf_erro edfhdr->edfparam[i].phys_max = edflib_atof_nonlocalized(scratchpad); if(edfhdr->edfparam[i].phys_max==edfhdr->edfparam[i].phys_min) { - *edf_error = EDFLIB_FILE_ERRORS_PHYS_MAX; + *edf_error = EDFLIB_FILE_CONTAINS_FORMAT_ERRORS; free(edf_hdr); free(edfhdr->edfparam); free(edfhdr); @@ -1995,7 +1892,7 @@ static struct edfhdrblock * edflib_check_edf_file(FILE *inputfile, int *edf_erro { if((scratchpad[j]<32)||(scratchpad[j]>126)) { - *edf_error = EDFLIB_FILE_ERRORS_DIG_MIN; + *edf_error = EDFLIB_FILE_CONTAINS_FORMAT_ERRORS; free(edf_hdr); free(edfhdr->edfparam); free(edfhdr); @@ -2005,21 +1902,21 @@ static struct edfhdrblock * edflib_check_edf_file(FILE *inputfile, int *edf_erro if(edflib_is_integer_number(scratchpad)) { - *edf_error = EDFLIB_FILE_ERRORS_DIG_MIN; + *edf_error = EDFLIB_FILE_CONTAINS_FORMAT_ERRORS; free(edf_hdr); free(edfhdr->edfparam); free(edfhdr); return NULL; } - n = edflib_atof_nonlocalized(scratchpad); + n = edflib_atoi_nonlocalized(scratchpad); if(edfhdr->edfplus) { if(edfhdr->edfparam[i].annotation) { - if(n!=-32768) + if(n!=-0x8000) { - *edf_error = EDFLIB_FILE_ERRORS_DIG_MIN; + *edf_error = EDFLIB_FILE_CONTAINS_FORMAT_ERRORS; free(edf_hdr); free(edfhdr->edfparam); free(edfhdr); @@ -2031,9 +1928,9 @@ static struct edfhdrblock * edflib_check_edf_file(FILE *inputfile, int *edf_erro { if(edfhdr->edfparam[i].annotation) { - if(n!=-8388608) + if(n!=-0x800000) { - *edf_error = EDFLIB_FILE_ERRORS_DIG_MIN; + *edf_error = EDFLIB_FILE_CONTAINS_FORMAT_ERRORS; free(edf_hdr); free(edfhdr->edfparam); free(edfhdr); @@ -2043,9 +1940,9 @@ static struct edfhdrblock * edflib_check_edf_file(FILE *inputfile, int *edf_erro } if(edfhdr->edf) { - if((n>32767)||(n<-32768)) + if((n>0x7fff)||(n<-0x8000)) { - *edf_error = EDFLIB_FILE_ERRORS_DIG_MIN; + *edf_error = EDFLIB_FILE_CONTAINS_FORMAT_ERRORS; free(edf_hdr); free(edfhdr->edfparam); free(edfhdr); @@ -2054,9 +1951,9 @@ static struct edfhdrblock * edflib_check_edf_file(FILE *inputfile, int *edf_erro } if(edfhdr->bdf) { - if((n>8388607)||(n<-8388608)) + if((n>0x7fffff)||(n<-0x800000)) { - *edf_error = EDFLIB_FILE_ERRORS_DIG_MIN; + *edf_error = EDFLIB_FILE_CONTAINS_FORMAT_ERRORS; free(edf_hdr); free(edfhdr->edfparam); free(edfhdr); @@ -2077,7 +1974,7 @@ static struct edfhdrblock * edflib_check_edf_file(FILE *inputfile, int *edf_erro { if((scratchpad[j]<32)||(scratchpad[j]>126)) { - *edf_error = EDFLIB_FILE_ERRORS_DIG_MAX; + *edf_error = EDFLIB_FILE_CONTAINS_FORMAT_ERRORS; free(edf_hdr); free(edfhdr->edfparam); free(edfhdr); @@ -2087,21 +1984,21 @@ static struct edfhdrblock * edflib_check_edf_file(FILE *inputfile, int *edf_erro if(edflib_is_integer_number(scratchpad)) { - *edf_error = EDFLIB_FILE_ERRORS_DIG_MAX; + *edf_error = EDFLIB_FILE_CONTAINS_FORMAT_ERRORS; free(edf_hdr); free(edfhdr->edfparam); free(edfhdr); return NULL; } - n = edflib_atof_nonlocalized(scratchpad); + n = edflib_atoi_nonlocalized(scratchpad); if(edfhdr->edfplus) { if(edfhdr->edfparam[i].annotation) { - if(n!=32767) + if(n!=0x7fff) { - *edf_error = EDFLIB_FILE_ERRORS_DIG_MAX; + *edf_error = EDFLIB_FILE_CONTAINS_FORMAT_ERRORS; free(edf_hdr); free(edfhdr->edfparam); free(edfhdr); @@ -2113,9 +2010,9 @@ static struct edfhdrblock * edflib_check_edf_file(FILE *inputfile, int *edf_erro { if(edfhdr->edfparam[i].annotation) { - if(n!=8388607) + if(n!=0x7fffff) { - *edf_error = EDFLIB_FILE_ERRORS_DIG_MAX; + *edf_error = EDFLIB_FILE_CONTAINS_FORMAT_ERRORS; free(edf_hdr); free(edfhdr->edfparam); free(edfhdr); @@ -2125,9 +2022,9 @@ static struct edfhdrblock * edflib_check_edf_file(FILE *inputfile, int *edf_erro } if(edfhdr->edf) { - if((n>32767)||(n<-32768)) + if((n>0x7fff)||(n<-0x8000)) { - *edf_error = EDFLIB_FILE_ERRORS_DIG_MAX; + *edf_error = EDFLIB_FILE_CONTAINS_FORMAT_ERRORS; free(edf_hdr); free(edfhdr->edfparam); free(edfhdr); @@ -2136,9 +2033,9 @@ static struct edfhdrblock * edflib_check_edf_file(FILE *inputfile, int *edf_erro } else { - if((n>8388607)||(n<-8388608)) + if((n>0x7fffff)||(n<-0x800000)) { - *edf_error = EDFLIB_FILE_ERRORS_DIG_MAX; + *edf_error = EDFLIB_FILE_CONTAINS_FORMAT_ERRORS; free(edf_hdr); free(edfhdr->edfparam); free(edfhdr); @@ -2146,9 +2043,9 @@ static struct edfhdrblock * edflib_check_edf_file(FILE *inputfile, int *edf_erro } } edfhdr->edfparam[i].dig_max = n; - if(edfhdr->edfparam[i].dig_max<(edfhdr->edfparam[i].dig_min + 1) && (edfhdr->bdfplus || edfhdr->edfplus)) + if(edfhdr->edfparam[i].dig_max<(edfhdr->edfparam[i].dig_min + 1)) { - *edf_error = EDFLIB_FILE_ERRORS_DIG_MAX; + *edf_error = EDFLIB_FILE_CONTAINS_FORMAT_ERRORS; free(edf_hdr); free(edfhdr->edfparam); free(edfhdr); @@ -2165,7 +2062,7 @@ static struct edfhdrblock * edflib_check_edf_file(FILE *inputfile, int *edf_erro { if((scratchpad[j]<32)||(scratchpad[j]>126)) { - *edf_error = EDFLIB_FILE_ERRORS_PREFILTER; + *edf_error = EDFLIB_FILE_CONTAINS_FORMAT_ERRORS; free(edf_hdr); free(edfhdr->edfparam); free(edfhdr); @@ -2174,6 +2071,24 @@ static struct edfhdrblock * edflib_check_edf_file(FILE *inputfile, int *edf_erro } strncpy(edfhdr->edfparam[i].prefilter, edf_hdr + 256 + (edfhdr->edfsignals * 136) + (i * 80), 80); edfhdr->edfparam[i].prefilter[80] = 0; + + if((edfhdr->edfplus) || (edfhdr->bdfplus)) + { + if(edfhdr->edfparam[i].annotation) + { + for(j=0; j<80; j++) + { + if(edfhdr->edfparam[i].prefilter[j]!=' ') + { + *edf_error = EDFLIB_FILE_CONTAINS_FORMAT_ERRORS; + free(edf_hdr); + free(edfhdr->edfparam); + free(edfhdr); + return NULL; + } + } + } + } } /*********************** NR OF SAMPLES IN EACH DATARECORD ********************/ @@ -2189,7 +2104,7 @@ static struct edfhdrblock * edflib_check_edf_file(FILE *inputfile, int *edf_erro { if((scratchpad[j]<32)||(scratchpad[j]>126)) { - *edf_error = EDFLIB_FILE_ERRORS_SAMPLES_DATARECORD; + *edf_error = EDFLIB_FILE_CONTAINS_FORMAT_ERRORS; free(edf_hdr); free(edfhdr->edfparam); free(edfhdr); @@ -2199,17 +2114,17 @@ static struct edfhdrblock * edflib_check_edf_file(FILE *inputfile, int *edf_erro if(edflib_is_integer_number(scratchpad)) { - *edf_error = EDFLIB_FILE_ERRORS_SAMPLES_DATARECORD; + *edf_error = EDFLIB_FILE_CONTAINS_FORMAT_ERRORS; free(edf_hdr); free(edfhdr->edfparam); free(edfhdr); return NULL; } - n = edflib_atof_nonlocalized(scratchpad); + n = edflib_atoi_nonlocalized(scratchpad); if(n<1) { - *edf_error = EDFLIB_FILE_ERRORS_SAMPLES_DATARECORD; + *edf_error = EDFLIB_FILE_CONTAINS_FORMAT_ERRORS; free(edf_hdr); free(edfhdr->edfparam); free(edfhdr); @@ -2225,7 +2140,7 @@ static struct edfhdrblock * edflib_check_edf_file(FILE *inputfile, int *edf_erro if(edfhdr->recordsize > (15 * 1024 * 1024)) { - *edf_error = EDFLIB_FILE_ERRORS_SAMPLES_DATARECORD; + *edf_error = EDFLIB_FILE_CONTAINS_FORMAT_ERRORS; free(edf_hdr); free(edfhdr->edfparam); free(edfhdr); @@ -2238,7 +2153,7 @@ static struct edfhdrblock * edflib_check_edf_file(FILE *inputfile, int *edf_erro if(edfhdr->recordsize > (10 * 1024 * 1024)) { - *edf_error = EDFLIB_FILE_ERRORS_SAMPLES_DATARECORD; + *edf_error = EDFLIB_FILE_CONTAINS_FORMAT_ERRORS; free(edf_hdr); free(edfhdr->edfparam); free(edfhdr); @@ -2251,15 +2166,32 @@ static struct edfhdrblock * edflib_check_edf_file(FILE *inputfile, int *edf_erro for(i=0; iedfsignals; i++) { strncpy(scratchpad, edf_hdr + 256 + (edfhdr->edfsignals * 224) + (i * 32), 32); - for(j=0; j<32; j++) + if(edfhdr->edf || edfhdr->bdfplus) { - if((scratchpad[j]<32)||(scratchpad[j]>126)) + for(j=0; j<32; j++) { - *edf_error = EDFLIB_FILE_CONTAINS_FORMAT_ERRORS; - free(edf_hdr); - free(edfhdr->edfparam); - free(edfhdr); - return NULL; + if(scratchpad[j] != ' ') + { + *edf_error = EDFLIB_FILE_CONTAINS_FORMAT_ERRORS; + free(edf_hdr); + free(edfhdr->edfparam); + free(edfhdr); + return NULL; + } + } + } + else + { + for(j=0; j<32; j++) + { + if((scratchpad[j] < 32) || (scratchpad[j] > 126)) + { + *edf_error = EDFLIB_FILE_CONTAINS_FORMAT_ERRORS; + free(edf_hdr); + free(edfhdr->edfparam); + free(edfhdr); + return NULL; + } } } strncpy(edfhdr->edfparam[i].reserved, edf_hdr + 256 + (edfhdr->edfsignals * 224) + (i * 32), 32); @@ -2312,7 +2244,7 @@ static struct edfhdrblock * edflib_check_edf_file(FILE *inputfile, int *edf_erro if((scratchpad2[8]<48)||(scratchpad2[8]>57)) error = 1; if((scratchpad2[9]<48)||(scratchpad2[9]>57)) error = 1; if((scratchpad2[10]<48)||(scratchpad2[10]>57)) error = 1; - if((edflib_atof_nonlocalized(scratchpad2)<1)||(edflib_atof_nonlocalized(scratchpad2)>31)) error = 1; + if((edflib_atoi_nonlocalized(scratchpad2)<1)||(edflib_atoi_nonlocalized(scratchpad2)>31)) error = 1; if(strcmp(scratchpad2 + 3, "JAN")) if(strcmp(scratchpad2 + 3, "FEB")) if(strcmp(scratchpad2 + 3, "MAR")) @@ -2360,15 +2292,15 @@ static struct edfhdrblock * edflib_check_edf_file(FILE *inputfile, int *edf_erro if(edfhdr->patient[p]=='M') { - edflib_strlcpy(edfhdr->plus_gender, "Male", 16); + edflib_strlcpy(edfhdr->plus_sex, "Male", 16); } if(edfhdr->patient[p]=='F') { - edflib_strlcpy(edfhdr->plus_gender, "Female", 16); + edflib_strlcpy(edfhdr->plus_sex, "Female", 16); } if(edfhdr->patient[p]=='X') { - edfhdr->plus_gender[0] = 0; + edfhdr->plus_sex[0] = 0; } for(i=0; i<(80-p);i++) { @@ -2382,6 +2314,9 @@ static struct edfhdrblock * edflib_check_edf_file(FILE *inputfile, int *edf_erro if(edfhdr->patient[p]=='X') { edfhdr->plus_birthdate[0] = 0; + edfhdr->plus_birthdate_day = 0; + edfhdr->plus_birthdate_month = 0; + edfhdr->plus_birthdate_year = 0; p += 2; } else @@ -2401,6 +2336,60 @@ static struct edfhdrblock * edflib_check_edf_file(FILE *inputfile, int *edf_erro edfhdr->plus_birthdate[6] = ' '; edfhdr->plus_birthdate[11] = 0; p += i + 1; + edfhdr->plus_birthdate_day = edflib_atoi_nonlocalized(edfhdr->plus_birthdate); + if(!strncmp(edfhdr->plus_birthdate + 3, "jan", 3)) + { + edfhdr->plus_birthdate_month = 1; + } + else if(!strncmp(edfhdr->plus_birthdate + 3, "feb", 3)) + { + edfhdr->plus_birthdate_month = 2; + } + else if(!strncmp(edfhdr->plus_birthdate + 3, "mar", 3)) + { + edfhdr->plus_birthdate_month = 3; + } + else if(!strncmp(edfhdr->plus_birthdate + 3, "apr", 3)) + { + edfhdr->plus_birthdate_month = 4; + } + else if(!strncmp(edfhdr->plus_birthdate + 3, "may", 3)) + { + edfhdr->plus_birthdate_month = 5; + } + else if(!strncmp(edfhdr->plus_birthdate + 3, "jun", 3)) + { + edfhdr->plus_birthdate_month = 6; + } + else if(!strncmp(edfhdr->plus_birthdate + 3, "jul", 3)) + { + edfhdr->plus_birthdate_month = 7; + } + else if(!strncmp(edfhdr->plus_birthdate + 3, "aug", 3)) + { + edfhdr->plus_birthdate_month = 8; + } + else if(!strncmp(edfhdr->plus_birthdate + 3, "sep", 3)) + { + edfhdr->plus_birthdate_month = 9; + } + else if(!strncmp(edfhdr->plus_birthdate + 3, "oct", 3)) + { + edfhdr->plus_birthdate_month = 10; + } + else if(!strncmp(edfhdr->plus_birthdate + 3, "nov", 3)) + { + edfhdr->plus_birthdate_month = 11; + } + else if(!strncmp(edfhdr->plus_birthdate + 3, "dec", 3)) + { + edfhdr->plus_birthdate_month = 12; + } + else + { + edfhdr->plus_birthdate_month = 0; + } + edfhdr->plus_birthdate_year = edflib_atoi_nonlocalized(edfhdr->plus_birthdate + 7); } for(i=0; i<(80-p);i++) @@ -2453,7 +2442,7 @@ static struct edfhdrblock * edflib_check_edf_file(FILE *inputfile, int *edf_erro if((scratchpad2[8]<48)||(scratchpad2[8]>57)) error = 1; if((scratchpad2[9]<48)||(scratchpad2[9]>57)) error = 1; if((scratchpad2[10]<48)||(scratchpad2[10]>57)) error = 1; - if((edflib_atof_nonlocalized(scratchpad2)<1)||(edflib_atof_nonlocalized(scratchpad2)>31)) error = 1; + if((edflib_atoi_nonlocalized(scratchpad2)<1)||(edflib_atoi_nonlocalized(scratchpad2)>31)) error = 1; r = 0; if(!strcmp(scratchpad2 + 3, "JAN")) r = 1; else if(!strcmp(scratchpad2 + 3, "FEB")) r = 2; @@ -2492,7 +2481,7 @@ static struct edfhdrblock * edflib_check_edf_file(FILE *inputfile, int *edf_erro if(error) { - *edf_error = EDFLIB_FILE_ERRORS_RECORDINGFIELD; + *edf_error = EDFLIB_FILE_CONTAINS_FORMAT_ERRORS; free(edf_hdr); free(edfhdr->edfparam); free(edfhdr); @@ -2508,23 +2497,21 @@ static struct edfhdrblock * edflib_check_edf_file(FILE *inputfile, int *edf_erro scratchpad[5] = 0; scratchpad[8] = 0; - if(edflib_atof_nonlocalized(scratchpad)!=edflib_atof_nonlocalized(scratchpad2)) error = 1; - if(edflib_atof_nonlocalized(scratchpad+3)!=r) error = 1; - if(edflib_atof_nonlocalized(scratchpad+6)!=edflib_atof_nonlocalized(scratchpad2+9)) error = 1; + if(edflib_atoi_nonlocalized(scratchpad)!=edflib_atoi_nonlocalized(scratchpad2)) error = 1; + if(edflib_atoi_nonlocalized(scratchpad+3)!=r) error = 1; + if(edflib_atoi_nonlocalized(scratchpad+6)!=edflib_atoi_nonlocalized(scratchpad2+9)) error = 1; if(error) { - *edf_error = EDFLIB_FILE_ERRORS_RECORDINGFIELD; + *edf_error = EDFLIB_FILE_CONTAINS_FORMAT_ERRORS; free(edf_hdr); free(edfhdr->edfparam); free(edfhdr); return NULL; } - edfhdr->startdate_year = edflib_atof_nonlocalized(scratchpad2 + 7); - - if(edfhdr->startdate_year<1970) + if(edfhdr->startdate_year != edflib_atoi_nonlocalized(scratchpad2 + 7)) { - *edf_error = EDFLIB_FILE_ERRORS_RECORDINGFIELD; + *edf_error = EDFLIB_FILE_CONTAINS_FORMAT_ERRORS; free(edf_hdr); free(edfhdr->edfparam); free(edfhdr); @@ -2621,20 +2608,16 @@ static struct edfhdrblock * edflib_check_edf_file(FILE *inputfile, int *edf_erro edfhdr->hdrsize = edfhdr->edfsignals * 256 + 256; - if (check_file_size != EDFLIB_DO_NOT_CHECK_FILE_SIZE) + fseeko(inputfile, 0LL, SEEK_END); + if(ftello(inputfile)!=(edfhdr->recordsize * edfhdr->datarecords + edfhdr->hdrsize)) { - fseeko(inputfile, 0LL, SEEK_END); - if(ftello(inputfile)<(edfhdr->recordsize * edfhdr->datarecords + edfhdr->hdrsize)) - { - printf("filesize %d != %d*%d+%d ",ftello(inputfile),edfhdr->recordsize, edfhdr->datarecords, edfhdr->hdrsize); - *edf_error = EDFLIB_FILE_ERRORS_FILESIZE; - free(edf_hdr); - free(edfhdr->edfparam); - free(edfhdr); - return NULL; - } - + *edf_error = EDFLIB_FILE_CONTAINS_FORMAT_ERRORS; + free(edf_hdr); + free(edfhdr->edfparam); + free(edfhdr); + return NULL; } + n = 0; for(i=0; iedfsignals; i++) @@ -2642,17 +2625,9 @@ static struct edfhdrblock * edflib_check_edf_file(FILE *inputfile, int *edf_erro edfhdr->edfparam[i].buf_offset = n; if(edfhdr->bdf) n += edfhdr->edfparam[i].smp_per_record * 3; else n += edfhdr->edfparam[i].smp_per_record * 2; - if ((edfhdr->edfparam[i].dig_max == edfhdr->edfparam[i].dig_min) || (edfhdr->edfparam[i].phys_max == edfhdr->edfparam[i].phys_min)) - { - edfhdr->edfparam[i].bitvalue = 1; - edfhdr->edfparam[i].offset = 0; - } - else - { edfhdr->edfparam[i].bitvalue = (edfhdr->edfparam[i].phys_max - edfhdr->edfparam[i].phys_min) / (edfhdr->edfparam[i].dig_max - edfhdr->edfparam[i].dig_min); edfhdr->edfparam[i].offset = edfhdr->edfparam[i].phys_max / edfhdr->edfparam[i].bitvalue - edfhdr->edfparam[i].dig_max; - } } edfhdr->file_hdl = inputfile; @@ -2824,6 +2799,7 @@ static int edflib_is_number(char *str) static long long edflib_get_long_duration(char *str) { int i, len=8, hasdot=0, dotposition=0; + long long value=0, radix; if((str[0] == '+') || (str[0] == '-')) @@ -2832,6 +2808,7 @@ static long long edflib_get_long_duration(char *str) { str[i] = str[i+1]; } + str[7] = ' '; } @@ -2887,31 +2864,13 @@ static long long edflib_get_long_duration(char *str) } -int edflib_version(void) +EDFLIB_API int edflib_version(void) { return EDFLIB_VERSION; } -int edflib_repair_file_size(const char *path, struct edfhdrblock *edfhdr) -{ - int p; - FILE *file; - - file = fopeno(path, "wb"); - if(edfhdr->datarecords<100000000LL) - { - fseeko(file, 236LL, SEEK_SET); - p = edflib_fprint_int_number_nonlocalized(file, (int)(edfhdr->datarecords), 0, 0); - if(p < 2) - { - fputc(' ', file); - } - } - fclose(file); - return 0; -} -static int edflib_get_annotations(struct edfhdrblock *edfhdr, int hdl, int read_annotations) +static int edflib_get_annotations(edfhdrblock_t *edfhdr, int hdl, int read_annotations_mode) { int i, j, k, p, r=0, n, edfsignals, @@ -2931,22 +2890,22 @@ static int edflib_get_annotations(struct edfhdrblock *edfhdr, int hdl, int read_ annots_in_tal, samplesize=2; - char *scratchpad, - *cnv_buf, - *time_in_txt, - *duration_in_txt; + char *scratchpad=NULL, + *cnv_buf=NULL, + *time_in_txt=NULL, + *duration_in_txt=NULL; long long data_record_duration, elapsedtime, time_tmp=0; - FILE *inputfile; + FILE *inputfile=NULL; - struct edfparamblock *edfparam; + edfparamblock_t *edfparam=NULL; - struct edf_annotationblock *new_annotation=NULL, - *malloc_list; + edf_read_annotationblock_t *new_annotation=NULL, + *malloc_list=NULL; inputfile = edfhdr->file_hdl; edfsignals = edfhdr->edfsignals; @@ -2980,6 +2939,8 @@ static int edflib_get_annotations(struct edfhdrblock *edfhdr, int hdl, int read_ if(max_tal_ln=EDFLIB_TIME_DIMENSION) + if((time_tmp>=EDFLIB_TIME_DIMENSION) || (time_tmp<0LL)) { error = 2; goto END; @@ -3108,6 +3069,11 @@ static int edflib_get_annotations(struct edfhdrblock *edfhdr, int hdl, int read_ else { edfhdr->starttime_offset = time_tmp; + if(read_annotations_mode==EDFLIB_DO_NOT_READ_ANNOTATIONS) + { + error = 0; + goto END_OUT; + } } } elapsedtime = time_tmp; @@ -3171,8 +3137,8 @@ static int edflib_get_annotations(struct edfhdrblock *edfhdr, int hdl, int read_ { if(edfhdr->annots_in_file >= edfhdr->annotlist_sz) { - malloc_list = (struct edf_annotationblock *)realloc(annotationslist[hdl], - sizeof(struct edf_annotationblock) * (edfhdr->annotlist_sz + EDFLIB_ANNOT_MEMBLOCKSZ)); + malloc_list = (edf_read_annotationblock_t *)realloc(annotationslist[hdl], + sizeof(edf_read_annotationblock_t) * (edfhdr->annotlist_sz + EDFLIB_ANNOT_MEMBLOCKSZ)); if(malloc_list==NULL) { free(cnv_buf); @@ -3191,13 +3157,31 @@ static int edflib_get_annotations(struct edfhdrblock *edfhdr, int hdl, int read_ new_annotation->annotation[0] = 0; - if(duration) edflib_strlcpy(new_annotation->duration, duration_in_txt, 16); - else new_annotation->duration[0] = 0; + if(duration) + { + edflib_strlcpy(new_annotation->duration, duration_in_txt, 20); + new_annotation->duration_l = edflib_get_long_time(duration_in_txt); + } + else + { + new_annotation->duration[0] = 0; + new_annotation->duration_l = -EDFLIB_TIME_DIMENSION; + } for(j=0; jannotation[j] = scratchpad[j]; + if((((unsigned char *)new_annotation->annotation)[j] < 32) || (((unsigned char *)new_annotation->annotation)[j] == 127)) + { + if((new_annotation->annotation[j] != '\t') && + (new_annotation->annotation[j] != '\n') && + (new_annotation->annotation[j] != '\r')) + { + error = 38; /* non-printable characters in description string */ + goto END; + } + } } new_annotation->annotation[j] = 0; @@ -3207,7 +3191,7 @@ static int edflib_get_annotations(struct edfhdrblock *edfhdr, int hdl, int read_ edfhdr->annots_in_file++; - if(read_annotations==EDFLIB_READ_ANNOTATIONS) + if(read_annotations_mode==EDFLIB_READ_ANNOTATIONS) { if(!(strncmp(new_annotation->annotation, "Recording ends", 14))) { @@ -3285,6 +3269,8 @@ static int edflib_get_annotations(struct edfhdrblock *edfhdr, int hdl, int read_ } } + END_OUT: + free(cnv_buf); free(scratchpad); free(time_in_txt); @@ -3321,7 +3307,6 @@ static int edflib_is_duration_number(char *str) } - static int edflib_is_onset_number(char *str) { int i, l, hasdot = 0; @@ -3351,7 +3336,6 @@ static int edflib_is_onset_number(char *str) } - static long long edflib_get_long_time(char *str) { int i, len, hasdot=0, dotposition=0, neg=0; @@ -3417,8 +3401,12 @@ static long long edflib_get_long_time(char *str) static void edflib_latin1_to_ascii(char *str, int len) { + /* ISO 8859-1 except for characters 0x80 to 0x9f which are taken from the extension CP-1252 */ + int i, value; + const char conv_table[]=".E.,F\".++^.Se.zY.i....|....<...-....\'u.....>...?AAAAAAECEEEEIIIIDNOOOOOxOUUUUYtsaaaaaaeceeeeiiiidnooooo:0uuuuyty"; + for(i=0; i=EDFLIB_MAXFILES) + handle = edfopen_file_writeonly(path, filetype, number_of_signals); + if(handle < 0) { - return EDFLIB_MAXFILES_REACHED; + return handle; } - for(i=0; ipath))) - { - return EDFLIB_FILE_ALREADY_OPENED; - } + edfclose_file(handle); + return -1; + } + + if(edf_set_physical_maximum(handle, i, phys_max_min)) + { + edfclose_file(handle); + return -1; + } + + if(edf_set_physical_minimum(handle, i, -phys_max_min)) + { + edfclose_file(handle); + return -1; + } + + if(edf_set_physical_dimension(handle, i, phys_dim)) + { + edfclose_file(handle); + return -1; + } + + snprintf(str, 32, "chan. %i", i + 1); + + if(edf_set_label(handle, i, str)) + { + edfclose_file(handle); + return -1; + } + + if(filetype == EDFLIB_FILETYPE_BDFPLUS) + { + if(edf_set_digital_maximum(handle, i, 0x7fffff)) + { + edfclose_file(handle); + return -1; + } + + if(edf_set_digital_minimum(handle, i, -0x800000)) + { + edfclose_file(handle); + return -1; + } + } + else + { + if(edf_set_digital_maximum(handle, i, 0x7fff)) + { + edfclose_file(handle); + return -1; + } + + if(edf_set_digital_minimum(handle, i, -0x8000)) + { + edfclose_file(handle); + return -1; + } + } + } + + return handle; +} + + +EDFLIB_API int edfopen_file_writeonly(const char *path, int filetype, int number_of_signals) +{ + int i, handle; + + FILE *file; + + edfhdrblock_t *hdr; + + union + { + char four[4]; + int one; + } byte_order_test_var; + + /* avoid surprises! */ + if((sizeof(char) != 1) || + (sizeof(short) != 2) || + (sizeof(int) != 4) || + (sizeof(long long) != 8) || + (sizeof(float) != 4) || + (sizeof(double) != 8)) + { + return EDFLIB_ARCH_ERROR; + } + + /* check endianness! */ + byte_order_test_var.one = 0x03020100; + if((byte_order_test_var.four[0] != 0) || + (byte_order_test_var.four[1] != 1) || + (byte_order_test_var.four[2] != 2) || + (byte_order_test_var.four[3] != 3)) + { + return EDFLIB_ARCH_ERROR; + } + + if((filetype!=EDFLIB_FILETYPE_EDFPLUS)&&(filetype!=EDFLIB_FILETYPE_BDFPLUS)) + { + return EDFLIB_FILETYPE_ERROR; + } + + if(edf_files_open>=EDFLIB_MAXFILES) + { + return EDFLIB_MAXFILES_REACHED; + } + + for(i=0; ipath))) + { + return EDFLIB_FILE_ALREADY_OPENED; + } } } @@ -3720,13 +3626,13 @@ int edfopen_file_writeonly(const char *path, int filetype, int number_of_signals return EDFLIB_NUMBER_OF_SIGNALS_INVALID; } - hdr = (struct edfhdrblock *)calloc(1, sizeof(struct edfhdrblock)); + hdr = (edfhdrblock_t *)calloc(1, sizeof(edfhdrblock_t)); if(hdr==NULL) { return EDFLIB_MALLOC_ERROR; } - hdr->edfparam = (struct edfparamblock *)calloc(1, sizeof(struct edfparamblock) * number_of_signals); + hdr->edfparam = (edfparamblock_t *)calloc(1, sizeof(edfparamblock_t) * number_of_signals); if(hdr->edfparam==NULL) { free(hdr); @@ -3789,80 +3695,39 @@ int edfopen_file_writeonly(const char *path, int filetype, int number_of_signals { hdr->edf = 1; hdr->edfplus = 1; - hdr->nr_annot_chns = 1; - - } - - if(filetype==EDFLIB_FILETYPE_EDF) - { - hdr->edf = 1; - hdr->edfplus = 0; - hdr->nr_annot_chns = 0; } if(filetype==EDFLIB_FILETYPE_BDFPLUS) { hdr->bdf = 1; hdr->bdfplus = 1; - hdr->nr_annot_chns = 1; - } - - if(filetype==EDFLIB_FILETYPE_BDF) - { - hdr->bdf = 1; - hdr->bdfplus = 0; - hdr->nr_annot_chns = 0; } hdr->long_data_record_duration = EDFLIB_TIME_DIMENSION; hdr->data_record_duration = 1.0; + hdr->nr_annot_chns = 1; + return handle; } -int edf_set_samplefrequency(int handle, int edfsignal, int samplefrequency) +EDFLIB_API int edf_set_samplefrequency(int handle, int edfsignal, int samplefrequency) { - if(handle<0) - { - return -1; - } - - if(handle>=EDFLIB_MAXFILES) - { - return -1; - } + if((handle<0)||(handle>=EDFLIB_MAXFILES)) return -1; - if(hdrlist[handle]==NULL) - { - return -1; - } + if(hdrlist[handle]==NULL) return -1; - if(!(hdrlist[handle]->writemode)) - { - return -1; - } + if(edfsignal<0) return -1; - if(edfsignal<0) - { - return -1; - } + if(!hdrlist[handle]->writemode) return -1; - if(edfsignal>=hdrlist[handle]->edfsignals) - { - return -1; - } + if(edfsignal>=hdrlist[handle]->edfsignals) return -1; - if(samplefrequency<1) - { - return -1; - } + if(samplefrequency<1) return -1; - if(hdrlist[handle]->datarecords) - { - return -1; - } + if(hdrlist[handle]->datarecords) return -1; hdrlist[handle]->edfparam[edfsignal].smp_per_record = samplefrequency; @@ -3870,37 +3735,17 @@ int edf_set_samplefrequency(int handle, int edfsignal, int samplefrequency) } -int edf_set_number_of_annotation_signals(int handle, int annot_signals) +EDFLIB_API int edf_set_number_of_annotation_signals(int handle, int annot_signals) { - if(handle<0) - { - return -1; - } - - if(handle>=EDFLIB_MAXFILES) - { - return -1; - } + if((handle<0)||(handle>=EDFLIB_MAXFILES)) return -1; - if(hdrlist[handle]==NULL) - { - return -1; - } + if(hdrlist[handle]==NULL) return -1; - if(!(hdrlist[handle]->writemode)) - { - return -1; - } + if(!hdrlist[handle]->writemode) return -1; - if(hdrlist[handle]->datarecords) - { - return -1; - } + if(hdrlist[handle]->datarecords) return -1; - if((annot_signals < 1) || (annot_signals > EDFLIB_MAX_ANNOTATION_CHANNELS)) - { - return -1; - } + if((annot_signals < 1) || (annot_signals > EDFLIB_MAX_ANNOTATION_CHANNELS)) return -1; hdrlist[handle]->nr_annot_chns = annot_signals; @@ -3908,37 +3753,17 @@ int edf_set_number_of_annotation_signals(int handle, int annot_signals) } -int edf_set_datarecord_duration(int handle, int duration) +EDFLIB_API int edf_set_datarecord_duration(int handle, int duration) { - if(handle<0) - { - return -1; - } + if((handle<0)||(handle>=EDFLIB_MAXFILES)) return -1; - if(handle>=EDFLIB_MAXFILES) - { - return -1; - } - - if(hdrlist[handle]==NULL) - { - return -1; - } + if(hdrlist[handle]==NULL) return -1; - if(!(hdrlist[handle]->writemode)) - { - return -1; - } + if(!hdrlist[handle]->writemode) return -1; - if(hdrlist[handle]->datarecords) - { - return -1; - } + if(hdrlist[handle]->datarecords) return -1; - if((duration < 100) || (duration > 6000000)) - { - return -1; - } + if((duration < 100) || (duration > 6000000)) return -1; hdrlist[handle]->long_data_record_duration = (long long)duration * 100LL; @@ -3961,37 +3786,17 @@ int edf_set_datarecord_duration(int handle, int duration) } -int edf_set_micro_datarecord_duration(int handle, int duration) +EDFLIB_API int edf_set_micro_datarecord_duration(int handle, int duration) { - if(handle<0) - { - return -1; - } - - if(handle>=EDFLIB_MAXFILES) - { - return -1; - } + if((handle<0)||(handle>=EDFLIB_MAXFILES)) return -1; - if(hdrlist[handle]==NULL) - { - return -1; - } + if(hdrlist[handle]==NULL) return -1; - if(!(hdrlist[handle]->writemode)) - { - return -1; - } + if(!hdrlist[handle]->writemode) return -1; - if(hdrlist[handle]->datarecords) - { - return -1; - } + if(hdrlist[handle]->datarecords) return -1; - if((duration < 1) || (duration > 9999)) - { - return -1; - } + if((duration < 1) || (duration > 9999)) return -1; hdrlist[handle]->long_data_record_duration = (long long)duration * 10LL; @@ -4001,37 +3806,17 @@ int edf_set_micro_datarecord_duration(int handle, int duration) } -int edf_set_subsecond_starttime(int handle, int subsecond) +EDFLIB_API int edf_set_subsecond_starttime(int handle, int subsecond) { - if(handle<0) - { - return -1; - } + if((handle<0)||(handle>=EDFLIB_MAXFILES)) return -1; - if(handle>=EDFLIB_MAXFILES) - { - return -1; - } - - if(hdrlist[handle]==NULL) - { - return -1; - } + if(hdrlist[handle]==NULL) return -1; - if(!(hdrlist[handle]->writemode)) - { - return -1; - } + if(!hdrlist[handle]->writemode) return -1; - if(hdrlist[handle]->datarecords) - { - return -1; - } + if(hdrlist[handle]->datarecords) return -1; - if((subsecond < 0) || (subsecond > 9999999)) - { - return -1; - } + if((subsecond < 0) || (subsecond > 9999999)) return -1; hdrlist[handle]->starttime_offset = (long long)subsecond; @@ -4039,7 +3824,7 @@ int edf_set_subsecond_starttime(int handle, int subsecond) } -int edfwrite_digital_short_samples(int handle, short *buf) +EDFLIB_API int edfwrite_digital_short_samples(int handle, short *buf) { int i, error, @@ -4051,38 +3836,17 @@ int edfwrite_digital_short_samples(int handle, short *buf) FILE *file; - struct edfhdrblock *hdr; + edfhdrblock_t *hdr; + if((handle<0)||(handle>=EDFLIB_MAXFILES)) return -1; - if(handle<0) - { - return -1; - } - - if(handle>=EDFLIB_MAXFILES) - { - return -1; - } + if(hdrlist[handle]==NULL) return -1; - if(hdrlist[handle]==NULL) - { - return -1; - } - - if(!(hdrlist[handle]->writemode)) - { - return -1; - } + if(!hdrlist[handle]->writemode) return -1; - if(hdrlist[handle]->edfsignals == 0) - { - return -1; - } + if(hdrlist[handle]->edfsignals == 0) return -1; - if(hdrlist[handle]->bdf == 1) - { - return -1; - } + if(hdrlist[handle]->bdf == 1) return -1; hdr = hdrlist[handle]; @@ -4096,10 +3860,7 @@ int edfwrite_digital_short_samples(int handle, short *buf) { error = edflib_write_edf_header(hdr); - if(error) - { - return error; - } + if(error) return error; } } @@ -4109,28 +3870,34 @@ int edfwrite_digital_short_samples(int handle, short *buf) digmin = hdr->edfparam[edfsignal].dig_min; + if(hdr->annot_chan_idx_pos == EDF_ANNOT_IDX_POS_START) + { + if(hdr->signal_write_sequence_pos == 0) + { + if(edflib_write_tal(hdr, file)) return -1; + } + } + else if(hdr->annot_chan_idx_pos == EDF_ANNOT_IDX_POS_MIDDLE) + { + if(hdr->signal_write_sequence_pos == (hdr->edfsignals / 2)) + { + if(edflib_write_tal(hdr, file)) return -1; + } + } + if(hdr->edf) { - if((digmax != 32767) || (digmin != -32768)) + if((digmax != 0x7fff) || (digmin != -0x8000)) { for(i=0; idigmax) - { - buf[i] = digmax; - } + if(buf[i]>digmax) buf[i] = digmax; - if(buf[i]wrbuf = (char *)malloc(sf * 3); - if(hdr->wrbuf == NULL) - { - return -1; - } + if(hdr->wrbuf == NULL) return -1; hdr->wrbufsize = sf * 3; - } for(i=0; idigmax) - { - value = digmax; - } + if(value>digmax) value = digmax; - if(valuewrbuf[i * 3] = value & 0xff; @@ -4172,10 +3929,7 @@ int edfwrite_digital_short_samples(int handle, short *buf) hdr->wrbuf[i * 3 + 2] = (value >> 16) & 0xff; } - if(fwrite(hdr->wrbuf, sf * 3, 1, file) != 1) - { - return -1; - } + if(fwrite(hdr->wrbuf, sf * 3, 1, file) != 1) return -1; } hdr->signal_write_sequence_pos++; @@ -4184,9 +3938,9 @@ int edfwrite_digital_short_samples(int handle, short *buf) { hdr->signal_write_sequence_pos = 0; - if(edflib_write_tal(hdr, file)) + if(hdr->annot_chan_idx_pos == EDF_ANNOT_IDX_POS_END) { - return -1; + if(edflib_write_tal(hdr, file)) return -1; } hdr->datarecords++; @@ -4198,7 +3952,7 @@ int edfwrite_digital_short_samples(int handle, short *buf) } -int edfwrite_digital_samples(int handle, int *buf) +EDFLIB_API int edfwrite_digital_samples(int handle, int *buf) { int i, error, @@ -4210,33 +3964,15 @@ int edfwrite_digital_samples(int handle, int *buf) FILE *file; - struct edfhdrblock *hdr; + edfhdrblock_t *hdr; + if((handle<0)||(handle>=EDFLIB_MAXFILES)) return -1; - if(handle<0) - { - return -1; - } + if(hdrlist[handle]==NULL) return -1; - if(handle>=EDFLIB_MAXFILES) - { - return -1; - } + if(!hdrlist[handle]->writemode) return -1; - if(hdrlist[handle]==NULL) - { - return -1; - } - - if(!(hdrlist[handle]->writemode)) - { - return -1; - } - - if(hdrlist[handle]->edfsignals == 0) - { - return -1; - } + if(hdrlist[handle]->edfsignals == 0) return -1; hdr = hdrlist[handle]; @@ -4250,10 +3986,7 @@ int edfwrite_digital_samples(int handle, int *buf) { error = edflib_write_edf_header(hdr); - if(error) - { - return error; - } + if(error) return error; } } @@ -4263,6 +3996,21 @@ int edfwrite_digital_samples(int handle, int *buf) digmin = hdr->edfparam[edfsignal].dig_min; + if(hdr->annot_chan_idx_pos == EDF_ANNOT_IDX_POS_START) + { + if(hdr->signal_write_sequence_pos == 0) + { + if(edflib_write_tal(hdr, file)) return -1; + } + } + else if(hdr->annot_chan_idx_pos == EDF_ANNOT_IDX_POS_MIDDLE) + { + if(hdr->signal_write_sequence_pos == (hdr->edfsignals / 2)) + { + if(edflib_write_tal(hdr, file)) return -1; + } + } + if(hdr->edf) { if(hdr->wrbufsize < (sf * 2)) @@ -4273,10 +4021,7 @@ int edfwrite_digital_samples(int handle, int *buf) hdr->wrbuf = (char *)malloc(sf * 2); - if(hdr->wrbuf == NULL) - { - return -1; - } + if(hdr->wrbuf == NULL) return -1; hdr->wrbufsize = sf * 2; } @@ -4285,25 +4030,16 @@ int edfwrite_digital_samples(int handle, int *buf) { value = buf[i]; - if(value>digmax) - { - value = digmax; - } + if(value>digmax) value = digmax; - if(valuewrbuf[i * 2] = value & 0xff; hdr->wrbuf[i * 2 + 1] = (value >> 8) & 0xff; } - if(fwrite(hdr->wrbuf, sf * 2, 1, file) != 1) - { - return -1; - } + if(fwrite(hdr->wrbuf, sf * 2, 1, file) != 1) return -1; } else // BDF { @@ -4315,10 +4051,7 @@ int edfwrite_digital_samples(int handle, int *buf) hdr->wrbuf = (char *)malloc(sf * 3); - if(hdr->wrbuf == NULL) - { - return -1; - } + if(hdr->wrbuf == NULL) return -1; hdr->wrbufsize = sf * 3; } @@ -4327,28 +4060,18 @@ int edfwrite_digital_samples(int handle, int *buf) { value = buf[i]; - if(value>digmax) - { - value = digmax; - } + if(value>digmax) value = digmax; - if(valuewrbuf[i * 3] = value & 0xff; hdr->wrbuf[i * 3 + 1] = (value >> 8) & 0xff; hdr->wrbuf[i * 3 + 2] = (value >> 16) & 0xff; - } - if(fwrite(hdr->wrbuf, sf * 3, 1, file) != 1) - { - return -1; - } + if(fwrite(hdr->wrbuf, sf * 3, 1, file) != 1) return -1; } hdr->signal_write_sequence_pos++; @@ -4357,9 +4080,9 @@ int edfwrite_digital_samples(int handle, int *buf) { hdr->signal_write_sequence_pos = 0; - if(edflib_write_tal(hdr, file)) + if(hdr->annot_chan_idx_pos == EDF_ANNOT_IDX_POS_END) { - return -1; + if(edflib_write_tal(hdr, file)) return -1; } hdr->datarecords++; @@ -4371,7 +4094,7 @@ int edfwrite_digital_samples(int handle, int *buf) } -int edf_blockwrite_digital_samples(int handle, int *buf) +EDFLIB_API int edf_blockwrite_digital_samples(int handle, int *buf) { int i, j, error, @@ -4384,38 +4107,17 @@ int edf_blockwrite_digital_samples(int handle, int *buf) FILE *file; - struct edfhdrblock *hdr; + edfhdrblock_t *hdr; + if((handle<0)||(handle>=EDFLIB_MAXFILES)) return -1; - if(handle<0) - { - return -1; - } - - if(handle>=EDFLIB_MAXFILES) - { - return -1; - } - - if(hdrlist[handle]==NULL) - { - return -1; - } + if(hdrlist[handle]==NULL) return -1; - if(!(hdrlist[handle]->writemode)) - { - return -1; - } + if(!hdrlist[handle]->writemode) return -1; - if(hdrlist[handle]->signal_write_sequence_pos) - { - return -1; - } + if(hdrlist[handle]->edfsignals == 0) return -1; - if(hdrlist[handle]->edfsignals == 0) - { - return -1; - } + if(hdrlist[handle]->signal_write_sequence_pos) return -1; hdr = hdrlist[handle]; @@ -4427,15 +4129,15 @@ int edf_blockwrite_digital_samples(int handle, int *buf) { error = edflib_write_edf_header(hdr); - if(error) - { - return error; - } + if(error) return error; } - buf_offset = 0; + if(hdr->annot_chan_idx_pos == EDF_ANNOT_IDX_POS_START) + { + if(edflib_write_tal(hdr, file)) return -1; + } - for(j=0; jedfparam[j].smp_per_record; @@ -4443,6 +4145,14 @@ int edf_blockwrite_digital_samples(int handle, int *buf) digmin = hdr->edfparam[j].dig_min; + if(hdr->annot_chan_idx_pos == EDF_ANNOT_IDX_POS_MIDDLE) + { + if(j == (edfsignals / 2)) + { + if(edflib_write_tal(hdr, file)) return -1; + } + } + if(hdr->edf) { if(hdr->wrbufsize < (sf * 2)) @@ -4453,10 +4163,7 @@ int edf_blockwrite_digital_samples(int handle, int *buf) hdr->wrbuf = (char *)malloc(sf * 2); - if(hdr->wrbuf == NULL) - { - return -1; - } + if(hdr->wrbuf == NULL) return -1; hdr->wrbufsize = sf * 2; } @@ -4465,25 +4172,16 @@ int edf_blockwrite_digital_samples(int handle, int *buf) { value = buf[i + buf_offset]; - if(value>digmax) - { - value = digmax; - } + if(value>digmax) value = digmax; - if(valuewrbuf[i * 2] = value & 0xff; hdr->wrbuf[i * 2 + 1] = (value >> 8) & 0xff; } - if(fwrite(hdr->wrbuf, sf * 2, 1, file) != 1) - { - return -1; - } + if(fwrite(hdr->wrbuf, sf * 2, 1, file) != 1) return -1; } else // BDF { @@ -4495,10 +4193,7 @@ int edf_blockwrite_digital_samples(int handle, int *buf) hdr->wrbuf = (char *)malloc(sf * 3); - if(hdr->wrbuf == NULL) - { - return -1; - } + if(hdr->wrbuf == NULL) return -1; hdr->wrbufsize = sf * 3; } @@ -4507,15 +4202,9 @@ int edf_blockwrite_digital_samples(int handle, int *buf) { value = buf[i + buf_offset]; - if(value>digmax) - { - value = digmax; - } + if(value>digmax) value = digmax; - if(valuewrbuf[i * 3] = value & 0xff; @@ -4524,18 +4213,15 @@ int edf_blockwrite_digital_samples(int handle, int *buf) hdr->wrbuf[i * 3 + 2] = (value >> 16) & 0xff; } - if(fwrite(hdr->wrbuf, sf * 3, 1, file) != 1) - { - return -1; - } + if(fwrite(hdr->wrbuf, sf * 3, 1, file) != 1) return -1; } buf_offset += sf; } - if(edflib_write_tal(hdr, file)) + if(hdr->annot_chan_idx_pos == EDF_ANNOT_IDX_POS_END) { - return -1; + if(edflib_write_tal(hdr, file)) return -1; } hdr->datarecords++; @@ -4546,7 +4232,7 @@ int edf_blockwrite_digital_samples(int handle, int *buf) } -int edf_blockwrite_digital_short_samples(int handle, short *buf) +EDFLIB_API int edf_blockwrite_digital_short_samples(int handle, short *buf) { int i, j, error, @@ -4559,43 +4245,19 @@ int edf_blockwrite_digital_short_samples(int handle, short *buf) FILE *file; - struct edfhdrblock *hdr; - - - if(handle<0) - { - return -1; - } + edfhdrblock_t *hdr; - if(handle>=EDFLIB_MAXFILES) - { - return -1; - } + if((handle<0)||(handle>=EDFLIB_MAXFILES)) return -1; - if(hdrlist[handle]==NULL) - { - return -1; - } + if(hdrlist[handle]==NULL) return -1; - if(!(hdrlist[handle]->writemode)) - { - return -1; - } + if(!hdrlist[handle]->writemode) return -1; - if(hdrlist[handle]->signal_write_sequence_pos) - { - return -1; - } + if(hdrlist[handle]->edfsignals == 0) return -1; - if(hdrlist[handle]->edfsignals == 0) - { - return -1; - } + if(hdrlist[handle]->signal_write_sequence_pos) return -1; - if(hdrlist[handle]->bdf == 1) - { - return -1; - } + if(hdrlist[handle]->bdf == 1) return -1; hdr = hdrlist[handle]; @@ -4613,9 +4275,12 @@ int edf_blockwrite_digital_short_samples(int handle, short *buf) } } - buf_offset = 0; + if(hdr->annot_chan_idx_pos == EDF_ANNOT_IDX_POS_START) + { + if(edflib_write_tal(hdr, file)) return -1; + } - for(j=0; jedfparam[j].smp_per_record; @@ -4623,9 +4288,17 @@ int edf_blockwrite_digital_short_samples(int handle, short *buf) digmin = hdr->edfparam[j].dig_min; + if(hdr->annot_chan_idx_pos == EDF_ANNOT_IDX_POS_MIDDLE) + { + if(j == (edfsignals / 2)) + { + if(edflib_write_tal(hdr, file)) return -1; + } + } + if(hdr->edf) { - if((digmax != 32767) || (digmin != -32768)) + if((digmax != 0x7fff) || (digmin != -0x8000)) { for(i=0; iwrbuf = (char *)malloc(sf * 3); - if(hdr->wrbuf == NULL) - { - return -1; - } + if(hdr->wrbuf == NULL) return -1; hdr->wrbufsize = sf * 3; } @@ -4668,15 +4335,9 @@ int edf_blockwrite_digital_short_samples(int handle, short *buf) { value = buf[i + buf_offset]; - if(value>digmax) - { - value = digmax; - } + if(value>digmax) value = digmax; - if(valuewrbuf[i * 3] = value & 0xff; @@ -4685,18 +4346,15 @@ int edf_blockwrite_digital_short_samples(int handle, short *buf) hdr->wrbuf[i * 3 + 2] = (value >> 16) & 0xff; } - if(fwrite(hdr->wrbuf, sf * 3, 1, file) != 1) - { - return -1; - } + if(fwrite(hdr->wrbuf, sf * 3, 1, file) != 1) return -1; } buf_offset += sf; } - if(edflib_write_tal(hdr, file)) + if(hdr->annot_chan_idx_pos == EDF_ANNOT_IDX_POS_END) { - return -1; + if(edflib_write_tal(hdr, file)) return -1; } hdr->datarecords++; @@ -4707,52 +4365,29 @@ int edf_blockwrite_digital_short_samples(int handle, short *buf) } -int edf_blockwrite_digital_3byte_samples(int handle, void *buf) +EDFLIB_API int edf_blockwrite_digital_3byte_samples(int handle, void *buf) { int j, error, edfsignals, - total_samples=0; + total_samples, + mid_samples; FILE *file; - struct edfhdrblock *hdr; - + edfhdrblock_t *hdr; - if(handle<0) - { - return -1; - } - - if(handle>=EDFLIB_MAXFILES) - { - return -1; - } + if((handle<0)||(handle>=EDFLIB_MAXFILES)) return -1; - if(hdrlist[handle]==NULL) - { - return -1; - } + if(hdrlist[handle]==NULL) return -1; - if(!(hdrlist[handle]->writemode)) - { - return -1; - } + if(!hdrlist[handle]->writemode) return -1; - if(hdrlist[handle]->signal_write_sequence_pos) - { - return -1; - } + if(hdrlist[handle]->edfsignals == 0) return -1; - if(hdrlist[handle]->edfsignals == 0) - { - return -1; - } + if(hdrlist[handle]->signal_write_sequence_pos) return -1; - if(hdrlist[handle]->bdf != 1) - { - return -1; - } + if(hdrlist[handle]->bdf != 1) return -1; hdr = hdrlist[handle]; @@ -4764,25 +4399,49 @@ int edf_blockwrite_digital_3byte_samples(int handle, void *buf) { error = edflib_write_edf_header(hdr); - if(error) - { - return error; - } + if(error) return error; + } + + if(hdr->annot_chan_idx_pos == EDF_ANNOT_IDX_POS_START) + { + if(edflib_write_tal(hdr, file)) return -1; } - for(j=0; jedfparam[j].smp_per_record; + + if(j < (edfsignals / 2)) mid_samples = total_samples; } - if(fwrite(buf, total_samples * 3, 1, file) != 1) + if(hdr->annot_chan_idx_pos == EDF_ANNOT_IDX_POS_MIDDLE) { - return -1; + if(mid_samples) + { + if(fwrite(buf, mid_samples * 3, 1, file) != 1) return -1; + + if(edflib_write_tal(hdr, file)) return -1; + + if(total_samples > mid_samples) + { + if(fwrite(((unsigned char *)buf) + (mid_samples * 3), (total_samples - mid_samples) * 3, 1, file) != 1) return -1; + } + } + else + { + if(edflib_write_tal(hdr, file)) return -1; + + if(fwrite(buf, total_samples * 3, 1, file) != 1) return -1; + } + } + else + { + if(fwrite(buf, total_samples * 3, 1, file) != 1) return -1; } - if(edflib_write_tal(hdr, file)) + if(hdr->annot_chan_idx_pos == EDF_ANNOT_IDX_POS_END) { - return -1; + if(edflib_write_tal(hdr, file)) return -1; } hdr->datarecords++; @@ -4793,7 +4452,7 @@ int edf_blockwrite_digital_3byte_samples(int handle, void *buf) } -int edfwrite_physical_samples(int handle, double *buf) +EDFLIB_API int edfwrite_physical_samples(int handle, double *buf) { int i, error, @@ -4808,33 +4467,15 @@ int edfwrite_physical_samples(int handle, double *buf) FILE *file; - struct edfhdrblock *hdr; - - - if(handle<0) - { - return -1; - } + edfhdrblock_t *hdr; - if(handle>=EDFLIB_MAXFILES) - { - return -1; - } + if((handle<0)||(handle>=EDFLIB_MAXFILES)) return -1; - if(hdrlist[handle]==NULL) - { - return -1; - } + if(hdrlist[handle]==NULL) return -1; - if(!(hdrlist[handle]->writemode)) - { - return -1; - } + if(!hdrlist[handle]->writemode) return -1; - if(hdrlist[handle]->edfsignals == 0) - { - return -1; - } + if(hdrlist[handle]->edfsignals == 0) return -1; hdr = hdrlist[handle]; @@ -4848,10 +4489,7 @@ int edfwrite_physical_samples(int handle, double *buf) { error = edflib_write_edf_header(hdr); - if(error) - { - return error; - } + if(error) return error; } } @@ -4865,6 +4503,21 @@ int edfwrite_physical_samples(int handle, double *buf) phys_offset = hdr->edfparam[edfsignal].offset; + if(hdr->annot_chan_idx_pos == EDF_ANNOT_IDX_POS_START) + { + if(hdr->signal_write_sequence_pos == 0) + { + if(edflib_write_tal(hdr, file)) return -1; + } + } + else if(hdr->annot_chan_idx_pos == EDF_ANNOT_IDX_POS_MIDDLE) + { + if(hdr->signal_write_sequence_pos == (hdr->edfsignals / 2)) + { + if(edflib_write_tal(hdr, file)) return -1; + } + } + if(hdr->edf) { if(hdr->wrbufsize < (sf * 2)) @@ -4875,10 +4528,7 @@ int edfwrite_physical_samples(int handle, double *buf) hdr->wrbuf = (char *)malloc(sf * 2); - if(hdr->wrbuf == NULL) - { - return -1; - } + if(hdr->wrbuf == NULL) return -1; hdr->wrbufsize = sf * 2; } @@ -4887,25 +4537,16 @@ int edfwrite_physical_samples(int handle, double *buf) { value = (buf[i] / bitvalue) - phys_offset; - if(value>digmax) - { - value = digmax; - } + if(value>digmax) value = digmax; - if(valuewrbuf[i * 2] = value & 0xff; hdr->wrbuf[i * 2 + 1] = (value >> 8) & 0xff; } - if(fwrite(hdr->wrbuf, sf * 2, 1, file) != 1) - { - return -1; - } + if(fwrite(hdr->wrbuf, sf * 2, 1, file) != 1) return -1; } else // BDF { @@ -4917,10 +4558,7 @@ int edfwrite_physical_samples(int handle, double *buf) hdr->wrbuf = (char *)malloc(sf * 3); - if(hdr->wrbuf == NULL) - { - return -1; - } + if(hdr->wrbuf == NULL) return -1; hdr->wrbufsize = sf * 3; } @@ -4929,15 +4567,9 @@ int edfwrite_physical_samples(int handle, double *buf) { value = (buf[i] / bitvalue) - phys_offset; - if(value>digmax) - { - value = digmax; - } + if(value>digmax) value = digmax; - if(valuewrbuf[i * 3] = value & 0xff; @@ -4946,10 +4578,7 @@ int edfwrite_physical_samples(int handle, double *buf) hdr->wrbuf[i * 3 + 2] = (value >> 16) & 0xff; } - if(fwrite(hdr->wrbuf, sf * 3, 1, file) != 1) - { - return -1; - } + if(fwrite(hdr->wrbuf, sf * 3, 1, file) != 1) return -1; } hdr->signal_write_sequence_pos++; @@ -4958,9 +4587,9 @@ int edfwrite_physical_samples(int handle, double *buf) { hdr->signal_write_sequence_pos = 0; - if(edflib_write_tal(hdr, file)) + if(hdr->annot_chan_idx_pos == EDF_ANNOT_IDX_POS_END) { - return -1; + if(edflib_write_tal(hdr, file)) return -1; } hdr->datarecords++; @@ -4972,7 +4601,7 @@ int edfwrite_physical_samples(int handle, double *buf) } -int edf_blockwrite_physical_samples(int handle, double *buf) +EDFLIB_API int edf_blockwrite_physical_samples(int handle, double *buf) { int i, j, error, @@ -4988,38 +4617,17 @@ int edf_blockwrite_physical_samples(int handle, double *buf) FILE *file; - struct edfhdrblock *hdr; - - - if(handle<0) - { - return -1; - } + edfhdrblock_t *hdr; - if(handle>=EDFLIB_MAXFILES) - { - return -1; - } + if((handle<0)||(handle>=EDFLIB_MAXFILES)) return -1; - if(hdrlist[handle]==NULL) - { - return -1; - } + if(hdrlist[handle]==NULL) return -1; - if(!(hdrlist[handle]->writemode)) - { - return -1; - } + if(!hdrlist[handle]->writemode) return -1; - if(hdrlist[handle]->signal_write_sequence_pos) - { - return -1; - } + if(hdrlist[handle]->edfsignals == 0) return -1; - if(hdrlist[handle]->edfsignals == 0) - { - return -1; - } + if(hdrlist[handle]->signal_write_sequence_pos) return -1; hdr = hdrlist[handle]; @@ -5031,15 +4639,15 @@ int edf_blockwrite_physical_samples(int handle, double *buf) { error = edflib_write_edf_header(hdr); - if(error) - { - return error; - } + if(error) return error; } - buf_offset = 0; + if(hdr->annot_chan_idx_pos == EDF_ANNOT_IDX_POS_START) + { + if(edflib_write_tal(hdr, file)) return -1; + } - for(j=0; jedfparam[j].smp_per_record; @@ -5051,6 +4659,14 @@ int edf_blockwrite_physical_samples(int handle, double *buf) phys_offset = hdr->edfparam[j].offset; + if(hdr->annot_chan_idx_pos == EDF_ANNOT_IDX_POS_MIDDLE) + { + if(j == (edfsignals / 2)) + { + if(edflib_write_tal(hdr, file)) return -1; + } + } + if(hdr->edf) { if(hdr->wrbufsize < (sf * 2)) @@ -5061,10 +4677,7 @@ int edf_blockwrite_physical_samples(int handle, double *buf) hdr->wrbuf = (char *)malloc(sf * 2); - if(hdr->wrbuf == NULL) - { - return -1; - } + if(hdr->wrbuf == NULL) return -1; hdr->wrbufsize = sf * 2; } @@ -5073,25 +4686,16 @@ int edf_blockwrite_physical_samples(int handle, double *buf) { value = (buf[i + buf_offset] / bitvalue) - phys_offset; - if(value>digmax) - { - value = digmax; - } + if(value>digmax) value = digmax; - if(valuewrbuf[i * 2] = value & 0xff; hdr->wrbuf[i * 2 + 1] = (value >> 8) & 0xff; } - if(fwrite(hdr->wrbuf, sf * 2, 1, file) != 1) - { - return -1; - } + if(fwrite(hdr->wrbuf, sf * 2, 1, file) != 1) return -1; } else // BDF { @@ -5103,10 +4707,7 @@ int edf_blockwrite_physical_samples(int handle, double *buf) hdr->wrbuf = (char *)malloc(sf * 3); - if(hdr->wrbuf == NULL) - { - return -1; - } + if(hdr->wrbuf == NULL) return -1; hdr->wrbufsize = sf * 3; } @@ -5115,15 +4716,9 @@ int edf_blockwrite_physical_samples(int handle, double *buf) { value = (buf[i + buf_offset] / bitvalue) - phys_offset; - if(value>digmax) - { - value = digmax; - } + if(value>digmax) value = digmax; - if(valuewrbuf[i * 3] = value & 0xff; @@ -5132,18 +4727,15 @@ int edf_blockwrite_physical_samples(int handle, double *buf) hdr->wrbuf[i * 3 + 2] = (value >> 16) & 0xff; } - if(fwrite(hdr->wrbuf, sf * 3, 1, file) != 1) - { - return -1; - } + if(fwrite(hdr->wrbuf, sf * 3, 1, file) != 1) return -1; } buf_offset += sf; } - if(edflib_write_tal(hdr, file)) + if(hdr->annot_chan_idx_pos == EDF_ANNOT_IDX_POS_END) { - return -1; + if(edflib_write_tal(hdr, file)) return -1; } hdr->datarecords++; @@ -5154,7 +4746,7 @@ int edf_blockwrite_physical_samples(int handle, double *buf) } -static int edflib_write_edf_header(struct edfhdrblock *hdr) +static int edflib_write_edf_header(edfhdrblock_t *hdr) { int i, j, p, q, len, @@ -5169,20 +4761,13 @@ static int edflib_write_edf_header(struct edfhdrblock *hdr) FILE *file; - file = hdr->file_hdl; edfsignals = hdr->edfsignals; - if(edfsignals<0) - { - return EDFLIB_NO_SIGNALS; - } + if(edfsignals<0) return EDFLIB_NO_SIGNALS; - if(edfsignals>EDFLIB_MAXSIGNALS) - { - return EDFLIB_TOO_MANY_SIGNALS; - } + if(edfsignals>EDFLIB_MAXSIGNALS) return EDFLIB_TOO_MANY_SIGNALS; hdr->eq_sf = 1; @@ -5192,31 +4777,16 @@ static int edflib_write_edf_header(struct edfhdrblock *hdr) for(i=0; iedfplus || hdr->bdfplus) - { - if(hdr->edfparam[i].smp_per_record<1) - { - return EDFLIB_NO_SAMPLES_IN_RECORD ; - } + if(hdr->edfparam[i].smp_per_record<1) return EDFLIB_NO_SAMPLES_IN_RECORD; - if(hdr->edfparam[i].dig_max==hdr->edfparam[i].dig_min) - { - return EDFLIB_DIGMIN_IS_DIGMAX; - } + if(hdr->edfparam[i].dig_max==hdr->edfparam[i].dig_min) return EDFLIB_DIGMIN_IS_DIGMAX; - if(hdr->edfparam[i].dig_maxedfparam[i].dig_min) - { - return EDFLIB_DIGMAX_LOWER_THAN_DIGMIN; - } + if(hdr->edfparam[i].dig_maxedfparam[i].dig_min) return EDFLIB_DIGMAX_LOWER_THAN_DIGMIN; - if(hdr->edfparam[i].phys_max==hdr->edfparam[i].phys_min) - { - return EDFLIB_PHYSMIN_IS_PHYSMAX; - } + if(hdr->edfparam[i].phys_max==hdr->edfparam[i].phys_min) return EDFLIB_PHYSMIN_IS_PHYSMAX; - hdr->recordsize += hdr->edfparam[i].smp_per_record; + hdr->recordsize += hdr->edfparam[i].smp_per_record; - } if(i > 0) { if(hdr->edfparam[i].smp_per_record != hdr->edfparam[i-1].smp_per_record) @@ -5226,7 +4796,6 @@ static int edflib_write_edf_header(struct edfhdrblock *hdr) } } - if(hdr->edf) { hdr->recordsize *= 2; @@ -5254,16 +4823,8 @@ static int edflib_write_edf_header(struct edfhdrblock *hdr) for(i=0; iedfparam[i].phys_max == hdr->edfparam[i].phys_min) || (hdr->edfparam[i].dig_max == hdr->edfparam[i].dig_min)) - { - hdr->edfparam[i].bitvalue = 1; - hdr->edfparam[i].offset = 0; - } - else - { hdr->edfparam[i].bitvalue = (hdr->edfparam[i].phys_max - hdr->edfparam[i].phys_min) / (hdr->edfparam[i].dig_max - hdr->edfparam[i].dig_min); hdr->edfparam[i].offset = hdr->edfparam[i].phys_max / hdr->edfparam[i].bitvalue - hdr->edfparam[i].dig_max; - } } rewind(file); @@ -5274,8 +4835,7 @@ static int edflib_write_edf_header(struct edfhdrblock *hdr) } else { - fputc(255, file); - fprintf(file, "BIOSEMI"); + fprintf(file, "\xff" "BIOSEMI"); } p = 0; @@ -5318,13 +4878,13 @@ static int edflib_write_edf_header(struct edfhdrblock *hdr) p += fprintf(file, "X "); } - if(hdr->plus_gender[0]=='M') + if(hdr->plus_sex[0]=='M') { fputc('M', file); } else { - if(hdr->plus_gender[0]=='F') + if(hdr->plus_sex[0]=='F') { fputc('F', file); } @@ -5348,7 +4908,7 @@ static int edflib_write_edf_header(struct edfhdrblock *hdr) fputc(hdr->plus_birthdate[0], file); fputc(hdr->plus_birthdate[1], file); fputc('-', file); - q = edflib_atof_nonlocalized(&(hdr->plus_birthdate[3])); + q = edflib_atoi_nonlocalized(&(hdr->plus_birthdate[3])); switch(q) { case 1: fprintf(file, "JAN"); break; @@ -5611,17 +5171,13 @@ static int edflib_write_edf_header(struct edfhdrblock *hdr) { fputc(' ', file); } - if(hdr->edfplus) + if(hdr->edf) { fprintf(file, "EDF+C"); } - else if(hdr->bdfplus) - { - fprintf(file, "BDF+C"); - } else { - fprintf(file, " "); + fprintf(file, "BDF+C"); } for(i=0; i<39; i++) { @@ -5645,8 +5201,39 @@ static int edflib_write_edf_header(struct edfhdrblock *hdr) fputc(' ', file); } + if(hdr->annot_chan_idx_pos == EDF_ANNOT_IDX_POS_START) + { + for(j=0; jnr_annot_chns; j++) + { + if(hdr->edf) + { + fprintf(file, "EDF Annotations "); + } + else + { + fprintf(file, "BDF Annotations "); + } + } + } for(i=0; iannot_chan_idx_pos == EDF_ANNOT_IDX_POS_MIDDLE) + { + if(i == (edfsignals / 2)) + { + for(j=0; jnr_annot_chns; j++) + { + if(hdr->edf) + { + fprintf(file, "EDF Annotations "); + } + else + { + fprintf(file, "BDF Annotations "); + } + } + } + } len = strlen(hdr->edfparam[i].label); edflib_latin1_to_ascii(hdr->edfparam[i].label, len); for(j=0; jnr_annot_chns; j++) + if(hdr->annot_chan_idx_pos == EDF_ANNOT_IDX_POS_END) { - if(hdr->edf) + for(j=0; jnr_annot_chns; j++) { - fprintf(file, "EDF Annotations "); + if(hdr->edf) + { + fprintf(file, "EDF Annotations "); + } + else + { + fprintf(file, "BDF Annotations "); + } } - else + } + if(hdr->annot_chan_idx_pos == EDF_ANNOT_IDX_POS_START) + { + for(j=0; j<(80 * hdr->nr_annot_chns); j++) { - fprintf(file, "BDF Annotations "); + fputc(' ', file); } } for(i=0; iannot_chan_idx_pos == EDF_ANNOT_IDX_POS_MIDDLE) + { + if(i == (edfsignals / 2)) + { + for(j=0; j<(80 * hdr->nr_annot_chns); j++) + { + fputc(' ', file); + } + } + } len = strlen(hdr->edfparam[i].transducer); edflib_latin1_to_ascii(hdr->edfparam[i].transducer, len); for(j=0; jnr_annot_chns; j++) + if(hdr->annot_chan_idx_pos == EDF_ANNOT_IDX_POS_END) { - for(i=0; i<80; i++) + for(j=0; j<(80 * hdr->nr_annot_chns); j++) { fputc(' ', file); } } + if(hdr->annot_chan_idx_pos == EDF_ANNOT_IDX_POS_START) + { + for(j=0; jnr_annot_chns; j++) + { + fprintf(file, " "); + } + } for(i=0; iannot_chan_idx_pos == EDF_ANNOT_IDX_POS_MIDDLE) + { + if(i == (edfsignals / 2)) + { + for(j=0; jnr_annot_chns; j++) + { + fprintf(file, " "); + } + } + } len = strlen(hdr->edfparam[i].physdimension); edflib_latin1_to_ascii(hdr->edfparam[i].physdimension, len); for(j=0; jnr_annot_chns; j++) + if(hdr->annot_chan_idx_pos == EDF_ANNOT_IDX_POS_END) + { + for(j=0; jnr_annot_chns; j++) + { + fprintf(file, " "); + } + } + if(hdr->annot_chan_idx_pos == EDF_ANNOT_IDX_POS_START) { - fprintf(file, " "); + for(j=0; jnr_annot_chns; j++) + { + fprintf(file, "-1 "); + } } for(i=0; iannot_chan_idx_pos == EDF_ANNOT_IDX_POS_MIDDLE) + { + if(i == (edfsignals / 2)) + { + for(j=0; jnr_annot_chns; j++) + { + fprintf(file, "-1 "); + } + } + } p = edflib_snprint_number_nonlocalized(str, hdr->edfparam[i].phys_min, 128); for(; p<8; p++) { @@ -5716,12 +5360,32 @@ static int edflib_write_edf_header(struct edfhdrblock *hdr) str[8] = 0; fprintf(file, "%s", str); } - for(j=0; jnr_annot_chns; j++) + if(hdr->annot_chan_idx_pos == EDF_ANNOT_IDX_POS_END) { - fprintf(file, "-1 "); + for(j=0; jnr_annot_chns; j++) + { + fprintf(file, "-1 "); + } + } + if(hdr->annot_chan_idx_pos == EDF_ANNOT_IDX_POS_START) + { + for(j=0; jnr_annot_chns; j++) + { + fprintf(file, "1 "); + } } for(i=0; iannot_chan_idx_pos == EDF_ANNOT_IDX_POS_MIDDLE) + { + if(i == (edfsignals / 2)) + { + for(j=0; jnr_annot_chns; j++) + { + fprintf(file, "1 "); + } + } + } p = edflib_snprint_number_nonlocalized(str, hdr->edfparam[i].phys_max, 128); for(; p<8; p++) { @@ -5730,50 +5394,141 @@ static int edflib_write_edf_header(struct edfhdrblock *hdr) str[8] = 0; fprintf(file, "%s", str); } - for(j=0; jnr_annot_chns; j++) + if(hdr->annot_chan_idx_pos == EDF_ANNOT_IDX_POS_END) { - fprintf(file, "1 "); + for(j=0; jnr_annot_chns; j++) + { + fprintf(file, "1 "); + } + } + if(hdr->annot_chan_idx_pos == EDF_ANNOT_IDX_POS_START) + { + for(j=0; jnr_annot_chns; j++) + { + if(hdr->edf) + { + fprintf(file, "-32768 "); + } + else + { + fprintf(file, "-8388608"); + } + } } for(i=0; iannot_chan_idx_pos == EDF_ANNOT_IDX_POS_MIDDLE) + { + if(i == (edfsignals / 2)) + { + for(j=0; jnr_annot_chns; j++) + { + if(hdr->edf) + { + fprintf(file, "-32768 "); + } + else + { + fprintf(file, "-8388608"); + } + } + } + } p = edflib_fprint_int_number_nonlocalized(file, hdr->edfparam[i].dig_min, 0, 0); for(; p<8; p++) { fputc(' ', file); } } - for(j=0; jnr_annot_chns; j++) + if(hdr->annot_chan_idx_pos == EDF_ANNOT_IDX_POS_END) { - if(hdr->edf) + for(j=0; jnr_annot_chns; j++) { - fprintf(file, "-32768 "); + if(hdr->edf) + { + fprintf(file, "-32768 "); + } + else + { + fprintf(file, "-8388608"); + } } - else + } + if(hdr->annot_chan_idx_pos == EDF_ANNOT_IDX_POS_START) + { + for(j=0; jnr_annot_chns; j++) { - fprintf(file, "-8388608"); + if(hdr->edf) + { + fprintf(file, "32767 "); + } + else + { + fprintf(file, "8388607 "); + } } } for(i=0; iannot_chan_idx_pos == EDF_ANNOT_IDX_POS_MIDDLE) + { + if(i == (edfsignals / 2)) + { + for(j=0; jnr_annot_chns; j++) + { + if(hdr->edf) + { + fprintf(file, "32767 "); + } + else + { + fprintf(file, "8388607 "); + } + } + } + } p = edflib_fprint_int_number_nonlocalized(file, hdr->edfparam[i].dig_max, 0, 0); for(; p<8; p++) { fputc(' ', file); } } - for(j=0; jnr_annot_chns; j++) + if(hdr->annot_chan_idx_pos == EDF_ANNOT_IDX_POS_END) { - if(hdr->edf) + for(j=0; jnr_annot_chns; j++) { - fprintf(file, "32767 "); + if(hdr->edf) + { + fprintf(file, "32767 "); + } + else + { + fprintf(file, "8388607 "); + } } - else + } + if(hdr->annot_chan_idx_pos == EDF_ANNOT_IDX_POS_START) + { + for(i=0; inr_annot_chns; i++) { - fprintf(file, "8388607 "); + for(j=0; j<80; j++) + { + fputc(' ', file); + } } } for(i=0; iannot_chan_idx_pos == EDF_ANNOT_IDX_POS_MIDDLE) + { + if(i == (edfsignals / 2)) + { + for(j=0; j<(80 * hdr->nr_annot_chns); j++) + { + fputc(' ', file); + } + } + } len = strlen(hdr->edfparam[i].prefilter); edflib_latin1_to_ascii(hdr->edfparam[i].prefilter, len); for(j=0; jnr_annot_chns; i++) + if(hdr->annot_chan_idx_pos == EDF_ANNOT_IDX_POS_END) { - for(j=0; j<80; j++) + for(i=0; inr_annot_chns; i++) { - fputc(' ', file); + for(j=0; j<80; j++) + { + fputc(' ', file); + } + } + } + if(hdr->annot_chan_idx_pos == EDF_ANNOT_IDX_POS_START) + { + for(j=0; jnr_annot_chns; j++) + { + if(hdr->edf) + { + p = edflib_fprint_int_number_nonlocalized(file, EDFLIB_ANNOTATION_BYTES / 2, 0, 0); + for(; p<8; p++) + { + fputc(' ', file); + } + } + else + { + p = edflib_fprint_int_number_nonlocalized(file, EDFLIB_ANNOTATION_BYTES / 3, 0, 0); + for(; p<8; p++) + { + fputc(' ', file); + } + } } } for(i=0; iannot_chan_idx_pos == EDF_ANNOT_IDX_POS_MIDDLE) + { + if(i == (edfsignals / 2)) + { + for(j=0; jnr_annot_chns; j++) + { + if(hdr->edf) + { + p = edflib_fprint_int_number_nonlocalized(file, EDFLIB_ANNOTATION_BYTES / 2, 0, 0); + for(; p<8; p++) + { + fputc(' ', file); + } + } + else + { + p = edflib_fprint_int_number_nonlocalized(file, EDFLIB_ANNOTATION_BYTES / 3, 0, 0); + for(; p<8; p++) + { + fputc(' ', file); + } + } + } + } + } p = edflib_fprint_int_number_nonlocalized(file, hdr->edfparam[i].smp_per_record, 0, 0); for(; p<8; p++) { fputc(' ', file); } } - for(j=0; jnr_annot_chns; j++) + if(hdr->annot_chan_idx_pos == EDF_ANNOT_IDX_POS_END) { - if(hdr->edf) + for(j=0; jnr_annot_chns; j++) { - p = edflib_fprint_int_number_nonlocalized(file, EDFLIB_ANNOTATION_BYTES / 2, 0, 0); - for(; p<8; p++) + if(hdr->edf) { - fputc(' ', file); + p = edflib_fprint_int_number_nonlocalized(file, EDFLIB_ANNOTATION_BYTES / 2, 0, 0); + for(; p<8; p++) + { + fputc(' ', file); + } } - } - else - { - p = edflib_fprint_int_number_nonlocalized(file, EDFLIB_ANNOTATION_BYTES / 3, 0, 0); - for(; p<8; p++) + else { - fputc(' ', file); + p = edflib_fprint_int_number_nonlocalized(file, EDFLIB_ANNOTATION_BYTES / 3, 0, 0); + for(; p<8; p++) + { + fputc(' ', file); + } } } } - for(i=0; i<(edfsignals * 32); i++) - { - fputc(' ', file); - } - for(i=0; i<(hdr->nr_annot_chns * 32); i++) + for(i=0; i<((edfsignals + hdr->nr_annot_chns) * 32); i++) { fputc(' ', file); } @@ -5832,42 +5636,21 @@ static int edflib_write_edf_header(struct edfhdrblock *hdr) } -int edf_set_label(int handle, int edfsignal, const char *label) +EDFLIB_API int edf_set_label(int handle, int edfsignal, const char *label) { - if(handle<0) - { - return -1; - } + if((handle<0)||(handle>=EDFLIB_MAXFILES)) return -1; - if(handle>=EDFLIB_MAXFILES) - { - return -1; - } + if(hdrlist[handle]==NULL) return -1; - if(hdrlist[handle]==NULL) - { - return -1; - } + if(!hdrlist[handle]->writemode) return -1; - if(!(hdrlist[handle]->writemode)) - { - return -1; - } + if(hdrlist[handle]->datarecords) return -1; - if(edfsignal<0) - { - return -1; - } + if((edfsignal<0) || (edfsignal>=hdrlist[handle]->edfsignals)) return -1; - if(edfsignal>=hdrlist[handle]->edfsignals) - { - return -1; - } + if(!strncmp(label, "EDF Annotations", 15)) return -1; - if(hdrlist[handle]->datarecords) - { - return -1; - } + if(!strncmp(label, "BDF Annotations", 15)) return -1; strncpy(hdrlist[handle]->edfparam[edfsignal].label, label, 16); @@ -5879,42 +5662,17 @@ int edf_set_label(int handle, int edfsignal, const char *label) } -int edf_set_physical_dimension(int handle, int edfsignal, const char *phys_dim) +EDFLIB_API int edf_set_physical_dimension(int handle, int edfsignal, const char *phys_dim) { - if(handle<0) - { - return -1; - } - - if(handle>=EDFLIB_MAXFILES) - { - return -1; - } - - if(hdrlist[handle]==NULL) - { - return -1; - } + if((handle<0)||(handle>=EDFLIB_MAXFILES)) return -1; - if(!(hdrlist[handle]->writemode)) - { - return -1; - } + if(hdrlist[handle]==NULL) return -1; - if(edfsignal<0) - { - return -1; - } + if(!hdrlist[handle]->writemode) return -1; - if(edfsignal>=hdrlist[handle]->edfsignals) - { - return -1; - } + if(hdrlist[handle]->datarecords) return -1; - if(hdrlist[handle]->datarecords) - { - return -1; - } + if((edfsignal<0) || (edfsignal>=hdrlist[handle]->edfsignals)) return -1; strncpy(hdrlist[handle]->edfparam[edfsignal].physdimension, phys_dim, 8); @@ -5926,42 +5684,17 @@ int edf_set_physical_dimension(int handle, int edfsignal, const char *phys_dim) } -int edf_set_physical_maximum(int handle, int edfsignal, double phys_max) +EDFLIB_API int edf_set_physical_maximum(int handle, int edfsignal, double phys_max) { - if(handle<0) - { - return -1; - } - - if(handle>=EDFLIB_MAXFILES) - { - return -1; - } + if((handle<0)||(handle>=EDFLIB_MAXFILES)) return -1; - if(hdrlist[handle]==NULL) - { - return -1; - } - - if(!(hdrlist[handle]->writemode)) - { - return -1; - } + if(hdrlist[handle]==NULL) return -1; - if(edfsignal<0) - { - return -1; - } + if(!hdrlist[handle]->writemode) return -1; - if(edfsignal>=hdrlist[handle]->edfsignals) - { - return -1; - } + if(hdrlist[handle]->datarecords) return -1; - if(hdrlist[handle]->datarecords) - { - return -1; - } + if((edfsignal<0) || (edfsignal>=hdrlist[handle]->edfsignals)) return -1; hdrlist[handle]->edfparam[edfsignal].phys_max = phys_max; @@ -5969,42 +5702,17 @@ int edf_set_physical_maximum(int handle, int edfsignal, double phys_max) } -int edf_set_physical_minimum(int handle, int edfsignal, double phys_min) +EDFLIB_API int edf_set_physical_minimum(int handle, int edfsignal, double phys_min) { - if(handle<0) - { - return -1; - } - - if(handle>=EDFLIB_MAXFILES) - { - return -1; - } - - if(hdrlist[handle]==NULL) - { - return -1; - } + if((handle<0)||(handle>=EDFLIB_MAXFILES)) return -1; - if(!(hdrlist[handle]->writemode)) - { - return -1; - } + if(hdrlist[handle]==NULL) return -1; - if(edfsignal<0) - { - return -1; - } + if(!hdrlist[handle]->writemode) return -1; - if(edfsignal>=hdrlist[handle]->edfsignals) - { - return -1; - } + if(hdrlist[handle]->datarecords) return -1; - if(hdrlist[handle]->datarecords) - { - return -1; - } + if((edfsignal<0) || (edfsignal>=hdrlist[handle]->edfsignals)) return -1; hdrlist[handle]->edfparam[edfsignal].phys_min = phys_min; @@ -6012,56 +5720,25 @@ int edf_set_physical_minimum(int handle, int edfsignal, double phys_min) } -int edf_set_digital_maximum(int handle, int edfsignal, int dig_max) +EDFLIB_API int edf_set_digital_maximum(int handle, int edfsignal, int dig_max) { - if(handle<0) - { - return -1; - } + if((handle<0)||(handle>=EDFLIB_MAXFILES)) return -1; - if(handle>=EDFLIB_MAXFILES) - { - return -1; - } - - if(hdrlist[handle]==NULL) - { - return -1; - } + if(hdrlist[handle]==NULL) return -1; - if(!(hdrlist[handle]->writemode)) - { - return -1; - } + if(!hdrlist[handle]->writemode) return -1; - if(edfsignal<0) - { - return -1; - } + if(hdrlist[handle]->datarecords) return -1; - if(edfsignal>=hdrlist[handle]->edfsignals) - { - return -1; - } + if((edfsignal<0) || (edfsignal>=hdrlist[handle]->edfsignals)) return -1; if(hdrlist[handle]->edf) { - if(dig_max > 32767) - { - return -1; - } + if(dig_max > 0x7fff) return -1; } else { - if(dig_max > 8388607) - { - return -1; - } - } - - if(hdrlist[handle]->datarecords) - { - return -1; + if(dig_max > 0x7fffff) return -1; } hdrlist[handle]->edfparam[edfsignal].dig_max = dig_max; @@ -6070,56 +5747,25 @@ int edf_set_digital_maximum(int handle, int edfsignal, int dig_max) } -int edf_set_digital_minimum(int handle, int edfsignal, int dig_min) +EDFLIB_API int edf_set_digital_minimum(int handle, int edfsignal, int dig_min) { - if(handle<0) - { - return -1; - } + if((handle<0)||(handle>=EDFLIB_MAXFILES)) return -1; - if(handle>=EDFLIB_MAXFILES) - { - return -1; - } + if(hdrlist[handle]==NULL) return -1; - if(hdrlist[handle]==NULL) - { - return -1; - } + if(!hdrlist[handle]->writemode) return -1; - if(!(hdrlist[handle]->writemode)) - { - return -1; - } - - if(edfsignal<0) - { - return -1; - } + if(hdrlist[handle]->datarecords) return -1; - if(edfsignal>=hdrlist[handle]->edfsignals) - { - return -1; - } + if((edfsignal<0) || (edfsignal>=hdrlist[handle]->edfsignals)) return -1; if(hdrlist[handle]->edf) { - if(dig_min < (-32768)) - { - return -1; - } + if(dig_min < (-0x8000)) return -1; } else { - if(dig_min < (-8388608)) - { - return -1; - } - } - - if(hdrlist[handle]->datarecords) - { - return -1; + if(dig_min < (-0x800000)) return -1; } hdrlist[handle]->edfparam[edfsignal].dig_min = dig_min; @@ -6128,32 +5774,15 @@ int edf_set_digital_minimum(int handle, int edfsignal, int dig_min) } -int edf_set_patientname(int handle, const char *patientname) +EDFLIB_API int edf_set_patientname(int handle, const char *patientname) { - if(handle<0) - { - return -1; - } + if((handle<0)||(handle>=EDFLIB_MAXFILES)) return -1; - if(handle>=EDFLIB_MAXFILES) - { - return -1; - } + if(hdrlist[handle]==NULL) return -1; - if(hdrlist[handle]==NULL) - { - return -1; - } - - if(!(hdrlist[handle]->writemode)) - { - return -1; - } + if(!hdrlist[handle]->writemode) return -1; - if(hdrlist[handle]->datarecords) - { - return -1; - } + if(hdrlist[handle]->datarecords) return -1; strncpy(hdrlist[handle]->plus_patient_name, patientname, 80); @@ -6165,32 +5794,15 @@ int edf_set_patientname(int handle, const char *patientname) } -int edf_set_patientcode(int handle, const char *patientcode) +EDFLIB_API int edf_set_patientcode(int handle, const char *patientcode) { - if(handle<0) - { - return -1; - } + if((handle<0)||(handle>=EDFLIB_MAXFILES)) return -1; - if(handle>=EDFLIB_MAXFILES) - { - return -1; - } - - if(hdrlist[handle]==NULL) - { - return -1; - } + if(hdrlist[handle]==NULL) return -1; - if(!(hdrlist[handle]->writemode)) - { - return -1; - } + if(!hdrlist[handle]->writemode) return -1; - if(hdrlist[handle]->datarecords) - { - return -1; - } + if(hdrlist[handle]->datarecords) return -1; strncpy(hdrlist[handle]->plus_patientcode, patientcode, 80); @@ -6202,79 +5814,48 @@ int edf_set_patientcode(int handle, const char *patientcode) } -int edf_set_gender(int handle, int gender) +EDFLIB_API int edf_set_sex(int handle, int sex) { - if(handle<0) - { - return -1; - } - - if(handle>=EDFLIB_MAXFILES) - { - return -1; - } + if((handle<0)||(handle>=EDFLIB_MAXFILES)) return -1; - if(hdrlist[handle]==NULL) - { - return -1; - } + if(hdrlist[handle]==NULL) return -1; - if(!(hdrlist[handle]->writemode)) - { - return -1; - } + if(!hdrlist[handle]->writemode) return -1; - if(hdrlist[handle]->datarecords) - { - return -1; - } + if(hdrlist[handle]->datarecords) return -1; - if((gender<0)||(gender>1)) - { - return -1; - } + if((sex<0)||(sex>1)) return -1; - if(gender) + if(sex) { - hdrlist[handle]->plus_gender[0] = 'M'; + hdrlist[handle]->plus_sex[0] = 'M'; } else { - hdrlist[handle]->plus_gender[0] = 'F'; + hdrlist[handle]->plus_sex[0] = 'F'; } - hdrlist[handle]->plus_gender[1] = 0; + hdrlist[handle]->plus_sex[1] = 0; return 0; } -int edf_set_birthdate(int handle, int birthdate_year, int birthdate_month, int birthdate_day) +EDFLIB_API int edf_set_gender(int handle, int sex) { - if(handle<0) - { - return -1; - } + return edf_set_sex(handle, sex); +} - if(handle>=EDFLIB_MAXFILES) - { - return -1; - } - if(hdrlist[handle]==NULL) - { - return -1; - } +EDFLIB_API int edf_set_birthdate(int handle, int birthdate_year, int birthdate_month, int birthdate_day) +{ + if((handle<0)||(handle>=EDFLIB_MAXFILES)) return -1; - if(!(hdrlist[handle]->writemode)) - { - return -1; - } + if(hdrlist[handle]==NULL) return -1; - if(hdrlist[handle]->datarecords) - { - return -1; - } + if(!hdrlist[handle]->writemode) return -1; + + if(hdrlist[handle]->datarecords) return -1; if((birthdate_year<1800) || (birthdate_year>3000) || (birthdate_month<1) || (birthdate_month>12) || @@ -6291,32 +5872,15 @@ int edf_set_birthdate(int handle, int birthdate_year, int birthdate_month, int b } -int edf_set_patient_additional(int handle, const char *patient_additional) +EDFLIB_API int edf_set_patient_additional(int handle, const char *patient_additional) { - if(handle<0) - { - return -1; - } - - if(handle>=EDFLIB_MAXFILES) - { - return -1; - } + if((handle<0)||(handle>=EDFLIB_MAXFILES)) return -1; - if(hdrlist[handle]==NULL) - { - return -1; - } + if(hdrlist[handle]==NULL) return -1; - if(!(hdrlist[handle]->writemode)) - { - return -1; - } + if(!hdrlist[handle]->writemode) return -1; - if(hdrlist[handle]->datarecords) - { - return -1; - } + if(hdrlist[handle]->datarecords) return -1; strncpy(hdrlist[handle]->plus_patient_additional, patient_additional, 80); @@ -6328,32 +5892,15 @@ int edf_set_patient_additional(int handle, const char *patient_additional) } -int edf_set_admincode(int handle, const char *admincode) +EDFLIB_API int edf_set_admincode(int handle, const char *admincode) { - if(handle<0) - { - return -1; - } + if((handle<0)||(handle>=EDFLIB_MAXFILES)) return -1; - if(handle>=EDFLIB_MAXFILES) - { - return -1; - } - - if(hdrlist[handle]==NULL) - { - return -1; - } + if(hdrlist[handle]==NULL) return -1; - if(!(hdrlist[handle]->writemode)) - { - return -1; - } + if(!hdrlist[handle]->writemode) return -1; - if(hdrlist[handle]->datarecords) - { - return -1; - } + if(hdrlist[handle]->datarecords) return -1; strncpy(hdrlist[handle]->plus_admincode, admincode, 80); @@ -6365,32 +5912,15 @@ int edf_set_admincode(int handle, const char *admincode) } -int edf_set_technician(int handle, const char *technician) +EDFLIB_API int edf_set_technician(int handle, const char *technician) { - if(handle<0) - { - return -1; - } - - if(handle>=EDFLIB_MAXFILES) - { - return -1; - } + if((handle<0)||(handle>=EDFLIB_MAXFILES)) return -1; - if(hdrlist[handle]==NULL) - { - return -1; - } + if(hdrlist[handle]==NULL) return -1; - if(!(hdrlist[handle]->writemode)) - { - return -1; - } + if(!hdrlist[handle]->writemode) return -1; - if(hdrlist[handle]->datarecords) - { - return -1; - } + if(hdrlist[handle]->datarecords) return -1; strncpy(hdrlist[handle]->plus_technician, technician, 80); @@ -6402,32 +5932,15 @@ int edf_set_technician(int handle, const char *technician) } -int edf_set_equipment(int handle, const char *equipment) +EDFLIB_API int edf_set_equipment(int handle, const char *equipment) { - if(handle<0) - { - return -1; - } - - if(handle>=EDFLIB_MAXFILES) - { - return -1; - } + if((handle<0)||(handle>=EDFLIB_MAXFILES)) return -1; - if(hdrlist[handle]==NULL) - { - return -1; - } + if(hdrlist[handle]==NULL) return -1; - if(!(hdrlist[handle]->writemode)) - { - return -1; - } + if(!hdrlist[handle]->writemode) return -1; - if(hdrlist[handle]->datarecords) - { - return -1; - } + if(hdrlist[handle]->datarecords) return -1; strncpy(hdrlist[handle]->plus_equipment, equipment, 80); @@ -6439,32 +5952,15 @@ int edf_set_equipment(int handle, const char *equipment) } -int edf_set_recording_additional(int handle, const char *recording_additional) +EDFLIB_API int edf_set_recording_additional(int handle, const char *recording_additional) { - if(handle<0) - { - return -1; - } - - if(handle>=EDFLIB_MAXFILES) - { - return -1; - } + if((handle<0)||(handle>=EDFLIB_MAXFILES)) return -1; - if(hdrlist[handle]==NULL) - { - return -1; - } + if(hdrlist[handle]==NULL) return -1; - if(!(hdrlist[handle]->writemode)) - { - return -1; - } + if(!hdrlist[handle]->writemode) return -1; - if(hdrlist[handle]->datarecords) - { - return -1; - } + if(hdrlist[handle]->datarecords) return -1; strncpy(hdrlist[handle]->plus_recording_additional, recording_additional, 80); @@ -6476,35 +5972,18 @@ int edf_set_recording_additional(int handle, const char *recording_additional) } -int edf_set_startdatetime(int handle, int startdate_year, int startdate_month, int startdate_day, - int starttime_hour, int starttime_minute, int starttime_second) +EDFLIB_API int edf_set_startdatetime(int handle, int startdate_year, int startdate_month, int startdate_day, + int starttime_hour, int starttime_minute, int starttime_second) { - if(handle<0) - { - return -1; - } - - if(handle>=EDFLIB_MAXFILES) - { - return -1; - } + if((handle<0)||(handle>=EDFLIB_MAXFILES)) return -1; - if(hdrlist[handle]==NULL) - { - return -1; - } + if(hdrlist[handle]==NULL) return -1; - if(!(hdrlist[handle]->writemode)) - { - return -1; - } + if(!hdrlist[handle]->writemode) return -1; - if(hdrlist[handle]->datarecords) - { - return -1; - } + if(hdrlist[handle]->datarecords) return -1; - if((startdate_year<1970) || (startdate_year>3000) || + if((startdate_year<1985) || (startdate_year>2084) || (startdate_month<1) || (startdate_month>12) || (startdate_day<1) || (startdate_day>31) || (starttime_hour<0) || (starttime_hour>23) || @@ -6525,42 +6004,32 @@ int edf_set_startdatetime(int handle, int startdate_year, int startdate_month, i } -int edfwrite_annotation_utf8(int handle, long long onset, long long duration, const char *description) +EDFLIB_API int edfwrite_annotation_utf8(int handle, long long onset, long long duration, const char *description) { - int i; + if(duration > 0LL) duration *= 100LL; - struct edf_write_annotationblock *list_annot, *malloc_list; + return edfwrite_annotation_utf8_hr(handle, onset * 100LL, duration, description); +} - if(handle<0) - { - return -1; - } +EDFLIB_API int edfwrite_annotation_utf8_hr(int handle, long long onset, long long duration, const char *description) +{ + int i; - if(handle>=EDFLIB_MAXFILES) - { - return -1; - } + edf_write_annotationblock_t *list_annot, *malloc_list; - if(hdrlist[handle]==NULL) - { - return -1; - } + if((handle<0)||(handle>=EDFLIB_MAXFILES)) return -1; - if(!(hdrlist[handle]->writemode)) - { - return -1; - } + if(hdrlist[handle]==NULL) return -1; - if(onset<0LL) - { - return -1; - } + if(!hdrlist[handle]->writemode) return -1; + + if(onset<0LL) return -1; if(hdrlist[handle]->annots_in_file >= hdrlist[handle]->annotlist_sz) { - malloc_list = (struct edf_write_annotationblock *)realloc(write_annotationslist[handle], - sizeof(struct edf_write_annotationblock) * (hdrlist[handle]->annotlist_sz + EDFLIB_ANNOT_MEMBLOCKSZ)); + malloc_list = (edf_write_annotationblock_t *)realloc(write_annotationslist[handle], + sizeof(edf_write_annotationblock_t) * (hdrlist[handle]->annotlist_sz + EDFLIB_ANNOT_MEMBLOCKSZ)); if(malloc_list==NULL) { return -1; @@ -6585,7 +6054,7 @@ int edfwrite_annotation_utf8(int handle, long long onset, long long duration, co break; } - if(list_annot->annotation[i] < 32) + if(((unsigned char *)(list_annot->annotation))[i] < 32) { list_annot->annotation[i] = '.'; } @@ -6597,42 +6066,32 @@ int edfwrite_annotation_utf8(int handle, long long onset, long long duration, co } -int edfwrite_annotation_latin1(int handle, long long onset, long long duration, const char *description) +EDFLIB_API int edfwrite_annotation_latin1(int handle, long long onset, long long duration, const char *description) { - struct edf_write_annotationblock *list_annot, *malloc_list; + if(duration > 0LL) duration *= 100LL; - char str[EDFLIB_WRITE_MAX_ANNOTATION_LEN + 1]; + return edfwrite_annotation_latin1_hr(handle, onset * 100LL, duration, description); +} - if(handle<0) - { - return -1; - } +EDFLIB_API int edfwrite_annotation_latin1_hr(int handle, long long onset, long long duration, const char *description) +{ + edf_write_annotationblock_t *list_annot, *malloc_list; - if(handle>=EDFLIB_MAXFILES) - { - return -1; - } + char str[EDFLIB_WRITE_MAX_ANNOTATION_LEN + 1]; - if(hdrlist[handle]==NULL) - { - return -1; - } + if((handle<0)||(handle>=EDFLIB_MAXFILES)) return -1; - if(!(hdrlist[handle]->writemode)) - { - return -1; - } + if(hdrlist[handle]==NULL) return -1; - if(onset<0LL) - { - return -1; - } + if(!hdrlist[handle]->writemode) return -1; + + if(onset<0LL) return -1; if(hdrlist[handle]->annots_in_file >= hdrlist[handle]->annotlist_sz) { - malloc_list = (struct edf_write_annotationblock *)realloc(write_annotationslist[handle], - sizeof(struct edf_write_annotationblock) * (hdrlist[handle]->annotlist_sz + EDFLIB_ANNOT_MEMBLOCKSZ)); + malloc_list = (edf_write_annotationblock_t *)realloc(write_annotationslist[handle], + sizeof(edf_write_annotationblock_t) * (hdrlist[handle]->annotlist_sz + EDFLIB_ANNOT_MEMBLOCKSZ)); if(malloc_list==NULL) { return -1; @@ -6659,6 +6118,24 @@ int edfwrite_annotation_latin1(int handle, long long onset, long long duration, } +EDFLIB_API int edf_set_annot_chan_idx_pos(int handle, int pos) +{ + if((handle<0)||(handle>=EDFLIB_MAXFILES)) return -1; + + if(hdrlist[handle]==NULL) return -1; + + if(!hdrlist[handle]->writemode) return -1; + + if(hdrlist[handle]->datarecords) return -1; + + if((pos < 0) || (pos > 2)) return -1; + + hdrlist[handle]->annot_chan_idx_pos = pos; + + return 0; +} + + static void edflib_remove_padding_trailing_spaces(char *str) { int i; @@ -6690,42 +6167,19 @@ static void edflib_remove_padding_trailing_spaces(char *str) } -int edf_set_prefilter(int handle, int edfsignal, const char *prefilter) +EDFLIB_API int edf_set_prefilter(int handle, int edfsignal, const char *prefilter) { - if(handle<0) - { - return -1; - } - - if(handle>=EDFLIB_MAXFILES) - { - return -1; - } + if((handle<0)||(handle>=EDFLIB_MAXFILES)) return -1; - if(hdrlist[handle]==NULL) - { - return -1; - } + if(hdrlist[handle]==NULL) return -1; - if(!(hdrlist[handle]->writemode)) - { - return -1; - } + if(!hdrlist[handle]->writemode) return -1; - if(edfsignal<0) - { - return -1; - } + if(hdrlist[handle]->datarecords) return -1; - if(edfsignal>=hdrlist[handle]->edfsignals) - { - return -1; - } + if((edfsignal<0) || (edfsignal>=hdrlist[handle]->edfsignals)) return -1; - if(hdrlist[handle]->datarecords) - { - return -1; - } + if(hdrlist[handle]->datarecords) return -1; strncpy(hdrlist[handle]->edfparam[edfsignal].prefilter, prefilter, 80); @@ -6737,42 +6191,19 @@ int edf_set_prefilter(int handle, int edfsignal, const char *prefilter) } -int edf_set_transducer(int handle, int edfsignal, const char *transducer) +EDFLIB_API int edf_set_transducer(int handle, int edfsignal, const char *transducer) { - if(handle<0) - { - return -1; - } - - if(handle>=EDFLIB_MAXFILES) - { - return -1; - } + if((handle<0)||(handle>=EDFLIB_MAXFILES)) return -1; - if(hdrlist[handle]==NULL) - { - return -1; - } + if(hdrlist[handle]==NULL) return -1; - if(!(hdrlist[handle]->writemode)) - { - return -1; - } + if(!hdrlist[handle]->writemode) return -1; - if(edfsignal<0) - { - return -1; - } + if(hdrlist[handle]->datarecords) return -1; - if(edfsignal>=hdrlist[handle]->edfsignals) - { - return -1; - } + if((edfsignal<0) || (edfsignal>=hdrlist[handle]->edfsignals)) return -1; - if(hdrlist[handle]->datarecords) - { - return -1; - } + if(hdrlist[handle]->datarecords) return -1; strncpy(hdrlist[handle]->edfparam[edfsignal].transducer, transducer, 80); @@ -6808,7 +6239,7 @@ static int edflib_fprint_int_number_nonlocalized(FILE *file, int q, int minimum, j++; - q = -q; + base = -base; } else { @@ -6880,7 +6311,7 @@ static int edflib_fprint_ll_number_nonlocalized(FILE *file, long long q, int min j++; - q = -q; + base = -base; } else { @@ -7020,7 +6451,7 @@ static int edflib_snprint_ll_number_nonlocalized(char *dest, long long q, int mi { dest[j++] = '-'; - q = -q; + base = -base; } else { @@ -7079,7 +6510,8 @@ static int edflib_snprint_ll_number_nonlocalized(char *dest, long long q, int mi dest[j] = 0; - return j;} + return j; +} static int edflib_snprint_number_nonlocalized(char *dest, double val, int sz) @@ -7090,15 +6522,6 @@ static int edflib_snprint_number_nonlocalized(char *dest, double val, int sz) if(sz < 1) return 0; - if(val < 0.0) - { - val -= 1e-12; - } - else - { - val += 1e-12; - } - q = (int)val; var = val - q; @@ -7378,19 +6801,15 @@ static int edflib_atoi_nonlocalized(const char *str) value *= 10; - value += (str[i] - '0'); + value += ((str[i] - '0') * sign); } - return value * sign; + return value; } -static int edflib_write_tal(struct edfhdrblock *hdr, FILE *file) +static int edflib_write_tal(edfhdrblock_t *hdr, FILE *file) { - if ((hdr->edf||hdr->bdf) && !(hdr->edfplus||hdr->bdfplus)){ - // EDF/BDF = means no annotations will be written. - return 0; - } int p; char str[EDFLIB_ANNOTATION_BYTES * (EDFLIB_MAX_ANNOTATION_CHANNELS + 1)]; @@ -7456,3 +6875,30 @@ static int edflib_strlcat(char *dst, const char *src, int sz) return (dstlen + srclen); } + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/pyedflib/_extensions/c/edflib.h b/pyedflib/_extensions/c/edflib.h index f45f92e8..d793df20 100644 --- a/pyedflib/_extensions/c/edflib.h +++ b/pyedflib/_extensions/c/edflib.h @@ -1,7 +1,7 @@ /* ***************************************************************************** * -* Copyright (c) 2009 - 2020 Teunis van Beelen +* Copyright (c) 2009 - 2024 Teunis van Beelen * All rights reserved. * * Email: teuniz@protonmail.com @@ -31,22 +31,134 @@ ***************************************************************************** */ +/** + * @file edflib.h + * + * In EDF, the resolution (or sensitivity) (e.g. uV/bit) and offset are stored using four parameters:
+ * digital maximum and minimum, and physical maximum and minimum.
+ * Here, digital means the raw data coming from a sensor or ADC. Physical means the units like uV.
+ * The resolution in units per least significant bit is calculated as follows:
+ * + * units per bit = (physical max - physical min) / (digital max - digital min)
+ * + * The digital offset is calculated as follows:
+ * + * offset = (physical max / units per bit) - digital max
+ * + * For a better explanation about the relation between digital data and physical data,
+ * read the document "Coding Schemes Used with Data Converters" (PDF):
+ * + * https://www.ti.com/general/docs/lit/getliterature.tsp?baseLiteratureNumber=sbaa042
+ * + * An EDF file usually contains multiple so-called datarecords. One datarecord usually has a duration of one second (this is the default but it's not mandatory).
+ * In that case a file with a duration of five minutes contains 300 datarecords. The duration of a datarecord can be freely chosen but, if possible, use values from
+ * 0.1 to 1 second for easier handling. Just make sure that the total size of one datarecord, expressed in bytes, does not exceed 10 MByte (15 MBytes for BDF(+)).
+ * + * The recommendation of a maximum datarecord size of 61440 bytes in the EDF(+) specification was useful in the time people were still using DOS as their main operating system.
+ * Using DOS and fast (near) pointers (16-bit pointers), the maximum allocatable block of memory was 64KByte.
+ * This is not a concern anymore so the maximum datarecord size now is limited to 10 MByte for EDF(+) and 15 MByte for BDF(+). This helps to accommodate for higher sampling rates
+ * used by modern Analog to Digital Converters.
+ * + * EDF header character encoding: The EDF specification says that only (printable) ASCII characters are allowed.
+ * When writing the header info, EDFlib will assume you are using Latin1 encoding and it will automatically convert
+ * characters with accents, umlauts, tilde, etc. to their "normal" equivalent without the accent/umlaut/tilde/etc.
+ * in order to create a valid EDF file.
+ * The description of an EDF+ annotation/event/trigger on the other hand, is always encoded in UTF-8 (which is forward compatible with ASCII).
+ * + * The sample frequency of a signal is calculated as follows: sf = (smp_in_datarecord * EDFLIB_TIME_DIMENSION) / datarecord_duration
+ * + * Annotation signals
+ * ==================
+ * + * EDF+ and BDF+ store the annotations/events/triggers in one or more signals (in order to be backwards compatible with EDF and BDF)
+ * and they can appear anywhere in the list of signals.
+ * The numbering of the signals in the file is zero based (starts at 0). Signals used for annotations are skipped by EDFlib.
+ * This means that the annotationsignal(s) in the file are hidden.
+ * Use the function edf_get_annotation() to get the annotations.
+ * + * So, when a file contains 7 signals and the third and fifth signal are annotation signals, the library will
+ * report that there are only 5 signals in the file.
+ * The library will "map" the (zero-based) signal numbers as follows: 0->0, 1->1, 2->3, 3->4, 4->6.
+ * This way you don't need to worry about which signals are annotationsignals, the library will take care of it.
+ * + * How the library stores time values
+ * ==================================
+ * + * To avoid rounding errors and to be able to compare values, the library stores some time values in variables of type long long int.
+ * In order not to lose the sub-second precision, all time values are scaled with a scaling factor: 10000000.
+ * This will limit the time resolution to 100 nanoseconds. To calculate the amount of seconds, divide
+ * the timevalue by 10000000 or use the macro EDFLIB_TIME_DIMENSION which is declared in edflib.h.
+ * The following variables use this scaling when you open a file in read mode: "file_duration", "starttime_subsecond" and "onset".
+ * + * EDFlib and thread-safety
+ * ========================
+ * The following functions are always MT-unsafe:
+ * edfopen_file_readonly() (race condition)
+ * edfclose_file() (race condition)
+ * edflib_get_handle() (race condition)
+ * + * When writing to or reading from the same file, all EDFlib functions are MT-unsafe (race condition).
+ * + * When accessing EDFlib from different threads, use a mutex.
+ * + * For more info about the EDF and EDF+ format, visit: https://edfplus.info/specs/
+ * + * For more info about the BDF and BDF+ format, visit: https://www.teuniz.net/edfbrowser/bdfplus%20format%20description.html
+ * + */ /* compile with options "-D_LARGEFILE64_SOURCE -D_LARGEFILE_SOURCE" */ - #ifndef EDFLIB_INCLUDED #define EDFLIB_INCLUDED - #include #include #include #include +/* + * If both EDFLIB_SO_DLL and EDFLIB_BUILD are defined: compile only EDFlib as a shared library (so, dll). + * When compiling on unix-like systems, add the -fvisibility=hidden to hide all symbols by + * default so that this macro can reveal them. + * + * If only EDFLIB_SO_DLL is defined: link with EDFlib as an external library (so, dll). + * EDFlib must be installed on your system (as an .so or .dll) when running your program. + * + * If both EDFLIB_SO_DLL and EDFLIB_BUILD are not defined: EDFlib will not be used as a shared library, + * it will be an integral part of your program instead. + * + */ + +/* +#define EDFLIB_SO_DLL +#define EDFLIB_BUILD +*/ + +#if defined(EDFLIB_SO_DLL) +# if defined(EDFLIB_BUILD) +# if defined(_WIN32) +# define EDFLIB_API __declspec(dllexport) +# elif defined(__ELF__) +# define EDFLIB_API __attribute__ ((visibility ("default"))) +# else +# define EDFLIB_API +# endif +# else +# if defined(_WIN32) +# define EDFLIB_API __declspec(dllimport) +# else +# define EDFLIB_API +# endif +# endif +#else +# define EDFLIB_API +#endif + + #define EDFLIB_TIME_DIMENSION (10000000LL) #define EDFLIB_MAXSIGNALS (640) @@ -56,10 +168,12 @@ #define EDFSEEK_CUR (1) #define EDFSEEK_END (2) +#define EDF_ANNOT_IDX_POS_END (0) +#define EDF_ANNOT_IDX_POS_MIDDLE (1) +#define EDF_ANNOT_IDX_POS_START (2) - -/* the following defines are used in the member "filetype" of the edf_hdr_struct */ -/* and as return value for the function edfopen_file_readonly() */ +/* the following defines are used in the member "filetype" of the edf_hdr_struct + and as return value for the function edfopen_file_readonly() */ #define EDFLIB_FILETYPE_EDF (0) #define EDFLIB_FILETYPE_EDFPLUS (1) #define EDFLIB_FILETYPE_BDF (2) @@ -67,8 +181,8 @@ #define EDFLIB_MALLOC_ERROR (-1) #define EDFLIB_NO_SUCH_FILE_OR_DIRECTORY (-2) -/* when this error occurs, try to open the file with EDFbrowser, - it will give you full details about the cause of the error. */ +/* when this error occurs, try to open the file with EDFbrowser (https://www.teuniz.net/edfbrowser/), + it will give you full details about the cause of the error. It can also fix most errors. */ #define EDFLIB_FILE_CONTAINS_FORMAT_ERRORS (-3) #define EDFLIB_MAXFILES_REACHED (-4) @@ -79,18 +193,13 @@ #define EDFLIB_NUMBER_OF_SIGNALS_INVALID (-9) #define EDFLIB_FILE_IS_DISCONTINUOUS (-10) #define EDFLIB_INVALID_READ_ANNOTS_VALUE (-11) -#define EDFLIB_INVALID_CHECK_SIZE_VALUE (-12) +#define EDFLIB_ARCH_ERROR (-12) /* values for annotations */ #define EDFLIB_DO_NOT_READ_ANNOTATIONS (0) #define EDFLIB_READ_ANNOTATIONS (1) #define EDFLIB_READ_ALL_ANNOTATIONS (2) -/* values for size check on edfopen_file_readonly */ -#define EDFLIB_CHECK_FILE_SIZE (0) -#define EDFLIB_DO_NOT_CHECK_FILE_SIZE (1) -#define EDFLIB_REPAIR_FILE_SIZE_IF_WRONG (2) - /* the following defines are possible errors returned by the first sample write action */ #define EDFLIB_NO_SIGNALS (-20) #define EDFLIB_TOO_MANY_SIGNALS (-21) @@ -100,626 +209,1055 @@ #define EDFLIB_PHYSMIN_IS_PHYSMAX (-25) #define EDFLIB_DATARECORD_SIZE_TOO_BIG (-26) -/* added for pyedflib */ - -#define EDFLIB_FILE_ERRORS_STARTDATE (-30) -#define EDFLIB_FILE_ERRORS_STARTTIME (-31) -#define EDFLIB_FILE_ERRORS_NUMBER_SIGNALS (-32) -#define EDFLIB_FILE_ERRORS_BYTES_HEADER (-33) -#define EDFLIB_FILE_ERRORS_RESERVED_FIELD (-34) -#define EDFLIB_FILE_ERRORS_NUMBER_DATARECORDS (-35) -#define EDFLIB_FILE_ERRORS_DURATION (-36) -#define EDFLIB_FILE_ERRORS_LABEL (-37) -#define EDFLIB_FILE_ERRORS_TRANSDUCER (-38) -#define EDFLIB_FILE_ERRORS_PHYS_DIMENSION (-39) -#define EDFLIB_FILE_ERRORS_PHYS_MAX (-40) -#define EDFLIB_FILE_ERRORS_PHYS_MIN (-41) -#define EDFLIB_FILE_ERRORS_DIG_MAX (-42) -#define EDFLIB_FILE_ERRORS_DIG_MIN (-43) -#define EDFLIB_FILE_ERRORS_PREFILTER (-44) -#define EDFLIB_FILE_ERRORS_SAMPLES_DATARECORD (-45) -#define EDFLIB_FILE_ERRORS_FILESIZE (-46) -#define EDFLIB_FILE_ERRORS_RECORDINGFIELD (-47) -#define EDFLIB_FILE_ERRORS_PATIENTNAME (-48) - - - #ifdef __cplusplus extern "C" { #endif +/** + * This structure contains the signal parameters. + */ +typedef struct edf_param_struct +{ + char label[17]; /*!< Label (name) of the signal, null-terminated string. */ + long long smp_in_file; /*!< Number of samples in the file. */ + double phys_max; /*!< Physical maximum, usually the maximum input of the ADC. */ + double phys_min; /*!< Physical minimum, usually the minimum input of the ADC. */ + int dig_max; /*!< Digital maximum, usually the maximum output of the ADC, cannot not be higher than 32767 for EDF or 8388607 for BDF. */ + int dig_min; /*!< Digital minimum, usually the minimum output of the ADC, cannot not be lower than -32768 for EDF or -8388608 for BDF. */ + int smp_in_datarecord; /*!< Number of samplesin a datarecord, if the datarecord has a duration of one second (default), then it equals the sample rate. */ + char physdimension[9]; /*!< Physical dimension (unit, e.g. uV, bpm, mA, etc.), null-terminated string. */ + char prefilter[81]; /*!< Prefilter settings, null-terminated string. */ + char transducer[81]; /*!< Transducer (sensor), null-terminated string. */ +} edflib_param_t; + +/** + * This structure is used for annotations/events/triggers. + */ +typedef struct edf_annotation_struct +{ + long long onset; /*!< Onset time of the event, expressed in units of 100 nanoseconds and relative to the start of the recording. */ + long long duration_l; /*!< Duration, expressed in units of 100 nanoseconds, if less than zero: unused or not applicable. */ + char duration[20]; /*!< Duration, expressed in seconds, this is a null-terminated ASCII string. */ + char annotation[EDFLIB_MAX_ANNOTATION_LEN + 1]; /*!< Description of the annotation/event/trigger, this is a null-terminated UTF8 string. */ +} edflib_annotation_t; + +/** + * This structure contains the general header info and parameters. It will be filled when calling the function edfopen_file_readonly(). + */ +typedef struct edf_hdr_struct +{ + int handle; /*!< A handle (identifier) used to distinguish the different files or -1 in case of an error. */ + int filetype; /*!< 0: EDF, 1: EDF+, 2: BDF, 3: BDF+, a negative number indicates an error code. */ + int edfsignals; /*!< Number of signals in the file, annotation channels are not included. */ + long long file_duration; /*!< Duration of the file expressed in units of 100 nanoseconds. */ + int startdate_day; /*!< Startdate: day: 1 - 31 */ + int startdate_month; /*!< Startdate: month: 1 - 12 */ + int startdate_year; /*!< Startdate: year: 1985 - 2084 */ + long long starttime_subsecond; /*!< Starttime subsecond expressed in units of 100 nanoseconds. Is always less than 10000000 (one second). Only used by EDF+ and BDF+. */ + int starttime_second; /*!< Starttime: second: 0 - 59 */ + int starttime_minute; /*!< Starttime: minute: 0 - 59 */ + int starttime_hour; /*!< Starttime: hour: 0 - 23 */ + char patient[81]; /*!< Null-terminated string, contains patient field of header, is always empty when filetype is EDFPLUS or BDFPLUS. */ + char recording[81]; /*!< Null-terminated string, contains recording field of header, is always empty when filetype is EDFPLUS or BDFPLUS. */ + char patientcode[81]; /*!< Null-terminated string, is always empty when filetype is EDF or BDF. */ + char sex[16]; /*!< Null-terminated string, is always empty when filetype is EDF or BDF. */ +#if defined(__GNUC__) + char gender[16] __attribute__ ((deprecated ("use sex"))); /*!< Deprecated, use \p sex. */ +#else + char gender[16]; /*!< Deprecated, use \p sex. */ +#endif + char birthdate[16]; /*!< Null-terminated string, is always empty when filetype is EDF or BDF. */ + int birthdate_day; /*!< Birthdate: day: 1 - 31 (zero in case of EDF or BDF). */ + int birthdate_month; /*!< Birthdate: month: 1 - 12 (zero in case of EDF or BDF). */ + int birthdate_year; /*!< Birthdate: year: 1800 - 3000 (zero in case of EDF or BDF). */ + char patient_name[81]; /*!< Null-terminated string, is always empty when filetype is EDF or BDF. */ + char patient_additional[81]; /*!< Null-terminated string, is always empty when filetype is EDF or BDF. */ + char admincode[81]; /*!< Null-terminated string, is always empty when filetype is EDF or BDF. */ + char technician[81]; /*!< Null-terminated string, is always empty when filetype is EDF or BDF. */ + char equipment[81]; /*!< Null-terminated string, is always empty when filetype is EDF or BDF. */ + char recording_additional[81]; /*!< Null-terminated string, is always empty when filetype is EDF or BDF. */ + long long datarecord_duration; /*!< Duration of a datarecord expressed in units of 100 nanoseconds. */ + long long datarecords_in_file; /*!< Number of datarecords in the file. */ + long long annotations_in_file; /*!< Number of annotations/events/triggers in the file. */ + edflib_param_t signalparam[EDFLIB_MAXSIGNALS]; /*!< array of structs containing the signal parameters. */ +} edflib_hdr_t; +/***************** the following functions are used to read files **************************/ -/* For more info about the EDF and EDF+ format, visit: https://edfplus.info/specs/ */ - -/* For more info about the BDF and BDF+ format, visit: https://www.teuniz.net/edfbrowser/bdfplus%20format%20description.html */ - -/* - * note: In EDF, the sensitivity (e.g. uV/bit) and offset are stored using four parameters: - * digital maximum and minimum, and physical maximum and minimum. - * Here, digital means the raw data coming from a sensor or ADC. Physical means the units like uV. - * The sensitivity in units/bit is calculated as follows: +/** + * Opens an existing file for reading. * - * units per bit = (physical max - physical min) / (digital max - digital min) + * @param[in] path + * null-terminated string containing the \p path to the file * - * The digital offset is calculated as follows: + * @param[out] edfhdr + * pointer to an \p edflib_hdr_t struct, all fields in this struct will be overwritten, + * it will be filled with all the relevant header- and signalinfo/parameters * - * offset = (physical max / units per bit) - digital max + * @param[in] read_annotations + * Must have one of the following values: + * - EDFLIB_DO_NOT_READ_ANNOTATIONS annotations will not be read (this can save time when opening a very large EDF+ or BDF+ file + * - EDFLIB_READ_ANNOTATIONS annotations will be read immediately, stops when an annotation has + * been found which contains the description "Recording ends" + * - EDFLIB_READ_ALL_ANNOTATIONS all annotations will be read immediately * - * For a better explanation about the relation between digital data and physical data, - * read the document "Coding Schemes Used with Data Converters" (PDF): + * @return + * 0 on success, in case of an error it returns -1 and an error code will be set in the member "filetype" of edfhdr. + * This function is required if you want to read a file * - * https://www.ti.com/general/docs/lit/getliterature.tsp?baseLiteratureNumber=sbaa042 + * In case of a file format error (-3), try to open the file with EDFbrowser: https://www.teuniz.net/edfbrowser/ + * It will give you full details about the cause of the error and it can also fix most errors. + */ +EDFLIB_API int edfopen_file_readonly(const char *path, edflib_hdr_t *edfhdr, int read_annotations); + +/** + * Reads \p n samples from \p edfsignal, starting from the current sample position indicator, into \p buf (edfsignal starts at 0). + * The values are converted to their physical values e.g. microVolts, beats per minute, etc. * - * note: An EDF file usually contains multiple so-called datarecords. One datarecord usually has a duration of one second (this is the default but it is not mandatory!). - * In that case a file with a duration of five minutes contains 300 datarecords. The duration of a datarecord can be freely choosen but, if possible, use values from - * 0.1 to 1 second for easier handling. Just make sure that the total size of one datarecord, expressed in bytes, does not exceed 10MByte (15MBytes for BDF(+)). + * @param[in] handle + * File handle. + * @param[in] edfsignal + * The zero-based index of the signal. + * @param[in] n + * Number of samples to read. The sample position indicator will be increased with the same amount. + * @param[out] buf + * Pointer to a buffer, size must be equal to, or bigger than, sizeof(double[n]) * - * The RECOMMENDATION of a maximum datarecordsize of 61440 bytes in the EDF and EDF+ specification was usefull in the time people were still using DOS as their main operating system. - * Using DOS and fast (near) pointers (16-bit pointers), the maximum allocatable block of memory was 64KByte. - * This is not a concern anymore so the maximum datarecord size now is limited to 10MByte for EDF(+) and 15MByte for BDF(+). This helps to accommodate for higher samplingrates - * used by modern Analog to Digital Converters. + * @return + * The number of samples read (this can be less than \p n or zero!) or -1 in case of an error + */ +EDFLIB_API int edfread_physical_samples(int handle, int edfsignal, int n, double *buf); + +/** + * Reads \p n samples from \p edfsignal, starting from the current sample position indicator, into \p buf (edfsignal starts at 0). + * The values are the "raw" digital values (e.g. from an ADC). * - * EDF header character encoding: The EDF specification says that only ASCII characters are allowed. - * EDFlib will automatically convert characters with accents, umlauts, tilde, etc. to their "normal" equivalent without the accent/umlaut/tilde/etc. + * @param[in] handle + * File handle. + * @param[in] edfsignal + * The zero-based index of the signal. + * @param[in] n + * Number of samples to read. The sample position indicator will be increased with the same amount. + * @param[out] buf + * Pointer to a buffer, size must be equal to, or bigger than, sizeof(double[n]) * - * The description/name of an EDF+ annotation on the other hand, is encoded in UTF-8. + * @return + * The number of samples read (this can be less than \p n or zero!) or -1 in case of an error + */ +EDFLIB_API int edfread_digital_samples(int handle, int edfsignal, int n, int *buf); + +/** + * Sets the sample position indicator for the edfsignal pointed to by \p edfsignal. + * The new position, measured in samples, is obtained by adding offset samples to the position specified by \p whence. + * If \p whence is set to EDFSEEK_SET, EDFSEEK_CUR, or EDFSEEK_END, the offset is relative to the start of the file, + * the current position indicator, or end-of-file, respectively. + * Note that every signal has it's own independent sample position indicator and \p edfseek() affects only one of them. * + * @param[in] handle + * File handle. + * @param[in] edfsignal + * The zero-based index of the signal. + * @param[in] offset + * Offset measured in samples. + * @param[in] whence + * Reference for \p offset: + * - EDFSEEK_SET start of the file + * - EDFSEEK_CUR current position + * - EDFSEEK_END end of the file + * + * @return + * The current offset or -1 in case of an error. */ +EDFLIB_API long long edfseek(int handle, int edfsignal, long long offset, int whence); +/** + * Obtains the current value of the sample position indicator for the edfsignal pointed to by \p edfsignal. + * Note that every signal has it's own independent sample position indicator and \p edftell() affects only one of them. + * + * @param[in] handle + * File handle. + * @param[in] edfsignal + * The zero-based index of the signal. + * + * @return + * The current offset or -1 in case of an error. + */ +EDFLIB_API long long edftell(int handle, int edfsignal); -struct edf_param_struct{ /* this structure contains all the relevant EDF-signal parameters of one signal */ - char label[17]; /* label (name) of the signal, null-terminated string */ - long long smp_in_file; /* number of samples of this signal in the file */ - double phys_max; /* physical maximum, usually the maximum input of the ADC */ - double phys_min; /* physical minimum, usually the minimum input of the ADC */ - int dig_max; /* digital maximum, usually the maximum output of the ADC, can not not be higher than 32767 for EDF or 8388607 for BDF */ - int dig_min; /* digital minimum, usually the minimum output of the ADC, can not not be lower than -32768 for EDF or -8388608 for BDF */ - int smp_in_datarecord; /* number of samples of this signal in a datarecord, if the datarecord has a duration of one second (default), then it equals the samplerate */ - char physdimension[9]; /* physical dimension (uV, bpm, mA, etc.), null-terminated string */ - char prefilter[81]; /* null-terminated string */ - char transducer[81]; /* null-terminated string */ - }; - - -struct edf_annotation_struct{ /* this structure is used for annotations */ - long long onset; /* onset time of the event, expressed in units of 100 nanoSeconds and relative to the start of the file */ - char duration[16]; /* duration time, this is a null-terminated ASCII text-string */ - char annotation[EDFLIB_MAX_ANNOTATION_LEN + 1]; /* description of the event in UTF-8, this is a null terminated string */ - }; - - -struct edf_hdr_struct{ /* this structure contains all the relevant EDF header info and will be filled when calling the function edf_open_file_readonly() */ - int handle; /* a handle (identifier) used to distinguish the different files */ - int filetype; /* 0: EDF, 1: EDFplus, 2: BDF, 3: BDFplus, a negative number means an error */ - int edfsignals; /* number of EDF signals in the file, annotation channels are NOT included */ - long long file_duration; /* duration of the file expressed in units of 100 nanoSeconds */ - int startdate_day; - int startdate_month; - int startdate_year; - long long starttime_subsecond; /* starttime offset expressed in units of 100 nanoSeconds. Is always less than 10000000 (one second). Only used by EDFplus and BDFplus */ - int starttime_second; - int starttime_minute; - int starttime_hour; - char patient[81]; /* null-terminated string, contains patientfield of header, is always empty when filetype is EDFPLUS or BDFPLUS */ - char recording[81]; /* null-terminated string, contains recordingfield of header, is always empty when filetype is EDFPLUS or BDFPLUS */ - char patientcode[81]; /* null-terminated string, is always empty when filetype is EDF or BDF */ - char gender[16]; /* null-terminated string, is always empty when filetype is EDF or BDF */ - char birthdate[16]; /* null-terminated string, is always empty when filetype is EDF or BDF */ - char patient_name[81]; /* null-terminated string, is always empty when filetype is EDF or BDF */ - char patient_additional[81]; /* null-terminated string, is always empty when filetype is EDF or BDF */ - char admincode[81]; /* null-terminated string, is always empty when filetype is EDF or BDF */ - char technician[81]; /* null-terminated string, is always empty when filetype is EDF or BDF */ - char equipment[81]; /* null-terminated string, is always empty when filetype is EDF or BDF */ - char recording_additional[81]; /* null-terminated string, is always empty when filetype is EDF or BDF */ - long long datarecord_duration; /* duration of a datarecord expressed in units of 100 nanoSeconds */ - long long datarecords_in_file; /* number of datarecords in the file */ - long long annotations_in_file; /* number of annotations in the file */ - struct edf_param_struct signalparam[EDFLIB_MAXSIGNALS]; /* array of structs which contain the relevant signal parameters */ - }; - - - - -/***************** the following functions are used to read files **************************/ - -int edfopen_file_readonly(const char *path, struct edf_hdr_struct *edfhdr, int read_annotations, int check_file_size); - -/* opens an existing file for reading */ -/* path is a null-terminated string containing the path to the file */ -/* hdr is a pointer to an edf_hdr_struct, all fields in this struct will be overwritten */ -/* the edf_hdr_struct will be filled with all the relevant header- and signalinfo/parameters */ - -/* read_annotations must have one of the following values: */ -/* EDFLIB_DO_NOT_READ_ANNOTATIONS annotations will not be read (this saves time when opening a very large EDFplus or BDFplus file */ -/* EDFLIB_READ_ANNOTATIONS annotations will be read immediately, stops when an annotation has */ -/* been found which contains the description "Recording ends" */ -/* EDFLIB_READ_ALL_ANNOTATIONS all annotations will be read immediately - */ -/* check_file_size must have one of the following values: */ -/* EDFLIB_CHECK_FILE_SIZE file size is checked and if wrong, the file will not be opened*/ -/* EDFLIB_DO_NOT_CHECK_FILE_SIZE the file will alsways be opened and the file size is not checked*/ -/* EDFLIB_REPAIR_FILE_SIZE_IF_WRONG the file size is checked and if it is wrong it will be fixed*/ - -/* returns 0 on success, in case of an error it returns -1 and an errorcode will be set in the member "filetype" of struct edf_hdr_struct */ -/* This function is required if you want to read a file */ - - - -int edfread_physical_samples(int handle, int edfsignal, int n, double *buf); - -/* reads n samples from edfsignal, starting from the current sample position indicator, into buf (edfsignal starts at 0) */ -/* the values are converted to their physical values e.g. microVolts, beats per minute, etc. */ -/* bufsize should be equal to or bigger than sizeof(double[n]) */ -/* the sample position indicator will be increased with the amount of samples read */ -/* returns the amount of samples read (this can be less than n or zero!) */ -/* or -1 in case of an error */ - - -int edfread_digital_samples(int handle, int edfsignal, int n, int *buf); - -/* reads n samples from edfsignal, starting from the current sample position indicator, into buf (edfsignal starts at 0) */ -/* the values are the "raw" digital values */ -/* bufsize should be equal to or bigger than sizeof(int[n]) */ -/* the sample position indicator will be increased with the amount of samples read */ -/* returns the amount of samples read (this can be less than n or zero!) */ -/* or -1 in case of an error */ - - -long long edfseek(int handle, int edfsignal, long long offset, int whence); - -/* The edfseek() function sets the sample position indicator for the edfsignal pointed to by edfsignal. */ -/* The new position, measured in samples, is obtained by adding offset samples to the position specified by whence. */ -/* If whence is set to EDFSEEK_SET, EDFSEEK_CUR, or EDFSEEK_END, the offset is relative to the start of the file, */ -/* the current position indicator, or end-of-file, respectively. */ -/* Returns the current offset. Otherwise, -1 is returned. */ -/* note that every signal has it's own independent sample position indicator and edfseek() affects only one of them */ - - -long long edftell(int handle, int edfsignal); - -/* The edftell() function obtains the current value of the sample position indicator for the edfsignal pointed to by edfsignal. */ -/* Returns the current offset. Otherwise, -1 is returned */ -/* note that every signal has it's own independent sample position indicator and edftell() affects only one of them */ - - -void edfrewind(int handle, int edfsignal); - -/* The edfrewind() function sets the sample position indicator for the edfsignal pointed to by edfsignal to the beginning of the file. */ -/* It is equivalent to: (void) edfseek(int handle, int edfsignal, 0LL, EDFSEEK_SET) */ -/* note that every signal has it's own independent sample position indicator and edfrewind() affects only one of them */ - - -int edf_get_annotation(int handle, int n, struct edf_annotation_struct *annot); - -/* Fills the edf_annotation_struct with the annotation n, returns 0 on success, otherwise -1 */ -/* The string that describes the annotation/event is encoded in UTF-8 */ -/* To obtain the number of annotations in a file, check edf_hdr_struct -> annotations_in_file. */ -/* returns 0 on success or -1 in case of an error */ - -/* -Notes: - -Annotationsignals -================= - -EDFplus and BDFplus store the annotations in one or more signals (in order to be backwards compatibel with EDF and BDF). -The counting of the signals in the file starts at 0. Signals used for annotations are skipped by EDFlib. -This means that the annotationsignal(s) in the file are hided. -Use the function edf_get_annotation() to get the annotations. - -So, when a file contains 5 signals and the third signal is used to store the annotations, the library will -report that there are only 4 signals in the file. -The library will "map" the signalnumbers as follows: 0->0, 1->1, 2->3, 3->4. -This way you don't need to worry about which signals are annotationsignals, the library will take care of it. - -How the library stores time-values -================================== - -To avoid rounding errors, the library stores some timevalues in variables of type long long int. -In order not to loose the subsecond precision, all timevalues have been multiplied by 10000000. -This will limit the timeresolution to 100 nanoSeconds. To calculate the amount of seconds, divide -the timevalue by 10000000 or use the macro EDFLIB_TIME_DIMENSION which is declared in edflib.h. -The following variables do use this when you open a file in read mode: "file_duration", "starttime_subsecond" and "onset". -*/ - -/***************** the following functions are used to read or write files **************************/ - -int edfclose_file(int handle); - -/* closes (and in case of writing, finalizes) the file */ -/* returns -1 in case of an error, 0 on success */ -/* this function MUST be called when you are finished reading or writing */ -/* This function is required after reading or writing. Failing to do so will cause */ -/* unnessecary memory usage and in case of writing it will cause a corrupted and incomplete file */ - - -int edflib_version(void); - -/* Returns the version number of this library, multiplied by hundred. if version is "1.00" than it will return 100 */ - - -int edflib_is_file_used(const char *path); - -/* returns 1 if the file is used, either for reading or writing */ -/* otherwise returns 0 */ +/** + * Sets the sample position indicator for the edfsignal pointed to by \p edfsignal to the beginning of the file. + * It is equivalent to: \p edfseek(handle, edfsignal, 0LL, EDFSEEK_SET). + * Note that every signal has it's own independent sample position indicator and \p edfrewind() affects only one of them. + * + * @param[in] handle + * File handle. + * @param[in] edfsignal + * The zero-based index of the signal. + * + * @return + * 0 on success or -1 in case of an error. + */ +EDFLIB_API int edfrewind(int handle, int edfsignal); +/** + * Fills the edflib_annotation_t structure with the annotation \p n. + * The string that describes the annotation/event is encoded in UTF-8. + * To obtain the number of annotations in a file, check edf_hdr_struct -> annotations_in_file. + * + * @param[in] handle + * File handle. + * @param[in] n + * The zero-based index number of the list of annotations. + * @param[out] annot + * Pointer to a struct that will be filled with the annotation. + * + * @return + * 0 on success or -1 in case of an error. + */ +EDFLIB_API int edf_get_annotation(int handle, int n, edflib_annotation_t *annot); -int edflib_get_number_of_open_files(void); +/***************** the following functions are used in read and write mode **************************/ -/* returns the number of open files, either for reading or writing */ +/** + * Closes (and in case of writing, finalizes) the file. + * + * This function MUST be called when you have finished reading or writing + * This function is required after reading or writing. Failing to do so will cause + * unnecessary memory usage and in case of writing it will cause a corrupted or incomplete file. + * + * @param[in] handle + * File handle. + * + * @return + * 0 on success or -1 in case of an error. + */ +EDFLIB_API int edfclose_file(int handle); +/** + * Returns the version number of this library, multiplied by hundred. if version is "1.00" then it will return 100. + * + * @return + * The version number. + */ +EDFLIB_API int edflib_version(void); -int edflib_get_handle(int file_number); +/** + * Returns 1 if the file is in use, either for reading or writing, otherwise returns 0. + * + * @param[in] path + * Pointer to a null-terminated string that contains the path to the file. + * + * @return + * 1 if the file is in use (either for reading or writing), otherwise 0. + */ +EDFLIB_API int edflib_is_file_used(const char *path); -/* returns the handle of an opened file, either for reading or writing */ -/* file_number starts with 0 */ -/* returns -1 if the file is not opened */ +/** + * Returns the number of open files. + * + * @return + * The number of open files, either for reading or writing. + */ +EDFLIB_API int edflib_get_number_of_open_files(void); +/** + * Returns the handle of an open file, either for reading or writing. + * + * @param[in] file_number + * A zero based index number of the list of open files. + * + * @return + * The file handle or -1 if the file_number >= number of open files. + */ +EDFLIB_API int edflib_get_handle(int file_number); /***************** the following functions are used to write files **************************/ +/** + * Opens an new file for writing. Warning: an already existing file with the same name will be silently overwritten without advance warning!
+ * This function is required if you want to write a file (or use edfopen_file_writeonly_with_params()) + * + * @param[in] path + * A null-terminated string containing the path and name of the file + * + * @param[in] filetype + * Must be EDFLIB_FILETYPE_EDFPLUS or EDFLIB_FILETYPE_BDFPLUS. + * + * @param[in] number_of_signals + * The number of signals you want to store into the file
+ * (excluding annotation signals, the library will take care of that). + * + * @return + * A file handle on success or a negative number in case of an error: + * - EDFLIB_MALLOC_ERROR + * - EDFLIB_NO_SUCH_FILE_OR_DIRECTORY + * - EDFLIB_MAXFILES_REACHED + * - EDFLIB_FILE_ALREADY_OPENED + * - EDFLIB_NUMBER_OF_SIGNALS_INVALID + * - EDFLIB_ARCH_ERROR + */ +EDFLIB_API int edfopen_file_writeonly(const char *path, int filetype, int number_of_signals); -int edfopen_file_writeonly(const char *path, int filetype, int number_of_signals); - -/* opens an new file for writing. warning, an already existing file with the same name will be silently overwritten without advance warning!! */ -/* path is a null-terminated string containing the path and name of the file */ -/* filetype must be EDFLIB_FILETYPE_EDFPLUS or EDFLIB_FILETYPE_BDFPLUS */ -/* returns a handle on success, you need this handle for the other functions */ -/* in case of an error it returns a negative number corresponding to one of the following values: */ -/* EDFLIB_MALLOC_ERROR */ -/* EDFLIB_NO_SUCH_FILE_OR_DIRECTORY */ -/* EDFLIB_MAXFILES_REACHED */ -/* EDFLIB_FILE_ALREADY_OPENED */ -/* EDFLIB_NUMBER_OF_SIGNALS_INVALID */ -/* This function is required if you want to write a file */ - - -int edf_set_samplefrequency(int handle, int edfsignal, int samplefrequency); - -/* Sets the samplefrequency of signal edfsignal. (In reallity, it sets the number of samples in a datarecord.) */ -/* Returns 0 on success, otherwise -1 */ -/* This function is required for every signal and can be called only after opening a */ -/* file in writemode and before the first sample write action */ - - -int edf_set_physical_maximum(int handle, int edfsignal, double phys_max); - -/* Sets the maximum physical value of signal edfsignal. (the value of the input of the ADC when the output equals the value of "digital maximum") */ -/* Returns 0 on success, otherwise -1 */ -/* This function is required for every signal and can be called only after opening a */ -/* file in writemode and before the first sample write action */ - - -int edf_set_physical_minimum(int handle, int edfsignal, double phys_min); - -/* Sets the minimum physical value of signal edfsignal. (the value of the input of the ADC when the output equals the value of "digital minimum") */ -/* Usually this will be (-(phys_max)) */ -/* Returns 0 on success, otherwise -1 */ -/* This function is required for every signal and can be called only after opening a */ -/* file in writemode and before the first sample write action */ - - -int edf_set_digital_maximum(int handle, int edfsignal, int dig_max); - -/* Sets the maximum digital value of signal edfsignal. The maximum value is 32767 for EDF+ and 8388607 for BDF+ */ -/* Usually it's the extreme output of the ADC */ -/* Returns 0 on success, otherwise -1 */ -/* This function is required for every signal and can be called only after opening a file in writemode */ -/* and before the first sample write action */ - - -int edf_set_digital_minimum(int handle, int edfsignal, int dig_min); - -/* Sets the minimum digital value of signal edfsignal. The minimum value is -32768 for EDF+ and -8388608 for BDF+ */ -/* Usually it's the extreme output of the ADC */ -/* Usually this will be (-(dig_max + 1)) */ -/* Returns 0 on success, otherwise -1 */ -/* This function is required for every signal and can be called only after opening a file in writemode */ -/* and before the first sample write action */ - - -int edf_set_label(int handle, int edfsignal, const char *label); - -/* Sets the label (name) of signal edfsignal. ("FP1", "SaO2", etc.) */ -/* label is a pointer to a NULL-terminated ASCII-string containing the label (name) of the signal edfsignal */ -/* Returns 0 on success, otherwise -1 */ -/* This function is recommended for every signal when you want to write a file */ -/* and can be called only after opening a file in writemode and before the first sample write action */ - - -int edf_set_prefilter(int handle, int edfsignal, const char *prefilter); - -/* Sets the prefilter of signal edfsignal ("HP:0.1Hz", "LP:75Hz N:50Hz", etc.). */ -/* prefilter is a pointer to a NULL-terminated ASCII-string containing the prefilter text of the signal edfsignal */ -/* Returns 0 on success, otherwise -1 */ -/* This function is optional and can be called only after opening a file in writemode and before */ -/* the first sample write action */ - - -int edf_set_transducer(int handle, int edfsignal, const char *transducer); - -/* Sets the transducer of signal edfsignal ("AgAgCl cup electrodes", etc.). */ -/* transducer is a pointer to a NULL-terminated ASCII-string containing the transducer text of the signal edfsignal */ -/* Returns 0 on success, otherwise -1 */ -/* This function is optional and can be called only after opening a file in writemode and before */ -/* the first sample write action */ - - -int edf_set_physical_dimension(int handle, int edfsignal, const char *phys_dim); - -/* Sets the physical dimension (unit) of signal edfsignal. ("uV", "BPM", "mA", "Degr.", etc.) */ -/* phys_dim is a pointer to a NULL-terminated ASCII-string containing the physical dimension of the signal edfsignal */ -/* Returns 0 on success, otherwise -1 */ -/* This function is recommended for every signal when you want to write a file */ -/* and can be called only after opening a file in writemode and before the first sample write action */ - - -int edf_set_startdatetime(int handle, int startdate_year, int startdate_month, int startdate_day, - int starttime_hour, int starttime_minute, int starttime_second); - -/* Sets the startdate and starttime. */ -/* year: 1970 - 3000, month: 1 - 12, day: 1 - 31 */ -/* hour: 0 - 23, minute: 0 - 59, second: 0 - 59 */ -/* If not called, the library will use the system date and time at runtime */ -/* Returns 0 on success, otherwise -1 */ -/* This function is optional and can be called only after opening a file in writemode */ -/* and before the first sample write action */ - - -int edf_set_patientname(int handle, const char *patientname); - -/* Sets the patientname. patientname is a pointer to a null-terminated ASCII-string. */ -/* Returns 0 on success, otherwise -1 */ -/* This function is optional and can be called only after opening a file in writemode */ -/* and before the first sample write action */ - - -int edf_set_patientcode(int handle, const char *patientcode); - -/* Sets the patientcode. patientcode is a pointer to a null-terminated ASCII-string. */ -/* Returns 0 on success, otherwise -1 */ -/* This function is optional and can be called only after opening a file in writemode */ -/* and before the first sample write action */ - - -int edf_set_gender(int handle, int gender); - -/* Sets the gender. 1 is male, 0 is female. */ -/* Returns 0 on success, otherwise -1 */ -/* This function is optional and can be called only after opening a file in writemode */ -/* and before the first sample write action */ - - - -int edf_set_birthdate(int handle, int birthdate_year, int birthdate_month, int birthdate_day); - -/* Sets the birthdate. */ -/* year: 1800 - 3000, month: 1 - 12, day: 1 - 31 */ -/* This function is optional */ -/* Returns 0 on success, otherwise -1 */ -/* This function is optional and can be called only after opening a file in writemode */ -/* and before the first sample write action */ - - -int edf_set_patient_additional(int handle, const char *patient_additional); - -/* Sets the additional patientinfo. patient_additional is a pointer to a null-terminated ASCII-string. */ -/* Returns 0 on success, otherwise -1 */ -/* This function is optional and can be called only after opening a file in writemode */ -/* and before the first sample write action */ - +/** + * This is a convenience function that can create a new EDF file and initializes the most important parameters.
+ * It assumes that all signals are sharing the same parameters (you can still change them though).
+ * Warning: an already existing file with the same name will be silently overwritten without advance warning!
+ * + * @param[in] path + * A null-terminated string containing the path and name of the file. + * + * @param[in] filetype + * Must be EDFLIB_FILETYPE_EDFPLUS or EDFLIB_FILETYPE_BDFPLUS. + * + * @param[in] number_of_signals + * The number of signals you want to store into the file
+ * (excluding annotation signals, the library will take care of that). + * + * @param[in] samplefrequency + * Sample frequency for all signals. (In reality, it sets the number of samples per datarecord which equals the sample frequency only when
+ * the datarecords have a duration of one second which is the default here.) + * + * @param[in] phys_max_min + * Physical maximum and minimum for all signals. + * + * @param[in] phys_dim + * Pointer to a NULL-terminated ASCII-string containing the physical dimension (unit) for all signals ("uV", "BPM", "mA", "Degr.", etc.). + * + * @return + * A file handle on success or a negative number in case of an error: + * - EDFLIB_MALLOC_ERROR + * - EDFLIB_NO_SUCH_FILE_OR_DIRECTORY + * - EDFLIB_MAXFILES_REACHED + * - EDFLIB_FILE_ALREADY_OPENED + * - EDFLIB_NUMBER_OF_SIGNALS_INVALID + * - EDFLIB_ARCH_ERROR + */ +EDFLIB_API int edfopen_file_writeonly_with_params(const char *path, int filetype, int number_of_signals, int samplefrequency, double phys_max_min, const char *phys_dim); + +/** + * Sets the sample frequency of signal edfsignal. In reality, it sets the number of samples in a datarecord
+ * which equals the sample frequency only when the datarecords have a duration of one second.
+ * The effective sample frequency is: samplefrequency / datarecord duration
+ * This function is required for every signal (except when using edfopen_file_writeonly_with_params()) and can be called
+ * only after opening a file in write mode and before the first sample write action.
+ * + * @param[in] handle + * File handle. + * + * @param[in] edfsignal + * The zero-based index of the signal. + * + * @param[in] samplefrequency + * Sample frequency, must be > 0; + * + * @return + * 0 on success, otherwise -1.
+ */ +EDFLIB_API int edf_set_samplefrequency(int handle, int edfsignal, int samplefrequency); + +/** + * Sets the maximum physical value of signal edfsignal. (the value of the input of the ADC when the output equals the value of "digital maximum")
+ * It is the highest value that the equipment is able to record. It does not necessarily mean the signal recorded reaches this level.
+ * In other words, it is the highest value that CAN occur in the recording.
+ * Must be un-equal to physical minimum.
+ * This function is required for every signal (except when using edfopen_file_writeonly_with_params()) and can be called
+ * only after opening a file in write mode and before the first sample write action.
+ * + * @param[in] handle + * File handle. + * + * @param[in] edfsignal + * The zero-based index of the signal. + * + * @param[in] phys_max + * Physical maximum, must be != physical minimum; + * + * @return + * 0 on success, otherwise -1.
+ */ +EDFLIB_API int edf_set_physical_maximum(int handle, int edfsignal, double phys_max); + +/** + * Sets the minimum physical value of signal edfsignal. (the value of the input of the ADC when the output equals the value of "digital minimum")
+ * It is the lowest value that the equipment is able to record. It does not necessarily mean the signal recorded reaches this level.
+ * In other words, it is the lowest value that CAN occur in the recording.
+ * Must be un-equal to physical maximum.
+ * This function is required for every signal (except when using edfopen_file_writeonly_with_params()) and can be called
+ * only after opening a file in write mode and before the first sample write action.
+ * + * @param[in] handle + * File handle. + * + * @param[in] edfsignal + * The zero-based index of the signal. + * + * @param[in] phys_min + * Physical minimum, must be != physical maximum; + * + * @return + * 0 on success, otherwise -1.
+ */ +EDFLIB_API int edf_set_physical_minimum(int handle, int edfsignal, double phys_min); + +/** + * Sets the maximum digital value of signal edfsignal. The maximum value is 32767 for EDF+ and 8388607 for BDF+.
+ * It is the highest value that the equipment is able to record. It does not necessarily mean the signal recorded reaches this level.
+ * In other words, it is the highest value that CAN occur in the recording.
+ * Must be higher than digital minimum.
+ * This function is required for every signal (except when using edfopen_file_writeonly_with_params()) and can be called
+ * only after opening a file in write mode and before the first sample write action.
+ * + * @param[in] handle + * File handle. + * + * @param[in] edfsignal + * The zero-based index of the signal. + * + * @param[in] dig_max + * Digital maximum, must be > digital minimum; + * + * @return + * 0 on success, otherwise -1.
+ */ +EDFLIB_API int edf_set_digital_maximum(int handle, int edfsignal, int dig_max); + +/** + * Sets the minimum digital value of signal edfsignal. The minimum value is -32768 for EDF+ and -8388608 for BDF+.
+ * It is the lowest value that the equipment is able to record. It does not necessarily mean the signal recorded reaches this level.
+ * In other words, it is the lowest value that CAN occur in the recording.
+ * Must be lower than digital maximum.
+ * This function is required for every signal (except when using edfopen_file_writeonly_with_params()) and can be called
+ * only after opening a file in write mode and before the first sample write action.
+ * + * @param[in] handle + * File handle. + * + * @param[in] edfsignal + * The zero-based index of the signal. + * + * @param[in] dig_min + * Digital minimum, must be < digital maximum; + * + * @return + * 0 on success, otherwise -1.
+ */ +EDFLIB_API int edf_set_digital_minimum(int handle, int edfsignal, int dig_min); -int edf_set_admincode(int handle, const char *admincode); +/** + * Sets the label (name) of signal \p edfsignal. ("EEG FP1", "SaO2", etc.).
+ * This function is recommended for every signal when you want to write a file
+ * and can be called only after opening a file in write mode and before the first sample write action.
+ * + * @param[in] handle + * File handle. + * + * @param[in] edfsignal + * The zero-based index of the signal. + * + * @param[in] label + * A pointer to a NULL-terminated ASCII-string containing the label (name) of the signal \p edfsignal. + * + * @return + * 0 on success, otherwise -1.
+ */ +EDFLIB_API int edf_set_label(int handle, int edfsignal, const char *label); -/* Sets the admincode. admincode is a pointer to a null-terminated ASCII-string. */ -/* Returns 0 on success, otherwise -1 */ -/* This function is optional and can be called only after opening a file in writemode */ -/* and before the first sample write action */ +/** + * Sets the prefilter of signal \p edfsignal e.g. "HP:0.1Hz", "LP:75Hz N:50Hz", etc.
+ * This function is optional and can be called only after opening a file in writemode and
+ * before the first sample write action. + * + * @param[in] handle + * File handle. + * + * @param[in] edfsignal + * The zero-based index of the signal. + * + * @param[in] prefilter + * A pointer to a NULL-terminated ASCII-string containing the prefilter text of the signal \p edfsignal. + * + * @return + * 0 on success, otherwise -1.
+ */ +EDFLIB_API int edf_set_prefilter(int handle, int edfsignal, const char *prefilter); +/** + * Sets the transducer of signal \p edfsignal e.g. "AgAgCl cup electrodes", etc.
+ * This function is optional and can be called only after opening a file in writemode and
+ * before the first sample write action. + * + * @param[in] handle + * File handle. + * + * @param[in] edfsignal + * The zero-based index of the signal. + * + * @param[in] transducer + * A pointer to a NULL-terminated ASCII-string containing the transducer text of the signal \p edfsignal. + * + * @return + * 0 on success, otherwise -1.
+ */ +EDFLIB_API int edf_set_transducer(int handle, int edfsignal, const char *transducer); -int edf_set_technician(int handle, const char *technician); +/** + * Sets the physical dimension (unit) of signal \p edfsignal. ("uV", "BPM", "mA", "Degr.", etc.).
+ * This function is recommended for every signal when you want to write a file
+ * and can be called only after opening a file in write mode and before the first sample write action.
+ * + * @param[in] handle + * File handle. + * + * @param[in] edfsignal + * The zero-based index of the signal. + * + * @param[in] phys_dim + * A pointer to a NULL-terminated ASCII-string containing the physical dimension (unit) of the signal \p edfsignal. + * + * @return + * 0 on success, otherwise -1.
+ */ +EDFLIB_API int edf_set_physical_dimension(int handle, int edfsignal, const char *phys_dim); + +/** + * Sets the startdate and starttime.
+ * If not called, the library will use the system date and time at runtime.
+ * This function is optional and can be called only after opening a file in write mode
+ * and before the first sample write action.
+ * Note: for anonymization purposes, the consensus is to use 1985-01-01 00:00:00 for the startdate and starttime. + * + * @param[in] handle + * File handle. + * + * @param[in] startdate_year + * 1985 - 2084 inclusive + * + * @param[in] startdate_month + * 1 - 12 inclusive + * + * @param[in] startdate_day + * 1 - 31 inclusive + * + * @param[in] starttime_hour + * 0 - 23 inclusive + * + * @param[in] starttime_minute + * 0 - 59 inclusive + * + * @param[in] starttime_second + * 0 - 59 inclusive + * + * @return + * 0 on success, otherwise -1.
+ */ +EDFLIB_API int edf_set_startdatetime(int handle, int startdate_year, int startdate_month, int startdate_day, + int starttime_hour, int starttime_minute, int starttime_second); -/* Sets the technicians name. technician is a pointer to a null-terminated ASCII-string. */ -/* Returns 0 on success, otherwise -1 */ -/* This function is optional and can be called only after opening a file in writemode */ -/* and before the first sample write action */ +/** + * Sets the subject name
+ * This function is optional and can be called only after opening a file in writemode and
+ * before the first sample write action. + * + * @param[in] handle + * File handle. + * + * @param[in] patientname + * A pointer to a NULL-terminated ASCII-string containing the subject name. + * + * @return + * 0 on success, otherwise -1.
+ */ +EDFLIB_API int edf_set_patientname(int handle, const char *patientname); +/** + * Sets the subject code
+ * This function is optional and can be called only after opening a file in writemode and
+ * before the first sample write action. + * + * @param[in] handle + * File handle. + * + * @param[in] patientcode + * A pointer to a NULL-terminated ASCII-string containing the subject code. + * + * @return + * 0 on success, otherwise -1.
+ */ +EDFLIB_API int edf_set_patientcode(int handle, const char *patientcode); -int edf_set_equipment(int handle, const char *equipment); +/** + * Sets the sex of the subject. 1 is male, 0 is female.
+ * This function is optional and can be called only after opening a file in writemode
+ * and before the first sample write action.
+ * + * @param[in] handle + * File handle. + * + * @param[in] sex + * 1: male, 0: female. + * + * @return + * 0 on success, otherwise -1.
+ */ +EDFLIB_API int edf_set_sex(int handle, int sex); -/* Sets the name of the equipment used during the aquisition. equipment is a pointer to a null-terminated ASCII-string. */ -/* Returns 0 on success, otherwise -1 */ -/* This function is optional and can be called only after opening a file in writemode */ -/* and before the first sample write action */ +#if defined(__GNUC__) +EDFLIB_API int edf_set_gender(int handle, int sex) __attribute__ ((deprecated ("use edf_set_sex()"))); +#else +EDFLIB_API int edf_set_gender(int handle, int sex); +#endif +/* DEPRECATED!! USE edf_set_sex() + * Sets the sex. 1 is male, 0 is female. + * Returns 0 on success, otherwise -1 + * This function is optional and can be called only after opening a file in writemode + * and before the first sample write action + */ +/** + * Sets the subject birthdate.
+ * This function is optional and can be called only after opening a file in write mode
+ * and before the first sample write action.
+ * + * @param[in] handle + * File handle. + * + * @param[in] birthdate_year + * 1800 - 3000 inclusive + * + * @param[in] birthdate_month + * 1 - 12 inclusive + * + * @param[in] birthdate_day + * 1 - 31 inclusive + * + * @return + * 0 on success, otherwise -1.
+ */ +EDFLIB_API int edf_set_birthdate(int handle, int birthdate_year, int birthdate_month, int birthdate_day); -int edf_set_recording_additional(int handle, const char *recording_additional); +/** + * Sets the additional subject info
+ * This function is optional and can be called only after opening a file in writemode and
+ * before the first sample write action. + * + * @param[in] handle + * File handle. + * + * @param[in] patient_additional + * A pointer to a NULL-terminated ASCII-string containing the additional subject info. + * + * @return + * 0 on success, otherwise -1.
+ */ +EDFLIB_API int edf_set_patient_additional(int handle, const char *patient_additional); -/* Sets the additional recordinginfo. recording_additional is a pointer to a null-terminated ASCII-string. */ -/* Returns 0 on success, otherwise -1 */ -/* This function is optional and can be called only after opening a file in writemode */ -/* and before the first sample write action */ +/** + * Sets the administration code
+ * This function is optional and can be called only after opening a file in writemode and
+ * before the first sample write action. + * + * @param[in] handle + * File handle. + * + * @param[in] admincode + * A pointer to a NULL-terminated ASCII-string containing the administration code. + * + * @return + * 0 on success, otherwise -1.
+ */ +EDFLIB_API int edf_set_admincode(int handle, const char *admincode); +/** + * Sets the technicians name or code
+ * This function is optional and can be called only after opening a file in writemode and
+ * before the first sample write action. + * + * @param[in] handle + * File handle. + * + * @param[in] technician + * A pointer to a NULL-terminated ASCII-string containing the technicians name or code. + * + * @return + * 0 on success, otherwise -1.
+ */ +EDFLIB_API int edf_set_technician(int handle, const char *technician); -int edfwrite_physical_samples(int handle, double *buf); +/** + * Sets the equipment brand and/or model
+ * This function is optional and can be called only after opening a file in writemode and
+ * before the first sample write action. + * + * @param[in] handle + * File handle. + * + * @param[in] equipment + * A pointer to a NULL-terminated ASCII-string containing the equipment brand and/or model
+ * used for the recording. + * + * @return + * 0 on success, otherwise -1.
+ */ +EDFLIB_API int edf_set_equipment(int handle, const char *equipment); -/* Writes n physical samples (uV, mA, Ohm) from *buf belonging to one signal */ -/* where n is the samplefrequency of that signal. */ -/* The physical samples will be converted to digital samples using the */ -/* values of physical maximum, physical minimum, digital maximum and digital minimum */ -/* The number of samples written is equal to the samplefrequency of the signal */ -/* Size of buf should be equal to or bigger than sizeof(double[samplefrequency]) */ -/* Call this function for every signal in the file. The order is important! */ -/* When there are 4 signals in the file, the order of calling this function */ -/* must be: signal 0, signal 1, signal 2, signal 3, signal 0, signal 1, signal 2, etc. */ -/* Returns 0 on success, otherwise -1 */ +/** + * Sets the additional info about the recording.
+ * This function is optional and can be called only after opening a file in writemode and
+ * before the first sample write action. + * + * @param[in] handle + * File handle. + * + * @param[in] recording_additional + * A pointer to a NULL-terminated ASCII-string containing the additional info about the recording. + * + * @return + * 0 on success, otherwise -1.
+ */ +EDFLIB_API int edf_set_recording_additional(int handle, const char *recording_additional); + +/** + * Writes n physical samples (uV, mA, Ohm) from \p buf belonging to one signal
+ * where n is the samplefrequency of that signal.
+ * Actually, n equals the number of samples per datarecord which equals the samplefrequency only
+ * when the datarecord duration has the default value of one second!
+ * The physical samples will be converted to digital samples using the
+ * values of physical maximum, physical minimum, digital maximum and digital minimum.
+ * Size of \p buf must be equal to or bigger than sizeof(double[samples per datarecord]).
+ * Call this function for every signal in the file. The order is important:
+ * When there are 4 signals in the file, the order of calling this function
+ * must be: signal 0, signal 1, signal 2, signal 3, signal 0, signal 1, signal 2, etc.
+ * + * @param[in] handle + * File handle. + * + * @param[in] buf + * A pointer to a buffer containing the samples. + * + * @return + * 0 on success, otherwise -1.
+ */ +EDFLIB_API int edfwrite_physical_samples(int handle, double *buf); + +/** + * Writes physical samples (uV, mA, Ohm) from \p buf
+ * \p buf must be filled with samples from all signals, starting with n samples of signal 0, n samples of signal 1, n samples of signal 2, etc.
+ * where n is the samplefrequency of that signal.
+ * Actually, n equals the number of samples per datarecord which equals the samplefrequency only
+ * when the datarecord duration has the default value of one second!
+ * The physical samples will be converted to digital samples using the
+ * values of physical maximum, physical minimum, digital maximum and digital minimum.
+ * The number of samples written equals the sum of the samples per datarecord of all signals. + * + * @param[in] handle + * File handle. + * + * @param[in] buf + * A pointer to a buffer containing the samples. + * + * @return + * 0 on success, otherwise -1.
+ */ +EDFLIB_API int edf_blockwrite_physical_samples(int handle, double *buf); + +/** + * Writes n "raw" digital samples from \p buf belonging to one signal
+ * where n is the samplefrequency of that signal.
+ * Actually, n equals the number of samples per datarecord which equals the samplefrequency only
+ * when the datarecord duration has the default value of one second!
+ * Size of \p buf should be equal to or bigger than sizeof(short[samples per datarecord]).
+ * Call this function for every signal in the file. The order is important:
+ * When there are 4 signals in the file, the order of calling this function
+ * must be: signal 0, signal 1, signal 2, signal 3, signal 0, signal 1, signal 2, etc.
+ * + * @param[in] handle + * File handle. + * + * @param[in] buf + * A pointer to a buffer containing the samples. + * + * @return + * 0 on success, otherwise -1.
+ */ +EDFLIB_API int edfwrite_digital_short_samples(int handle, short *buf); + +/** + * Writes n "raw" digital samples from \p buf belonging to one signal
+ * where n is the samplefrequency of that signal.
+ * Actually, n equals the number of samples per datarecord which equals the samplefrequency only
+ * when the datarecord duration has the default value of one second!
+ * The 16 (or 24 in case of BDF+) least significant bits of the samples will be written to the
+ * file without any conversion.
+ * Size of \p buf should be equal to or bigger than sizeof(int[samples per datarecord]).
+ * Call this function for every signal in the file. The order is important:
+ * When there are 4 signals in the file, the order of calling this function
+ * must be: signal 0, signal 1, signal 2, signal 3, signal 0, signal 1, signal 2, etc.
+ * + * @param[in] handle + * File handle. + * + * @param[in] buf + * A pointer to a buffer containing the samples. + * + * @return + * 0 on success, otherwise -1.
+ */ +EDFLIB_API int edfwrite_digital_samples(int handle, int *buf); + +/** + * Writes "raw" digital samples from \p buf
+ * \p buf must be filled with samples from all signals, starting with n samples of signal 0, n samples of signal 1, n samples of signal 2, etc.
+ * where n is the samplefrequency of that signal.
+ * Actually, n equals the number of samples per datarecord which equals the samplefrequency only
+ * when the datarecord duration has the default value of one second!
+ * One sample equals 3 bytes, order is little endian (least significant byte first).
+ * Encoding is second's complement, most significant bit of most significant byte is the sign-bit.
+ * Because the size of a 3-byte sample is 24-bit, this function can only be used when writing a BDF+ file.
+ * The number of samples written equals the sum of the samples per datarecord of all signals. + * + * @param[in] handle + * File handle. + * + * @param[in] buf + * A pointer to a buffer containing the samples. + * + * @return + * 0 on success, otherwise -1.
+ */ +EDFLIB_API int edf_blockwrite_digital_3byte_samples(int handle, void *buf); + +/** + * Writes "raw" digital samples from \p buf
+ * \p buf must be filled with samples from all signals, starting with n samples of signal 0, n samples of signal 1, n samples of signal 2, etc.
+ * where n is the samplefrequency of that signal.
+ * Actually, n equals the number of samples per datarecord which equals the samplefrequency only
+ * when the datarecord duration has the default value of one second!
+ * One sample equals 2 bytes, order is little endian (least significant byte first).
+ * Encoding is second's complement, most significant bit of most significant byte is the sign-bit.
+ * Because the size of a 2-byte sample is 16-bit, this function can only be used when writing an EDF+ file.
+ * The number of samples written equals the sum of the samples per datarecord of all signals. + * + * @param[in] handle + * File handle. + * + * @param[in] buf + * A pointer to a buffer containing the samples. + * + * @return + * 0 on success, otherwise -1.
+ */ +EDFLIB_API int edf_blockwrite_digital_short_samples(int handle, short *buf); + +/** + * Writes "raw" digital samples from \p buf
+ * \p buf must be filled with samples from all signals, starting with n samples of signal 0, n samples of signal 1, n samples of signal 2, etc.
+ * where n is the samplefrequency of that signal.
+ * Actually, n equals the number of samples per datarecord which equals the samplefrequency only
+ * when the datarecord duration has the default value of one second!
+ * The 16 (or 24 in case of BDF+) least significant bits of the samples will be written to the
+ * file without any conversion.
+ * The number of samples written equals the sum of the samples per datarecord of all signals. + * + * @param[in] handle + * File handle. + * + * @param[in] buf + * A pointer to a buffer containing the samples. + * + * @return + * 0 on success, otherwise -1.
+ */ +EDFLIB_API int edf_blockwrite_digital_samples(int handle, int *buf); +/** + * Writes an annotation/event to the file.
+ * This function is optional and can be called only after opening a file in writemode
+ * and before closing the file.
+ * + * @param[in] handle + * File handle. + * + * @param[in] onset + * microseconds since start of recording. + * + * @param[in] duration + * microseconds, > 0 or -1 if not used. + * + * @param[in] description + * A null-terminated UTF8-string containing the text that describes the event. + * + * @return + * 0 on success, otherwise -1.
+ */ +EDFLIB_API int edfwrite_annotation_utf8_hr(int handle, long long onset, long long duration, const char *description); -int edf_blockwrite_physical_samples(int handle, double *buf); +#if defined(__GNUC__) +EDFLIB_API int edfwrite_annotation_utf8(int handle, long long onset, long long duration, const char *description) __attribute__ ((deprecated ("use edfwrite_annotation_utf8_hr()"))); +#else +EDFLIB_API int edfwrite_annotation_utf8(int handle, long long onset, long long duration, const char *description); +#endif +/* DEPRECATED!! USE edfwrite_annotation_utf8_hr() + * writes an annotation/event to the file + * onset is relative to the start of the file + * onset and duration are in units of 100 microseconds! resolution is 0.0001 second! + * for example: 34.071 seconds must be written as 340710 + * if duration is unknown or not applicable: set a negative number (-1) + * description is a null-terminated UTF8-string containing the text that describes the event + * This function is optional and can be called only after opening a file in writemode + * and before closing the file + */ -/* Writes physical samples (uV, mA, Ohm) from *buf */ -/* buf must be filled with samples from all signals, starting with n samples of signal 0, n samples of signal 1, n samples of signal 2, etc. */ -/* where n is the samplefrequency of that signal. */ -/* buf must be filled with samples from all signals, starting with signal 0, 1, 2, etc. */ -/* one block equals one second */ -/* The physical samples will be converted to digital samples using the */ -/* values of physical maximum, physical minimum, digital maximum and digital minimum */ -/* The number of samples written is equal to the sum of the samplefrequencies of all signals */ -/* Size of buf should be equal to or bigger than sizeof(double) multiplied by the sum of the samplefrequencies of all signals */ -/* Returns 0 on success, otherwise -1 */ +/** + * Writes an annotation/event to the file.
+ * This function is optional and can be called only after opening a file in writemode
+ * and before closing the file. + * + * @param[in] handle + * File handle. + * + * @param[in] onset + * microseconds since start of recording. + * + * @param[in] duration + * microseconds, > 0 or -1 if not used. + * + * @param[in] description + * A null-terminated Latin1-string containing the text that describes the event. + * + * @return + * 0 on success, otherwise -1.
+ */ +EDFLIB_API int edfwrite_annotation_latin1_hr(int handle, long long onset, long long duration, const char *description); +#if defined(__GNUC__) +EDFLIB_API int edfwrite_annotation_latin1(int handle, long long onset, long long duration, const char *description) __attribute__ ((deprecated ("use edfwrite_annotation_latin1_hr()"))); +#else +EDFLIB_API int edfwrite_annotation_latin1(int handle, long long onset, long long duration, const char *description); +#endif +/* DEPRECATED!! USE edfwrite_annotation_latin1_hr() + * writes an annotation/event to the file + * onset is relative to the start of the file + * onset and duration are in units of 100 microseconds! resolution is 0.0001 second! + * for example: 34.071 seconds must be written as 340710 + * if duration is unknown or not applicable: set a negative number (-1) + * description is a null-terminated Latin1-string containing the text that describes the event + * This function is optional and can be called only after opening a file in writemode + * and before closing the file + */ -int edfwrite_digital_short_samples(int handle, short *buf); +/** + * Sets the datarecord duration. The default value is 1 second.
+ * ATTENTION: the argument \p duration is expressed in units of 10 microseconds.
+ * So, if you want to set the datarecord duration to 0.1 second, you must write a value of 10000.
+ * The datarecord duration must be in the range 0.001 to 60 seconds.
+ * This function can be used when you want to use a samplerate
+ * which is not an integer. For example, if you want to use a samplerate of 0.5 Hz,
+ * set the samplefrequency to 5 Hz and the datarecord duration to 10 seconds,
+ * or set the samplefrequency to 1 Hz and the datarecord duration to 2 seconds.
+ * This function is optional and can be called after opening a
+ * file in writemode and before the first sample write action. + * + * @param[in] handle + * File handle. + * + * @param[in] duration + * Datarecord duration expressed in units of 10 microSecond. + * + * @return + * 0 on success, otherwise -1.
+ */ +EDFLIB_API int edf_set_datarecord_duration(int handle, int duration); + +/** + * Sets the datarecord duration to a very small value.
+ * ATTENTION: the argument \p duration is expressed in units of 1 microSecond.
+ * The datarecord duration must be in the range 1 to 9999 microseconds.
+ * This function can be used when you want to use a very high samplerate.
+ * For example, if you want to use a samplerate of 5 GHz,
+ * set the samplefrequency to 5000 Hz and the datarecord duration to 1 micro-second.
+ * Do not use this function if not necessary.
+ * This function was added to accommodate for high speed ADC's e.g. Digital Sampling Oscilloscopes
+ * This function is optional and can be called after opening a
+ * file in writemode and before the first sample write action. + * + * @param[in] handle + * File handle. + * + * @param[in] duration + * Datarecord duration expressed in units of 10 microSecond. + * + * @return + * 0 on success, otherwise -1.
+ */ +EDFLIB_API int edf_set_micro_datarecord_duration(int handle, int duration); + +/** + * Sets the number of annotation signals. The default value is 1.
+ * This function is optional and can be called only after opening a file in writemode
+ * and before the first sample write action.
+ * Normally you don't need to change the default value. Only when the number of annotations
+ * you expect to write is more than the number of datarecords in the recording, you can use
+ * this function to increase the storage space for annotations.
+ * + * @param[in] handle + * File handle. + * + * @param[in] annot_signals + * Number of annotation signals, must be in the range 1 - 64 inclusive. + * + * @return + * 0 on success, otherwise -1.
+ */ +EDFLIB_API int edf_set_number_of_annotation_signals(int handle, int annot_signals); + +/** + * Sets the subsecond starttime expressed in units of 100 nanoseconds.
+ * Valid range is 0 to 9999999 inclusive. Default is 0.
+ * This function is optional and can be called only after opening a file in writemode
+ * and before the first sample write action.
+ * It is recommended to use a maximum resolution of not more than 100 microseconds.
+ * E.g. use 1234000 to set a starttime offset of 0.1234 seconds (instead of for example 1234217).
+ * In other words, leave the last 3 digits at zero.
+ * + * @param[in] handle + * File handle. + * + * @param[in] subsecond + * Subsecond starttime expressed in units of 100 nanoseconds. + * + * @return + * 0 on success, otherwise -1.
+ */ +EDFLIB_API int edf_set_subsecond_starttime(int handle, int subsecond); -/* Writes n "raw" digital samples from *buf belonging to one signal */ -/* where n is the samplefrequency of that signal. */ -/* The samples will be written to the file without any conversion. */ -/* Because the size of a short is 16-bit, do not use this function with BDF (24-bit) */ -/* The number of samples written is equal to the samplefrequency of the signal */ -/* Size of buf should be equal to or bigger than sizeof(short[samplefrequency]) */ -/* Call this function for every signal in the file. The order is important! */ -/* When there are 4 signals in the file, the order of calling this function */ -/* must be: signal 0, signal 1, signal 2, signal 3, signal 0, signal 1, signal 2, etc. */ -/* Returns 0 on success, otherwise -1 */ +/** + * Sets the preferred position of the annotation channels(s) before, after or in the middle of the list
+ * of regular signals. The default is to put them at the end (after the regular signals).
+ * This function is optional and can be called only after opening a file in writemode
+ * and before the first sample write action.
+ * + * @param[in] handle + * File handle. + * + * @param[in] pos + * Preferred position of the annotation channel(s):
+ * EDF_ANNOT_IDX_POS_START
+ * EDF_ANNOT_IDX_POS_MIDDLE
+ * EDF_ANNOT_IDX_POS_END
+ * + * @return + * 0 on success, otherwise -1.
+ */ +EDFLIB_API int edf_set_annot_chan_idx_pos(int handle, int pos); +#ifdef __cplusplus +} /* extern "C" */ +#endif -int edfwrite_digital_samples(int handle, int *buf); +#endif -/* Writes n "raw" digital samples from *buf belonging to one signal */ -/* where n is the samplefrequency of that signal. */ -/* The 16 (or 24 in case of BDF) least significant bits of the sample will be written to the */ -/* file without any conversion. */ -/* The number of samples written is equal to the samplefrequency of the signal */ -/* Size of buf should be equal to or bigger than sizeof(int[samplefrequency]) */ -/* Call this function for every signal in the file. The order is important! */ -/* When there are 4 signals in the file, the order of calling this function */ -/* must be: signal 0, signal 1, signal 2, signal 3, signal 0, signal 1, signal 2, etc. */ -/* Returns 0 on success, otherwise -1 */ -int edf_blockwrite_digital_3byte_samples(int handle, void *buf); -/* Writes "raw" digital samples from *buf. */ -/* buf must be filled with samples from all signals, starting with n samples of signal 0, n samples of signal 1, n samples of signal 2, etc. */ -/* where n is the samplefrequency of that signal. */ -/* One block equals one second. One sample equals 3 bytes, order is little endian (least significant byte first) */ -/* Encoding is second's complement, most significant bit of most significant byte is the sign-bit */ -/* The samples will be written to the file without any conversion. */ -/* Because the size of a 3-byte sample is 24-bit, this function can only be used when writing a BDF file */ -/* The number of samples written is equal to the sum of the samplefrequencies of all signals. */ -/* Size of buf should be equal to or bigger than: the sum of the samplefrequencies of all signals x 3 bytes */ -/* Returns 0 on success, otherwise -1 */ - - -int edf_blockwrite_digital_short_samples(int handle, short *buf); - -/* Writes "raw" digital samples from *buf. */ -/* buf must be filled with samples from all signals, starting with n samples of signal 0, n samples of signal 1, n samples of signal 2, etc. */ -/* where n is the samplefrequency of that signal. */ -/* One block equals one second. */ -/* The samples will be written to the file without any conversion. */ -/* Because the size of a short is 16-bit, do not use this function with BDF (24-bit) */ -/* The number of samples written is equal to the sum of the samplefrequencies of all signals. */ -/* Size of buf should be equal to or bigger than sizeof(short) multiplied by the sum of the samplefrequencies of all signals */ -/* Returns 0 on success, otherwise -1 */ - - -int edf_blockwrite_digital_samples(int handle, int *buf); - -/* Writes "raw" digital samples from *buf. */ -/* buf must be filled with samples from all signals, starting with n samples of signal 0, n samples of signal 1, n samples of signal 2, etc. */ -/* where n is the samplefrequency of that signal. */ -/* One block equals one second. */ -/* The 16 (or 24 in case of BDF) least significant bits of the sample will be written to the */ -/* file without any conversion. */ -/* The number of samples written is equal to the sum of the samplefrequencies of all signals. */ -/* Size of buf should be equal to or bigger than sizeof(int) multiplied by the sum of the samplefrequencies of all signals */ -/* Returns 0 on success, otherwise -1 */ - - -int edfwrite_annotation_utf8(int handle, long long onset, long long duration, const char *description); - -/* writes an annotation/event to the file */ -/* onset is relative to the start of the file */ -/* onset and duration are in units of 100 microSeconds! resolution is 0.0001 second! */ -/* for example: 34.071 seconds must be written as 340710 */ -/* if duration is unknown or not applicable: set a negative number (-1) */ -/* description is a null-terminated UTF8-string containing the text that describes the event */ -/* This function is optional and can be called only after opening a file in writemode */ -/* and before closing the file */ - - -int edfwrite_annotation_latin1(int handle, long long onset, long long duration, const char *description); - -/* writes an annotation/event to the file */ -/* onset is relative to the start of the file */ -/* onset and duration are in units of 100 microSeconds! resolution is 0.0001 second! */ -/* for example: 34.071 seconds must be written as 340710 */ -/* if duration is unknown or not applicable: set a negative number (-1) */ -/* description is a null-terminated Latin1-string containing the text that describes the event */ -/* This function is optional and can be called only after opening a file in writemode */ -/* and before closing the file */ - - -int edf_set_datarecord_duration(int handle, int duration); - -/* Sets the datarecord duration. The default value is 1 second. */ -/* ATTENTION: the argument "duration" is expressed in units of 10 microSeconds! */ -/* So, if you want to set the datarecord duration to 0.1 second, you must give */ -/* the argument "duration" a value of "10000". */ -/* This function is optional, normally you don't need to change the default value. */ -/* The datarecord duration must be in the range 0.001 to 60 seconds. */ -/* Returns 0 on success, otherwise -1 */ -/* This function is NOT REQUIRED but can be called after opening a */ -/* file in writemode and before the first sample write action. */ -/* This function can be used when you want to use a samplerate */ -/* which is not an integer. For example, if you want to use a samplerate of 0.5 Hz, */ -/* set the samplefrequency to 5 Hz and the datarecord duration to 10 seconds, */ -/* or set the samplefrequency to 1 Hz and the datarecord duration to 2 seconds. */ -/* Do not use this function if not necessary. */ - - -int edf_set_micro_datarecord_duration(int handle, int duration); - -/* Sets the datarecord duration to a very small value. */ -/* ATTENTION: the argument "duration" is expressed in units of 1 microSecond! */ -/* This function is optional, normally you don't need to change the default value. */ -/* The datarecord duration must be in the range 1 to 9999 micro-seconds. */ -/* Returns 0 on success, otherwise -1 */ -/* This function is NOT REQUIRED but can be called after opening a */ -/* file in writemode and before the first sample write action. */ -/* This function can be used when you want to use a very high samplerate. */ -/* For example, if you want to use a samplerate of 5 GHz, */ -/* set the samplefrequency to 5000 Hz and the datarecord duration to 1 micro-second. */ -/* Do not use this function if not necessary. */ -/* This function was added to accommodate for high speed ADC's e.g. Digital Sampling Oscilloscopes */ - - -int edf_set_number_of_annotation_signals(int handle, int annot_signals); - -/* Sets the number of annotation signals. The default value is 1 */ -/* This function is optional and can be called only after opening a file in writemode */ -/* and before the first sample write action */ -/* Normally you don't need to change the default value. Only when the number of annotations */ -/* you want to write is higher than the number of datarecords in the recording, you can use */ -/* this function to increase the storage space for annotations */ -/* Minimum is 1, maximum is 64 */ -/* Returns 0 on success, otherwise -1 */ - - -int edf_set_subsecond_starttime(int handle, int subsecond); -/* Sets the subsecond starttime expressed in units of 100 nanoSeconds */ -/* Valid range is 0 to 9999999 inclusive. Default is 0 */ -/* This function is optional and can be called only after opening a file in writemode */ -/* and before the first sample write action */ -/* Returns 0 on success, otherwise -1 */ -/* It is strongly recommended to use a maximum resolution of no more than 100 micro-Seconds. */ -/* e.g. use 1234000 to set a starttime offset of 0.1234 seconds (instead of 1234567) */ -/* in other words, leave the last 3 digits at zero */ -#ifdef __cplusplus -} /* extern "C" */ -#endif -#endif From 9430c20a42f02de7f5f5d2ecef5b2048b6ebd5fd Mon Sep 17 00:00:00 2001 From: Dimitri Papadopoulos <3234522+DimitriPapadopoulos@users.noreply.github.com> Date: Sun, 2 Jul 2023 21:08:37 +0200 Subject: [PATCH 2/4] Increase resolution when writing annotations The new resolution is 1 microsecond, instead of 100 microseconds: https://gitlab.com/Teuniz/EDFlib/-/commit/6005976bc5894f84fcdc17dffcb287f40dfe6c9b --- pyedflib/_extensions/_pyedflib.pyi | 8 ++++---- pyedflib/_extensions/_pyedflib.pyx | 10 +++++----- pyedflib/_extensions/c_edf.pxd | 6 ++++-- pyedflib/edfwriter.py | 19 +++++++++++++------ 4 files changed, 26 insertions(+), 17 deletions(-) diff --git a/pyedflib/_extensions/_pyedflib.pyi b/pyedflib/_extensions/_pyedflib.pyi index 4d4a8616..66298afe 100644 --- a/pyedflib/_extensions/_pyedflib.pyi +++ b/pyedflib/_extensions/_pyedflib.pyi @@ -46,8 +46,8 @@ __all__ = [ 'set_technician', 'set_transducer', 'tell', - 'write_annotation_latin1', - 'write_annotation_utf8', + 'write_annotation_latin1_hr', + 'write_annotation_utf8_hr', 'write_digital_samples', 'write_digital_short_samples', 'write_errors', @@ -158,8 +158,8 @@ class EdfAnnotation: annotation: str def set_patientcode(handle: int, patientcode: str | bytes) -> int: ... -def write_annotation_latin1(handle: int, onset: int, duration: int, description: str | bytes) -> int: ... -def write_annotation_utf8(handle: int, onset: int, duration: int, description: str | bytes) -> int: ... +def write_annotation_latin1_hr(handle: int, onset: int, duration: int, description: str | bytes) -> int: ... +def write_annotation_utf8_hr(handle: int, onset: int, duration: int, description: str | bytes) -> int: ... def set_technician(handle: int, technician: str | bytes) -> int: ... def get_annotation(handle: int, n: int, edf_annotation: EdfAnnotation) -> int: ... def read_int_samples(handle: int, edfsignal: int, n: int, buf: np.ndarray[np.int32_t]) -> int: ... diff --git a/pyedflib/_extensions/_pyedflib.pyx b/pyedflib/_extensions/_pyedflib.pyx index 9631f7be..bf82ff7f 100644 --- a/pyedflib/_extensions/_pyedflib.pyx +++ b/pyedflib/_extensions/_pyedflib.pyx @@ -4,7 +4,7 @@ __doc__ = """Cython wrapper for low-level C edflib implementation.""" __all__ = ['lib_version', 'CyEdfReader', 'set_patientcode', 'set_starttime_subsecond', - 'write_annotation_latin1', 'write_annotation_utf8', 'set_technician', 'EdfAnnotation', + 'write_annotation_latin1_hr', 'write_annotation_utf8_hr', 'set_technician', 'EdfAnnotation', 'get_annotation', 'read_int_samples', 'blockwrite_digital_samples', 'blockwrite_physical_samples', 'set_recording_additional', 'write_physical_samples' ,'set_patientname', 'set_physical_minimum', 'read_physical_samples', 'close_file', 'set_physical_maximum', 'open_file_writeonly', @@ -438,11 +438,11 @@ def set_patientcode(int handle, char *patientcode): # check if rw? return c_edf.edf_set_patientcode(handle, patientcode) -cpdef int write_annotation_latin1(int handle, long long onset, long long duration, char *description): - return c_edf.edfwrite_annotation_latin1(handle, onset, duration, description) +cpdef int write_annotation_latin1_hr(int handle, long long onset, long long duration, char *description): + return c_edf.edfwrite_annotation_latin1_hr(handle, onset, duration, description) -cpdef int write_annotation_utf8(int handle, long long onset, long long duration, char *description): - return c_edf.edfwrite_annotation_utf8(handle, onset, duration, description) +cpdef int write_annotation_utf8_hr(int handle, long long onset, long long duration, char *description): + return c_edf.edfwrite_annotation_utf8_hr(handle, onset, duration, description) cpdef int set_technician(int handle, char *technician): return c_edf.edf_set_technician(handle, technician) diff --git a/pyedflib/_extensions/c_edf.pxd b/pyedflib/_extensions/c_edf.pxd index 356275cb..10de6c0b 100644 --- a/pyedflib/_extensions/c_edf.pxd +++ b/pyedflib/_extensions/c_edf.pxd @@ -7,8 +7,10 @@ include "edf.pxi" cdef extern from "c/edflib.h": int edf_set_patientcode(int, char *) - int edfwrite_annotation_latin1(int, long long int, long long int, char *) - int edfwrite_annotation_utf8(int, long long int, long long int, char *) + int edfwrite_annotation_utf8(int, long long, long long, const char *) + int edfwrite_annotation_latin1_hr(int, long long int, long long int, char *) + int edfwrite_annotation_latin1(int, long long, long long, const char *) + int edfwrite_annotation_utf8_hr(int, long long int, long long int, char *) int edflib_version() cdef struct edf_annotation_struct: long long int onset diff --git a/pyedflib/edfwriter.py b/pyedflib/edfwriter.py index 47116f03..10eae9b4 100644 --- a/pyedflib/edfwriter.py +++ b/pyedflib/edfwriter.py @@ -12,6 +12,13 @@ import math from functools import reduce from fractions import Fraction +from ._extensions._pyedflib import FILETYPE_EDFPLUS, FILETYPE_BDFPLUS, FILETYPE_BDF, FILETYPE_EDF +from ._extensions._pyedflib import open_file_writeonly, set_physical_maximum, set_patient_additional, set_digital_maximum +from ._extensions._pyedflib import set_birthdate, set_digital_minimum, set_technician, set_recording_additional, set_patientname +from ._extensions._pyedflib import set_patientcode, set_equipment, set_admincode, set_sex, set_datarecord_duration, set_number_of_annotation_signals +from ._extensions._pyedflib import set_startdatetime, set_starttime_subsecond, set_samples_per_record, set_physical_minimum, set_label, set_physical_dimension +from ._extensions._pyedflib import set_transducer, set_prefilter, write_physical_samples, close_file, write_annotation_latin1_hr, write_annotation_utf8_hr +from ._extensions._pyedflib import blockwrite_physical_samples, write_errors, blockwrite_digital_samples, write_digital_short_samples, write_digital_samples, blockwrite_digital_short_samples import numpy as np @@ -47,8 +54,8 @@ set_starttime_subsecond, set_technician, set_transducer, - write_annotation_latin1, - write_annotation_utf8, + write_annotation_latin1_hr, + write_annotation_utf8_hr, write_digital_samples, write_digital_short_samples, write_errors, @@ -1013,16 +1020,16 @@ def writeAnnotation(self, onset_in_seconds: Union[int, float], duration_in_secon if str_format == 'utf_8': if duration_in_seconds >= 0: - return write_annotation_utf8(self.handle, np.round(onset_in_seconds*10000).astype(np.int64), np.round(duration_in_seconds*10000).astype(int), du(description)) + return write_annotation_utf8_hr(self.handle, np.round(onset_in_seconds*1000000).astype(np.int64), np.round(duration_in_seconds*1000000).astype(np.int64), du(description)) else: - return write_annotation_utf8(self.handle, np.round(onset_in_seconds*10000).astype(np.int64), -1, du(description)) + return write_annotation_utf8_hr(self.handle, np.round(onset_in_seconds*1000000).astype(np.int64), -1, du(description)) else: if duration_in_seconds >= 0: # FIX: description must be bytes. string will fail in u function - return write_annotation_latin1(self.handle, np.round(onset_in_seconds*10000).astype(np.int64), np.round(duration_in_seconds*10000).astype(int), u(description).encode('latin1')) # type: ignore + return write_annotation_latin1_hr(self.handle, np.round(onset_in_seconds*1000000).astype(np.int64), np.round(duration_in_seconds*1000000).astype(np.int64), u(description).encode('latin1')) # type: ignore else: # FIX: description must be bytes. string will fail in u function - return write_annotation_latin1(self.handle, np.round(onset_in_seconds*10000).astype(np.int64), -1, u(description).encode('latin1')) # type: ignore + return write_annotation_latin1_hr(self.handle, np.round(onset_in_seconds*1000000).astype(np.int64), -1, u(description).encode('latin1')) # type: ignore def close(self) -> None: """ From 9e449e6080806b242849901eaaba5332e9770340 Mon Sep 17 00:00:00 2001 From: Dimitri Papadopoulos <3234522+DimitriPapadopoulos@users.noreply.github.com> Date: Sun, 2 Jul 2023 21:33:34 +0200 Subject: [PATCH 3/4] =?UTF-8?q?Change=20gender=20=E2=86=92=20sex?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit https://gitlab.com/Teuniz/EDFlib/-/commit/2bd510e09369dfd64eab6a756bb19e43fe48e872 --- pyedflib/_extensions/_pyedflib.pyx | 8 ++++---- pyedflib/_extensions/c_edf.pxd | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/pyedflib/_extensions/_pyedflib.pyx b/pyedflib/_extensions/_pyedflib.pyx index bf82ff7f..9f58f6e3 100644 --- a/pyedflib/_extensions/_pyedflib.pyx +++ b/pyedflib/_extensions/_pyedflib.pyx @@ -274,12 +274,12 @@ cdef class CyEdfReader: property sex: def __get__(self): - return self.hdr.gender + return self.hdr.sex property gender: def __get__(self): warnings.warn("Variable 'gender' is deprecated, use 'sex' instead.", DeprecationWarning, stacklevel=2) - return self.hdr.gender + return self.hdr.sex property birthdate: def __get__(self): @@ -583,11 +583,11 @@ def rewind(handle, edfsignal): def set_sex(handle, sex): """int edf_set_sex(int handle, int sex)""" if sex is None: return 0 #don't set sex at all to prevent default 'F' - return c_edf.edf_set_gender(handle, sex) + return c_edf.edf_set_sex(handle, sex) def set_gender(handle, gender): warnings.warn("Function 'set_gender' is deprecated, use 'set_sex' instead.", DeprecationWarning, stacklevel=2) - return set_sex(handle, gender) + return c_edf.edf_set_sex(handle, gender) def set_physical_dimension(handle, edfsignal, phys_dim): """int edf_set_physical_dimension(int handle, int edfsignal, const char *phys_dim)""" diff --git a/pyedflib/_extensions/c_edf.pxd b/pyedflib/_extensions/c_edf.pxd index 10de6c0b..ba767e8f 100644 --- a/pyedflib/_extensions/c_edf.pxd +++ b/pyedflib/_extensions/c_edf.pxd @@ -57,7 +57,7 @@ cdef extern from "c/edflib.h": char * patient char * recording char * patientcode - char * gender + char * sex char * birthdate char * patient_name char * patient_additional @@ -81,7 +81,7 @@ cdef extern from "c/edflib.h": int edf_blockwrite_digital_samples(int, int *) long long int edftell(int, int) void edfrewind(int, int) - int edf_set_gender(int, int) + int edf_set_sex(int, int) int edf_set_physical_dimension(int, int, char *) int edf_set_transducer(int, int, char *) int edf_set_prefilter(int, int, char *) From 8e111859aac6dc6f97df06c07dc592b8383e4286 Mon Sep 17 00:00:00 2001 From: Dimitri Papadopoulos <3234522+DimitriPapadopoulos@users.noreply.github.com> Date: Mon, 3 Jul 2023 21:38:38 +0200 Subject: [PATCH 4/4] Apply local patch to EDFlib v1.26 --- pyedflib/_extensions/c/edflib.c | 294 ++++++++++++++++++++------------ pyedflib/_extensions/c/edflib.h | 37 +++- 2 files changed, 220 insertions(+), 111 deletions(-) diff --git a/pyedflib/_extensions/c/edflib.c b/pyedflib/_extensions/c/edflib.c index 097e32dd..0d6ecaed 100644 --- a/pyedflib/_extensions/c/edflib.c +++ b/pyedflib/_extensions/c/edflib.c @@ -183,7 +183,8 @@ static int edf_files_open=0; static edfhdrblock_t *hdrlist[EDFLIB_MAXFILES]; -static edfhdrblock_t * edflib_check_edf_file(FILE *, int *); +static edfhdrblock_t * edflib_check_edf_file(FILE *, int *, int); +static int edflib_repair_file_size(const char *, edfhdrblock_t *); static int edflib_is_integer_number(char *); static int edflib_is_number(char *); static long long edflib_get_long_duration(char *); @@ -247,7 +248,7 @@ EDFLIB_API int edflib_get_handle(int file_number) } -EDFLIB_API int edfopen_file_readonly(const char *path, edflib_hdr_t *edfhdr, int read_annotations_mode) +EDFLIB_API int edfopen_file_readonly(const char *path, edflib_hdr_t *edfhdr, int read_annotations_mode, int check_file_size) { int i, j, channel, @@ -299,6 +300,17 @@ EDFLIB_API int edfopen_file_readonly(const char *path, edflib_hdr_t *edfhdr, int return -1; } + if(check_file_size<0) + { + edfhdr->filetype = EDFLIB_INVALID_CHECK_SIZE_VALUE; + return -1; + } + if(check_file_size>2) + { + edfhdr->filetype = EDFLIB_INVALID_CHECK_SIZE_VALUE; + return -1; + } + if(edf_files_open>=EDFLIB_MAXFILES) { edfhdr->filetype = EDFLIB_MAXFILES_REACHED; @@ -327,7 +339,17 @@ EDFLIB_API int edfopen_file_readonly(const char *path, edflib_hdr_t *edfhdr, int return -1; } - hdr = edflib_check_edf_file(file, &edf_error); + hdr = edflib_check_edf_file(file, &edf_error, check_file_size); + if (hdr==NULL && edf_error==EDFLIB_FILE_CONTAINS_FORMAT_ERRORS && check_file_size==EDFLIB_REPAIR_FILE_SIZE_IF_WRONG) + { + hdr = edflib_check_edf_file(file, &edf_error, EDFLIB_DO_NOT_CHECK_FILE_SIZE); + fclose(file); + edflib_repair_file_size(path, hdr); + free(hdr->edfparam); + free(hdr); + file = fopeno(path, "rb"); + hdr = edflib_check_edf_file(file, &edf_error, EDFLIB_CHECK_FILE_SIZE); + } if(hdr==NULL) { edfhdr->filetype = edf_error; @@ -1170,7 +1192,7 @@ EDFLIB_API int edf_get_annotation(int handle, int n, edflib_annotation_t *annot) } -static edfhdrblock_t * edflib_check_edf_file(FILE *inputfile, int *edf_error) +static edfhdrblock_t * edflib_check_edf_file(FILE *inputfile, int *edf_error, int check_file_size) { int i, j, p, r=0, n, dotposition, @@ -1308,7 +1330,7 @@ static edfhdrblock_t * edflib_check_edf_file(FILE *inputfile, int *edf_error) { if((scratchpad[i]<32)||(scratchpad[i]>126)) { - *edf_error = EDFLIB_FILE_CONTAINS_FORMAT_ERRORS; + *edf_error = EDFLIB_FILE_ERRORS_STARTDATE; free(edf_hdr); free(edfhdr); return NULL; @@ -1329,7 +1351,7 @@ static edfhdrblock_t * edflib_check_edf_file(FILE *inputfile, int *edf_error) if(error) { scratchpad[8] = 0; - *edf_error = EDFLIB_FILE_CONTAINS_FORMAT_ERRORS; + *edf_error = EDFLIB_FILE_ERRORS_STARTDATE; free(edf_hdr); free(edfhdr); return NULL; @@ -1343,7 +1365,7 @@ static edfhdrblock_t * edflib_check_edf_file(FILE *inputfile, int *edf_error) { strncpy(scratchpad, edf_hdr + 168, 8); scratchpad[8] = 0; - *edf_error = EDFLIB_FILE_CONTAINS_FORMAT_ERRORS; + *edf_error = EDFLIB_FILE_ERRORS_STARTDATE; free(edf_hdr); free(edfhdr); return NULL; @@ -1353,7 +1375,7 @@ static edfhdrblock_t * edflib_check_edf_file(FILE *inputfile, int *edf_error) { strncpy(scratchpad, edf_hdr + 168, 8); scratchpad[8] = 0; - *edf_error = EDFLIB_FILE_CONTAINS_FORMAT_ERRORS; + *edf_error = EDFLIB_FILE_ERRORS_STARTDATE; free(edf_hdr); free(edfhdr); return NULL; @@ -1379,7 +1401,7 @@ static edfhdrblock_t * edflib_check_edf_file(FILE *inputfile, int *edf_error) { if((scratchpad[i]<32)||(scratchpad[i]>126)) { - *edf_error = EDFLIB_FILE_CONTAINS_FORMAT_ERRORS; + *edf_error = EDFLIB_FILE_ERRORS_STARTTIME; free(edf_hdr); free(edfhdr); return NULL; @@ -1402,7 +1424,7 @@ static edfhdrblock_t * edflib_check_edf_file(FILE *inputfile, int *edf_error) { strncpy(scratchpad, edf_hdr + 176, 8); scratchpad[8] = 0; - *edf_error = EDFLIB_FILE_CONTAINS_FORMAT_ERRORS; + *edf_error = EDFLIB_FILE_ERRORS_STARTTIME; free(edf_hdr); free(edfhdr); return NULL; @@ -1416,7 +1438,7 @@ static edfhdrblock_t * edflib_check_edf_file(FILE *inputfile, int *edf_error) { strncpy(scratchpad, edf_hdr + 176, 8); scratchpad[8] = 0; - *edf_error = EDFLIB_FILE_CONTAINS_FORMAT_ERRORS; + *edf_error = EDFLIB_FILE_ERRORS_STARTTIME; free(edf_hdr); free(edfhdr); return NULL; @@ -1426,7 +1448,7 @@ static edfhdrblock_t * edflib_check_edf_file(FILE *inputfile, int *edf_error) { strncpy(scratchpad, edf_hdr + 176, 8); scratchpad[8] = 0; - *edf_error = EDFLIB_FILE_CONTAINS_FORMAT_ERRORS; + *edf_error = EDFLIB_FILE_ERRORS_STARTTIME; free(edf_hdr); free(edfhdr); return NULL; @@ -1436,7 +1458,7 @@ static edfhdrblock_t * edflib_check_edf_file(FILE *inputfile, int *edf_error) { strncpy(scratchpad, edf_hdr + 176, 8); scratchpad[8] = 0; - *edf_error = EDFLIB_FILE_CONTAINS_FORMAT_ERRORS; + *edf_error = EDFLIB_FILE_ERRORS_STARTTIME; free(edf_hdr); free(edfhdr); return NULL; @@ -1460,7 +1482,7 @@ static edfhdrblock_t * edflib_check_edf_file(FILE *inputfile, int *edf_error) { if((scratchpad[i]<32)||(scratchpad[i]>126)) { - *edf_error = EDFLIB_FILE_CONTAINS_FORMAT_ERRORS; + *edf_error = EDFLIB_FILE_ERRORS_NUMBER_SIGNALS; free(edf_hdr); free(edfhdr); return NULL; @@ -1469,7 +1491,7 @@ static edfhdrblock_t * edflib_check_edf_file(FILE *inputfile, int *edf_error) if(edflib_is_integer_number(scratchpad)) { - *edf_error = EDFLIB_FILE_CONTAINS_FORMAT_ERRORS; + *edf_error = EDFLIB_FILE_ERRORS_NUMBER_SIGNALS; free(edf_hdr); free(edfhdr); return NULL; @@ -1477,7 +1499,7 @@ static edfhdrblock_t * edflib_check_edf_file(FILE *inputfile, int *edf_error) edfhdr->edfsignals = edflib_atoi_nonlocalized(scratchpad); if(edfhdr->edfsignals<1) { - *edf_error = EDFLIB_FILE_CONTAINS_FORMAT_ERRORS; + *edf_error = EDFLIB_FILE_ERRORS_NUMBER_SIGNALS; free(edf_hdr); free(edfhdr); return NULL; @@ -1485,7 +1507,7 @@ static edfhdrblock_t * edflib_check_edf_file(FILE *inputfile, int *edf_error) if(edfhdr->edfsignals>EDFLIB_MAXSIGNALS) { - *edf_error = EDFLIB_FILE_CONTAINS_FORMAT_ERRORS; + *edf_error = EDFLIB_FILE_ERRORS_NUMBER_SIGNALS; free(edf_hdr); free(edfhdr); return NULL; @@ -1500,7 +1522,7 @@ static edfhdrblock_t * edflib_check_edf_file(FILE *inputfile, int *edf_error) { if((scratchpad[i]<32)||(scratchpad[i]>126)) { - *edf_error = EDFLIB_FILE_CONTAINS_FORMAT_ERRORS; + *edf_error = EDFLIB_FILE_ERRORS_BYTES_HEADER; free(edf_hdr); free(edfhdr); return NULL; @@ -1509,7 +1531,7 @@ static edfhdrblock_t * edflib_check_edf_file(FILE *inputfile, int *edf_error) if(edflib_is_integer_number(scratchpad)) { - *edf_error = EDFLIB_FILE_CONTAINS_FORMAT_ERRORS; + *edf_error = EDFLIB_FILE_ERRORS_BYTES_HEADER; free(edf_hdr); free(edfhdr); return NULL; @@ -1518,7 +1540,7 @@ static edfhdrblock_t * edflib_check_edf_file(FILE *inputfile, int *edf_error) n = edflib_atoi_nonlocalized(scratchpad); if((edfhdr->edfsignals * 256 + 256)!=n) { - *edf_error = EDFLIB_FILE_CONTAINS_FORMAT_ERRORS; + *edf_error = EDFLIB_FILE_ERRORS_BYTES_HEADER; free(edf_hdr); free(edfhdr); return NULL; @@ -1535,7 +1557,7 @@ static edfhdrblock_t * edflib_check_edf_file(FILE *inputfile, int *edf_error) { if((scratchpad[i]<32)||(scratchpad[i]>126)) { - *edf_error = EDFLIB_FILE_CONTAINS_FORMAT_ERRORS; + *edf_error = EDFLIB_FILE_ERRORS_RESERVED_FIELD; free(edf_hdr); free(edfhdr); return NULL; @@ -1556,7 +1578,7 @@ static edfhdrblock_t * edflib_check_edf_file(FILE *inputfile, int *edf_error) } else if(strncmp(scratchpad, " ", 44)) { - *edf_error = EDFLIB_FILE_CONTAINS_FORMAT_ERRORS; + *edf_error = EDFLIB_FILE_ERRORS_RESERVED_FIELD; free(edf_hdr); free(edfhdr); return NULL; @@ -1590,7 +1612,7 @@ static edfhdrblock_t * edflib_check_edf_file(FILE *inputfile, int *edf_error) { if((scratchpad[i]<32)||(scratchpad[i]>126)) { - *edf_error = EDFLIB_FILE_CONTAINS_FORMAT_ERRORS; + *edf_error = EDFLIB_FILE_ERRORS_NUMBER_DATARECORDS; free(edf_hdr); free(edfhdr); return NULL; @@ -1599,7 +1621,7 @@ static edfhdrblock_t * edflib_check_edf_file(FILE *inputfile, int *edf_error) if(edflib_is_integer_number(scratchpad)) { - *edf_error = EDFLIB_FILE_CONTAINS_FORMAT_ERRORS; + *edf_error = EDFLIB_FILE_ERRORS_NUMBER_DATARECORDS; free(edf_hdr); free(edfhdr); return NULL; @@ -1608,7 +1630,7 @@ static edfhdrblock_t * edflib_check_edf_file(FILE *inputfile, int *edf_error) edfhdr->datarecords = edflib_atoi_nonlocalized(scratchpad); if(edfhdr->datarecords<1) { - *edf_error = EDFLIB_FILE_CONTAINS_FORMAT_ERRORS; + *edf_error = EDFLIB_FILE_ERRORS_NUMBER_DATARECORDS; free(edf_hdr); free(edfhdr); return NULL; @@ -1623,7 +1645,7 @@ static edfhdrblock_t * edflib_check_edf_file(FILE *inputfile, int *edf_error) { if((scratchpad[i]<32)||(scratchpad[i]>126)) { - *edf_error = EDFLIB_FILE_CONTAINS_FORMAT_ERRORS; + *edf_error = EDFLIB_FILE_ERRORS_DURATION; free(edf_hdr); free(edfhdr); return NULL; @@ -1632,7 +1654,7 @@ static edfhdrblock_t * edflib_check_edf_file(FILE *inputfile, int *edf_error) if(edflib_is_number(scratchpad)) { - *edf_error = EDFLIB_FILE_CONTAINS_FORMAT_ERRORS; + *edf_error = EDFLIB_FILE_ERRORS_DURATION; free(edf_hdr); free(edfhdr); return NULL; @@ -1641,7 +1663,7 @@ static edfhdrblock_t * edflib_check_edf_file(FILE *inputfile, int *edf_error) edfhdr->data_record_duration = edflib_atof_nonlocalized(scratchpad); if(edfhdr->data_record_duration < -0.000001) { - *edf_error = EDFLIB_FILE_CONTAINS_FORMAT_ERRORS; + *edf_error = EDFLIB_FILE_ERRORS_DURATION; free(edf_hdr); free(edfhdr); return NULL; @@ -1689,7 +1711,7 @@ static edfhdrblock_t * edflib_check_edf_file(FILE *inputfile, int *edf_error) { if((scratchpad[j]<32)||(scratchpad[j]>126)) { - *edf_error = EDFLIB_FILE_CONTAINS_FORMAT_ERRORS; + *edf_error = EDFLIB_FILE_ERRORS_LABEL; free(edf_hdr); free(edfhdr->edfparam); free(edfhdr); @@ -1727,7 +1749,7 @@ static edfhdrblock_t * edflib_check_edf_file(FILE *inputfile, int *edf_error) } if(edfhdr->edfplus&&(!edfhdr->nr_annot_chns)) { - *edf_error = EDFLIB_FILE_CONTAINS_FORMAT_ERRORS; + *edf_error = EDFLIB_FILE_ERRORS_LABEL; free(edf_hdr); free(edfhdr->edfparam); free(edfhdr); @@ -1735,7 +1757,7 @@ static edfhdrblock_t * edflib_check_edf_file(FILE *inputfile, int *edf_error) } if(edfhdr->bdfplus&&(!edfhdr->nr_annot_chns)) { - *edf_error = EDFLIB_FILE_CONTAINS_FORMAT_ERRORS; + *edf_error = EDFLIB_FILE_ERRORS_LABEL; free(edf_hdr); free(edfhdr->edfparam); free(edfhdr); @@ -1745,7 +1767,7 @@ static edfhdrblock_t * edflib_check_edf_file(FILE *inputfile, int *edf_error) { if(edfhdr->data_record_duration<0.0000001) { - *edf_error = EDFLIB_FILE_CONTAINS_FORMAT_ERRORS; + *edf_error = EDFLIB_FILE_ERRORS_LABEL; free(edf_hdr); free(edfhdr->edfparam); free(edfhdr); @@ -1762,7 +1784,7 @@ static edfhdrblock_t * edflib_check_edf_file(FILE *inputfile, int *edf_error) { if((scratchpad[j]<32)||(scratchpad[j]>126)) { - *edf_error = EDFLIB_FILE_CONTAINS_FORMAT_ERRORS; + *edf_error = EDFLIB_FILE_ERRORS_TRANSDUCER; free(edf_hdr); free(edfhdr->edfparam); free(edfhdr); @@ -1780,7 +1802,7 @@ static edfhdrblock_t * edflib_check_edf_file(FILE *inputfile, int *edf_error) { if(edfhdr->edfparam[i].transducer[j]!=' ') { - *edf_error = EDFLIB_FILE_CONTAINS_FORMAT_ERRORS; + *edf_error = EDFLIB_FILE_ERRORS_TRANSDUCER; free(edf_hdr); free(edfhdr->edfparam); free(edfhdr); @@ -1800,7 +1822,7 @@ static edfhdrblock_t * edflib_check_edf_file(FILE *inputfile, int *edf_error) { if((scratchpad[j]<32)||(scratchpad[j]>126)) { - *edf_error = EDFLIB_FILE_CONTAINS_FORMAT_ERRORS; + *edf_error = EDFLIB_FILE_ERRORS_PHYS_DIMENSION; free(edf_hdr); free(edfhdr->edfparam); free(edfhdr); @@ -1822,7 +1844,7 @@ static edfhdrblock_t * edflib_check_edf_file(FILE *inputfile, int *edf_error) { if((scratchpad[j]<32)||(scratchpad[j]>126)) { - *edf_error = EDFLIB_FILE_CONTAINS_FORMAT_ERRORS; + *edf_error = EDFLIB_FILE_ERRORS_PHYS_MIN; free(edf_hdr); free(edfhdr->edfparam); free(edfhdr); @@ -1832,7 +1854,7 @@ static edfhdrblock_t * edflib_check_edf_file(FILE *inputfile, int *edf_error) if(edflib_is_number(scratchpad)) { - *edf_error = EDFLIB_FILE_CONTAINS_FORMAT_ERRORS; + *edf_error = EDFLIB_FILE_ERRORS_PHYS_MIN; free(edf_hdr); free(edfhdr->edfparam); free(edfhdr); @@ -1853,7 +1875,7 @@ static edfhdrblock_t * edflib_check_edf_file(FILE *inputfile, int *edf_error) { if((scratchpad[j]<32)||(scratchpad[j]>126)) { - *edf_error = EDFLIB_FILE_CONTAINS_FORMAT_ERRORS; + *edf_error = EDFLIB_FILE_ERRORS_PHYS_MAX; free(edf_hdr); free(edfhdr->edfparam); free(edfhdr); @@ -1863,7 +1885,7 @@ static edfhdrblock_t * edflib_check_edf_file(FILE *inputfile, int *edf_error) if(edflib_is_number(scratchpad)) { - *edf_error = EDFLIB_FILE_CONTAINS_FORMAT_ERRORS; + *edf_error = EDFLIB_FILE_ERRORS_PHYS_MAX; free(edf_hdr); free(edfhdr->edfparam); free(edfhdr); @@ -1873,7 +1895,7 @@ static edfhdrblock_t * edflib_check_edf_file(FILE *inputfile, int *edf_error) edfhdr->edfparam[i].phys_max = edflib_atof_nonlocalized(scratchpad); if(edfhdr->edfparam[i].phys_max==edfhdr->edfparam[i].phys_min) { - *edf_error = EDFLIB_FILE_CONTAINS_FORMAT_ERRORS; + *edf_error = EDFLIB_FILE_ERRORS_PHYS_MAX; free(edf_hdr); free(edfhdr->edfparam); free(edfhdr); @@ -1892,7 +1914,7 @@ static edfhdrblock_t * edflib_check_edf_file(FILE *inputfile, int *edf_error) { if((scratchpad[j]<32)||(scratchpad[j]>126)) { - *edf_error = EDFLIB_FILE_CONTAINS_FORMAT_ERRORS; + *edf_error = EDFLIB_FILE_ERRORS_DIG_MIN; free(edf_hdr); free(edfhdr->edfparam); free(edfhdr); @@ -1902,7 +1924,7 @@ static edfhdrblock_t * edflib_check_edf_file(FILE *inputfile, int *edf_error) if(edflib_is_integer_number(scratchpad)) { - *edf_error = EDFLIB_FILE_CONTAINS_FORMAT_ERRORS; + *edf_error = EDFLIB_FILE_ERRORS_DIG_MIN; free(edf_hdr); free(edfhdr->edfparam); free(edfhdr); @@ -1916,7 +1938,7 @@ static edfhdrblock_t * edflib_check_edf_file(FILE *inputfile, int *edf_error) { if(n!=-0x8000) { - *edf_error = EDFLIB_FILE_CONTAINS_FORMAT_ERRORS; + *edf_error = EDFLIB_FILE_ERRORS_DIG_MIN; free(edf_hdr); free(edfhdr->edfparam); free(edfhdr); @@ -1930,7 +1952,7 @@ static edfhdrblock_t * edflib_check_edf_file(FILE *inputfile, int *edf_error) { if(n!=-0x800000) { - *edf_error = EDFLIB_FILE_CONTAINS_FORMAT_ERRORS; + *edf_error = EDFLIB_FILE_ERRORS_DIG_MIN; free(edf_hdr); free(edfhdr->edfparam); free(edfhdr); @@ -1942,7 +1964,7 @@ static edfhdrblock_t * edflib_check_edf_file(FILE *inputfile, int *edf_error) { if((n>0x7fff)||(n<-0x8000)) { - *edf_error = EDFLIB_FILE_CONTAINS_FORMAT_ERRORS; + *edf_error = EDFLIB_FILE_ERRORS_DIG_MIN; free(edf_hdr); free(edfhdr->edfparam); free(edfhdr); @@ -1953,7 +1975,7 @@ static edfhdrblock_t * edflib_check_edf_file(FILE *inputfile, int *edf_error) { if((n>0x7fffff)||(n<-0x800000)) { - *edf_error = EDFLIB_FILE_CONTAINS_FORMAT_ERRORS; + *edf_error = EDFLIB_FILE_ERRORS_DIG_MIN; free(edf_hdr); free(edfhdr->edfparam); free(edfhdr); @@ -1974,7 +1996,7 @@ static edfhdrblock_t * edflib_check_edf_file(FILE *inputfile, int *edf_error) { if((scratchpad[j]<32)||(scratchpad[j]>126)) { - *edf_error = EDFLIB_FILE_CONTAINS_FORMAT_ERRORS; + *edf_error = EDFLIB_FILE_ERRORS_DIG_MAX; free(edf_hdr); free(edfhdr->edfparam); free(edfhdr); @@ -1984,7 +2006,7 @@ static edfhdrblock_t * edflib_check_edf_file(FILE *inputfile, int *edf_error) if(edflib_is_integer_number(scratchpad)) { - *edf_error = EDFLIB_FILE_CONTAINS_FORMAT_ERRORS; + *edf_error = EDFLIB_FILE_ERRORS_DIG_MAX; free(edf_hdr); free(edfhdr->edfparam); free(edfhdr); @@ -1998,7 +2020,7 @@ static edfhdrblock_t * edflib_check_edf_file(FILE *inputfile, int *edf_error) { if(n!=0x7fff) { - *edf_error = EDFLIB_FILE_CONTAINS_FORMAT_ERRORS; + *edf_error = EDFLIB_FILE_ERRORS_DIG_MAX; free(edf_hdr); free(edfhdr->edfparam); free(edfhdr); @@ -2012,7 +2034,7 @@ static edfhdrblock_t * edflib_check_edf_file(FILE *inputfile, int *edf_error) { if(n!=0x7fffff) { - *edf_error = EDFLIB_FILE_CONTAINS_FORMAT_ERRORS; + *edf_error = EDFLIB_FILE_ERRORS_DIG_MAX; free(edf_hdr); free(edfhdr->edfparam); free(edfhdr); @@ -2024,7 +2046,7 @@ static edfhdrblock_t * edflib_check_edf_file(FILE *inputfile, int *edf_error) { if((n>0x7fff)||(n<-0x8000)) { - *edf_error = EDFLIB_FILE_CONTAINS_FORMAT_ERRORS; + *edf_error = EDFLIB_FILE_ERRORS_DIG_MAX; free(edf_hdr); free(edfhdr->edfparam); free(edfhdr); @@ -2035,7 +2057,7 @@ static edfhdrblock_t * edflib_check_edf_file(FILE *inputfile, int *edf_error) { if((n>0x7fffff)||(n<-0x800000)) { - *edf_error = EDFLIB_FILE_CONTAINS_FORMAT_ERRORS; + *edf_error = EDFLIB_FILE_ERRORS_DIG_MAX; free(edf_hdr); free(edfhdr->edfparam); free(edfhdr); @@ -2043,9 +2065,9 @@ static edfhdrblock_t * edflib_check_edf_file(FILE *inputfile, int *edf_error) } } edfhdr->edfparam[i].dig_max = n; - if(edfhdr->edfparam[i].dig_max<(edfhdr->edfparam[i].dig_min + 1)) + if(edfhdr->edfparam[i].dig_max<(edfhdr->edfparam[i].dig_min + 1) && (edfhdr->bdfplus || edfhdr->edfplus)) { - *edf_error = EDFLIB_FILE_CONTAINS_FORMAT_ERRORS; + *edf_error = EDFLIB_FILE_ERRORS_DIG_MAX; free(edf_hdr); free(edfhdr->edfparam); free(edfhdr); @@ -2062,7 +2084,7 @@ static edfhdrblock_t * edflib_check_edf_file(FILE *inputfile, int *edf_error) { if((scratchpad[j]<32)||(scratchpad[j]>126)) { - *edf_error = EDFLIB_FILE_CONTAINS_FORMAT_ERRORS; + *edf_error = EDFLIB_FILE_ERRORS_PREFILTER; free(edf_hdr); free(edfhdr->edfparam); free(edfhdr); @@ -2071,24 +2093,6 @@ static edfhdrblock_t * edflib_check_edf_file(FILE *inputfile, int *edf_error) } strncpy(edfhdr->edfparam[i].prefilter, edf_hdr + 256 + (edfhdr->edfsignals * 136) + (i * 80), 80); edfhdr->edfparam[i].prefilter[80] = 0; - - if((edfhdr->edfplus) || (edfhdr->bdfplus)) - { - if(edfhdr->edfparam[i].annotation) - { - for(j=0; j<80; j++) - { - if(edfhdr->edfparam[i].prefilter[j]!=' ') - { - *edf_error = EDFLIB_FILE_CONTAINS_FORMAT_ERRORS; - free(edf_hdr); - free(edfhdr->edfparam); - free(edfhdr); - return NULL; - } - } - } - } } /*********************** NR OF SAMPLES IN EACH DATARECORD ********************/ @@ -2104,7 +2108,7 @@ static edfhdrblock_t * edflib_check_edf_file(FILE *inputfile, int *edf_error) { if((scratchpad[j]<32)||(scratchpad[j]>126)) { - *edf_error = EDFLIB_FILE_CONTAINS_FORMAT_ERRORS; + *edf_error = EDFLIB_FILE_ERRORS_SAMPLES_DATARECORD; free(edf_hdr); free(edfhdr->edfparam); free(edfhdr); @@ -2114,7 +2118,7 @@ static edfhdrblock_t * edflib_check_edf_file(FILE *inputfile, int *edf_error) if(edflib_is_integer_number(scratchpad)) { - *edf_error = EDFLIB_FILE_CONTAINS_FORMAT_ERRORS; + *edf_error = EDFLIB_FILE_ERRORS_SAMPLES_DATARECORD; free(edf_hdr); free(edfhdr->edfparam); free(edfhdr); @@ -2124,7 +2128,7 @@ static edfhdrblock_t * edflib_check_edf_file(FILE *inputfile, int *edf_error) n = edflib_atoi_nonlocalized(scratchpad); if(n<1) { - *edf_error = EDFLIB_FILE_CONTAINS_FORMAT_ERRORS; + *edf_error = EDFLIB_FILE_ERRORS_SAMPLES_DATARECORD; free(edf_hdr); free(edfhdr->edfparam); free(edfhdr); @@ -2140,7 +2144,7 @@ static edfhdrblock_t * edflib_check_edf_file(FILE *inputfile, int *edf_error) if(edfhdr->recordsize > (15 * 1024 * 1024)) { - *edf_error = EDFLIB_FILE_CONTAINS_FORMAT_ERRORS; + *edf_error = EDFLIB_FILE_ERRORS_SAMPLES_DATARECORD; free(edf_hdr); free(edfhdr->edfparam); free(edfhdr); @@ -2153,7 +2157,7 @@ static edfhdrblock_t * edflib_check_edf_file(FILE *inputfile, int *edf_error) if(edfhdr->recordsize > (10 * 1024 * 1024)) { - *edf_error = EDFLIB_FILE_CONTAINS_FORMAT_ERRORS; + *edf_error = EDFLIB_FILE_ERRORS_SAMPLES_DATARECORD; free(edf_hdr); free(edfhdr->edfparam); free(edfhdr); @@ -2311,7 +2315,7 @@ static edfhdrblock_t * edflib_check_edf_file(FILE *inputfile, int *edf_error) } p += i + 1; - if(edfhdr->patient[p]=='X') + if(edfhdr->patient[p]=='X' && edfhdr->patient[p+1]==' ') { edfhdr->plus_birthdate[0] = 0; edfhdr->plus_birthdate_day = 0; @@ -2481,7 +2485,7 @@ static edfhdrblock_t * edflib_check_edf_file(FILE *inputfile, int *edf_error) if(error) { - *edf_error = EDFLIB_FILE_CONTAINS_FORMAT_ERRORS; + *edf_error = EDFLIB_FILE_ERRORS_RECORDINGFIELD; free(edf_hdr); free(edfhdr->edfparam); free(edfhdr); @@ -2502,7 +2506,7 @@ static edfhdrblock_t * edflib_check_edf_file(FILE *inputfile, int *edf_error) if(edflib_atoi_nonlocalized(scratchpad+6)!=edflib_atoi_nonlocalized(scratchpad2+9)) error = 1; if(error) { - *edf_error = EDFLIB_FILE_CONTAINS_FORMAT_ERRORS; + *edf_error = EDFLIB_FILE_ERRORS_RECORDINGFIELD; free(edf_hdr); free(edfhdr->edfparam); free(edfhdr); @@ -2511,7 +2515,7 @@ static edfhdrblock_t * edflib_check_edf_file(FILE *inputfile, int *edf_error) if(edfhdr->startdate_year != edflib_atoi_nonlocalized(scratchpad2 + 7)) { - *edf_error = EDFLIB_FILE_CONTAINS_FORMAT_ERRORS; + *edf_error = EDFLIB_FILE_ERRORS_RECORDINGFIELD; free(edf_hdr); free(edfhdr->edfparam); free(edfhdr); @@ -2608,14 +2612,18 @@ static edfhdrblock_t * edflib_check_edf_file(FILE *inputfile, int *edf_error) edfhdr->hdrsize = edfhdr->edfsignals * 256 + 256; - fseeko(inputfile, 0LL, SEEK_END); - if(ftello(inputfile)!=(edfhdr->recordsize * edfhdr->datarecords + edfhdr->hdrsize)) - { - *edf_error = EDFLIB_FILE_CONTAINS_FORMAT_ERRORS; - free(edf_hdr); - free(edfhdr->edfparam); - free(edfhdr); - return NULL; + if (check_file_size != EDFLIB_DO_NOT_CHECK_FILE_SIZE) + { + fseeko(inputfile, 0LL, SEEK_END); + if(ftello(inputfile)<(edfhdr->recordsize * edfhdr->datarecords + edfhdr->hdrsize)) + { + printf("filesize %ld != %d*%lld+%d ",ftello(inputfile),edfhdr->recordsize, edfhdr->datarecords, edfhdr->hdrsize); + *edf_error = EDFLIB_FILE_ERRORS_FILESIZE; + free(edf_hdr); + free(edfhdr->edfparam); + free(edfhdr); + return NULL; + } } n = 0; @@ -2626,8 +2634,16 @@ static edfhdrblock_t * edflib_check_edf_file(FILE *inputfile, int *edf_error) if(edfhdr->bdf) n += edfhdr->edfparam[i].smp_per_record * 3; else n += edfhdr->edfparam[i].smp_per_record * 2; - edfhdr->edfparam[i].bitvalue = (edfhdr->edfparam[i].phys_max - edfhdr->edfparam[i].phys_min) / (edfhdr->edfparam[i].dig_max - edfhdr->edfparam[i].dig_min); - edfhdr->edfparam[i].offset = edfhdr->edfparam[i].phys_max / edfhdr->edfparam[i].bitvalue - edfhdr->edfparam[i].dig_max; + if (edfhdr->edfparam[i].dig_max==edfhdr->edfparam[i].dig_min || edfhdr->edfparam[i].phys_max==edfhdr->edfparam[i].phys_min) + { + edfhdr->edfparam[i].bitvalue = 1; + edfhdr->edfparam[i].offset = 0; + } + else + { + edfhdr->edfparam[i].bitvalue = (edfhdr->edfparam[i].phys_max - edfhdr->edfparam[i].phys_min) / (edfhdr->edfparam[i].dig_max - edfhdr->edfparam[i].dig_min); + edfhdr->edfparam[i].offset = edfhdr->edfparam[i].phys_max / edfhdr->edfparam[i].bitvalue - edfhdr->edfparam[i].dig_max; + } } edfhdr->file_hdl = inputfile; @@ -2870,6 +2886,25 @@ EDFLIB_API int edflib_version(void) } +static int edflib_repair_file_size(const char *path, edfhdrblock_t *edfhdr) +{ + int p; + FILE *file; + file = fopeno(path, "wb"); + if(edfhdr->datarecords<100000000LL) + { + fseeko(file, 236LL, SEEK_SET); + p = edflib_fprint_int_number_nonlocalized(file, (int)(edfhdr->datarecords), 0, 0); + if(p < 2) + { + fputc(' ', file); + } + } + fclose(file); + return 0; +} + + static int edflib_get_annotations(edfhdrblock_t *edfhdr, int hdl, int read_annotations_mode) { int i, j, k, p, r=0, n, @@ -3697,18 +3732,31 @@ EDFLIB_API int edfopen_file_writeonly(const char *path, int filetype, int number hdr->edfplus = 1; } + if(filetype==EDFLIB_FILETYPE_EDF) + { + hdr->edf = 1; + hdr->edfplus = 0; + hdr->nr_annot_chns = 0; + } + if(filetype==EDFLIB_FILETYPE_BDFPLUS) { hdr->bdf = 1; hdr->bdfplus = 1; + hdr->nr_annot_chns = 1; + } + + if(filetype==EDFLIB_FILETYPE_BDF) + { + hdr->bdf = 1; + hdr->bdfplus = 0; + hdr->nr_annot_chns = 0; } hdr->long_data_record_duration = EDFLIB_TIME_DIMENSION; hdr->data_record_duration = 1.0; - hdr->nr_annot_chns = 1; - return handle; } @@ -4777,15 +4825,30 @@ static int edflib_write_edf_header(edfhdrblock_t *hdr) for(i=0; iedfparam[i].smp_per_record<1) return EDFLIB_NO_SAMPLES_IN_RECORD; - - if(hdr->edfparam[i].dig_max==hdr->edfparam[i].dig_min) return EDFLIB_DIGMIN_IS_DIGMAX; - - if(hdr->edfparam[i].dig_maxedfparam[i].dig_min) return EDFLIB_DIGMAX_LOWER_THAN_DIGMIN; - - if(hdr->edfparam[i].phys_max==hdr->edfparam[i].phys_min) return EDFLIB_PHYSMIN_IS_PHYSMAX; - - hdr->recordsize += hdr->edfparam[i].smp_per_record; + if (hdr->edfplus || hdr->bdfplus) + { + if(hdr->edfparam[i].smp_per_record<1) + { + return EDFLIB_NO_SAMPLES_IN_RECORD; + } + + if(hdr->edfparam[i].dig_max==hdr->edfparam[i].dig_min) + { + return EDFLIB_DIGMIN_IS_DIGMAX; + } + + if(hdr->edfparam[i].dig_maxedfparam[i].dig_min) + { + return EDFLIB_DIGMAX_LOWER_THAN_DIGMIN; + } + + if(hdr->edfparam[i].phys_max==hdr->edfparam[i].phys_min) + { + return EDFLIB_PHYSMIN_IS_PHYSMAX; + } + + hdr->recordsize += hdr->edfparam[i].smp_per_record; + } if(i > 0) { @@ -4823,8 +4886,16 @@ static int edflib_write_edf_header(edfhdrblock_t *hdr) for(i=0; iedfparam[i].bitvalue = (hdr->edfparam[i].phys_max - hdr->edfparam[i].phys_min) / (hdr->edfparam[i].dig_max - hdr->edfparam[i].dig_min); - hdr->edfparam[i].offset = hdr->edfparam[i].phys_max / hdr->edfparam[i].bitvalue - hdr->edfparam[i].dig_max; + if ((hdr->edfparam[i].phys_max == hdr->edfparam[i].phys_min) || (hdr->edfparam[i].dig_max == hdr->edfparam[i].dig_min)) + { + hdr->edfparam[i].bitvalue = 1; + hdr->edfparam[i].offset = 0; + } + else + { + hdr->edfparam[i].bitvalue = (hdr->edfparam[i].phys_max - hdr->edfparam[i].phys_min) / (hdr->edfparam[i].dig_max - hdr->edfparam[i].dig_min); + hdr->edfparam[i].offset = hdr->edfparam[i].phys_max / hdr->edfparam[i].bitvalue - hdr->edfparam[i].dig_max; + } } rewind(file); @@ -5171,14 +5242,18 @@ static int edflib_write_edf_header(edfhdrblock_t *hdr) { fputc(' ', file); } - if(hdr->edf) + if(hdr->edfplus) { fprintf(file, "EDF+C"); } - else + else if(hdr->bdfplus) { fprintf(file, "BDF+C"); } + else + { + fprintf(file, " "); + } for(i=0; i<39; i++) { fputc(' ', file); @@ -6810,6 +6885,11 @@ static int edflib_atoi_nonlocalized(const char *str) static int edflib_write_tal(edfhdrblock_t *hdr, FILE *file) { + if((hdr->edf||hdr->bdf) && !(hdr->edfplus||hdr->bdfplus)) + { + // EDF/BDF = no annotations will be written. + return 0; + } int p; char str[EDFLIB_ANNOTATION_BYTES * (EDFLIB_MAX_ANNOTATION_CHANNELS + 1)]; diff --git a/pyedflib/_extensions/c/edflib.h b/pyedflib/_extensions/c/edflib.h index d793df20..bb82333d 100644 --- a/pyedflib/_extensions/c/edflib.h +++ b/pyedflib/_extensions/c/edflib.h @@ -200,6 +200,11 @@ #define EDFLIB_READ_ANNOTATIONS (1) #define EDFLIB_READ_ALL_ANNOTATIONS (2) +/* values for size check on edfopen_file_readonly */ +#define EDFLIB_CHECK_FILE_SIZE (0) +#define EDFLIB_DO_NOT_CHECK_FILE_SIZE (1) +#define EDFLIB_REPAIR_FILE_SIZE_IF_WRONG (2) + /* the following defines are possible errors returned by the first sample write action */ #define EDFLIB_NO_SIGNALS (-20) #define EDFLIB_TOO_MANY_SIGNALS (-21) @@ -209,6 +214,28 @@ #define EDFLIB_PHYSMIN_IS_PHYSMAX (-25) #define EDFLIB_DATARECORD_SIZE_TOO_BIG (-26) +/* added for pyedflib */ +#define EDFLIB_INVALID_CHECK_SIZE_VALUE (-13) +#define EDFLIB_FILE_ERRORS_STARTDATE (-30) +#define EDFLIB_FILE_ERRORS_STARTTIME (-31) +#define EDFLIB_FILE_ERRORS_NUMBER_SIGNALS (-32) +#define EDFLIB_FILE_ERRORS_BYTES_HEADER (-33) +#define EDFLIB_FILE_ERRORS_RESERVED_FIELD (-34) +#define EDFLIB_FILE_ERRORS_NUMBER_DATARECORDS (-35) +#define EDFLIB_FILE_ERRORS_DURATION (-36) +#define EDFLIB_FILE_ERRORS_LABEL (-37) +#define EDFLIB_FILE_ERRORS_TRANSDUCER (-38) +#define EDFLIB_FILE_ERRORS_PHYS_DIMENSION (-39) +#define EDFLIB_FILE_ERRORS_PHYS_MAX (-40) +#define EDFLIB_FILE_ERRORS_PHYS_MIN (-41) +#define EDFLIB_FILE_ERRORS_DIG_MAX (-42) +#define EDFLIB_FILE_ERRORS_DIG_MIN (-43) +#define EDFLIB_FILE_ERRORS_PREFILTER (-44) +#define EDFLIB_FILE_ERRORS_SAMPLES_DATARECORD (-45) +#define EDFLIB_FILE_ERRORS_FILESIZE (-46) +#define EDFLIB_FILE_ERRORS_RECORDINGFIELD (-47) +#define EDFLIB_FILE_ERRORS_PATIENTNAME (-48) + #ifdef __cplusplus extern "C" { #endif @@ -299,16 +326,18 @@ typedef struct edf_hdr_struct * - EDFLIB_DO_NOT_READ_ANNOTATIONS annotations will not be read (this can save time when opening a very large EDF+ or BDF+ file * - EDFLIB_READ_ANNOTATIONS annotations will be read immediately, stops when an annotation has * been found which contains the description "Recording ends" - * - EDFLIB_READ_ALL_ANNOTATIONS all annotations will be read immediately + * @param[in] check_file_size + * Must have one of the following values: + * - EDFLIB_CHECK_FILE_SIZE file size is checked and if wrong, the file will not be opened + * - EDFLIB_DO_NOT_CHECK_FILE_SIZE the file will alsways be opened and the file size is not checked + * - EDFLIB_REPAIR_FILE_SIZE_IF_WRONG the file size is checked and if it is wrong it will be fixed * - * @return - * 0 on success, in case of an error it returns -1 and an error code will be set in the member "filetype" of edfhdr. * This function is required if you want to read a file * * In case of a file format error (-3), try to open the file with EDFbrowser: https://www.teuniz.net/edfbrowser/ * It will give you full details about the cause of the error and it can also fix most errors. */ -EDFLIB_API int edfopen_file_readonly(const char *path, edflib_hdr_t *edfhdr, int read_annotations); +EDFLIB_API int edfopen_file_readonly(const char *path, edflib_hdr_t *edfhdr, int read_annotations, int check_file_size); /** * Reads \p n samples from \p edfsignal, starting from the current sample position indicator, into \p buf (edfsignal starts at 0).