Logo Search packages:      
Sourcecode: edfbrowser version File versions  Download package

edf_annotations.cpp

/*
***************************************************************************
*
* Author: Teunis van Beelen
*
* Copyright (C) 2007, 2008, 2009 Teunis van Beelen
*
* teuniz@gmail.com
*
***************************************************************************
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation version 2 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
***************************************************************************
*
* This version of GPL is at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
*
***************************************************************************
*/



#include "edf_annotations.h"



void EDF_annotations::sort_annotations(struct annotationblock *annots)
{
  int order_changed=1,
      modified;


  struct annotationblock *tmp_annot;

  long long onset;

  char duration[17],
       annotation[MAX_ANNOTATION_LEN + 1];



  while(order_changed)
  {
    order_changed = 0;

    tmp_annot = annots;

    while(tmp_annot!=NULL)
    {
      if(tmp_annot->next_annotation==NULL)
      {
        break;
      }

      if(tmp_annot->next_annotation->onset<tmp_annot->onset)
      {
        onset = tmp_annot->next_annotation->onset;

        strcpy(duration, tmp_annot->next_annotation->duration);

        strcpy(annotation, tmp_annot->next_annotation->annotation);

        modified = tmp_annot->next_annotation->modified;

        tmp_annot->next_annotation->onset = tmp_annot->onset;

        strcpy(tmp_annot->next_annotation->duration, tmp_annot->duration);

        strcpy(tmp_annot->next_annotation->annotation, tmp_annot->annotation);

        tmp_annot->next_annotation->modified = tmp_annot->modified;

        tmp_annot->onset = onset;

        strcpy(tmp_annot->duration, duration);

        strcpy(tmp_annot->annotation, annotation);

        tmp_annot->modified = modified;

        order_changed = 1;
      }

      tmp_annot = tmp_annot->next_annotation;
    }
  }
}




