/*{{{ write_synamps_exit(transform_info_ptr tinfo) {*/ METHODDEF void write_synamps_exit(transform_info_ptr tinfo) { struct write_synamps_storage *local_arg=(struct write_synamps_storage *)tinfo->methods->local_storage; #define SETUP_OFFSET_NSWEEPS 360 #define SETUP_OFFSET_NUMSAMPLES 864 #define SETUP_OFFSET_EVENTTABLEPOS 886 /* Apparently NeuroScan write this even for epoched files although there's no event table there... * It is important there to compute bytes_per_sample */ local_arg->EEG.EventTablePos=ftell(local_arg->SCAN); if (local_arg->output_format==FORMAT_CNTFILE) { TEEG TagType; EVENT1 event; int const nevents=local_arg->triggers.current_length/sizeof(struct trigger); int n; TagType.Teeg=TEEG_EVENT_TAB1; TagType.Size=(nevents+1)*sm_EVENT1[0].offset; /* sm_EVENT1[0].offset is sizeof(EVENT1) in the file. */ TagType.p_o.Offset=0L; # ifndef LITTLE_ENDIAN change_byteorder((char *)&TagType, sm_TEEG); # endif write_struct((char *)&TagType, sm_TEEG, local_arg->SCAN); for (n=0; n<nevents; n++) { struct trigger * const intrig=((struct trigger *)local_arg->triggers.buffer_start)+n; int acc=NAV_STARTSTOP, type=0, resp=0, keyboard=0; while (acc>=0 && intrig->code!=neuroscan_accept_translation[acc]) acc--; if (acc<0) { acc=0; if (intrig->code>0) { type=intrig->code; } else { resp=(-intrig->code)&0xf; if (resp==0) { keyboard=(-intrig->code)>>4; if (keyboard==0) { TRACEMS1(tinfo->emethods, 1, "write_synamps_exit: Can't decipher event code %d\n", MSGPARM(intrig->code)); } else { keyboard--; } } } }
/*{{{ write_rec_close_file(transform_info_ptr tinfo) {*/ LOCAL void write_rec_close_file(transform_info_ptr tinfo) { struct write_rec_storage *local_arg=(struct write_rec_storage *)tinfo->methods->local_storage; char numbuf[NUMBUF_LENGTH]; snprintf(numbuf, NUMBUF_LENGTH, "%ld", local_arg->nr_of_records); memset(&local_arg->fheader.nr_of_records, ' ', sizeof(local_arg->fheader.nr_of_records)); copy_nstring(local_arg->fheader.nr_of_records, numbuf, sizeof(local_arg->fheader.nr_of_records)); fseek(local_arg->outfptr, 0L, SEEK_SET); #ifndef LITTLE_ENDIAN change_byteorder((char *)&local_arg->fheader, sm_REC_file); #endif write_struct((char *)&local_arg->fheader, sm_REC_file, local_arg->outfptr); if (local_arg->outfptr!=stdout && local_arg->outfptr!=stderr) { fclose(local_arg->outfptr); } else { fflush(local_arg->outfptr); } }
/*{{{ 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; }
/*{{{ write_synamps(transform_info_ptr tinfo) {*/ METHODDEF DATATYPE * write_synamps(transform_info_ptr calltinfo) { struct write_synamps_storage *local_arg=(struct write_synamps_storage *)calltinfo->methods->local_storage; transform_argument *args=calltinfo->methods->arguments; NEUROSCAN_EPOCHED_SWEEP_HEAD sweephead; long tsdata_step, tsdata_steps, tsdata_stepwidth; array myarray; /* Note that 'tinfo' instead of 'tinfoptr' is used here so that we don't have to modify * all of the older code which stored only one epoch */ transform_info_ptr tinfo=calltinfo; if (args[ARGS_LINKED].is_set) { /* Go to the start: */ for (; tinfo->previous!=NULL; tinfo=tinfo->previous); } for (; tinfo!=NULL; tinfo=tinfo->next) { DATATYPE * const orig_tsdata=tinfo->tsdata; /*{{{ Assert that epoch size didn't change & itemsize==1*/ if (tinfo->itemsize!=1) { ERREXIT(tinfo->emethods, "write_synamps: Only itemsize=1 is supported.\n"); } if (local_arg->EEG.nchannels!=tinfo->nr_of_channels) { ERREXIT2(tinfo->emethods, "write_synamps: nr_of_channels was %d, now %d\n", MSGPARM(local_arg->EEG.nchannels), MSGPARM(tinfo->nr_of_channels)); } /*}}} */ if (tinfo->data_type==FREQ_DATA) { tinfo->nr_of_points=tinfo->nroffreq; tsdata_steps=tinfo->nrofshifts; tsdata_stepwidth=tinfo->nr_of_channels*tinfo->nroffreq*tinfo->itemsize; } else { tsdata_steps=1; tsdata_stepwidth=0; } for (tsdata_step=0; tsdata_step<tsdata_steps; tinfo->tsdata+=tsdata_stepwidth, tsdata_step++) { switch (local_arg->output_format) { case FORMAT_EEGFILE: if (local_arg->EEG.pnts!=tinfo->nr_of_points) { ERREXIT2(tinfo->emethods, "write_synamps: nr_of_points was %d, now %d\n", MSGPARM(local_arg->EEG.pnts), MSGPARM(tinfo->nr_of_points)); } /*{{{ Set sweephead values*/ sweephead.accept=1; sweephead.type=254; sweephead.correct=0; sweephead.rt=0; sweephead.response=0; if (tinfo->condition>0) { sweephead.type=tinfo->condition&0xff; } else if (tinfo->condition<0 && (-tinfo->condition)<=0xf) { sweephead.type=0; sweephead.response= -tinfo->condition; } else { /* KeyBoard event: Do it the same way 'Edit' does when epoching, * mapping F1 to type=1 and so on (overlap with stim codes, but they * should know how they want it...) */ sweephead.type= (-tinfo->condition)>>4; } /*}}} */ /*{{{ Write sweephead struct*/ # ifndef LITTLE_ENDIAN change_byteorder((char *)&sweephead, sm_NEUROSCAN_EPOCHED_SWEEP_HEAD); # endif write_struct((char *)&sweephead, sm_NEUROSCAN_EPOCHED_SWEEP_HEAD, local_arg->SCAN); # ifndef LITTLE_ENDIAN change_byteorder((char *)&sweephead, sm_NEUROSCAN_EPOCHED_SWEEP_HEAD); # endif /*}}} */ local_arg->EEG.nsweeps++; /* This gets patched into the header by write_synamps_exit */ local_arg->EEG.compsweeps++; local_arg->EEG.acceptcnt++; break; case FORMAT_AVGFILE: if (local_arg->EEG.NumSamples!=0) { ERREXIT(tinfo->emethods, "write_synamps: Only a single epoch may be written to an .AVG file!\n"); } case FORMAT_CNTFILE: if (tinfo->triggers.buffer_start!=NULL) { struct trigger *intrig=(struct trigger *)tinfo->triggers.buffer_start+1; while (intrig->code!=0) { push_trigger(&local_arg->triggers,local_arg->EEG.NumSamples+intrig->position,intrig->code,intrig->description); intrig++; } } local_arg->EEG.NumSamples+=tinfo->nr_of_points; break; } tinfo_array(tinfo, &myarray); if (local_arg->output_format==FORMAT_AVGFILE) { /* points are the elements */ float *pdata, * const buffer=(float *)malloc(myarray.nr_of_elements*sizeof(float)); const char *fill="\0\0\0\0\0"; if (buffer==NULL) { ERREXIT(tinfo->emethods, "write_synamps: Error allocating AVGFILE buffer\n"); } do { int const channel=myarray.current_vector; /* Write the `5-byte channel header that is no longer used' */ fwrite(fill, 1, 5, local_arg->SCAN); pdata=buffer; do { *pdata=NEUROSCAN_FLOATCONV(&local_arg->Channels[channel], array_scan(&myarray)); # ifndef LITTLE_ENDIAN Intel_float(pdata); # endif pdata++; } while (myarray.message==ARRAY_CONTINUE); if ((int)fwrite(buffer,sizeof(float),myarray.nr_of_elements,local_arg->SCAN)!=myarray.nr_of_elements) { ERREXIT(tinfo->emethods, "write_synamps: Error writing data point\n"); } } while (myarray.message!=ARRAY_ENDOFSCAN); free(buffer); } else { int16_t * const buffer=(int16_t *)malloc(myarray.nr_of_vectors*sizeof(int16_t)); if (buffer==NULL) { ERREXIT(tinfo->emethods, "write_synamps: Error allocating buffer\n"); } array_transpose(&myarray); /* channels are the elements */ do { int channel=0; do { DATATYPE hold=array_scan(&myarray), hold2; /* Code anything exceeding the representable range, including +-Inf, as min/max representable value. */ hold2=NEUROSCAN_SHORTCONV(&local_arg->Channels[channel], hold); if (hold2< -32768) hold2= -32768; else if (hold2> 32767) hold2= 32767; buffer[channel]=(int16_t)hold2; # ifndef LITTLE_ENDIAN Intel_int16(&buffer[channel]); # endif channel++; } while (myarray.message==ARRAY_CONTINUE); if ((int)fwrite(buffer,sizeof(int16_t),myarray.nr_of_elements,local_arg->SCAN)!=myarray.nr_of_elements) { ERREXIT(tinfo->emethods, "write_synamps: Error writing data point\n"); } } while (myarray.message!=ARRAY_ENDOFSCAN); free(buffer); } } /* FREQ_DATA shifts loop */ tinfo->tsdata=orig_tsdata; if (!args[ARGS_LINKED].is_set) { break; } } /* Linked epochs loop */ return calltinfo->tsdata; /* Simply to return something `useful' */ }
/*{{{ write_rec_open_file(transform_info_ptr tinfo) {*/ LOCAL void write_rec_open_file(transform_info_ptr tinfo) { struct write_rec_storage *local_arg=(struct write_rec_storage *)tinfo->methods->local_storage; transform_argument *args=tinfo->methods->arguments; FILE *outfptr=NULL; if (strcmp(args[ARGS_OFILE].arg.s, "stdout")==0) outfptr=stdout; else if (strcmp(args[ARGS_OFILE].arg.s, "stderr")==0) outfptr=stderr; local_arg->appendmode=args[ARGS_APPEND].is_set; if (local_arg->appendmode) { /*{{{ Append mode open if cofile exists and is of non-zero length*/ if (outfptr==NULL) { if ((outfptr=fopen(args[ARGS_OFILE].arg.s, "r+b"))!=NULL) { fseek(outfptr, 0L, SEEK_END); if (ftell(outfptr)==0L) { local_arg->appendmode=FALSE; /* If at start: write header */ } } } /*}}} */ } if (outfptr==NULL) { /*{{{ Open the REC file in truncate mode*/ local_arg->appendmode=FALSE; /* write header */ if ((outfptr=fopen(args[ARGS_OFILE].arg.s, "wb"))==NULL) { ERREXIT1(tinfo->emethods, "write_rec_open_file: Can't open %s\n", MSGPARM(args[ARGS_OFILE].arg.s)); } /*}}} */ } local_arg->outfptr=outfptr; if (local_arg->appendmode) { /* Read rather than write header in append mode */ fseek(outfptr, 0L, SEEK_SET); if (read_struct((char *)&local_arg->fheader, sm_REC_file, outfptr)==0) { ERREXIT1(tinfo->emethods, "write_rec_open_file: Can't read header in file %s\n", MSGPARM(args[ARGS_OFILE].arg.s)); } # ifndef LITTLE_ENDIAN change_byteorder((char *)&local_arg->fheader, sm_REC_file); # endif local_arg->nr_of_records=atoi(local_arg->fheader.nr_of_records); fseek(outfptr, 0L, SEEK_END); } else { /*{{{ Write header*/ REC_channel_header channelheader; const long channelheader_length=CHANNELHEADER_SIZE_PER_CHANNEL*tinfo->nr_of_channels; int channel; short dd, mm, yy, yyyy, hh, mi, ss; char numbuf[NUMBUF_LENGTH]; setlocale(LC_NUMERIC, "C"); /* Print fractional numbers with decimal point */ #define fileheader local_arg->fheader memset(&fileheader, ' ', sizeof(REC_file_header)); copy_nstring(fileheader.version, "0", sizeof(fileheader.version)); if (args[ARGS_PATIENT].is_set) copy_nstring(fileheader.patient, args[ARGS_PATIENT].arg.s, sizeof(fileheader.patient)); if (args[ARGS_RECORDING].is_set) copy_nstring(fileheader.recording, args[ARGS_RECORDING].arg.s, sizeof(fileheader.recording)); if (args[ARGS_DATETIME].is_set) { char * const comma=strchr(args[ARGS_DATETIME].arg.s, ','); if (comma==NULL) { ERREXIT(tinfo->emethods, "write_rec_open_file: Datetime format is dd.mm.yy,hh.mi.ss !\n"); } copy_nstring(fileheader.startdate, args[ARGS_DATETIME].arg.s, sizeof(fileheader.startdate)); copy_nstring(fileheader.starttime, comma+1, sizeof(fileheader.starttime)); } else if (tinfo->comment!=NULL) { if (!args[ARGS_RECORDING].is_set) copy_nstring(fileheader.recording, tinfo->comment, sizeof(fileheader.recording)); if (comment2time(tinfo->comment, &dd, &mm, &yy, &yyyy, &hh, &mi, &ss)) { snprintf(numbuf, NUMBUF_LENGTH, "%02d.%02d.%02d", dd, mm, yy); copy_nstring(fileheader.startdate, numbuf, sizeof(fileheader.startdate)); snprintf(numbuf, NUMBUF_LENGTH, "%02d.%02d.%02d", hh, mi, ss); copy_nstring(fileheader.starttime, numbuf, sizeof(fileheader.starttime)); } } if (*fileheader.startdate==' ') { /* Date/time weren't set otherwise: */ copy_nstring(fileheader.startdate, "00.00.00", sizeof(fileheader.startdate)); copy_nstring(fileheader.starttime, "00.00.00", sizeof(fileheader.starttime)); } snprintf(numbuf, NUMBUF_LENGTH, "%ld", sm_REC_file[0].offset+channelheader_length); copy_nstring(fileheader.bytes_in_header, numbuf, sizeof(fileheader.bytes_in_header)); copy_nstring(fileheader.data_format_version, (args[ARGS_DATA_FORMAT_VERSION].is_set ? args[ARGS_DATA_FORMAT_VERSION].arg.s : "write_rec file"), sizeof(fileheader.data_format_version)); local_arg->nr_of_records=0; copy_nstring(fileheader.nr_of_records, "-1", sizeof(fileheader.nr_of_records)); snprintf(numbuf, NUMBUF_LENGTH, "%g", ((double)local_arg->samples_per_record)/tinfo->sfreq); copy_nstring(fileheader.duration_s, numbuf, sizeof(fileheader.duration_s)); snprintf(numbuf, NUMBUF_LENGTH, "%d", tinfo->nr_of_channels); copy_nstring(fileheader.nr_of_channels, numbuf, sizeof(fileheader.nr_of_channels)); #ifndef LITTLE_ENDIAN change_byteorder((char *)&fileheader, sm_REC_file); #endif write_struct((char *)&fileheader, sm_REC_file, outfptr); #ifndef LITTLE_ENDIAN change_byteorder((char *)&fileheader, sm_REC_file); #endif #undef fileheader if ((channelheader.label=(char (*)[16])malloc(channelheader_length))==NULL) { ERREXIT(tinfo->emethods, "write_rec_open_file: Error allocating channelheader memory\n"); } channelheader.transducer=(char (*)[80])(channelheader.label+tinfo->nr_of_channels); channelheader.dimension=(char (*)[8])(channelheader.transducer+tinfo->nr_of_channels); channelheader.physmin=(char (*)[8])(channelheader.dimension+tinfo->nr_of_channels); channelheader.physmax=(char (*)[8])(channelheader.physmin+tinfo->nr_of_channels); channelheader.digmin=(char (*)[8])(channelheader.physmax+tinfo->nr_of_channels); channelheader.digmax=(char (*)[8])(channelheader.digmin+tinfo->nr_of_channels); channelheader.prefiltering=(char (*)[80])(channelheader.digmax+tinfo->nr_of_channels); channelheader.samples_per_record=(char (*)[8])(channelheader.prefiltering+tinfo->nr_of_channels); channelheader.reserved=(char (*)[32])(channelheader.samples_per_record+tinfo->nr_of_channels); memset(channelheader.label, ' ', channelheader_length); for (channel=0; channel<tinfo->nr_of_channels; channel++) { copy_nstring(channelheader.dimension[channel], "uV", sizeof(channelheader.dimension[channel])); copy_nstring(channelheader.label[channel], tinfo->channelnames[channel], sizeof(channelheader.label[channel])); snprintf(numbuf, NUMBUF_LENGTH, "%g", (double)local_arg->digmin*local_arg->resolution); copy_nstring(channelheader.physmin[channel], numbuf, sizeof(channelheader.physmin[channel])); snprintf(numbuf, NUMBUF_LENGTH, "%g", (double)local_arg->digmax*local_arg->resolution); copy_nstring(channelheader.physmax[channel], numbuf, sizeof(channelheader.physmax[channel])); snprintf(numbuf, NUMBUF_LENGTH, "%ld", local_arg->digmin); copy_nstring(channelheader.digmin[channel], numbuf, sizeof(channelheader.digmin[channel])); snprintf(numbuf, NUMBUF_LENGTH, "%ld", local_arg->digmax); copy_nstring(channelheader.digmax[channel], numbuf, sizeof(channelheader.digmax[channel])); snprintf(numbuf, NUMBUF_LENGTH, "%ld", local_arg->samples_per_record); copy_nstring(channelheader.samples_per_record[channel], numbuf, sizeof(channelheader.samples_per_record[channel])); } setlocale(LC_NUMERIC, ""); /* Reset locale to environment */ if (tinfo->nr_of_channels!=(int)fwrite((void *)channelheader.label, CHANNELHEADER_SIZE_PER_CHANNEL, tinfo->nr_of_channels, local_arg->outfptr)) { ERREXIT(tinfo->emethods, "write_rec_open_file: Error writing channel headers\n"); } free(channelheader.label); /*}}} */ } }
/*{{{ read_neurofile_init(transform_info_ptr tinfo) {*/ METHODDEF void read_neurofile_init(transform_info_ptr tinfo) { struct read_neurofile_storage *local_arg=(struct read_neurofile_storage *)tinfo->methods->local_storage; transform_argument *args=tinfo->methods->arguments; int channel; FILE *dsc; #ifdef __GNUC__ char filename[strlen(args[ARGS_IFILE].arg.s)+5]; #else char filename[MAX_PATHLEN]; #endif growing_buf_init(&local_arg->triggers); strcpy(filename, args[ARGS_IFILE].arg.s); strcat(filename, ".dsc"); if((dsc=fopen(filename, "rb"))==NULL) { ERREXIT1(tinfo->emethods, "read_neurofile_init: Can't open dsc file >%s<\n", MSGPARM(filename)); } if (read_struct((char *)&local_arg->seq, sm_sequence, dsc)==0) { ERREXIT1(tinfo->emethods, "read_neurofile_init: Can't read header in file >%s<\n", MSGPARM(filename)); } fclose(dsc); #ifndef LITTLE_ENDIAN change_byteorder((char *)&local_arg->seq, sm_sequence); #endif local_arg->points_in_file = 256L*local_arg->seq.length; tinfo->points_in_file=local_arg->points_in_file; tinfo->sfreq=local_arg->sfreq=neurofile_map_sfreq(local_arg->seq.fastrate); local_arg->nr_of_channels=local_arg->seq.nfast; local_arg->factor=local_arg->seq.gain/1000.0; local_arg->stringlength=0; for (channel=0; channel<local_arg->nr_of_channels; channel++) { local_arg->stringlength+=strlen((char *)local_arg->seq.elnam[channel])+1; } /*{{{ Process options*/ local_arg->fromepoch=(args[ARGS_FROMEPOCH].is_set ? args[ARGS_FROMEPOCH].arg.i : 1); local_arg->epochs=(args[ARGS_EPOCHS].is_set ? args[ARGS_EPOCHS].arg.i : -1); /*}}} */ /*{{{ Parse arguments that can be in seconds*/ local_arg->beforetrig=tinfo->beforetrig=gettimeslice(tinfo, args[ARGS_BEFORETRIG].arg.s); local_arg->aftertrig=tinfo->aftertrig=gettimeslice(tinfo, args[ARGS_AFTERTRIG].arg.s); local_arg->offset=(args[ARGS_OFFSET].is_set ? gettimeslice(tinfo, args[ARGS_OFFSET].arg.s) : 0); /*}}} */ strcpy(filename+strlen(args[ARGS_IFILE].arg.s), ".eeg"); if((local_arg->infile=fopen(filename, "rb"))==NULL) { ERREXIT1(tinfo->emethods, "read_neurofile_init: Can't open file >%s<\n", MSGPARM(filename)); } if ((local_arg->last_values=(DATATYPE *)calloc(local_arg->nr_of_channels, sizeof(DATATYPE)))==NULL) { ERREXIT(tinfo->emethods, "read_neurofile_init: Error allocating last_values memory\n"); } local_arg->trigcodes=NULL; if (!args[ARGS_CONTINUOUS].is_set) { /* The actual trigger file is read when the first event is accessed! */ if (args[ARGS_TRIGLIST].is_set) { local_arg->trigcodes=get_trigcode_list(args[ARGS_TRIGLIST].arg.s); if (local_arg->trigcodes==NULL) { ERREXIT(tinfo->emethods, "read_neurofile_init: Error allocating triglist memory\n"); } } } else { if (local_arg->aftertrig==0) { /* Continuous mode: If aftertrig==0, automatically read up to the end of file */ if (local_arg->points_in_file==0) { ERREXIT(tinfo->emethods, "read_neurofile: Unable to determine the number of samples in the input file!\n"); } local_arg->aftertrig=local_arg->points_in_file-local_arg->beforetrig; } } read_neurofile_reset_triggerbuffer(tinfo); local_arg->current_trigger=0; local_arg->current_point=0; tinfo->filetriggersp=&local_arg->triggers; tinfo->methods->init_done=TRUE; }
/*{{{ read_freiburg_init(transform_info_ptr tinfo) {*/ METHODDEF void read_freiburg_init(transform_info_ptr tinfo) { struct read_freiburg_storage *local_arg=(struct read_freiburg_storage *)tinfo->methods->local_storage; transform_argument *args=tinfo->methods->arguments; struct stat statbuf; /*{{{ Process options*/ local_arg->fromepoch=(args[ARGS_FROMEPOCH].is_set ? args[ARGS_FROMEPOCH].arg.i : 1); local_arg->epochs=(args[ARGS_EPOCHS].is_set ? args[ARGS_EPOCHS].arg.i : -1); /*}}} */ local_arg->channelnames=NULL; local_arg->uV_per_bit=NULL; growing_buf_init(&local_arg->segment_table); /* This sets buffer_start=NULL */ local_arg->nr_of_channels=0; if (args[ARGS_CONTINUOUS].is_set) { /*{{{ Open a continuous (sleep, Bernd Tritschler) file*/ FILE *infile; local_arg->in_channels= &sleep_channels[0]; if (stat(args[ARGS_IFILE].arg.s, &statbuf)!= 0 || !S_ISREG(statbuf.st_mode)) { /* File does not exist or isn't a regular file: Try BT format */ #ifdef __GNUC__ char co_name[strlen(args[ARGS_IFILE].arg.s)+4]; char coa_name[strlen(args[ARGS_IFILE].arg.s)+5]; #else char co_name[MAX_PATHLEN]; char coa_name[MAX_PATHLEN]; #endif char coa_buf[MAX_COALINE]; FILE *coafile; strcpy(co_name, args[ARGS_IFILE].arg.s); strcat(co_name, ".co"); if((infile=fopen(co_name,"rb"))==NULL) { ERREXIT1(tinfo->emethods, "read_freiburg_init: Can't open file %s\n", MSGPARM(co_name)); } local_arg->infile=infile; if (args[ARGS_REPAIR_OFFSET].is_set) { fseek(infile, args[ARGS_REPAIR_OFFSET].arg.i, SEEK_SET); } else { if (read_struct((char *)&local_arg->btfile, sm_BT_file, infile)==0) { ERREXIT1(tinfo->emethods, "read_freiburg_init: Header read error in file %s\n", MSGPARM(co_name)); } # ifndef LITTLE_ENDIAN change_byteorder((char *)&local_arg->btfile, sm_BT_file); # endif } strcpy(coa_name, args[ARGS_IFILE].arg.s); strcat(coa_name, ".coa"); if((coafile=fopen(coa_name,"rb"))==NULL) { TRACEMS1(tinfo->emethods, 0, "read_freiburg_init: No file %s found\n", MSGPARM(coa_name)); } else { while (!feof(coafile)) { Bool repeat; fgets(coa_buf, MAX_COALINE-1, coafile); do { repeat=FALSE; if (strncmp(coa_buf, "Channel_Table ", 14)==0) { int havechannels=0, stringlength=0; long tablepos=ftell(coafile); char *innames; while (!feof(coafile)) { char *eol; fgets(coa_buf, MAX_COALINE-1, coafile); if (!isdigit(*coa_buf)) break; if (strncmp(coa_buf, "0 0 ", 4)==0) { /* Empty channel descriptors: Don't generate channelnames */ } else { for (eol=coa_buf+strlen(coa_buf)-1; eol>=coa_buf && (*eol=='\n' || *eol=='\r'); eol--) *eol='\0'; /* This includes 1 for the zero at the end: */ stringlength+=strlen(strrchr(coa_buf, ' ')); } havechannels++; } if (havechannels==0) continue; /* Channel table is unuseable */ local_arg->nr_of_channels=havechannels; innames=NULL; if ((stringlength!=0 && ((local_arg->channelnames=(char **)malloc(havechannels*sizeof(char *)))==NULL || (innames=(char *)malloc(stringlength))==NULL)) || (local_arg->uV_per_bit=(float *)malloc(havechannels*sizeof(float)))==NULL) { ERREXIT(tinfo->emethods, "read_freiburg_init: Error allocating .coa memory\n"); } fseek(coafile, tablepos, SEEK_SET); havechannels=0; while (!feof(coafile)) { char *eol; fgets(coa_buf, MAX_COALINE-1, coafile); if (!isdigit(*coa_buf)) break; for (eol=coa_buf+strlen(coa_buf)-1; eol>=coa_buf && (*eol=='\n' || *eol=='\r'); eol--) *eol='\0'; if (innames!=NULL) { strcpy(innames, strrchr(coa_buf, ' ')+1); local_arg->channelnames[havechannels]=innames; innames+=strlen(innames)+1; } /* The sensitivity in .coa files is given as nV/Bit */ local_arg->uV_per_bit[havechannels]=atoi(strchr(coa_buf, ' ')+1)/1000.0; if (local_arg->uV_per_bit[havechannels]==0.0) { local_arg->uV_per_bit[havechannels]=0.086; TRACEMS1(tinfo->emethods, 1, "read_freiburg_init: Sensitivity for channel %d set to 86 nV/Bit\n", MSGPARM(havechannels)); } havechannels++; } repeat=TRUE; } else if (strncmp(coa_buf, SEGMENT_TABLE_STRING, strlen(SEGMENT_TABLE_STRING))==0) { long current_offset=0; char *inbuf=coa_buf; Bool havesomething=FALSE; growing_buf_allocate(&local_arg->segment_table, 0); while (!feof(coafile)) { int const nextchar=fgetc(coafile); if (nextchar=='\r' || nextchar=='\n' || nextchar==' ') { if (havesomething) { *inbuf = '\0'; current_offset+=atoi(coa_buf); growing_buf_append(&local_arg->segment_table, (char *)¤t_offset, sizeof(long)); inbuf=coa_buf; havesomething=FALSE; } if (nextchar=='\n') break; } else { *inbuf++ = nextchar; havesomething=TRUE; } } repeat=FALSE; } } while (repeat); } fclose(coafile); if (local_arg->uV_per_bit==NULL) { TRACEMS1(tinfo->emethods, 0, "read_freiburg_init: No channel table found in file %s\n", MSGPARM(coa_name)); } if (local_arg->segment_table.buffer_start==NULL) { TRACEMS1(tinfo->emethods, 0, "read_freiburg_init: No segment table found in file %s\n", MSGPARM(coa_name)); } /* Determine the exact number of points in file: Start with the previous * segment and add the last segment. */ fstat(fileno(infile),&statbuf); //printf("File size is %ld\n", statbuf.st_size); //printf("Last segment (EOF) at %ld\n", ((long *)local_arg->segment_table.buffer_start)[local_arg->segment_table.current_length/sizeof(long)-1]); while (local_arg->segment_table.current_length>=1 && ((long *)local_arg->segment_table.buffer_start)[local_arg->segment_table.current_length/sizeof(long)-1]>=statbuf.st_size) { //printf("%ld - Removing last segment!\n", ((long *)local_arg->segment_table.buffer_start)[local_arg->segment_table.current_length/sizeof(long)-1]); local_arg->segment_table.current_length--; } /* Size without the last segment */ tinfo->points_in_file=(local_arg->segment_table.current_length/sizeof(long)-1)*SEGMENT_LENGTH; /* Count the points in the last segment */ { array myarray; int length_of_last_segment=0; myarray.element_skip=tinfo->itemsize=1; myarray.nr_of_vectors=1; myarray.nr_of_elements=local_arg->nr_of_channels; if (array_allocate(&myarray)==NULL) { ERREXIT(tinfo->emethods, "read_freiburg_init: Error allocating myarray\n"); } fseek(infile, ((long *)local_arg->segment_table.buffer_start)[local_arg->segment_table.current_length/sizeof(long)-1], SEEK_SET); //printf("Seeking to %ld\n", ((long *)local_arg->segment_table.buffer_start)[local_arg->segment_table.current_length/sizeof(long)-1]); tinfo->nr_of_channels=local_arg->nr_of_channels; /* This is used by freiburg_get_segment_init! */ freiburg_get_segment_init(tinfo); while (freiburg_get_segment(tinfo, &myarray)==0) length_of_last_segment++; freiburg_get_segment_free(tinfo); tinfo->points_in_file+=length_of_last_segment; TRACEMS1(tinfo->emethods, 1, "read_freiburg_init: Last segment has %ld points\n",length_of_last_segment); array_free(&myarray); } } if (local_arg->channelnames==NULL && local_arg->btfile.text[0]=='\0') { local_arg->in_channels= &goeppi_channels[0]; TRACEMS(tinfo->emethods, 0, "read_freiburg_init: Assuming Goeppingen style setup!\n"); } local_arg->continuous_type=SLEEP_BT_TYPE; TRACEMS(tinfo->emethods, 1, "read_freiburg_init: Opened file in BT format\n"); } else { if((infile=fopen(args[ARGS_IFILE].arg.s,"rb"))==NULL) { ERREXIT1(tinfo->emethods, "read_freiburg_init: Can't open file %s\n", MSGPARM(args[ARGS_IFILE].arg.s)); } if (args[ARGS_REPAIR_OFFSET].is_set) { fseek(infile, args[ARGS_REPAIR_OFFSET].arg.i, SEEK_SET); } else { if (read_struct((char *)&local_arg->btfile, sm_BT_file, infile)==0) { ERREXIT1(tinfo->emethods, "read_freiburg_init: Header read error in file %s\n", MSGPARM(args[ARGS_IFILE].arg.s)); } # ifdef LITTLE_ENDIAN change_byteorder((char *)&local_arg->btfile, sm_BT_file); # endif } local_arg->continuous_type=SLEEP_KL_TYPE; /* Year and day are swapped in KL format with respect to BT format... */ {short buf=local_arg->btfile.start_year; local_arg->btfile.start_year=local_arg->btfile.start_day; local_arg->btfile.start_day=buf;} /* Well, sometimes or most of the time, in KL files the sampling interval * was not set correctly... */ if (!args[ARGS_SFREQ].is_set && local_arg->btfile.sampling_interval_us!=9765 && local_arg->btfile.sampling_interval_us!=9766) { TRACEMS1(tinfo->emethods, 0, "read_freiburg_init: sampling_interval_us was %d, corrected!\n", MSGPARM(local_arg->btfile.sampling_interval_us)); local_arg->btfile.sampling_interval_us=9766; } TRACEMS(tinfo->emethods, 1, "read_freiburg_init: Opened file in KL format\n"); } if (args[ARGS_REPAIR_CHANNELS].is_set) local_arg->btfile.nr_of_channels=args[ARGS_REPAIR_CHANNELS].arg.i; tinfo->nr_of_channels=local_arg->btfile.nr_of_channels; if (tinfo->nr_of_channels<=0 || tinfo->nr_of_channels>MAX_NUMBER_OF_CHANNELS_IN_EP) { ERREXIT1(tinfo->emethods, "read_freiburg_init: Impossible: %d channels?\n", MSGPARM(tinfo->nr_of_channels)); } if (local_arg->nr_of_channels==0) { local_arg->nr_of_channels=tinfo->nr_of_channels; } else { if (local_arg->nr_of_channels!=tinfo->nr_of_channels) { ERREXIT2(tinfo->emethods, "read_freiburg_init: Setup has %d channels, but the file has %d!\n", MSGPARM(local_arg->nr_of_channels), MSGPARM(tinfo->nr_of_channels)); } } local_arg->sfreq=(args[ARGS_SFREQ].is_set ? args[ARGS_SFREQ].arg.d : 1.0e6/local_arg->btfile.sampling_interval_us); tinfo->sfreq=local_arg->sfreq; if (tinfo->sfreq<=0.0 || tinfo->sfreq>MAX_POSSIBLE_SFREQ) { ERREXIT1(tinfo->emethods, "read_freiburg_init: Impossible: sfreq=%gHz?\n", MSGPARM(tinfo->sfreq)); } /*{{{ Parse arguments that can be in seconds*/ tinfo->nr_of_points=gettimeslice(tinfo, args[ARGS_NCHANNELS].arg.s); if (tinfo->nr_of_points<=0) { /* Read the whole file as one epoch */ TRACEMS1(tinfo->emethods, 1, "read_freiburg_init: Reading %ld points\n",tinfo->points_in_file); tinfo->nr_of_points=tinfo->points_in_file; } local_arg->offset=(args[ARGS_OFFSET].is_set ? gettimeslice(tinfo, args[ARGS_OFFSET].arg.s) : 0); local_arg->epochlength=tinfo->nr_of_points; /*}}} */ tinfo->beforetrig= -local_arg->offset; tinfo->aftertrig=tinfo->nr_of_points+local_arg->offset; /*}}} */ } else { local_arg->in_channels= &freiburg_channels[0]; local_arg->current_trigger=0; if (stat(args[ARGS_IFILE].arg.s, &statbuf)!=0) { ERREXIT1(tinfo->emethods, "read_freiburg_init: Can't stat file %s\n", MSGPARM(args[ARGS_IFILE].arg.s)); } local_arg->nr_of_channels=atoi(args[ARGS_NCHANNELS].arg.s); /* average mode if the name does not belong to a directory */ local_arg->average_mode= !S_ISDIR(statbuf.st_mode); tinfo->nr_of_channels=MAX_NUMBER_OF_CHANNELS_IN_EP; } freiburg_get_segment_init(tinfo); local_arg->current_point=0; tinfo->methods->init_done=TRUE; }
int main(int argc, char **argv) { SETUP EEG; ELECTLOC *Channels=(ELECTLOC *)NULL; TEEG TagType; int ntags; long SizeofHeader; /* no. of bytes in header of source file */ enum NEUROSCAN_SUBTYPES SubType; /* This tells, once and for all, the file type */ int errflag=0, c; enum {EVENTLIST_NONE, EVENTLIST_SYNAMPS, EVENTLIST_AVG_Q} event_list=EVENTLIST_NONE; enum {EVENTPOS_POINTS, EVENTPOS_MSEC, EVENTPOS_SEC} eventpos_type=EVENTPOS_POINTS; char *filename; FILE *SCAN; int NoOfChannels, channel; int filearg; /*{{{ Process command line*/ mainargv=argv; while ((c=getopt(argc, argv, "eEms"))!=EOF) { switch (c) { case 'e': event_list=EVENTLIST_SYNAMPS; break; case 'E': event_list=EVENTLIST_AVG_Q; break; case 'm': eventpos_type=EVENTPOS_MSEC; break; case 's': eventpos_type=EVENTPOS_SEC; break; case '?': default: errflag++; continue; } } if (argc-optind<END_OF_ARGS || errflag>0) { fprintf(stderr, "Usage: %s [options] synamps_filename1 synamps_filename2 ...\n" " Options are:\n" "\t-e: Output the event table in NeuroScan format\n" "\t-E: Output the event table in avg_q format\n" "\t-m: avg_q Marker positions should be output in milliseconds\n" "\t-s: avg_q Marker positions should be output in seconds\n" , argv[0]); exit(1); } for (filearg=SYNAMPSFILE; argc-optind-filearg>=END_OF_ARGS; filearg++) { filename=MAINARG(filearg); SCAN=fopen(filename,"rb"); if(SCAN==NULL) { fprintf(stderr, "%s: Can't open file %s\n", argv[0], filename); continue; } if (read_struct((char *)&EEG, sm_SETUP, SCAN)==0) { fprintf(stderr, "%s: Short file %s\n", argv[0], filename); continue; } #ifndef LITTLE_ENDIAN change_byteorder((char *)&EEG, sm_SETUP); #endif if (strncmp(&EEG.rev[0],"Version",7)!=0) { fprintf(stderr, "%s: %s is not a NeuroScan file\n", argv[0], filename); continue; } /* The actual criteria to decide upon the file type (average, continuous etc) * by the header have been moved to neurohdr.h because it's black magic... */ SubType=NEUROSCAN_SUBTYPE(&EEG); if (event_list==EVENTLIST_NONE) { printf("NeuroScan File %s: File type is `%s'\n\n", filename, neuroscan_subtype_names[SubType]); print_structcontents((char *)&EEG, sm_SETUP, smd_SETUP, stdout); } if (EEG.ChannelOffset<=1) EEG.ChannelOffset=sizeof(short); /*{{{ Allocate channel header*/ if ((Channels=(ELECTLOC *)malloc(EEG.nchannels*sizeof(ELECTLOC)))==NULL) { fprintf(stderr, "%s: Error allocating Channels list\n", argv[0]); exit(1); } /*}}} */ if (event_list==EVENTLIST_NONE) { printf("\nCHANNEL HEADERS" "\n---------------\n"); } /* For minor_rev<4, 32 electrode structures were hardcoded - but the data is * there for all the channels... */ NoOfChannels = (EEG.minor_rev<4 ? 32 : EEG.nchannels); for (channel=0; channel<NoOfChannels; channel++) { read_struct((char *)&Channels[channel], sm_ELECTLOC, SCAN); #ifndef LITTLE_ENDIAN change_byteorder((char *)&Channels[channel], sm_ELECTLOC); #endif if (event_list==EVENTLIST_NONE) { printf("\nChannel number %d:\n", channel+1); print_structcontents((char *)&Channels[channel], sm_ELECTLOC, smd_ELECTLOC, stdout); } } if (EEG.minor_rev<4) { NoOfChannels = EEG.nchannels; /* Copy the channel descriptors over from the first 32: */ for (; channel<NoOfChannels; channel++) { memcpy(&Channels[channel], &Channels[channel%32], sizeof(ELECTLOC)); } } SizeofHeader = ftell(SCAN); if (event_list==EVENTLIST_AVG_Q) { long int const NumSamples = (EEG.EventTablePos - SizeofHeader)/NoOfChannels/sizeof(short); printf("# NeuroScan File %s: File type is `%s'\n# Sfreq=%d\n# NumSamples=%ld\n", filename, neuroscan_subtype_names[SubType], EEG.rate, NumSamples); } switch(SubType) { case NST_CONTINUOUS: case NST_SYNAMPS: /*{{{ Read the events header and array*/ if (event_list==EVENTLIST_NONE) { printf("\nEVENT TABLE HEADER" "\n------------------\n"); } fseek(SCAN,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, SCAN)) { fprintf(stderr, "%s: Error reading event table header\n", argv[0]); exit(1); } # ifndef LITTLE_ENDIAN change_byteorder((char *)&TagType, sm_TEEG); # endif if (event_list==EVENTLIST_NONE) { print_structcontents((char *)&TagType, sm_TEEG, smd_TEEG, stdout); } if (TagType.Teeg==TEEG_EVENT_TAB1 || TagType.Teeg==TEEG_EVENT_TAB2) { struct_member * const sm_EVENT=(TagType.Teeg==TEEG_EVENT_TAB1 ? sm_EVENT1 : sm_EVENT2); struct_member_description * const smd_EVENT=(TagType.Teeg==TEEG_EVENT_TAB1 ? smd_EVENT1 : smd_EVENT2); EVENT2 event; int tag; int TrigVal; int KeyBoard; int KeyPad; int code; enum NEUROSCAN_ACCEPTVALUES Accept; ntags=TagType.Size/sm_EVENT[0].offset; /* sm_EVENT[0].offset is the size of the structure in file. */ if (event_list==EVENTLIST_NONE) { printf("\nEVENT TABLE (Type %d)" "\n--------------------\n", TagType.Teeg); } for (tag=0; tag<ntags; tag++) { if (1!=read_struct((char *)&event, sm_EVENT, SCAN)) { fprintf(stderr, "%s: Can't access event table header, CNT file is probably corrupted.\n", argv[0]); exit(1); } # ifndef LITTLE_ENDIAN change_byteorder((char *)&event, sm_EVENT); # endif TrigVal=event.StimType &0xff; KeyBoard=event.KeyBoard&0xf; KeyPad=Event_KeyPad_value(event); Accept=Event_Accept_value(event); /* The `accept' values NAV_DCRESET and NAV_STARTSTOP always occur alone, * while the NAV_REJECT and NAV_ACCEPT enclose rejected CNT blocks and * might occur within a marker as well (at least NAV_REJECT). */ code=TrigVal-KeyPad+neuroscan_accept_translation[Accept]; if (code==0) { code= -((KeyBoard+1)<<4); } switch(event_list) { case EVENTLIST_NONE: print_structcontents((char *)&event, sm_EVENT, smd_EVENT, stdout); printf("\n"); break; case EVENTLIST_SYNAMPS: if (code!=0) printf("%4d %4d %4d 0 0.0000 %ld\n", tag+1, TrigVal, KeyBoard+KeyPad, event.Offset); break; case EVENTLIST_AVG_Q: if (code!=0) { long const pos=(event.Offset-SizeofHeader)/sizeof(short)/EEG.nchannels; if (Accept==NAV_REJECT && code!=neuroscan_accept_translation[NAV_REJECT]) { printf("#"); } switch (eventpos_type) { case EVENTPOS_POINTS: printf("%ld %d\n", pos, code); break; case EVENTPOS_MSEC: printf("%.8gms %d\n", ((float)pos)/EEG.rate*1000, code); break; case EVENTPOS_SEC: printf("%.8gs %d\n", ((float)pos)/EEG.rate, code); break; } } break; } } } else { fprintf(stderr, "%s: Unknown tag type %d\n", argv[0], TagType.Teeg); exit(1); } /*}}} */ break; case NST_EPOCHS: { NEUROSCAN_EPOCHED_SWEEP_HEAD sweephead; int epoch, code; if (event_list==EVENTLIST_NONE) { printf("\nEPOCHED SWEEP HEADERS" "\n---------------------\n"); } for (epoch=0; epoch<EEG.compsweeps; epoch++) { long const filepos=epoch*(sm_NEUROSCAN_EPOCHED_SWEEP_HEAD[0].offset+EEG.pnts*EEG.nchannels*sizeof(short))+SizeofHeader; /* sm_NEUROSCAN_EPOCHED_SWEEP_HEAD[0].offset is sizeof(NEUROSCAN_EPOCHED_SWEEP_HEAD) on those other systems... */ fseek(SCAN,filepos,SEEK_SET); read_struct((char *)&sweephead, sm_NEUROSCAN_EPOCHED_SWEEP_HEAD, SCAN); # ifndef LITTLE_ENDIAN change_byteorder((char *)&sweephead, sm_NEUROSCAN_EPOCHED_SWEEP_HEAD); # endif code=(sweephead.type!=0 ? sweephead.type : -sweephead.response); switch(event_list) { case EVENTLIST_NONE: printf("\nEpoch number %d:\n", epoch+1); print_structcontents((char *)&sweephead, sm_NEUROSCAN_EPOCHED_SWEEP_HEAD, smd_NEUROSCAN_EPOCHED_SWEEP_HEAD, stdout); break; case EVENTLIST_SYNAMPS: /* The fourth item is actually `acc'(uracy) (of response, -1=no resp), but let's use it for the accept value now */ printf("%4d %4d %4d %d 0.0000 %ld\n", epoch+1, sweephead.type, sweephead.response, sweephead.accept, filepos); break; case EVENTLIST_AVG_Q: { long const pos=epoch*EEG.pnts; if (sweephead.accept==0) { printf("#"); } switch (eventpos_type) { case EVENTPOS_POINTS: printf("%ld %d\n", pos, code); break; case EVENTPOS_MSEC: printf("%gms %d\n", ((float)pos)/EEG.rate*1000, code); break; case EVENTPOS_SEC: printf("%gs %d\n", ((float)pos)/EEG.rate, code); break; } } break; } } } break; default: break; } free(Channels); fclose(SCAN); } return 0; }
int main(int argc, char **argv) { int filearg; int errflag=0, c; int channel; /*{{{ Process command line*/ mainargv=argv; while ((c=getopt(argc, argv, ""))!=EOF) { } if (argc-optind<END_OF_ARGS || errflag>0) { fprintf(stderr, "Usage: %s [options] Inomed_filename1 Inomed_filename2 ...\n" " Options are:\n" , argv[0]); exit(1); } for (filearg=INOMEDFILEARG; argc-optind-filearg>=END_OF_ARGS; filearg++) { char *filename=MAINARG(filearg); FILE *INOMEDFILE=fopen(filename,"rb"); if(INOMEDFILE==NULL) { fprintf(stderr, "%s: Can't open file %s\n", argv[0], filename); continue; } if (strlen(filename)>=4 && strcmp(filename+strlen(filename)-4, ".dat")==0) { PlotWinInfo EEG; if (read_struct((char *)&EEG, sm_PlotWinInfo, INOMEDFILE)==0) { fprintf(stderr, "%s: Short file %s\n", argv[0], filename); continue; } #ifndef LITTLE_ENDIAN change_byteorder((char *)&EEG, sm_PlotWinInfo); #endif print_structcontents((char *)&EEG, sm_PlotWinInfo, smd_PlotWinInfo, stdout); } else { MULTI_CHANNEL_CONTINUOUS EEG; if (read_struct((char *)&EEG, sm_MULTI_CHANNEL_CONTINUOUS, INOMEDFILE)==0) { fprintf(stderr, "%s: Short file %s\n", argv[0], filename); continue; } #ifndef LITTLE_ENDIAN change_byteorder((char *)&EEG, sm_MULTI_CHANNEL_CONTINUOUS); #endif print_structcontents((char *)&EEG, sm_MULTI_CHANNEL_CONTINUOUS, smd_MULTI_CHANNEL_CONTINUOUS, stdout); for (channel=0; channel<EEG.sNumberOfChannels; channel++) { printf("\nChannel %d\n", channel+1); if (read_struct((char *)&EEG.strctChannel[channel], sm_CHANNEL, INOMEDFILE)==0 ||read_struct((char *)&EEG.strctChannel[channel].strctHighPass, sm_DIG_FILTER, INOMEDFILE)==0 ||read_struct((char *)&EEG.strctChannel[channel].strctLowPass, sm_DIG_FILTER, INOMEDFILE)==0) { fprintf(stderr, "%s: Short file %s\n", argv[0], filename); continue; } #ifndef LITTLE_ENDIAN change_byteorder((char *)&EEG.strctChannel[channel], sm_CHANNEL); change_byteorder((char *)&EEG.strctChannel[channel].strctHighPass, sm_DIG_FILTER); change_byteorder((char *)&EEG.strctChannel[channel].strctLowPass, sm_DIG_FILTER); #endif print_structcontents((char *)&EEG.strctChannel[channel], sm_CHANNEL, smd_CHANNEL, stdout); printf("HighPass:\n"); print_structcontents((char *)&EEG.strctChannel[channel].strctHighPass, sm_DIG_FILTER, smd_DIG_FILTER, stdout); printf("LowPass:\n"); print_structcontents((char *)&EEG.strctChannel[channel].strctLowPass, sm_DIG_FILTER, smd_DIG_FILTER, stdout); } } fclose(INOMEDFILE); } return 0; }
/* This function has all the knowledge about events in the various file types */ LOCAL void read_synamps_build_trigbuffer(transform_info_ptr tinfo) { struct read_synamps_storage * const local_arg=(struct read_synamps_storage *)tinfo->methods->local_storage; transform_argument *args=tinfo->methods->arguments; if (local_arg->triggers.buffer_start==NULL) { growing_buf_allocate(&local_arg->triggers, 0); } else { growing_buf_clear(&local_arg->triggers); } if (args[ARGS_TRIGFILE].is_set) { FILE * const triggerfile=(strcmp(args[ARGS_TRIGFILE].arg.s,"stdin")==0 ? stdin : fopen(args[ARGS_TRIGFILE].arg.s, "r")); TRACEMS(tinfo->emethods, 1, "read_synamps_build_trigbuffer: Reading event file\n"); if (triggerfile==NULL) { ERREXIT1(tinfo->emethods, "read_synamps_build_trigbuffer: Can't open trigger file >%s<\n", MSGPARM(args[ARGS_TRIGFILE].arg.s)); } while (TRUE) { long trigpoint; char *description; int const code=read_trigger_from_trigfile(triggerfile, tinfo->sfreq, &trigpoint, &description); if (code==0) break; push_trigger(&local_arg->triggers, trigpoint, code, description); free_pointer((void **)&description); } if (triggerfile!=stdin) fclose(triggerfile); } else { switch(local_arg->SubType) { case NST_CONTINUOUS: case NST_SYNAMPS: { /*{{{ Read the events header and array*/ /* We handle errors through setting errormessage, because we want to continue * with a warning if we are in continuous mode or read from an event file */ TEEG TagType; EVENT2 event; TRACEMS(tinfo->emethods, 1, "read_synamps_build_trigbuffer: Reading event table\n"); 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 (read_struct((char *)&TagType, sm_TEEG, local_arg->SCAN)==1) { # ifndef LITTLE_ENDIAN change_byteorder((char *)&TagType, sm_TEEG); # endif if (TagType.Teeg==TEEG_EVENT_TAB1 || TagType.Teeg==TEEG_EVENT_TAB2) { /*{{{ Read the event table*/ struct_member * const sm_EVENT=(TagType.Teeg==TEEG_EVENT_TAB1 ? sm_EVENT1 : sm_EVENT2); int ntags, tag; ntags=TagType.Size/sm_EVENT[0].offset; /* sm_EVENT[0].offset is the size of the structure in file. */ for (tag=0; tag<ntags; tag++) { long trigger_position=0; int TrigVal=0, KeyPad=0, KeyBoard=0; enum NEUROSCAN_ACCEPTVALUES Accept=(enum NEUROSCAN_ACCEPTVALUES)0; if (read_struct((char *)&event, sm_EVENT, local_arg->SCAN)==0) { ERREXIT(tinfo->emethods, "read_synamps_build_trigbuffer: Can't read an event table entry.\n"); break; } # ifndef LITTLE_ENDIAN change_byteorder((char *)&event, sm_EVENT); # endif trigger_position=offset2point(tinfo,event.Offset); TrigVal=event.StimType &0xff; KeyBoard=event.KeyBoard&0xf; KeyPad=Event_KeyPad_value(event); Accept=Event_Accept_value(event); if (!args[ARGS_NOREJECTED].is_set || Accept!=NAV_REJECT) { read_synamps_push_keys(tinfo, trigger_position, TrigVal, KeyPad, KeyBoard, Accept); } } /*}}} */ } else { ERREXIT1(tinfo->emethods, "read_synamps_build_trigbuffer: Unknown tag type %d.\n", MSGPARM(TagType.Teeg)); } } else { ERREXIT(tinfo->emethods, "read_synamps_build_trigbuffer: Can't read the event table header.\n"); } /*}}} */ } break; case NST_CONT0: { /*{{{ CONT0: Two trailing marker channels*/ long current_triggerpoint=0; unsigned short *pdata; TRACEMS(tinfo->emethods, 1, "read_synamps_build_trigbuffer: Analyzing CONT0 marker channels\n"); while (current_triggerpoint<local_arg->EEG.NumSamples) { int TrigVal=0, KeyPad=0, KeyBoard=0; enum NEUROSCAN_ACCEPTVALUES Accept=(enum NEUROSCAN_ACCEPTVALUES)0; read_synamps_seek_point(tinfo, current_triggerpoint); pdata=(unsigned short *)local_arg->buffer+current_triggerpoint-local_arg->first_point_in_buffer+local_arg->nchannels; TrigVal =pdata[0]&0xff; KeyBoard=pdata[1]&0xf; if (KeyBoard>13) KeyBoard=0; if (TrigVal!=0 || KeyBoard!=0) { read_synamps_push_keys(tinfo, current_triggerpoint, TrigVal, KeyPad, KeyBoard, Accept); current_triggerpoint++; while (current_triggerpoint<local_arg->EEG.NumSamples) { int This_TrigVal, This_KeyBoard; read_synamps_seek_point(tinfo, current_triggerpoint); pdata=(unsigned short *)local_arg->buffer+current_triggerpoint-local_arg->first_point_in_buffer+local_arg->nchannels; This_TrigVal =pdata[0]&0xff; This_KeyBoard=pdata[1]&0xf; if (This_KeyBoard>13) This_KeyBoard=0; if (This_TrigVal!=TrigVal || This_KeyBoard!=KeyBoard) break; current_triggerpoint++; } } } /*}}} */ } break; case NST_DCMES: { /*{{{ DC-MES: Single, leading marker channel*/ long current_triggerpoint=0; unsigned short *pdata; TRACEMS(tinfo->emethods, 1, "read_synamps_build_trigbuffer: Analyzing DCMES marker channel\n"); while (current_triggerpoint<local_arg->EEG.NumSamples) { int TrigVal=0, KeyPad=0, KeyBoard=0; enum NEUROSCAN_ACCEPTVALUES Accept=(enum NEUROSCAN_ACCEPTVALUES)0; read_synamps_seek_point(tinfo, current_triggerpoint); pdata=(unsigned short *)local_arg->buffer+current_triggerpoint-local_arg->first_point_in_buffer; TrigVal= *pdata&0xff; KeyBoard=(*pdata>>8)&0xf; if (KeyBoard>13) KeyBoard=0; if (TrigVal!=0 || KeyBoard!=0) { read_synamps_push_keys(tinfo, current_triggerpoint, TrigVal, KeyPad, KeyBoard, Accept); current_triggerpoint++; while (current_triggerpoint<local_arg->EEG.NumSamples) { int This_TrigVal, This_KeyBoard; read_synamps_seek_point(tinfo, current_triggerpoint); pdata=(unsigned short *)local_arg->buffer+current_triggerpoint-local_arg->first_point_in_buffer; This_TrigVal= *pdata&0xff; This_KeyBoard=(*pdata>>8)&0xf; if (This_KeyBoard>13) This_KeyBoard=0; if (This_TrigVal!=TrigVal || This_KeyBoard!=KeyBoard) break; current_triggerpoint++; } } } /*}}} */ } break; default: break; } }
/*{{{ write_vitaport_exit(transform_info_ptr tinfo) {*/ METHODDEF void write_vitaport_exit(transform_info_ptr tinfo) { struct write_vitaport_storage *local_arg=(struct write_vitaport_storage *)tinfo->methods->local_storage; int channel, NoOfChannels=local_arg->fileheader.knum; long point; long const channellen=local_arg->total_points*sizeof(uint16_t); long const hdlen=local_arg->fileheader.hdlen; uint16_t checksum=0; local_arg->fileheaderII.dlen=hdlen+NoOfChannels*channellen; /*{{{ Write the file headers*/ # ifdef LITTLE_ENDIAN change_byteorder((char *)&local_arg->fileheader, sm_vitaport_fileheader); change_byteorder((char *)&local_arg->fileheaderII, sm_vitaportII_fileheader); change_byteorder((char *)&local_arg->fileext, sm_vitaportII_fileext); # endif write_struct((char *)&local_arg->fileheader, sm_vitaport_fileheader, local_arg->outfile); write_struct((char *)&local_arg->fileheaderII, sm_vitaportII_fileheader, local_arg->outfile); write_struct((char *)&local_arg->fileext, sm_vitaportII_fileext, local_arg->outfile); /*}}} */ for (channel=0; channel<NoOfChannels; channel++) { /*{{{ Write a channel header*/ /* This is the factor as we'd like to have it... */ float factor=((float)(local_arg->channelmax[channel]> -local_arg->channelmin[channel] ? local_arg->channelmax[channel] : -local_arg->channelmin[channel]))/SHRT_MAX; if (strncmp(local_arg->channelheaders[channel].kname, VP_MARKERCHANNEL_NAME, 6)==0) { strcpy(local_arg->channelheaders[channel].kunit, "mrk"); local_arg->channelheaders[channel].datype=VP_DATYPE_MARKER; /* Since the marker channel is read without the conversion factors, * set the conversion to 1.0 for this channel */ local_arg->channelheaders[channel].mulfac=local_arg->channelheaders[channel].divfac=1; local_arg->channelheaders[channel].offset=0; } else { float const logdiff=log(factor)-TARGET_LOG_SHORTVAL; local_arg->channelheaders[channel].offset=0; if (logdiff<0) { /*{{{ Factor is small: Better to fix divfac and calculate mulfac after that*/ double const divfac=exp(-logdiff); if (divfac>SHRT_MAX) { local_arg->channelheaders[channel].divfac=SHRT_MAX; } else { local_arg->channelheaders[channel].divfac=(unsigned short)divfac; } /* The +1 takes care that we never get below the `ideal' factor computed above. */ local_arg->channelheaders[channel].mulfac=(unsigned short)(factor*local_arg->channelheaders[channel].divfac+1); if (local_arg->channelheaders[channel].mulfac==0) { local_arg->channelheaders[channel].mulfac=1; local_arg->channelheaders[channel].divfac=(unsigned short)(1.0/factor-1); } /*}}} */ } else { /*{{{ Factor is large: Better to fix mulfac and calculate divfac after that*/ double const mulfac=exp(logdiff); if (mulfac>SHRT_MAX) { local_arg->channelheaders[channel].mulfac=SHRT_MAX; } else { local_arg->channelheaders[channel].mulfac=(unsigned short)mulfac; } /* The -1 takes care that we never get below the `ideal' factor computed above. */ local_arg->channelheaders[channel].divfac=(unsigned short)(local_arg->channelheaders[channel].mulfac/factor-1); if (local_arg->channelheaders[channel].divfac==0) { local_arg->channelheaders[channel].mulfac=(unsigned short)(factor+1); local_arg->channelheaders[channel].divfac=1; } /*}}} */ } } /* Now see which factor we actually got constructed */ factor=((float)local_arg->channelheaders[channel].mulfac)/local_arg->channelheaders[channel].divfac; local_arg->channelheadersII[channel].doffs=channel*channellen; local_arg->channelheadersII[channel].dlen=channellen; # ifdef LITTLE_ENDIAN change_byteorder((char *)&local_arg->channelheaders[channel], sm_vitaport_channelheader); change_byteorder((char *)&local_arg->channelheadersII[channel], sm_vitaportIIrchannelheader); # endif write_struct((char *)&local_arg->channelheaders[channel], sm_vitaport_channelheader, local_arg->outfile); write_struct((char *)&local_arg->channelheadersII[channel], sm_vitaportIIrchannelheader, local_arg->outfile); # ifdef LITTLE_ENDIAN change_byteorder((char *)&local_arg->channelheaders[channel], sm_vitaport_channelheader); change_byteorder((char *)&local_arg->channelheadersII[channel], sm_vitaportIIrchannelheader); # endif /*}}} */ } fwrite(&checksum, sizeof(checksum), 1, local_arg->outfile); TRACEMS(tinfo->emethods, 1, "write_vitaport_exit: Copying channels to output file...\n"); /* We close and re-open the channel file because buffering is much more * efficient at least with DJGPP if the file is either only read or written */ fclose(local_arg->channelfile); if ((local_arg->channelfile=fopen(local_arg->channelfilename, "rb"))==NULL) { ERREXIT1(tinfo->emethods, "write_vitaport_exit: Can't open temp file %s\n", MSGPARM(local_arg->channelfilename)); } for (channel=0; channel<NoOfChannels; channel++) { /*{{{ Copy a channel to the target file */ float const factor=((float)local_arg->channelheaders[channel].mulfac)/local_arg->channelheaders[channel].divfac; unsigned short const offset=local_arg->channelheaders[channel].offset; for (point=0; point<local_arg->total_points; point++) { DATATYPE dat; int16_t s; fseek(local_arg->channelfile, (point*NoOfChannels+channel)*sizeof(DATATYPE), SEEK_SET); if (fread(&dat, sizeof(DATATYPE), 1, local_arg->channelfile)!=1) { ERREXIT(tinfo->emethods, "write_vitaport_exit: Error reading temp file.\n"); } s= (int16_t)rint(dat/factor)-offset; # ifdef LITTLE_ENDIAN Intel_int16((uint16_t *)&s); # endif if (fwrite(&s, sizeof(s), 1, local_arg->outfile)!=1) { ERREXIT(tinfo->emethods, "write_vitaport_exit: Write error.\n"); } } /*}}} */ } fclose(local_arg->channelfile); unlink(local_arg->channelfilename); if (local_arg->triggers.current_length!=0) { long tagno, n_events; uint32_t length, trigpoint; int const nevents=local_arg->triggers.current_length/sizeof(struct trigger); struct vitaport_idiotic_multiplemarkertablenames *markertable_entry; /* Try to keep a security space of at least 20 free events */ for (markertable_entry=markertable_names; markertable_entry->markertable_name!=NULL && markertable_entry->idiotically_fixed_length<nevents+20; markertable_entry++); if (markertable_entry->markertable_name==NULL) { if ((markertable_entry-1)->idiotically_fixed_length<=nevents) { /* Drop the requirement for at least 20 free events */ markertable_entry--; } else { /* No use... */ ERREXIT1(tinfo->emethods, "write_vitaport_exit: %d events wouldn't fit into the fixed-length VITAGRAPH marker tables!\nBlame the Vitaport people!\n", MSGPARM(nevents)); } } n_events=markertable_entry->idiotically_fixed_length; fwrite(markertable_entry->markertable_name, 1, VP_TABLEVAR_LENGTH, local_arg->outfile); length=n_events*sizeof(length); #ifdef LITTLE_ENDIAN Intel_int32((uint32_t *)&length); #endif fwrite(&length, sizeof(length), 1, local_arg->outfile); for (tagno=0; tagno<n_events; tagno++) { if (tagno<nevents) { struct trigger * const intrig=((struct trigger *)local_arg->triggers.buffer_start)+tagno; /* Trigger positions are given in ms units */ trigpoint=(long)rint(intrig->position*1000.0/local_arg->sfreq); /* Make trigpoint uneven if code%2==1 */ trigpoint=trigpoint-trigpoint%2+(intrig->code-1)%2; } else { trigpoint= -1; } #ifdef LITTLE_ENDIAN Intel_int32((uint32_t *)&trigpoint); #endif fwrite(&trigpoint, sizeof(trigpoint), 1, local_arg->outfile); } for (; tagno<n_events; tagno++) { trigpoint= -1; #ifdef LITTLE_ENDIAN Intel_int32((uint32_t *)&trigpoint); #endif fwrite(&trigpoint, sizeof(trigpoint), 1, local_arg->outfile); } } fclose(local_arg->outfile); /*{{{ Free memory*/ free_pointer((void **)&local_arg->channelfilename); free_pointer((void **)&local_arg->channelmax); free_pointer((void **)&local_arg->channelmin); free_pointer((void **)&local_arg->channelheaders); free_pointer((void **)&local_arg->channelheadersII); if (local_arg->triggers.buffer_start!=NULL) { clear_triggers(&local_arg->triggers); growing_buf_free(&local_arg->triggers); } /*}}} */ tinfo->methods->init_done=FALSE; }