コード例 #1
0
ファイル: trim.c プロジェクト: berndf/avg_q
/*{{{  trim(transform_info_ptr tinfo) {*/
METHODDEF DATATYPE *
trim(transform_info_ptr tinfo) {
 struct trim_storage *local_arg=(struct trim_storage *)tinfo->methods->local_storage;
 transform_argument *args=tinfo->methods->arguments;
 int item, shift, nrofshifts=1;
 long nr_of_input_ranges,nr_of_ranges;
 long output_points;
 long rangeno, current_output_point=0;
 const Bool collapse=args[ARGS_COLLAPSE].is_set || args[ARGS_COLLAPSE_Q].is_set;
 const DATATYPE collapse_quantile=(args[ARGS_COLLAPSE].is_set&&args[ARGS_COLLAPSE].arg.i==COLLAPSE_BY_MEDIAN ? 0.5 : (args[ARGS_COLLAPSE_Q].is_set ? args[ARGS_COLLAPSE_Q].arg.d/100.0 : 0.0));
 array myarray, newarray;
 DATATYPE *oldtsdata;
 DATATYPE *new_xdata=NULL;
 growing_buf ranges, tokenbuf;
 growing_buf triggers;

 growing_buf_init(&ranges);
 growing_buf_init(&tokenbuf);
 growing_buf_init(&triggers);

 if (tinfo->data_type==FREQ_DATA) {
  tinfo->nr_of_points=tinfo->nroffreq;
  nrofshifts=tinfo->nrofshifts;
 }

 /*{{{  Parse the ranges argument */
 nr_of_input_ranges=growing_buf_count_tokens(&local_arg->rangearg);
 if (nr_of_input_ranges<=0 || nr_of_input_ranges%2!=0) {
  ERREXIT(tinfo->emethods, "trim: Need an even number of arguments >=2\n");
 }
 nr_of_input_ranges/=2;
 output_points=0;
 growing_buf_allocate(&ranges, 0);
 growing_buf_allocate(&tokenbuf, 0);
 growing_buf_get_firsttoken(&local_arg->rangearg,&tokenbuf);
 while (tokenbuf.current_length>0) {
  struct range thisrange;
  if (args[ARGS_USE_CHANNEL].is_set) {
   int const channel=find_channel_number(tinfo,args[ARGS_USE_CHANNEL].arg.s);
   if (channel>=0) {
    DATATYPE const minval=get_value(tokenbuf.buffer_start, NULL);
    growing_buf_get_nexttoken(&local_arg->rangearg,&tokenbuf);
    DATATYPE const maxval=get_value(tokenbuf.buffer_start, NULL);
    array indata;
    tinfo_array(tinfo, &indata);
    indata.current_vector=channel;
    thisrange.offset= -1; /* Marks no start recorded yet */
    do {
     DATATYPE const currval=indata.read_element(&indata);
     if (currval>=minval && currval<=maxval) {
      if (thisrange.offset== -1) {
       thisrange.offset=indata.current_element;
       thisrange.length= 1;
      } else {
       thisrange.length++;
      }
     } else {
      if (thisrange.offset!= -1) {
       growing_buf_append(&ranges, (char *)&thisrange, sizeof(struct range));
       output_points+=(collapse ? 1 : thisrange.length);
       thisrange.offset= -1;
      }
     }
     array_advance(&indata);
    } while (indata.message==ARRAY_CONTINUE);
    if (thisrange.offset!= -1) {
     growing_buf_append(&ranges, (char *)&thisrange, sizeof(struct range));
     output_points+=(collapse ? 1 : thisrange.length);
    }
   } else {
    ERREXIT1(tinfo->emethods, "set xdata_from_channel: Unknown channel name >%s<\n", MSGPARM(args[ARGS_USE_CHANNEL].arg.s));
   }
  } else {
   if (args[ARGS_USE_XVALUES].is_set) {
    if (tinfo->xdata==NULL) create_xaxis(tinfo, NULL);
    thisrange.offset=decode_xpoint(tinfo, tokenbuf.buffer_start);
    growing_buf_get_nexttoken(&local_arg->rangearg,&tokenbuf);
    thisrange.length=decode_xpoint(tinfo, tokenbuf.buffer_start)-thisrange.offset+1;
   } else {
    thisrange.offset=gettimeslice(tinfo, tokenbuf.buffer_start);
    growing_buf_get_nexttoken(&local_arg->rangearg,&tokenbuf);
    thisrange.length=gettimeslice(tinfo, tokenbuf.buffer_start);
    if (thisrange.length==0) {
     thisrange.length=tinfo->nr_of_points-thisrange.offset;
    }
   }
   if (thisrange.length<=0) {
    ERREXIT1(tinfo->emethods, "trim: length is %d but must be >0.\n", MSGPARM(thisrange.length));
   }
   growing_buf_append(&ranges, (char *)&thisrange, sizeof(struct range));
   output_points+=(collapse ? 1 : thisrange.length);
  }
  growing_buf_get_nexttoken(&local_arg->rangearg,&tokenbuf);
 }
 /*}}}  */

 nr_of_ranges=ranges.current_length/sizeof(struct range);
 if (nr_of_ranges==0) {
  TRACEMS(tinfo->emethods, 0, "trim: No valid ranges selected, rejecting epoch.\n");
  return NULL;
 }
 TRACEMS2(tinfo->emethods, 1, "trim: nr_of_ranges=%ld, output_points=%ld\n", MSGPARM(nr_of_ranges), MSGPARM(output_points));

 newarray.nr_of_vectors=tinfo->nr_of_channels*nrofshifts;
 newarray.nr_of_elements=output_points;
 newarray.element_skip=tinfo->itemsize;
 if (array_allocate(&newarray)==NULL) {
  ERREXIT(tinfo->emethods, "trim: Error allocating memory.\n");
 }
 oldtsdata=tinfo->tsdata;

 if (tinfo->xdata!=NULL) {
  /* Store xchannelname at the end of xdata, as in create_xaxis(); otherwise we'll have 
   * a problem after free()'ing xdata... */
  new_xdata=(DATATYPE *)malloc(output_points*sizeof(DATATYPE)+strlen(tinfo->xchannelname)+1);
  if (new_xdata==NULL) {
   ERREXIT(tinfo->emethods, "trim: Error allocating xdata memory.\n");
  }
 }

 if (tinfo->triggers.buffer_start!=NULL) {
  struct trigger trig= *(struct trigger *)tinfo->triggers.buffer_start;
  growing_buf_allocate(&triggers, 0);
  /* Record the file position... */
  if (collapse) {
   /* Make triggers in subsequent append() work as expected at least with
    * continuous reading */
   trig.position=local_arg->current_epoch*nr_of_ranges;
   trig.code= -1;
  }
  growing_buf_append(&triggers, (char *)&trig, sizeof(struct trigger));
 }
 
 for (rangeno=0; rangeno<nr_of_ranges; rangeno++) {
  struct range *rangep=((struct range *)(ranges.buffer_start))+rangeno;
  long const old_startpoint=(rangep->offset>0 ?  rangep->offset : 0);
  long const new_startpoint=(rangep->offset<0 ? -rangep->offset : 0);

 /*{{{  Transfer the data*/
 if (old_startpoint<tinfo->nr_of_points 
  /* Skip this explicitly if no "real" point needs copying (length confined within negative offset)
   * since otherwise an endless loop can result as the stop conditions below look at the array 
   * states and no array is touched... */
  && new_startpoint<rangep->length)
 for (item=0; item<tinfo->itemsize; item++) {
  array_use_item(&newarray, item);
  for (shift=0; shift<nrofshifts; shift++) {
   tinfo_array(tinfo, &myarray);
   array_use_item(&myarray, item);
  do {
   DATATYPE sum=0.0;
   long reached_length=new_startpoint;
   myarray.current_element= old_startpoint;
   if (collapse) {
    newarray.current_element=current_output_point;
    newarray.message=ARRAY_CONTINUE;	/* Otherwise the loop below may finish promptly... */
    if (args[ARGS_COLLAPSE].is_set)
    switch (args[ARGS_COLLAPSE].arg.i) {
     case COLLAPSE_BY_HIGHEST:
      sum= -FLT_MAX;
      break;
     case COLLAPSE_BY_LOWEST:
      sum=  FLT_MAX;
      break;
     default:
      break;
    }
   } else {
    newarray.current_element=current_output_point+new_startpoint;
   }
   if (collapse && collapse_quantile>0.0) {
    array helparray=myarray;
    helparray.ringstart=ARRAY_ELEMENT(&myarray);
    helparray.current_element=helparray.current_vector=0;
    helparray.nr_of_vectors=1;
    helparray.nr_of_elements=rangep->length;
    sum=array_quantile(&helparray,collapse_quantile);
    myarray.message=ARRAY_CONTINUE;
   } else
   do {
    if (reached_length>=rangep->length) break;
    if (args[ARGS_COLLAPSE].is_set) {
     DATATYPE const hold=array_scan(&myarray);
     switch (args[ARGS_COLLAPSE].arg.i) {
      case COLLAPSE_BY_SUMMATION:
      case COLLAPSE_BY_AVERAGING:
       sum+=hold;
       break;
      case COLLAPSE_BY_HIGHEST:
       if (hold>sum) sum=hold;
       break;
      case COLLAPSE_BY_LOWEST:
       if (hold<sum) sum=hold;
       break;
      default:
       break;
     }
    } else {
     array_write(&newarray, array_scan(&myarray));
    }
    reached_length++;
   } while (newarray.message==ARRAY_CONTINUE && myarray.message==ARRAY_CONTINUE);
   if (collapse) {
    if (args[ARGS_COLLAPSE].is_set && args[ARGS_COLLAPSE].arg.i==COLLAPSE_BY_AVERAGING && item<tinfo->itemsize-tinfo->leaveright) sum/=reached_length;
    array_write(&newarray, sum);
   }
   if (newarray.message==ARRAY_CONTINUE) {
    array_nextvector(&newarray);
   }
   if (myarray.message==ARRAY_CONTINUE) {
    array_nextvector(&myarray);
   }
  } while (myarray.message==ARRAY_ENDOFVECTOR);
   tinfo->tsdata+=myarray.nr_of_vectors*myarray.nr_of_elements*myarray.element_skip;
  }
  tinfo->tsdata=oldtsdata;
 }
 /*}}}  */

 if (new_xdata!=NULL) {
  /*{{{  Transfer xdata*/
  DATATYPE sum=0.0;
  long reached_length=new_startpoint;
  long point, newpoint;
  if (collapse) {
   newpoint=current_output_point;
  } else {
   newpoint=current_output_point+new_startpoint;
  }
  for (point=old_startpoint;
    point<tinfo->nr_of_points && reached_length<rangep->length;
    point++) {
   if (collapse) {
    sum+=tinfo->xdata[point];
   } else {
    new_xdata[newpoint]=tinfo->xdata[point];
    newpoint++;
   }
   reached_length++;
  }
  if (collapse) {
   /* Summation of x axis values does not appear to make sense, so we always average: */
   new_xdata[newpoint]=sum/reached_length;
  }
  /*}}}  */
  /* Save xchannelname to the end of new_xdata */
  strcpy((char *)(new_xdata+output_points),tinfo->xchannelname);
 }

  if (tinfo->triggers.buffer_start!=NULL) {
   /* Collect triggers... */
   struct trigger *intrig=(struct trigger *)tinfo->triggers.buffer_start+1;
   while (intrig->code!=0) {
    if (intrig->position>=old_startpoint && intrig->position<old_startpoint+rangep->length) {
     struct trigger trig= *intrig;
     if (collapse) {
      trig.position=current_output_point;
     } else {
      trig.position=intrig->position-old_startpoint+current_output_point;
     }
     growing_buf_append(&triggers, (char *)&trig, sizeof(struct trigger));
    }
    intrig++;
   }
  }
  current_output_point+=(collapse ? 1 : rangep->length);
 }

 if (new_xdata!=NULL) {
  free(tinfo->xdata);
  tinfo->xdata=new_xdata;
  tinfo->xchannelname=(char *)(new_xdata+output_points);
 }
 if (tinfo->triggers.buffer_start!=NULL) {
  struct trigger trig;
  /* Write end marker */
  trig.position=0;
  trig.code=0;
  growing_buf_append(&triggers, (char *)&trig, sizeof(struct trigger));
  growing_buf_free(&tinfo->triggers);
  tinfo->triggers=triggers;
 }

 tinfo->multiplexed=FALSE;
 tinfo->nr_of_points=output_points;
 if (tinfo->data_type==FREQ_DATA) {
  tinfo->nroffreq=tinfo->nr_of_points;
 } else {
  tinfo->beforetrig-=((struct range *)(ranges.buffer_start))->offset;
  tinfo->aftertrig=output_points-tinfo->beforetrig;
 }
 tinfo->length_of_output_region=tinfo->nr_of_points*tinfo->nr_of_channels*tinfo->itemsize*nrofshifts;
 local_arg->current_epoch++;

 growing_buf_free(&tokenbuf);
 growing_buf_free(&ranges);

 return newarray.start;
}
コード例 #2
0
/*{{{  write_synamps_init(transform_info_ptr tinfo) {*/
METHODDEF void
write_synamps_init(transform_info_ptr tinfo) {
 struct write_synamps_storage *local_arg=(struct write_synamps_storage *)tinfo->methods->local_storage;
 transform_argument *args=tinfo->methods->arguments;
 double xmin, xmax, ymin, ymax;
 int NoOfChannels=tinfo->nr_of_channels;
 int channel;

 growing_buf_init(&local_arg->triggers);
 local_arg->output_format=(args[ARGS_OUTPUTFORMAT].is_set ? (enum output_formats)args[ARGS_OUTPUTFORMAT].arg.i : FORMAT_EEGFILE);
 local_arg->SCAN=fopen(args[ARGS_OFILE].arg.s, "r+b");
 if (!args[ARGS_APPEND].is_set || local_arg->SCAN==NULL) {   /* target does not exist*/
 /*{{{  Create file*/
 if (local_arg->SCAN!=NULL) fclose(local_arg->SCAN);
 /*{{{  Calculate the span in x-y channel positions*/
 xmin=ymin=  FLT_MAX; 
 xmax=ymax= -FLT_MAX; 
 for (channel=0; channel<tinfo->nr_of_channels; channel++) {
  const double this_x=tinfo->probepos[3*channel], this_y=tinfo->probepos[3*channel+1];
  if (this_x>xmax) xmax=this_x;
  if (this_x<xmin) xmin=this_x;
  if (this_y>ymax) ymax=this_y;
  if (this_y<ymin) ymin=this_y;
 }
 if (xmax==xmin) {
  xmax+=0.5;
  xmin-=0.5;
 }
 if (ymax==ymin) {
  ymax+=0.5;
  ymin-=0.5;
 }
 /*}}}  */

 if ((local_arg->SCAN=fopen(args[ARGS_OFILE].arg.s, "wb"))==NULL) {
  ERREXIT1(tinfo->emethods, "write_synamps_init: Can't open %s\n", MSGPARM(args[ARGS_OFILE].arg.s));
 }
 /*{{{  Many settings, taken from example files...*/
 strcpy(local_arg->EEG.rev, "Version 3.0");
 local_arg->EEG.AdditionalFiles=local_arg->EEG.NextFile=local_arg->EEG.PrevFile=0;
 switch (local_arg->output_format) {
  case FORMAT_EEGFILE:
   local_arg->EEG.review = 1;
   local_arg->EEG.savemode=NSM_EEGF;
   local_arg->EEG.type = NTY_EPOCHED;
   local_arg->EEG.ContinousType=0;
   local_arg->EEG.nsweeps=local_arg->EEG.compsweeps=local_arg->EEG.acceptcnt=0;
   break;
  case FORMAT_CNTFILE:
   local_arg->EEG.review = 1;
   local_arg->EEG.savemode=NSM_CONT;
   local_arg->EEG.type = 0;
   local_arg->EEG.ContinousType=NST_SYNAMPS-NST_CONT0;
   local_arg->EEG.nsweeps=1;
   local_arg->EEG.compsweeps=local_arg->EEG.acceptcnt=0;
   break;
  case FORMAT_AVGFILE:
   local_arg->EEG.review = 0;
   local_arg->EEG.savemode=NSM_AVGD;
   local_arg->EEG.type = NTY_AVERAGED;
   local_arg->EEG.ContinousType=0;
   local_arg->EEG.nsweeps=local_arg->EEG.compsweeps=local_arg->EEG.acceptcnt=(tinfo->nrofaverages>0 ? tinfo->nrofaverages : 1);
   break;
 }
 /* Since the comment can be of arbitrary length and thus also larger than the
  * rest of the header, we should limit ourselves to the size of the id field */
 strncpy(local_arg->EEG.id, tinfo->comment, sizeof(local_arg->EEG.id));
 /* The date is coded in the comment, and read_synamps appends the date and time
  * from the corresponding fields and the contents of the id field, so that
  * the comment2time reader could be confused by the two date/time fields if we
  * would not somehow invalidate remnants of the date field here... */
 {char *slash;
  while ((slash=strchr(local_arg->EEG.id, '/'))!=NULL) {
   *slash='|';
  }
 }
 strcpy(local_arg->EEG.oper, "Unspecified");
 strcpy(local_arg->EEG.doctor, "Unspecified");
 strcpy(local_arg->EEG.referral, "Unspecified");
 strcpy(local_arg->EEG.hospital, "Unspecified");
 strcpy(local_arg->EEG.patient, "Unspecified");
 local_arg->EEG.age = 0;
 local_arg->EEG.sex = 'U';
 local_arg->EEG.hand = 'U';
 strcpy(local_arg->EEG.med, "Unspecified");
 strcpy(local_arg->EEG.category, "Unspecified");
 strcpy(local_arg->EEG.state, "Unspecified");
 strcpy(local_arg->EEG.label, "Unspecified");
 {short dd, mm, yy, yyyy, hh, mi, ss;
 if (comment2time(tinfo->comment, &dd, &mm, &yy, &yyyy, &hh, &mi, &ss)) {
  char buffer[16]; /* Must be long enough to fit date (10) and time (12) +1 */
  /* This is necessary because the date field was devised for 2-digit years.
   * With 4-digit years it uses all 10 bytes and the trailing zero
   * does not fit in any more. */
  snprintf(buffer, 16, "%02d/%02d/%04d", mm, dd, yyyy);
  strncpy(local_arg->EEG.date, buffer, sizeof(local_arg->EEG.date));
  snprintf(buffer, 16, "%02d:%02d:%02d", hh, mi, ss);
  strncpy(local_arg->EEG.time, buffer, sizeof(local_arg->EEG.time));
 }
 }
 local_arg->EEG.rejectcnt = 0;
 local_arg->EEG.pnts=(tinfo->data_type==FREQ_DATA ? tinfo->nroffreq : tinfo->nr_of_points);
 local_arg->EEG.nchannels=NoOfChannels;
 local_arg->EEG.avgupdate=1;
 local_arg->EEG.domain=(tinfo->data_type==FREQ_DATA ? 1 : 0);
 local_arg->EEG.variance=0;
 local_arg->EEG.rate=(uint16_t)rint(tinfo->sfreq);
 if (tinfo->data_type==FREQ_DATA) {
  /* I know that this field is supposed to contain the taper window size in %,
     but we need some way to store basefreq and 'rate' is only integer... */
  local_arg->EEG.SpectWinLength=tinfo->basefreq;
 }
 if (local_arg->EEG.rate==0) {
  local_arg->EEG.rate=1;
  TRACEMS(tinfo->emethods, 0, "write_synamps_init: Rate was zero, corrected to 1!\n");
 }
 local_arg->EEG.scale=3.4375;	/* This is a common sensitivity factor, used if sensitivities for channels are zero */
 local_arg->EEG.veogcorrect=0;
 local_arg->EEG.heogcorrect=0;
 local_arg->EEG.aux1correct=0;
 local_arg->EEG.aux2correct=0;
 local_arg->EEG.veogtrig=15;	/* Trigger threshold in percent of the maximum */
 local_arg->EEG.heogtrig=10;
 local_arg->EEG.aux1trig=10;
 local_arg->EEG.aux2trig=10;
 local_arg->EEG.veogchnl=find_channel_number(tinfo, "VEOG");
 local_arg->EEG.heogchnl=find_channel_number(tinfo, "HEOG");
 local_arg->EEG.veogdir=0;	/* 0=positive, 1=negative */
 local_arg->EEG.veog_n=10;	/* "Number of points per waveform", really: minimum acceptable # averages */
 local_arg->EEG.heog_n=10;
 local_arg->EEG.veogmaxcnt=(int16_t)rint(0.3*tinfo->sfreq);	/* "Number of observations per point", really: event window size in points */
 local_arg->EEG.heogmaxcnt=(int16_t)rint(0.5*tinfo->sfreq);
 local_arg->EEG.AmpSensitivity=10;	/* External Amplifier gain */
 local_arg->EEG.baseline=0;
 local_arg->EEG.reject=0;
 local_arg->EEG.trigtype=2;	/* 2=Port */
 local_arg->EEG.trigval=255;	/* Hold */
 local_arg->EEG.dir=0;	/* Invert (negative up)=0 */
 local_arg->EEG.dispmin= -1;	/* displayed y range */
 local_arg->EEG.dispmax= +1;
 local_arg->EEG.DisplayXmin=local_arg->EEG.AutoMin=local_arg->EEG.rejstart=local_arg->EEG.offstart=local_arg->EEG.xmin= -tinfo->beforetrig/tinfo->sfreq;
 local_arg->EEG.DisplayXmax=local_arg->EEG.AutoMax=local_arg->EEG.rejstop=local_arg->EEG.offstop=local_arg->EEG.xmax= tinfo->aftertrig/tinfo->sfreq;
 local_arg->EEG.zmin=0.0;
 local_arg->EEG.zmax=0.1;
 strcpy(local_arg->EEG.ref, "A1-A2");
 strcpy(local_arg->EEG.screen,   "--------");
 local_arg->EEG.CalMode=2;
 local_arg->EEG.CalMethod=0;
 local_arg->EEG.CalUpdate=1;
 local_arg->EEG.CalBaseline=0;
 local_arg->EEG.CalSweeps=5;
 local_arg->EEG.CalAttenuator=1;
 local_arg->EEG.CalPulseVolt=1;
 local_arg->EEG.CalPulseStart=0;
 local_arg->EEG.CalPulseStop=0;
 local_arg->EEG.CalFreq=10;
 strcpy(local_arg->EEG.taskfile, "--------");
 strcpy(local_arg->EEG.seqfile,  "--------");	/* Otherwise tries to read a seqfile */
 local_arg->EEG.HeadGain=150;
 local_arg->EEG.FspFValue=2.5;
 local_arg->EEG.FspBlockSize=200;
 local_arg->EEG.fratio=1.0;
 local_arg->EEG.minor_rev=12;	/* Necessary ! Otherwise a different file structure is assumed... */
 local_arg->EEG.eegupdate=1;

 local_arg->EEG.xscale=local_arg->EEG.yscale=0;
 local_arg->EEG.xsize=40;
 local_arg->EEG.ysize=20;
 local_arg->EEG.ACmode=0;

 local_arg->EEG.XScaleValue=XSCALEVALUE;
 local_arg->EEG.XScaleInterval=XSCALEINTERVAL;
 local_arg->EEG.YScaleValue=YSCALEVALUE;
 local_arg->EEG.YScaleInterval=YSCALEINTERVAL;

 local_arg->EEG.ScaleToolX1=20;
 local_arg->EEG.ScaleToolY1=170;
 local_arg->EEG.ScaleToolX2=23.1535;
 local_arg->EEG.ScaleToolY2=153.87;

 local_arg->EEG.port=715;
 local_arg->EEG.NumSamples=0;
 local_arg->EEG.FilterFlag=0;
 local_arg->EEG.LowCutoff=4;
 local_arg->EEG.LowPoles=2;
 local_arg->EEG.HighCutoff=50;
 local_arg->EEG.HighPoles=2;
 local_arg->EEG.FilterType=3;
 local_arg->EEG.FilterDomain=1;
 local_arg->EEG.SnrFlag=0;
 local_arg->EEG.CoherenceFlag=0;
 local_arg->EEG.ContinousSeconds=4;
 local_arg->EEG.ChannelOffset=sizeof(int16_t);
 local_arg->EEG.AutoCorrectFlag=0;
 local_arg->EEG.DCThreshold='F';
 /*}}}  */
 /*{{{  Write SETUP structure*/
# ifndef LITTLE_ENDIAN
 change_byteorder((char *)&local_arg->EEG, sm_SETUP);
# endif
 write_struct((char *)&local_arg->EEG, sm_SETUP, local_arg->SCAN);
# ifndef LITTLE_ENDIAN
 change_byteorder((char *)&local_arg->EEG, sm_SETUP);
# endif
 /*}}}  */

 if ((local_arg->Channels=(ELECTLOC *)calloc(NoOfChannels,sizeof(ELECTLOC)))==NULL) {
  ERREXIT(tinfo->emethods, "write_synamps_init: Error allocating Channels list\n");
 }
 for (channel=0; channel<NoOfChannels; channel++) {
  /*{{{  Settings in the channel structure*/
  strncpy(local_arg->Channels[channel].lab, tinfo->channelnames[channel],sizeof(local_arg->Channels[channel].lab));
  local_arg->Channels[channel].reference=0;
  local_arg->Channels[channel].skip=0;
  local_arg->Channels[channel].reject=0;
  local_arg->Channels[channel].display=1;
  local_arg->Channels[channel].bad=0;
  local_arg->Channels[channel].n=(local_arg->output_format==FORMAT_AVGFILE ? local_arg->EEG.acceptcnt : (local_arg->output_format==FORMAT_CNTFILE ? 0 : 1));
  local_arg->Channels[channel].avg_reference=0;
  local_arg->Channels[channel].ClipAdd=0;
  local_arg->Channels[channel].x_coord= (tinfo->probepos[3*channel  ]-xmin)/(xmax-xmin)*RANGE_TO_COVER+XOFFSET;
  local_arg->Channels[channel].y_coord=((ymax-tinfo->probepos[3*channel+1])/(ymax-ymin)*RANGE_TO_COVER+YOFFSET)/3;
  local_arg->Channels[channel].veog_wt=0;
  local_arg->Channels[channel].veog_std=0;
  local_arg->Channels[channel].heog_wt=0;
  local_arg->Channels[channel].heog_std=0;
  local_arg->Channels[channel].baseline=0;
  local_arg->Channels[channel].Filtered=0;
  local_arg->Channels[channel].sensitivity=204.8/args[ARGS_CONVFACTOR].arg.d; /* This arranges for conv_factor to act as the expected product before integer truncation */
  local_arg->Channels[channel].Gain=5;
  local_arg->Channels[channel].HiPass=0;	/* 0=DC */
  local_arg->Channels[channel].LoPass=4;
  local_arg->Channels[channel].Page=0;
  local_arg->Channels[channel].Size=0;
  local_arg->Channels[channel].Impedance=0;
  local_arg->Channels[channel].PhysicalChnl=channel;	/* Channel mapping */
  local_arg->Channels[channel].Rectify=0;
  local_arg->Channels[channel].calib=1.0;
  /*}}}  */
  /*{{{  Write ELECTLOC struct*/
#  ifndef LITTLE_ENDIAN
  change_byteorder((char *)&local_arg->Channels[channel], sm_ELECTLOC);
#  endif
  write_struct((char *)&local_arg->Channels[channel], sm_ELECTLOC, local_arg->SCAN);
#  ifndef LITTLE_ENDIAN
  change_byteorder((char *)&local_arg->Channels[channel], sm_ELECTLOC);
#  endif
  /*}}}  */
 }
 local_arg->SizeofHeader = ftell(local_arg->SCAN);
 TRACEMS2(tinfo->emethods, 1, "write_synamps_init: Creating file %s, format `%s'\n", MSGPARM(args[ARGS_OFILE].arg.s), MSGPARM(neuroscan_subtype_names[NEUROSCAN_SUBTYPE(&local_arg->EEG)]));
 /*}}}  */
 } else {
  /*{{{  Append to file*/
  enum NEUROSCAN_SUBTYPES SubType;
  if (read_struct((char *)&local_arg->EEG, sm_SETUP, local_arg->SCAN)==0) {
   ERREXIT(tinfo->emethods, "write_synamps_init: Can't read file header.\n");
  }
#  ifndef LITTLE_ENDIAN
  change_byteorder((char *)&local_arg->EEG, sm_SETUP);
#  endif
  NoOfChannels = local_arg->EEG.nchannels;
  /*{{{  Allocate channel header*/
  if ((local_arg->Channels=(ELECTLOC *)malloc(NoOfChannels*sizeof(ELECTLOC)))==NULL) {
   ERREXIT(tinfo->emethods, "write_synamps_init: Error allocating Channels list\n");
  }
  /*}}}  */
  for (channel=0; channel<NoOfChannels; channel++) {
   if (read_struct((char *)&local_arg->Channels[channel], sm_ELECTLOC, local_arg->SCAN)==0) {
    ERREXIT(tinfo->emethods, "write_synamps_init: Can't read channel headers.\n");
   }
#  ifndef LITTLE_ENDIAN
   change_byteorder((char *)&local_arg->Channels[channel], sm_ELECTLOC);
#  endif
  }
  local_arg->SizeofHeader = ftell(local_arg->SCAN);
  SubType=NEUROSCAN_SUBTYPE(&local_arg->EEG);
  switch (SubType) {
   case NST_EPOCHS:
    if (local_arg->output_format!=FORMAT_EEGFILE) {
     TRACEMS(tinfo->emethods, 0, "write_synamps_init: Appending to epoch file, discarding option -c\n");
     local_arg->output_format=FORMAT_EEGFILE;
    }
    fseek(local_arg->SCAN, 0, SEEK_END);
    break;
   case NST_CONTINUOUS:
   case NST_SYNAMPS: {
    TEEG TagType;
    EVENT1 event;
    if (local_arg->output_format!=FORMAT_CNTFILE) {
     TRACEMS(tinfo->emethods, 0, "write_synamps_init: Appending to continuous file, assuming option -c\n");
     local_arg->output_format=FORMAT_CNTFILE;
    }
    fseek(local_arg->SCAN, local_arg->EEG.EventTablePos, SEEK_SET);
    /* Here we face two evils in one header: Coding enums as chars and
     * allowing longs at odd addresses. Well... */
    if (1==read_struct((char *)&TagType, sm_TEEG, local_arg->SCAN)) {
#    ifndef LITTLE_ENDIAN
     change_byteorder((char *)&TagType, sm_TEEG);
#    endif
     if (TagType.Teeg==TEEG_EVENT_TAB1) {
      /*{{{  Read the event table*/
      int tag;
      int const ntags=TagType.Size/sm_EVENT1[0].offset;	/* sm_EVENT1[0].offset is sizeof(EVENT1) in the file. */
      for (tag=0; tag<ntags; tag++) {
       if (1!=read_struct((char *)&event, sm_EVENT1, local_arg->SCAN)) {
	ERREXIT(tinfo->emethods, "write_synamps_init: Can't read an event table entry.\n");
	break;
       }
#      ifndef LITTLE_ENDIAN
       change_byteorder((char *)&event, sm_EVENT1);
#      endif
       {
       int const TrigVal=event.StimType &0xff;
       int const KeyBoard=event.KeyBoard&0xf;
       int const KeyPad=Event_KeyPad_value(event);
       int const Accept=Event_Accept_value(event);
       int code=TrigVal-KeyPad+neuroscan_accept_translation[Accept];
       if (code==0) {
        code= -((KeyBoard+1)<<4);
       }
       push_trigger(&local_arg->triggers,offset2point(tinfo, event.Offset),code,NULL);
       }
      }
      /*}}}  */
     } else {
      ERREXIT(tinfo->emethods, "write_synamps_init: Type 2 events are not yet supported.\n");
     }
    } else {
     ERREXIT(tinfo->emethods, "write_synamps_init: Can't read the event table header.\n");
    }
    fseek(local_arg->SCAN, local_arg->EEG.EventTablePos, SEEK_SET);
    }
    break;
   default:
    ERREXIT1(tinfo->emethods, "write_synamps: Cannot append to file type `%s'\n", MSGPARM(neuroscan_subtype_names[SubType]));
    break;
  }
  /* Conformance to the incoming epochs is checked in write_synamps */
  TRACEMS1(tinfo->emethods, 1, "write_synamps_init: Appending to file %s\n", MSGPARM(args[ARGS_OFILE].arg.s));
  /*}}}  */
 }

 tinfo->methods->init_done=TRUE;
}