int EDF_annotations::get_annotations(int file_num, struct edfhdrblock *edfhdr, struct annotationblock **annotslist)
{
  int i, j, k, p, r=0, n,
      edfsignals,
      datarecords,
      recordsize,
      discontinuous,
      *annot_ch,
      nr_annot_chns,
      max,
      onset,
      duration,
      duration_start,
      zero,
      max_tal_ln,
      error,
      annots_in_record,
      annots_in_tal,
      samplesize=2;

  char *scratchpad,
       *cnv_buf,
       *time_in_txt,
       *duration_in_txt;


  long long data_record_duration,
            elapsedtime,
            time_tmp=0;

  FILE *inputfile;

  struct edfparamblock *edfparam;

  struct annotationblock *new_annotation=NULL,
                         *temp_annotation;


//   for(i=0; i<6000; i++)
//   {
//     new_annotation = (struct annotationblock *)s_calloc(1, sizeof(struct annotationblock));
//
//     new_annotation->next_annotation = NULL;
//     new_annotation->file_num = file_num;
//
//     sprintf(new_annotation->annotation, "test %i", i);
//
//     new_annotation->onset = -((TIME_DIMENSION * 10LL) / 6000LL) * i;
//
//     if(*annotslist!=NULL)
//     {
//       temp_annotation = *annotslist;
//       while(temp_annotation->next_annotation)  temp_annotation = temp_annotation->next_annotation;
//
//       new_annotation->former_annotation = temp_annotation;
//       temp_annotation->next_annotation = new_annotation;
//     }
//     else
//     {
//       new_annotation->former_annotation = NULL;
//       *annotslist = new_annotation;
//     }
//   }
//
//   for(i=0; i<5; i++)
//   {
//     new_annotation = (struct annotationblock *)s_calloc(1, sizeof(struct annotationblock));
//
//     new_annotation->next_annotation = NULL;
//     new_annotation->file_num = file_num;
//
//     sprintf(new_annotation->annotation, "test2 %i", i);
//
//     new_annotation->onset = (TIME_DIMENSION * 2LL) * i;
//
//     if(*annotslist!=NULL)
//     {
//       temp_annotation = *annotslist;
//       while(temp_annotation->next_annotation)  temp_annotation = temp_annotation->next_annotation;
//
//       new_annotation->former_annotation = temp_annotation;
//       temp_annotation->next_annotation = new_annotation;
//     }
//     else
//     {
//       new_annotation->former_annotation = NULL;
//       *annotslist = new_annotation;
//     }
//   }



  inputfile = edfhdr->file_hdl;
  edfsignals = edfhdr->edfsignals;
  recordsize = edfhdr->recordsize;
  edfparam = edfhdr->edfparam;
  nr_annot_chns = edfhdr->nr_annot_chns;
  datarecords = edfhdr->datarecords;
  data_record_duration = edfhdr->long_data_record_duration;
  discontinuous = edfhdr->discontinuous;
  annot_ch = edfhdr->annot_ch;

  if(edfhdr->edfplus)
  {
    samplesize = 2;
  }
  if(edfhdr->bdfplus)
  {
    samplesize = 3;
  }

  cnv_buf = (char *)calloc(1, recordsize);
  if(cnv_buf==NULL)
  {
    UI_Messagewindow popuperror("Error", "Memory allocation error occurred when trying to read annotations.\n"
                                "(cnv_buf)");
    return(1);
  }

  max_tal_ln = 0;

  for(i=0; i<nr_annot_chns; i++)
  {
    if(max_tal_ln<edfparam[annot_ch[i]].smp_per_record * samplesize)  max_tal_ln = edfparam[annot_ch[i]].smp_per_record * samplesize;
  }

  if(max_tal_ln<128)  max_tal_ln = 128;

  scratchpad = (char *)calloc(1, max_tal_ln + 3);
  if(scratchpad==NULL)
  {
    UI_Messagewindow popuperror("Error", "Memory allocation error occurred when trying to read annotations.\n"
                                "(scratchpad)");
    free(cnv_buf);
    return(1);
  }

  time_in_txt = (char *)calloc(1, max_tal_ln + 3);
  if(time_in_txt==NULL)
  {
    UI_Messagewindow popuperror("Error", "Memory allocation error occurred when trying to read annotations.\n"
                                "(time_in_txt)");
    free(cnv_buf);
    free(scratchpad);
    return(1);
  }

  duration_in_txt = (char *)calloc(1, max_tal_ln + 3);
  if(duration_in_txt==NULL)
  {
    UI_Messagewindow popuperror("Error", "Memory allocation error occurred when trying to read annotations.\n"
                                "(duration_in_txt)");
    free(cnv_buf);
    free(scratchpad);
    free(time_in_txt);
    return(1);
  }

  if(fseeko64(inputfile, (edfsignals + 1) * 256, SEEK_SET))
  {
    UI_Messagewindow popuperror("Error", "An error occurred when reading inputfile annotations.");
    free(cnv_buf);
    free(scratchpad);
    free(time_in_txt);
    free(duration_in_txt);
    return(2);
  }

  QApplication::setOverrideCursor(Qt::WaitCursor);

  elapsedtime = 0;

  for(i=0; i<datarecords; i++)
  {
    qApp->processEvents();

    if(fread(cnv_buf, recordsize, 1, inputfile)!=1)
    {
      QApplication::restoreOverrideCursor();
      UI_Messagewindow popuperror("Error", "An error occurred when reading inputfile annotations.");
      free(cnv_buf);
      free(scratchpad);
      free(time_in_txt);
      free(duration_in_txt);
      return(2);
    }


/************** process annotationsignals (if any) **************/

    error = 0;

    for(r=0; r<nr_annot_chns; r++)
    {
      n = 0;
      zero = 0;
      onset = 0;
      duration = 0;
      duration_start = 0;
      scratchpad[0] = 0;
      annots_in_tal = 0;
      annots_in_record = 0;

      p = edfparam[annot_ch[r]].buf_offset;
      max = edfparam[annot_ch[r]].smp_per_record * samplesize;

/************** process one annotation signal ****************/

      if(cnv_buf[p + max - 1]!=0)
      {
        error = 5;
        goto END;
      }

      if(!r)  /* if it's the first annotation signal, then check */
      {       /* the timekeeping annotation */
        error = 1;

        for(k=0; k<(max-2); k++)
        {
          scratchpad[k] = cnv_buf[p + k];

          if(scratchpad[k]==20)
          {
            if(cnv_buf[p + k + 1]!=20)
            {
              error = 6;
              goto END;
            }
            scratchpad[k] = 0;
            if(is_onset_number(scratchpad))
            {
              error = 36;
              goto END;
            }
            else
            {
              time_tmp = get_long_time(scratchpad);
              if(i)
              {
                if(discontinuous)
                {
                  if((time_tmp-elapsedtime)<data_record_duration)
                  {
                    error = 4;
                    goto END;
                  }
                }
                else
                {
                  if((time_tmp-elapsedtime)!=data_record_duration)
                  {
                    error = 3;
                    goto END;
                  }
                }
              }
              else
              {
                if(time_tmp>=TIME_DIMENSION)
                {
                  error = 2;
                  goto END;
                }
                else
                {
                  edfhdr->starttime_offset = time_tmp;
                }
              }
              elapsedtime = time_tmp;
              error = 0;
              break;
            }
          }
        }
      }

      for(k=0; k<max; k++)
      {
        scratchpad[n] = cnv_buf[p + k];

        if(!scratchpad[n])
        {
          if(!zero)
          {
            if(k)
            {
              if(cnv_buf[p + k - 1]!=20)
              {
                error = 33;
                goto END;
              }
            }
            n = 0;
            onset = 0;
            duration = 0;
            duration_start = 0;
            scratchpad[0] = 0;
            annots_in_tal = 0;
          }
          zero++;
          continue;
        }
        if(zero>1)
        {
          error = 34;
          goto END;
        }
        zero = 0;

        if((scratchpad[n]==20)||(scratchpad[n]==21))
        {
          if(scratchpad[n]==21)
          {
            if(duration||duration_start||onset||annots_in_tal)
            {               /* it's not allowed to have multiple duration fields */
              error = 35;   /* in one TAL or to have a duration field which is   */
              goto END;     /* not immediately behind the onsetfield             */
            }
            duration_start = 1;
          }

          if((scratchpad[n]==20)&&onset&&(!duration_start))
          {
            if(r||annots_in_record)
            {
              if(n)
              {
                new_annotation = (struct annotationblock *)s_calloc(1, sizeof(struct annotationblock));
                if(new_annotation==NULL)
                {
                  UI_Messagewindow popuperror("Error", "Memory allocation error occurred while reading annotations.");
                  free(cnv_buf);
                  free(scratchpad);
                  free(time_in_txt);
                  free(duration_in_txt);
                  return(1);
                }

                new_annotation->next_annotation = NULL;
                new_annotation->file_num = file_num;

                new_annotation->annotation[0] = 0;

                if(duration)  strcpy(new_annotation->duration, duration_in_txt);
                else  new_annotation->duration[0] = 0;

                for(j=0; j<n; j++)
                {
                  if(j==MAX_ANNOTATION_LEN)  break;
                  new_annotation->annotation[j] = scratchpad[j];
                }
                new_annotation->annotation[j] = 0;

                new_annotation->onset = get_long_time(time_in_txt);

                if(*annotslist!=NULL)
                {
                  temp_annotation = *annotslist;
                  while(temp_annotation->next_annotation)  temp_annotation = temp_annotation->next_annotation;

                  new_annotation->former_annotation = temp_annotation;
                  temp_annotation->next_annotation = new_annotation;
                }
                else
                {
                  new_annotation->former_annotation = NULL;
                  *annotslist = new_annotation;
                }
              }
            }

            annots_in_tal++;
            annots_in_record++;
            n = 0;
            continue;
          }

          if(!onset)
          {
            scratchpad[n] = 0;
            if(is_onset_number(scratchpad))
            {
              error = 36;
              goto END;
            }
            onset = 1;
            n = 0;
            strcpy(time_in_txt, scratchpad);
            continue;
          }

          if(duration_start)
          {
            scratchpad[n] = 0;
            if(is_duration_number(scratchpad))
            {
              error = 37;
              goto END;
            }

            for(j=0; j<n; j++)
            {
              if(j==15)  break;
              duration_in_txt[j] = scratchpad[j];
              if((duration_in_txt[j]<32)||(duration_in_txt[j]>126))
              {
                duration_in_txt[j] = '.';
              }
            }
            duration_in_txt[j] = 0;

            duration = 1;
            duration_start = 0;
            n = 0;
            continue;
          }
        }

        n++;
      }

 END:

/****************** end ************************/

      if(error)
      {
        QApplication::restoreOverrideCursor();
        UI_Messagewindow popuperror("Error", "Can not read annotations because there is an EDF or BDF incompatibility in this file.\n"
                                    "For more information, run the EDF/BDF compatibility checker in the Tools menu.");
        free(cnv_buf);
        free(scratchpad);
        free(time_in_txt);
        free(duration_in_txt);
        return(9);
      }
    }
  }

  sort_annotations(annotslist[file_num]);

  QApplication::restoreOverrideCursor();

  free(cnv_buf);
  free(scratchpad);
  free(time_in_txt);
  free(duration_in_txt);

  return(0);
}




int EDF_annotations::is_duration_number(char *str)
{
  int i, l, hasdot = 0;

  l = strlen(str);

  if(!l)  return(1);

  if((str[0] == '.')||(str[l-1] == '.'))  return(1);

  for(i=0; i<l; i++)
  {
    if(str[i]=='.')
    {
      if(hasdot)  return(1);
      hasdot++;
    }
    else
    {
      if((str[i]<48)||(str[i]>57))  return(1);
    }
  }

  return(0);
}



int EDF_annotations::is_onset_number(char *str)
{
  int i, l, hasdot = 0;

  l = strlen(str);

  if(l<2)  return(1);

  if((str[0]!='+')&&(str[0]!='-'))  return(1);

  if((str[1] == '.')||(str[l-1] == '.'))  return(1);

  for(i=1; i<l; i++)
  {
    if(str[i]=='.')
    {
      if(hasdot)  return(1);
      hasdot++;
    }
    else
    {
      if((str[i]<48)||(str[i]>57))  return(1);
    }
  }

  return(0);
}



long long EDF_annotations::get_long_time(char *str)
{
  int i, len, hasdot=0, dotposition=0;

  long long value=0, radix;

  str = str + 1;

  len = strlen(str);

  for(i=0; i<len; i++)
  {
    if(str[i]=='.')
    {
      hasdot = 1;
      dotposition = i;
      break;
    }
  }

  if(hasdot)
  {
    radix = TIME_DIMENSION;

    for(i=dotposition-1; i>=0; i--)
    {
        value += ((long long)(str[i] - 48)) * radix;
        radix *= 10;
    }

    radix = TIME_DIMENSION / 10;

    for(i=dotposition+1; i<len; i++)
    {
        value += ((long long)(str[i] - 48)) * radix;
        radix /= 10;
    }
  }
  else
  {
    radix = TIME_DIMENSION;

    for(i=len-1; i>=0; i--)
    {
        value += ((long long)(str[i] - 48)) * radix;
        radix *= 10;
    }
  }

  if(str[-1]=='-')  value = -value;

  return(value);
}






Generated by  Doxygen 1.6.0   Back to index