/*{{{ write_rec_init(transform_info_ptr tinfo) {*/ METHODDEF void write_rec_init(transform_info_ptr tinfo) { struct write_rec_storage *local_arg=(struct write_rec_storage *)tinfo->methods->local_storage; transform_argument *args=tinfo->methods->arguments; int bits=(args[ARGS_BITS].is_set ? args[ARGS_BITS].arg.i : DEFAULT_BITS); local_arg->resolution=(args[ARGS_RESOLUTION].is_set ? args[ARGS_RESOLUTION].arg.d : 1.0); local_arg->samples_per_record=args[ARGS_SAMPLES_PER_RECORD].is_set ? gettimeslice(tinfo, args[ARGS_SAMPLES_PER_RECORD].arg.s) : (tinfo->data_type==FREQ_DATA ? tinfo->nroffreq : tinfo->nr_of_points); local_arg->current_sample=0L; if ((local_arg->outbuf=(short *)malloc(tinfo->nr_of_channels*local_arg->samples_per_record*sizeof(short)))==NULL) { ERREXIT(tinfo->emethods, "write_rec_init: Error allocating buffer memory.\n"); } if (bits<1) { ERREXIT1(tinfo->emethods, "write_rec_init: Invalid number of bits %d\n", MSGPARM(bits)); } if (local_arg->resolution<=0.0) { ERREXIT1(tinfo->emethods, "write_rec_init: A resolution<=0.0 is not allowed\n", MSGPARM(bits)); } local_arg->digmin=(-1L<<(bits-1)); local_arg->digmax=(~local_arg->digmin); local_arg->overflow_has_occurred=FALSE; if (args[ARGS_CLOSE].is_set==FALSE) write_rec_open_file(tinfo); tinfo->methods->init_done=TRUE; }
/*{{{ write_mfx_init(transform_info_ptr tinfo) {*/ METHODDEF void write_mfx_init(transform_info_ptr tinfo) { struct write_mfx_storage *local_arg=(struct write_mfx_storage *)tinfo->methods->local_storage; transform_argument *args=tinfo->methods->arguments; int NoOfChannels=tinfo->nr_of_channels; int channel; local_arg->mfxfile=mfx_open(args[ARGS_OFILE].arg.s, "r+b", MFX_DATATYPE); if (!args[ARGS_APPEND].is_set || local_arg->mfxfile==NULL) { /* target does not exist*/ /*{{{ Create file*/ if (local_arg->mfxfile!=NULL) mfx_close(local_arg->mfxfile); if ((local_arg->mfxfile=mfx_create(args[ARGS_OFILE].arg.s, (args[ARGS_CREATE_TRIGGERCHANNEL].is_set ? NoOfChannels+1 : NoOfChannels), MFX_DATATYPE))==NULL) { ERREXIT1(tinfo->emethods, "write_mfx_init: Can't open file >%s<\n", MSGPARM(args[ARGS_OFILE].arg.s)); } if (mfx_describefile(local_arg->mfxfile, tinfo->comment, 1.0/tinfo->sfreq, (args[ARGS_CONTINUOUS].is_set ? 0 : tinfo->nr_of_points), -tinfo->beforetrig/tinfo->sfreq)!=MFX_NOERR) { ERREXIT1(tinfo->emethods, "write_mfx_init: mfx_describefile error %s\n", MSGPARM(mfx_errors[mfx_lasterr])); } for (channel=0; channel<NoOfChannels; channel++) { double * const pos_mfx=local_arg->mfxfile->channelheaders[channel].position; double * const pos_tinfo=tinfo->probepos+3*channel; int i; const Bool is_electric=(*tinfo->channelnames[channel]!='M'); if (mfx_describechannel(local_arg->mfxfile, channel+1, tinfo->channelnames[channel], (is_electric ? "uV" : "fT"), (is_electric ? DT_EEGTYPE : DT_MEGTYPE), SHRT_MIN/args[ARGS_CONVFACTOR].arg.d, SHRT_MAX/args[ARGS_CONVFACTOR].arg.d)!=MFX_NOERR) { ERREXIT1(tinfo->emethods, "write_mfx_init: mfx_describechannel error %s\n", MSGPARM(mfx_errors[mfx_lasterr])); } for (i=0; i<3; i++) { pos_mfx[i]=pos_tinfo[i]; } } if (args[ARGS_CREATE_TRIGGERCHANNEL].is_set) { if (mfx_describechannel(local_arg->mfxfile, channel+1, "TRIGGER", "T", DT_TRIGGER, -32768.0, 32767.0)!=MFX_NOERR) { ERREXIT1(tinfo->emethods, "write_mfx_init: mfx_describechannel error %s\n", MSGPARM(mfx_errors[mfx_lasterr])); } } /*}}} */ } else { /*{{{ Append to file*/ mfx_seek(local_arg->mfxfile, 0L, SEEK_END); /*}}} */ } if ((local_arg->mfxfile->selected_channels=(int *)malloc(NoOfChannels*sizeof(int)))==NULL) { ERREXIT(tinfo->emethods, "write_mfx_init: Error allocating selection array\n"); } for (channel=0; channel<NoOfChannels; channel++) { local_arg->mfxfile->selected_channels[channel]=channel+1; } local_arg->mfxfile->nr_of_channels_selected=NoOfChannels; tinfo->methods->init_done=TRUE; }
/*{{{ get_mfxepoch_init(transform_info_ptr tinfo)*/ METHODDEF void get_mfxepoch_init(transform_info_ptr tinfo) { struct get_mfxepoch_storage *local_arg=(struct get_mfxepoch_storage *)tinfo->methods->local_storage; transform_argument *args=tinfo->methods->arguments; int skipepochs; if ((local_arg->fileptr=mfx_open(args[ARGS_IFILE].arg.s, "rb", MFX_DATATYPE))==NULL) { ERREXIT2(tinfo->emethods, "get_mfxepoch_init: Can't open mfx file %s: %s\n", MSGPARM(args[ARGS_IFILE].arg.s), MSGPARM(mfx_errors[mfx_lasterr])); } if ((tinfo->nr_of_channels=mfx_cselect(local_arg->fileptr, args[ARGS_CHANNELNAMES].arg.s))==0) { ERREXIT1(tinfo->emethods, "get_mfxepoch_init: mfx_cselect error %s\n", MSGPARM(mfx_errors[mfx_lasterr])); } get_mfxinfo(local_arg->fileptr, tinfo); get_mfxinfo_free(tinfo); /* We don't need the channel names etc. here */ /*{{{ Parse arguments that can be in seconds*/ local_arg->beforetrig=gettimeslice(tinfo, args[ARGS_BEFORETRIG].arg.s); local_arg->aftertrig=gettimeslice(tinfo, args[ARGS_AFTERTRIG].arg.s); local_arg->offset=(args[ARGS_OFFSET].is_set ? gettimeslice(tinfo, args[ARGS_OFFSET].arg.s) : 0); /*}}} */ 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->trigname=(args[ARGS_TRIGNAME].is_set ? args[ARGS_TRIGNAME].arg.s : "TRIGGER"); if (strcmp(local_arg->trigname, "0")==0) { local_arg->trigname=NULL; local_arg->offset-= (long int)rint(local_arg->fileptr->fileheader.epoch_begin_latency*tinfo->sfreq); local_arg->beforetrig+=local_arg->offset; local_arg->aftertrig-=local_arg->offset; } skipepochs=local_arg->fromepoch-1; /*{{{ Skip triggers if fromepoch parameter demands it*/ while (skipepochs>0) { mfx_seektrigger(local_arg->fileptr, local_arg->trigname, args[ARGS_TRIGCODE].arg.i); if (mfx_lasterr!=MFX_NOERR) { ERREXIT(tinfo->emethods, "get_mfxepoch_init: Error seeking to first trigger\n"); } skipepochs--; } /*}}} */ tinfo->methods->init_done=TRUE; }
/*{{{ write_mfx(transform_info_ptr tinfo) {*/ METHODDEF DATATYPE * write_mfx(transform_info_ptr tinfo) { struct write_mfx_storage *local_arg=(struct write_mfx_storage *)tinfo->methods->local_storage; /*{{{ Assert that epoch size didn't change & itemsize==1*/ if (tinfo->itemsize!=1) { ERREXIT(tinfo->emethods, "write_mfx: Only itemsize=1 is supported.\n"); } if (local_arg->mfxfile->nr_of_channels_selected!=tinfo->nr_of_channels) { ERREXIT2(tinfo->emethods, "write_mfx: nr_of_channels was %d, now %d\n", MSGPARM(local_arg->mfxfile->nr_of_channels_selected), MSGPARM(tinfo->nr_of_channels)); } /*}}} */ multiplexed(tinfo); if (tinfo->data_type==FREQ_DATA) tinfo->nr_of_points=tinfo->nroffreq; if (mfx_write((void *)tinfo->tsdata, tinfo->nr_of_points, local_arg->mfxfile)!=MFX_NOERR) { ERREXIT1(tinfo->emethods, "write_mfx_init: mfx_write error %s\n", MSGPARM(mfx_errors[mfx_lasterr])); } return tinfo->tsdata; /* Simply to return something `useful' */ }
/*{{{ export_point(transform_info_ptr tinfo) {*/ METHODDEF DATATYPE * export_point(transform_info_ptr tinfo) { struct export_point_info *exp_info=(struct export_point_info *)tinfo->methods->local_storage; transform_argument *args=tinfo->methods->arguments; array_dump_format format=(args[ARGS_MATLAB].is_set ? ARRAY_MATLAB : ARRAY_ASCII); int channel, itempart, i; double *channelpos; array myarray, newarray; if (exp_info->pointno<0 || exp_info->pointno>=tinfo->nr_of_points) { ERREXIT1(tinfo->emethods, "export_point: Point number %d is out of range.\n", MSGPARM(exp_info->pointno)); } TRACEMS2(tinfo->emethods, 1, "export_point: Exporting point number %d to file %s\n", MSGPARM(exp_info->pointno), MSGPARM(args[ARGS_OFILE].arg.s)); if (args[ARGS_CLOSE].is_set) export_file_open(tinfo); tinfo_array(tinfo, &myarray); myarray.current_element=exp_info->pointno; if (exp_info->channelcoords_to_display==0 && tinfo->itemsize==1) { /*{{{ Don't need to build new array, just access tinfo*/ newarray=myarray; array_transpose(&newarray); array_setto_vector(&newarray); /* Select only one element */ array_transpose(&newarray); /*}}} */ } else { /*{{{ Build new array containing the data*/ newarray.nr_of_vectors=myarray.nr_of_vectors; newarray.nr_of_elements=exp_info->channelcoords_to_display+tinfo->itemsize; newarray.element_skip=1; if (array_allocate(&newarray)==NULL) { ERREXIT(tinfo->emethods, "export_point: Can't allocate output array\n"); } for (channel=0; channel<tinfo->nr_of_channels; channel++) { channelpos=tinfo->probepos+3*channel; for (i=0; i<exp_info->channelcoords_to_display; i++) { array_write(&newarray, channelpos[i]); } myarray.current_vector=channel; for (itempart=0; itempart<tinfo->itemsize; itempart++) { array_use_item(&myarray, itempart); array_write(&newarray, READ_ELEMENT(&myarray)); } } /*}}} */ } array_dump(exp_info->file, &newarray, format); if (newarray.nr_of_elements>1) array_free(&newarray); if (args[ARGS_CLOSE].is_set) export_file_close(tinfo); return tinfo->tsdata; }
/*{{{ scale_by_init(transform_info_ptr tinfo)*/ METHODDEF void scale_by_init(transform_info_ptr tinfo) { struct scale_by_storage *local_arg=(struct scale_by_storage *)tinfo->methods->local_storage; transform_argument *args=tinfo->methods->arguments; if (args[ARGS_TYPE].is_set) { local_arg->type=(enum scale_by_type)args[ARGS_TYPE].arg.i; if (local_arg->type==SCALE_BY_NORMALIZE) { ERREXIT(tinfo->emethods, "scale_by_init: Using '1.0' is deprecated. Please use 'invnorm' instead!\n"); } } else { local_arg->type=SCALE_BY_FACTOR; } if (local_arg->type==SCALE_BY_FACTOR || local_arg->type==SCALE_BY_INVQUANTILE || local_arg->type==SCALE_BY_INVPOINTQUANTILE ) { if (!args[ARGS_FACTOR].is_set) { ERREXIT(tinfo->emethods, "scale_by_init: A factor must be given!\n"); } local_arg->factor=args[ARGS_FACTOR].arg.d; if ((local_arg->type==SCALE_BY_INVQUANTILE || local_arg->type==SCALE_BY_INVPOINTQUANTILE) && (local_arg->factor<0 || local_arg->factor>1)) { ERREXIT(tinfo->emethods, "scale_by_init: factor must be between 0 and 1 for quantile!\n"); } } if (args[ARGS_BYNAME].is_set) { if (local_arg->type==SCALE_BY_INVQUANTILE) { ERREXIT(tinfo->emethods, "scale_by_init: Channel name list does not work with invquantile!\n"); } /* Note that this is NULL if no channel matched, which is why we need have_channel_list as well... */ local_arg->channel_list=expand_channel_list(tinfo, args[ARGS_BYNAME].arg.s); local_arg->have_channel_list=TRUE; } else { local_arg->channel_list=NULL; local_arg->have_channel_list=FALSE; } local_arg->fromitem=0; local_arg->toitem=tinfo->itemsize-tinfo->leaveright-1; if (args[ARGS_ITEMPART].is_set) { local_arg->fromitem=local_arg->toitem=args[ARGS_ITEMPART].arg.i; if (local_arg->fromitem<0 || local_arg->fromitem>=tinfo->itemsize) { ERREXIT1(tinfo->emethods, "scale_by_init: No item number %d in file\n", MSGPARM(local_arg->fromitem)); } } tinfo->methods->init_done=TRUE; }
/*{{{ export_file_open and export_file_close*/ LOCAL void export_file_open(transform_info_ptr tinfo) { struct export_point_info *exp_info=(struct export_point_info *)tinfo->methods->local_storage; transform_argument *args=tinfo->methods->arguments; if (strcmp(args[ARGS_OFILE].arg.s, "stdout")==0) { exp_info->file=stdout; } else if (strcmp(args[ARGS_OFILE].arg.s, "stderr")==0) { exp_info->file=stderr; } else { if ((exp_info->file=fopen(args[ARGS_OFILE].arg.s, args[ARGS_APPEND].is_set ? "a" : "w"))==NULL) { ERREXIT1(tinfo->emethods, "export_file_open: Can't open file >%s<\n", MSGPARM(args[ARGS_OFILE].arg.s)); } } }
/*{{{ write_vitaport(transform_info_ptr tinfo) {*/ METHODDEF DATATYPE * write_vitaport(transform_info_ptr tinfo) { struct write_vitaport_storage *local_arg=(struct write_vitaport_storage *)tinfo->methods->local_storage; array myarray; int channel; /*{{{ Assert that epoch size didn't change & itemsize==1*/ if (tinfo->itemsize!=1) { ERREXIT(tinfo->emethods, "write_vitaport: Only itemsize=1 is supported.\n"); } if (local_arg->fileheader.knum!=tinfo->nr_of_channels) { ERREXIT2(tinfo->emethods, "write_vitaport: nr_of_channels was %d, now %d\n", MSGPARM(local_arg->fileheader.knum), MSGPARM(tinfo->nr_of_channels)); } /*}}} */ if (tinfo->data_type==FREQ_DATA) tinfo->nr_of_points=tinfo->nroffreq; tinfo_array(tinfo, &myarray); array_transpose(&myarray); /* channels are the elements: Temp file is interlaced */ do { channel=0; do { DATATYPE dat=array_scan(&myarray); if (fwrite(&dat, sizeof(DATATYPE), 1, local_arg->channelfile)!=1) { ERREXIT(tinfo->emethods, "write_vitaport: Error writing temp file.\n"); } /* Keep track of the scaling... */ if (dat>local_arg->channelmax[channel]) local_arg->channelmax[channel]=dat; if (dat<local_arg->channelmin[channel]) local_arg->channelmin[channel]=dat; channel++; } while (myarray.message==ARRAY_CONTINUE); } while (myarray.message!=ARRAY_ENDOFSCAN); 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->total_points+intrig->position,intrig->code,intrig->description); intrig++; } } local_arg->total_points+=tinfo->nr_of_points; return tinfo->tsdata; /* Simply to return something `useful' */ }
/*{{{ echo_init(transform_info_ptr tinfo) {*/ METHODDEF void echo_init(transform_info_ptr tinfo) { struct echo_storage *local_arg=(struct echo_storage *)tinfo->methods->local_storage; transform_argument *args=tinfo->methods->arguments; char const *inbuf=args[ARGS_STRING].arg.s; growing_buf_init(&local_arg->buf); growing_buf_allocate(&local_arg->buf, 0); while (*inbuf !='\0') { char c=*inbuf++; if (c=='\\') { char c1; switch (c1=*inbuf++) { case 'n': c='\n'; break; case 't': c='\t'; break; case '\0': inbuf--; break; default: c=c1; break; } if (c=='\0') break; } growing_buf_appendchar(&local_arg->buf, c); } growing_buf_appendchar(&local_arg->buf, '\0'); if (!args[ARGS_OFILE].is_set) { local_arg->outfile=NULL; } else if (strcmp(args[ARGS_OFILE].arg.s, "stdout")==0) { local_arg->outfile=stdout; } else if (strcmp(args[ARGS_OFILE].arg.s, "stderr")==0) { local_arg->outfile=stderr; } else if ((local_arg->outfile=fopen(args[ARGS_OFILE].arg.s, "a"))==NULL) { ERREXIT1(tinfo->emethods, "echo_init: Can't open file >%s<\n", MSGPARM(args[ARGS_OFILE].arg.s)); } tinfo->methods->init_done=TRUE; }
/*{{{ null_source(transform_info_ptr tinfo) {*/ METHODDEF DATATYPE * null_source(transform_info_ptr tinfo) { struct null_source_storage *local_arg=(struct null_source_storage *)tinfo->methods->local_storage; array myarray; if (local_arg->epochs--==0) return NULL; tinfo->beforetrig=local_arg->beforetrig; tinfo->aftertrig=local_arg->aftertrig; tinfo->nr_of_points=local_arg->beforetrig+local_arg->aftertrig; tinfo->nr_of_channels=local_arg->nr_of_channels; tinfo->nrofaverages=1; if (tinfo->nr_of_points<=0) { ERREXIT1(tinfo->emethods, "null_source: Invalid nr_of_points %d\n", MSGPARM(tinfo->nr_of_points)); } /*{{{ Configure myarray*/ myarray.element_skip=tinfo->itemsize=local_arg->itemsize; tinfo->multiplexed=FALSE; myarray.nr_of_elements=tinfo->nr_of_points; myarray.nr_of_vectors=tinfo->nr_of_channels; if (array_allocate(&myarray)==NULL || (tinfo->comment=(char *)malloc(MAX_COMMENTLEN))==NULL) { ERREXIT(tinfo->emethods, "null_source: Error allocating data\n"); } /*}}} */ snprintf(tinfo->comment, MAX_COMMENTLEN, "null_source"); /* Force create_channelgrid to really allocate the channel info anew. * Otherwise, free_tinfo will free someone else's data ! */ tinfo->channelnames=NULL; tinfo->probepos=NULL; create_channelgrid(tinfo); /* Create defaults for any missing channel info */ local_arg->current_epoch=0; tinfo->z_label=NULL; tinfo->sfreq=local_arg->sfreq; tinfo->tsdata=myarray.start; tinfo->length_of_output_region=tinfo->nr_of_channels*tinfo->nr_of_points*tinfo->itemsize; tinfo->leaveright=0; tinfo->data_type=TIME_DATA; local_arg->current_epoch++; return tinfo->tsdata; }
/*{{{ 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); /*}}} */ } }
/*{{{ recode_init(transform_info_ptr tinfo) {*/ METHODDEF void recode_init(transform_info_ptr tinfo) { struct recode_storage *local_arg=(struct recode_storage *)tinfo->methods->local_storage; transform_argument *args=tinfo->methods->arguments; growing_buf buf, tokenbuf; struct blockdef *inblocks; int nr_of_blocks=0, block; Bool havearg; if (args[ARGS_BYNAME].is_set) { /* Note that this is NULL if no channel matched, which is why we need have_channel_list as well... */ local_arg->channel_list=expand_channel_list(tinfo, args[ARGS_BYNAME].arg.s); local_arg->have_channel_list=TRUE; } else { local_arg->channel_list=NULL; local_arg->have_channel_list=FALSE; } local_arg->fromitem=0; local_arg->toitem=tinfo->itemsize-tinfo->leaveright-1; if (args[ARGS_ITEMPART].is_set) { local_arg->fromitem=local_arg->toitem=args[ARGS_ITEMPART].arg.i; if (local_arg->fromitem<0 || local_arg->fromitem>=tinfo->itemsize) { ERREXIT1(tinfo->emethods, "recode_init: No item number %d in file\n", MSGPARM(local_arg->fromitem)); } } growing_buf_init(&buf); growing_buf_takethis(&buf, args[ARGS_BLOCKS].arg.s); growing_buf_init(&tokenbuf); growing_buf_allocate(&tokenbuf,0); havearg=growing_buf_get_firsttoken(&buf,&tokenbuf); while (havearg) { nr_of_blocks++; havearg=growing_buf_get_nexttoken(&buf,&tokenbuf); } havearg=growing_buf_get_firsttoken(&buf,&tokenbuf); if (!havearg || nr_of_blocks%4!=0) { ERREXIT(tinfo->emethods, "recode_init: Number of args must be divisible by 4.\n"); } nr_of_blocks/=4; if ((local_arg->blockdefs=(struct blockdef *)malloc(nr_of_blocks*sizeof(struct blockdef)))==NULL) { ERREXIT(tinfo->emethods, "recode_init: Error allocating blockdefs memory\n"); } for (inblocks=local_arg->blockdefs, block=0; havearg; block++, inblocks++) { inblocks->fromstart=get_value(tokenbuf.buffer_start, NULL); growing_buf_get_nexttoken(&buf,&tokenbuf); inblocks->fromend=get_value(tokenbuf.buffer_start, NULL); growing_buf_get_nexttoken(&buf,&tokenbuf); inblocks->tostart=get_value(tokenbuf.buffer_start, NULL); growing_buf_get_nexttoken(&buf,&tokenbuf); inblocks->toend=get_value(tokenbuf.buffer_start, NULL); havearg=growing_buf_get_nexttoken(&buf,&tokenbuf); inblocks->last_block=(block==nr_of_blocks-1); if (isnan(inblocks->fromstart) || isnan(inblocks->fromend)) { if (!isnan(inblocks->fromstart) || !isnan(inblocks->fromend)) { ERREXIT(tinfo->emethods, "recode_init: NaN cannot be mixed in from block!\n"); } if (inblocks->tostart!=inblocks->toend) { ERREXIT(tinfo->emethods, "recode_init: NaN can only be recoded to one value!\n"); } } if (isnan(inblocks->tostart) || isnan(inblocks->toend)) { if (!isnan(inblocks->tostart) || !isnan(inblocks->toend)) { ERREXIT(tinfo->emethods, "recode_init: NaN cannot be mixed in to block!\n"); } } } growing_buf_free(&tokenbuf); growing_buf_free(&buf); tinfo->methods->init_done=TRUE; }
/*{{{ project(transform_info_ptr tinfo)*/ METHODDEF DATATYPE * project(transform_info_ptr tinfo) { struct project_args_struct *project_args=(struct project_args_struct *)tinfo->methods->local_storage; transform_argument *args=tinfo->methods->arguments; DATATYPE *retvalue=tinfo->tsdata; array indata, scalars, *vectors= &project_args->vectors; int itempart, itemparts=tinfo->itemsize-tinfo->leaveright; if (project_args->project_mode==PROJECT_MODE_MULTIPLY) { if (!(tinfo->nr_of_channels==vectors->nr_of_vectors ||(tinfo->nr_of_channels==1 && tinfo->itemsize==vectors->nr_of_vectors))) { ERREXIT(tinfo->emethods, "project: Number of scalars and maps doesn't match!\n"); } } else { if (vectors->nr_of_elements!=tinfo->nr_of_channels) { ERREXIT2(tinfo->emethods, "project: %d channels in epoch, but %d channels in project file.\n", MSGPARM(tinfo->nr_of_channels), MSGPARM(vectors->nr_of_elements)); } } array_reset(vectors); tinfo_array(tinfo, &indata); array_transpose(&indata); /* Vectors are maps */ /* Be sure that different output items are adjacent... */ scalars.nr_of_elements=vectors->nr_of_vectors; switch (project_args->project_mode) { case PROJECT_MODE_SCALAR: scalars.nr_of_vectors=tinfo->nr_of_points; scalars.element_skip=itemparts; break; case PROJECT_MODE_SSP: case PROJECT_MODE_SSPS: scalars.nr_of_vectors=1; scalars.element_skip=1; break; case PROJECT_MODE_MULTIPLY: scalars=indata; if (tinfo->nr_of_channels!=vectors->nr_of_vectors) { /* Ie, one channel and weights in the items: Convert from 1 element to * itemsize elements */ scalars.element_skip=1; scalars.nr_of_elements=tinfo->itemsize; itemparts=1; } indata.element_skip=itemparts; indata.nr_of_elements=vectors->nr_of_elements; /* New number of channels */ indata.nr_of_vectors=scalars.nr_of_vectors; /* New number of points */ if (array_allocate(&indata)==NULL) { ERREXIT(tinfo->emethods, "project: Can't allocate new indata array\n"); } break; } if (project_args->project_mode==PROJECT_MODE_MULTIPLY) { array_transpose(vectors); /* Now the elements are the subspace dimensions */ for (itempart=0; itempart<itemparts; itempart++) { array_use_item(&indata, itempart); array_use_item(&scalars, itempart); do { /*{{{ Build the signal subspace vector*/ do { array_write(&indata, array_multiply(vectors, &scalars, MULT_SAMESIZE)); } while (indata.message==ARRAY_CONTINUE); /*}}} */ } while (indata.message!=ARRAY_ENDOFSCAN); } array_transpose(vectors); } else { if (array_allocate(&scalars)==NULL) { ERREXIT(tinfo->emethods, "project: Can't allocate scalars array\n"); } for (itempart=0; itempart<itemparts; itempart++) { array_use_item(&indata, itempart); if (project_args->project_mode==PROJECT_MODE_SCALAR) { array_use_item(&scalars, itempart); } do { /*{{{ Calculate the projection scalars*/ do { /* With all vectors in turn: */ DATATYPE product=0.0; do { if (project_args->channel_list!=NULL && !is_in_channellist(vectors->current_element+1, project_args->channel_list)) { array_advance(vectors); array_advance(&indata); } else { product+=array_scan(&indata)*array_scan(vectors); } } while (vectors->message==ARRAY_CONTINUE); array_write(&scalars, product); if (scalars.message==ARRAY_CONTINUE) array_previousvector(&indata); } while (scalars.message==ARRAY_CONTINUE); /*}}} */ switch (project_args->project_mode) { case PROJECT_MODE_SCALAR: break; case PROJECT_MODE_SSP: /*{{{ Build the signal subspace vector*/ array_transpose(vectors); /* Now the elements are the subspace dimensions */ array_previousvector(&indata); do { array_write(&indata, array_multiply(vectors, &scalars, MULT_VECTOR)); } while (indata.message==ARRAY_CONTINUE); array_transpose(vectors); /*}}} */ break; case PROJECT_MODE_SSPS: /*{{{ Subtract the signal subspace vector*/ array_transpose(vectors); /* Now the elements are the subspace dimensions */ array_previousvector(&indata); do { array_write(&indata, READ_ELEMENT(&indata)-array_multiply(vectors, &scalars, MULT_VECTOR)); } while (indata.message==ARRAY_CONTINUE); array_transpose(vectors); /*}}} */ break; default: /* Can't happen, just to keep the compiler happy... */ ERREXIT(tinfo->emethods, "project: This cannot happen!\n"); break; } } while (indata.message!=ARRAY_ENDOFSCAN); } } /*{{{ Prepare tinfo to reflect the data structure returned*/ switch (project_args->project_mode) { case PROJECT_MODE_SCALAR: if (args[ARGS_USE_CHANNELS].is_set) { tinfo->nr_of_channels=vectors->nr_of_vectors; tinfo->itemsize=itemparts; } else { tinfo->nr_of_channels=1; tinfo->itemsize=itemparts*vectors->nr_of_vectors; } tinfo->length_of_output_region=scalars.nr_of_elements*scalars.element_skip*scalars.nr_of_vectors; tinfo->leaveright=0; tinfo->multiplexed=TRUE; if (tinfo->channelnames!=NULL) { free_pointer((void **)&tinfo->channelnames[0]); free_pointer((void **)&tinfo->channelnames); } free_pointer((void **)&tinfo->probepos); create_channelgrid(tinfo); retvalue=scalars.start; break; case PROJECT_MODE_SSP: case PROJECT_MODE_SSPS: array_free(&scalars); retvalue=tinfo->tsdata; break; case PROJECT_MODE_MULTIPLY: /* Note that we don't free `scalars' because it just points to the original tsdata! */ /* Have to set this correctly so that copy_channelinfo works... */ tinfo->nr_of_channels=indata.nr_of_elements; copy_channelinfo(tinfo, project_args->save_side_tinfo.channelnames, project_args->save_side_tinfo.probepos); tinfo->nr_of_points=indata.nr_of_vectors; tinfo->itemsize=indata.element_skip; tinfo->length_of_output_region=tinfo->nr_of_channels*tinfo->nr_of_points*tinfo->itemsize; retvalue=indata.start; tinfo->multiplexed=TRUE; break; } /*}}} */ return retvalue; }
/* This function has all the knowledge about events in the various file types */ LOCAL void read_neurofile_build_trigbuffer(transform_info_ptr tinfo) { struct read_neurofile_storage *local_arg=(struct read_neurofile_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_neurofile_build_trigbuffer: Reading event file\n"); if (triggerfile==NULL) { ERREXIT1(tinfo->emethods, "read_neurofile_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 { TRACEMS(tinfo->emethods, 0, "read_neurofile_build_trigbuffer: No trigger source known.\n"); } }
/*{{{ read_neurofile(transform_info_ptr tinfo) {*/ METHODDEF DATATYPE * read_neurofile(transform_info_ptr tinfo) { struct read_neurofile_storage *local_arg=(struct read_neurofile_storage *)tinfo->methods->local_storage; transform_argument *args=tinfo->methods->arguments; array myarray; FILE *infile=local_arg->infile; Bool not_correct_trigger=FALSE; long trigger_point, file_start_point, file_end_point; char *innamebuf; int channel; char *description=NULL; if (local_arg->epochs--==0) return NULL; tinfo->beforetrig=local_arg->beforetrig; tinfo->aftertrig=local_arg->aftertrig; tinfo->nr_of_points=local_arg->beforetrig+local_arg->aftertrig; tinfo->nr_of_channels=local_arg->nr_of_channels; tinfo->nrofaverages=1; if (tinfo->nr_of_points<=0) { ERREXIT1(tinfo->emethods, "read_neurofile: Invalid nr_of_points %d\n", MSGPARM(tinfo->nr_of_points)); } /*{{{ Find the next window that fits into the actual data*/ /* This is just for the Continuous option (no trigger file): */ file_end_point=local_arg->current_point-1; do { if (args[ARGS_CONTINUOUS].is_set) { /* Simulate a trigger at current_point+beforetrig */ file_start_point=file_end_point+1; trigger_point=file_start_point+tinfo->beforetrig; file_end_point=trigger_point+tinfo->aftertrig-1; if (local_arg->points_in_file>0 && file_end_point>=local_arg->points_in_file) return NULL; local_arg->current_trigger++; local_arg->current_point+=tinfo->nr_of_points; tinfo->condition=0; } else do { tinfo->condition=read_neurofile_read_trigger(tinfo, &trigger_point, &description); if (tinfo->condition==0) return NULL; /* No more triggers in file */ file_start_point=trigger_point-tinfo->beforetrig+local_arg->offset; file_end_point=trigger_point+tinfo->aftertrig-1-local_arg->offset; if (local_arg->trigcodes==NULL) { not_correct_trigger=FALSE; } else { int trigno=0; not_correct_trigger=TRUE; while (local_arg->trigcodes[trigno]!=0) { if (local_arg->trigcodes[trigno]==tinfo->condition) { not_correct_trigger=FALSE; break; } trigno++; } } } while (not_correct_trigger || file_start_point<0 || (local_arg->points_in_file>0 && file_end_point>=local_arg->points_in_file)); } while (--local_arg->fromepoch>0); if (description==NULL) { TRACEMS3(tinfo->emethods, 1, "read_neurofile: Reading around tag %d at %d, condition=%d\n", MSGPARM(local_arg->current_trigger), MSGPARM(trigger_point), MSGPARM(tinfo->condition)); } else { TRACEMS4(tinfo->emethods, 1, "read_neurofile: Reading around tag %d at %d, condition=%d, description=%s\n", MSGPARM(local_arg->current_trigger), MSGPARM(trigger_point), MSGPARM(tinfo->condition), MSGPARM(description)); } /*{{{ Handle triggers within the epoch (option -T)*/ if (args[ARGS_TRIGTRANSFER].is_set) { int trigs_in_epoch, code; long trigpoint; long const old_current_trigger=local_arg->current_trigger; char *thisdescription; /* First trigger entry holds file_start_point */ push_trigger(&tinfo->triggers, file_start_point, -1, NULL); read_neurofile_reset_triggerbuffer(tinfo); for (trigs_in_epoch=1; (code=read_neurofile_read_trigger(tinfo, &trigpoint, &thisdescription))!=0;) { if (trigpoint>=file_start_point && trigpoint<=file_end_point) { push_trigger(&tinfo->triggers, trigpoint-file_start_point, code, thisdescription); trigs_in_epoch++; } } push_trigger(&tinfo->triggers, 0, 0, NULL); /* End of list */ local_arg->current_trigger=old_current_trigger; } /*}}} */ fseek(infile, file_start_point*tinfo->nr_of_channels, SEEK_SET); /*{{{ Configure myarray*/ myarray.element_skip=tinfo->itemsize=1; tinfo->multiplexed=TRUE; myarray.nr_of_elements=tinfo->nr_of_channels; myarray.nr_of_vectors=tinfo->nr_of_points; if (array_allocate(&myarray)==NULL || (tinfo->channelnames=(char **)malloc(tinfo->nr_of_channels*sizeof(char *)))==NULL || (innamebuf=(char *)malloc(local_arg->stringlength))==NULL || (tinfo->comment=(char *)malloc(strlen((char *)local_arg->seq.comment)+(1+17+1)))==NULL) { ERREXIT(tinfo->emethods, "read_neurofile: Error allocating data\n"); } /*}}} */ sprintf(tinfo->comment, "%s %02d/%02d/%02d,%02d:%02d:%02d", local_arg->seq.comment, local_arg->seq.month, local_arg->seq.day, local_arg->seq.year, local_arg->seq.hour, local_arg->seq.minute, local_arg->seq.second); for (channel=0; channel<tinfo->nr_of_channels; channel++) { strcpy(innamebuf, (char *)local_arg->seq.elnam[channel]); tinfo->channelnames[channel]=innamebuf; innamebuf+=strlen(innamebuf)+1; } do { signed char exponent; short delta; if (fread(&exponent, sizeof(exponent), 1, infile)!=1) { ERREXIT(tinfo->emethods, "read_neurofile: Error reading data\n"); } delta=exponent; exponent&=0x03; if (exponent==0x03) { delta>>=2; } else { delta=(delta&0xfffc)<<(exponent*2); } local_arg->last_values[myarray.current_element]+=delta; array_write(&myarray, local_arg->last_values[myarray.current_element]*local_arg->factor); } while (myarray.message!=ARRAY_ENDOFSCAN);
/*{{{ writeasc_open_file(transform_info_ptr tinfo) {*/ LOCAL void writeasc_open_file(transform_info_ptr tinfo) { struct writeasc_storage *local_arg=(struct writeasc_storage *)tinfo->methods->local_storage; transform_argument *args=tinfo->methods->arguments; FILE *outfptr=NULL; Bool append_mode=args[ARGS_APPEND].is_set; if (strcmp(args[ARGS_OFILE].arg.s, "stdout")==0) outfptr=stdout; else if (strcmp(args[ARGS_OFILE].arg.s, "stderr")==0) outfptr=stderr; if (append_mode) { /*{{{ Append mode open*/ if (outfptr==NULL) { if ((outfptr=fopen(args[ARGS_OFILE].arg.s, "a+b"))==NULL) { ERREXIT1(tinfo->emethods, "writeasc_init: Can't append to %s\n", MSGPARM(args[ARGS_OFILE].arg.s)); } } fseek(outfptr, 0L, 2); /* It is important here to overwrite the append_mode flag only for THIS open * operation, because writeasc_open_file will get called repeatedly if -c is * also set, and then the file will already be there the second time and we want * to append to it... */ if (ftell(outfptr)==0L) append_mode=FALSE; /* If at start: write header */ /*}}} */ } if (outfptr==NULL) { /*{{{ Truncate mode open*/ if ((outfptr=fopen(args[ARGS_OFILE].arg.s, "wb"))==NULL) { ERREXIT1(tinfo->emethods, "writeasc_init: Can't open %s\n", MSGPARM(args[ARGS_OFILE].arg.s)); } /*}}} */ } local_arg->outfptr=outfptr; if (append_mode) { /* Don't write header in append mode. * Also set the local_arg values to (nearly) impossible numbers in order to * force these values to be assigned in the epoch header */ local_arg->sfreq= -123456789; local_arg->beforetrig= -123456789; local_arg->leaveright= -123456789; } else { if (args[ARGS_BINARY].is_set) { /*{{{ Write binary header*/ char outbuf[OUTBUFSIZE], *inoutbuf; unsigned short shortbuf=ASC_BF_MAGIC; fwrite((void *)&shortbuf, 2, 1, outfptr); inoutbuf=outbuf; snprintf(inoutbuf, OUTBUFSIZE-(inoutbuf-outbuf), "Sfreq=%f\n", (float)tinfo->sfreq); inoutbuf+=strlen(inoutbuf); if (tinfo->beforetrig>0) { snprintf(inoutbuf, OUTBUFSIZE-(inoutbuf-outbuf), "BeforeTrig=%d\n", tinfo->beforetrig); inoutbuf+=strlen(inoutbuf); } if (tinfo->leaveright>0) { snprintf(inoutbuf, OUTBUFSIZE-(inoutbuf-outbuf), "Leaveright=%d\n", tinfo->leaveright); inoutbuf+=strlen(inoutbuf); } shortbuf=inoutbuf-outbuf; fwrite((void *)&shortbuf, 2, 1, outfptr); fwrite((void *)outbuf, (int)shortbuf, 1, outfptr); /*}}} */ } else { /*{{{ Write ascii header*/ fprintf(outfptr, "Sfreq=%f\n", (float)tinfo->sfreq); if (tinfo->beforetrig>0) fprintf(outfptr, "BeforeTrig=%d\n", tinfo->beforetrig); if (tinfo->leaveright>0) fprintf(outfptr, "Leaveright=%d\n", tinfo->leaveright); /*}}} */ } local_arg->sfreq=tinfo->sfreq; local_arg->beforetrig=tinfo->beforetrig; local_arg->leaveright=tinfo->leaveright; } }
GLOBAL struct source_desc * var_random_srcmodule(transform_info_ptr tinfo, char **args) { int n_harmonics, n_noisedips, i, n_dipoles; char **inargs=args; DATATYPE *memptr; float random_pos=0.0, random_moment=0.0; double freq_default=0.1; struct source_desc *sourcep; struct dipole_desc *dipolep; if (args==(char **)NULL) { ERREXIT(tinfo->emethods, "var_random_srcmodule: Usage: var_random_dipoles ( n_harmonics n_noisedips )\n"); } if (*inargs!=NULL) n_harmonics=atoi(*inargs++); if (*inargs!=NULL) n_noisedips=atoi(*inargs++); if (inargs-args!=2) { ERREXIT(tinfo->emethods, "var_random_srcmodule: Need at least two arguments ( n_harmonics n_noisedips )\n"); } n_dipoles=n_harmonics+n_noisedips; if ((sourcep=(struct source_desc *)malloc(sizeof(struct source_desc)+(sizeof(struct dipole_desc)+3*3*sizeof(DATATYPE))*n_dipoles))==NULL) { ERREXIT(tinfo->emethods, "var_random_srcmodule: Error allocating memory\n"); } sourcep->nrofsources=n_dipoles; dipolep=sourcep->dipoles=(struct dipole_desc *)(sourcep+1); memptr=(DATATYPE *)(dipolep+n_dipoles); for (i=0; i<n_dipoles; i++, dipolep++, memptr+=9) { dipolep->position.start=memptr; dipolep->dip_moment.start=memptr+3; dipolep->initial_moment.start=memptr+6; /*{{{ Read switchable options: FREQ_DEFAULT, RANDOM_POS, RANDOM_MOMENT keyword*/ if (*inargs!=NULL && strcmp(*inargs, "FREQ_DEFAULT")==0) { if (*++inargs!=NULL) { freq_default=atof(*inargs); inargs++; } } if (*inargs!=NULL && strcmp(*inargs, "RANDOM_POS")==0) { if (*++inargs!=NULL) { random_pos=atof(*inargs); inargs++; } } if (*inargs!=NULL && strcmp(*inargs, "RANDOM_MOMENT")==0) { if (*++inargs!=NULL) { random_moment=atof(*inargs); inargs++; } } /*}}} */ dipolep->position.nr_of_elements=dipolep->dip_moment.nr_of_elements=dipolep->initial_moment.nr_of_elements=3; dipolep->position.nr_of_vectors=dipolep->dip_moment.nr_of_vectors=dipolep->initial_moment.nr_of_vectors=1; dipolep->position.element_skip=dipolep->dip_moment.element_skip=dipolep->initial_moment.element_skip=1; dipolep->position.vector_skip=dipolep->dip_moment.vector_skip=dipolep->initial_moment.vector_skip=3; array_setreadwrite(&dipolep->position); array_setreadwrite(&dipolep->dip_moment); array_setreadwrite(&dipolep->initial_moment); array_reset(&dipolep->position); array_reset(&dipolep->dip_moment); array_reset(&dipolep->initial_moment); /* The parameter is the frequency relative to half the sampling frequency: */ dipolep->time[1]=M_PI*readval(tinfo, &inargs, freq_default); if (dipolep->time[1]<=0) { ERREXIT1(tinfo->emethods, "var_random_srcmodule: Frequency==%d\n", MSGPARM(dipolep->time[1])); } if (random_pos>0.0) { float x, y, z; sphere_random(random_pos, &x, &y, &z); array_write(&dipolep->position, readval(tinfo, &inargs, x)); array_write(&dipolep->position, readval(tinfo, &inargs, y)); array_write(&dipolep->position, readval(tinfo, &inargs, z)); } else { array_write(&dipolep->position, readval(tinfo, &inargs, 1)); array_write(&dipolep->position, readval(tinfo, &inargs, 1)); array_write(&dipolep->position, readval(tinfo, &inargs, 7.5)); } if (random_moment>0.0) { float x, y, z; sphere_random(random_moment, &x, &y, &z); array_write(&dipolep->dip_moment, readval(tinfo, &inargs, x)); array_write(&dipolep->dip_moment, readval(tinfo, &inargs, y)); array_write(&dipolep->dip_moment, readval(tinfo, &inargs, z)); } else { array_write(&dipolep->dip_moment, readval(tinfo, &inargs, 1)); array_write(&dipolep->dip_moment, readval(tinfo, &inargs, 0)); array_write(&dipolep->dip_moment, readval(tinfo, &inargs, 0)); } if (i<n_harmonics) { /*{{{ Set harmonic behaviour*/ dipolep->time_function_init= &harmonic_time_init; dipolep->time_function= &harmonic_time; dipolep->time_function_exit= &harmonic_time_exit; /*}}} */ } else { /*{{{ Set noise behaviour*/ dipolep->time_function_init= &noise_time_init; dipolep->time_function= &noise_time; dipolep->time_function_exit= &noise_time_exit; /*}}} */ } } return sourcep; }
/*{{{ project_init(transform_info_ptr tinfo)*/ METHODDEF void project_init(transform_info_ptr tinfo) { struct project_args_struct *project_args=(struct project_args_struct *)tinfo->methods->local_storage; transform_argument *args=tinfo->methods->arguments; transform_info_ptr side_tinfo= &project_args->side_tinfo; array *vectors= &project_args->vectors; growing_buf buf; #define BUFFER_SIZE 80 char buffer[BUFFER_SIZE]; side_tinfo->methods= &project_args->methods; side_tinfo->emethods=tinfo->emethods; select_readasc(side_tinfo); growing_buf_init(&buf); growing_buf_allocate(&buf, 0); if (args[ARGS_FROMEPOCH].is_set) { snprintf(buffer, BUFFER_SIZE, "-f %ld ", args[ARGS_FROMEPOCH].arg.i); growing_buf_appendstring(&buf, buffer); } if (args[ARGS_EPOCHS].is_set) { project_args->epochs=args[ARGS_EPOCHS].arg.i; if (project_args->epochs<=0) { ERREXIT(tinfo->emethods, "project_init: The number of epochs must be positive.\n"); } } else { project_args->epochs=1; } snprintf(buffer, BUFFER_SIZE, "-e %d ", project_args->epochs); growing_buf_appendstring(&buf, buffer); growing_buf_appendstring(&buf, args[ARGS_PROJECTFILE].arg.s); if (!buf.can_be_freed || !setup_method(side_tinfo, &buf)) { ERREXIT(tinfo->emethods, "project_init: Error setting readasc arguments.\n"); } project_args->points=(args[ARGS_POINTS].is_set ? args[ARGS_POINTS].arg.i : 1); project_args->nr_of_item=(args[ARGS_NROFITEM].is_set ? args[ARGS_NROFITEM].arg.i : 0); project_args->orthogonalize_vectors_first=args[ARGS_ORTHOGONALIZE].is_set; if (args[ARGS_SUBSPACE].is_set) { project_args->project_mode=PROJECT_MODE_SSP; } else if (args[ARGS_SUBTRACT_SUBSPACE].is_set) { project_args->project_mode=PROJECT_MODE_SSPS; } else if (args[ARGS_MULTIPLY].is_set) { project_args->project_mode=PROJECT_MODE_MULTIPLY; } else { project_args->project_mode=PROJECT_MODE_SCALAR; } if (args[ARGS_CHANNELNAMES].is_set) { project_args->channel_list=expand_channel_list(tinfo, args[ARGS_CHANNELNAMES].arg.s); if (project_args->channel_list==NULL) { ERREXIT(tinfo->emethods, "project_init: Zero channels were selected by -N!\n"); } } else { project_args->channel_list=NULL; } (*side_tinfo->methods->transform_init)(side_tinfo); /*{{{ Read first project_file epoch and allocate vectors array accordingly*/ if ((side_tinfo->tsdata=(*side_tinfo->methods->transform)(side_tinfo))==NULL) { ERREXIT(tinfo->emethods, "project_init: Can't get the first project epoch.\n"); } if (project_args->project_mode==PROJECT_MODE_MULTIPLY) { /* Save channel names and positions for later */ project_args->save_side_tinfo.nr_of_channels=side_tinfo->nr_of_channels; copy_channelinfo(&project_args->save_side_tinfo, side_tinfo->channelnames, side_tinfo->probepos); } if (project_args->points==0) project_args->points=side_tinfo->nr_of_points; if (project_args->points>side_tinfo->nr_of_points) { ERREXIT1(tinfo->emethods, "project_init: There are only %d points in the project_file epoch.\n", MSGPARM(side_tinfo->nr_of_points)); } if (args[ARGS_AT_XVALUE].is_set) { project_args->nr_of_point=find_pointnearx(side_tinfo, (DATATYPE)atof(args[ARGS_NROFPOINT].arg.s)); } else { project_args->nr_of_point=gettimeslice(side_tinfo, args[ARGS_NROFPOINT].arg.s); } vectors->nr_of_vectors=project_args->epochs*project_args->points; vectors->nr_of_elements=side_tinfo->nr_of_channels; vectors->element_skip=1; if (array_allocate(vectors)==NULL) { ERREXIT(tinfo->emethods, "project_init: Error allocating vectors memory\n"); } /*}}} */ do { /*{{{ Copy [points] vectors from project_file to vectors array*/ array indata; int point; if (vectors->nr_of_elements!=side_tinfo->nr_of_channels) { ERREXIT(side_tinfo->emethods, "project_init: Varying channel numbers in project file!\n"); } if (project_args->nr_of_point>=side_tinfo->nr_of_points) { ERREXIT2(side_tinfo->emethods, "project_init: nr_of_point=%d, nr_of_points=%d\n", MSGPARM(project_args->nr_of_point), MSGPARM(side_tinfo->nr_of_points)); } if (project_args->nr_of_item>=side_tinfo->itemsize) { ERREXIT2(side_tinfo->emethods, "project_init: nr_of_item=%d, itemsize=%d\n", MSGPARM(project_args->nr_of_item), MSGPARM(side_tinfo->itemsize)); } for (point=0; point<project_args->points; point++) { tinfo_array(side_tinfo, &indata); array_transpose(&indata); /* Vector = map */ if (vectors->nr_of_elements!=indata.nr_of_elements) { ERREXIT(side_tinfo->emethods, "project_init: vector size doesn't match\n"); } indata.current_vector=project_args->nr_of_point+point; array_setto_vector(&indata); array_use_item(&indata, project_args->nr_of_item); array_copy(&indata, vectors); } /*}}} */ free_tinfo(side_tinfo); } while ((side_tinfo->tsdata=(*side_tinfo->methods->transform)(side_tinfo))!=NULL); if (vectors->message!=ARRAY_ENDOFSCAN) { ERREXIT1(tinfo->emethods, "project_init: Less than %d epochs in project file\n", MSGPARM(vectors->nr_of_vectors)); } /*{{{ Set unused channels to zero if requested*/ if (args[ARGS_ZERO_UNUSEDCOEFFICIENTS].is_set) { if (project_args->channel_list!=NULL) { do { do { if (is_in_channellist(vectors->current_element+1, project_args->channel_list)) { array_advance(vectors); } else { array_write(vectors, 0.0); } } while (vectors->message==ARRAY_CONTINUE); } while (vectors->message!=ARRAY_ENDOFSCAN); } else { ERREXIT(tinfo->emethods, "project_init: Option -z only makes sense in combination with -N!\n"); } } /*}}} */ /*{{{ De-mean vectors if requested*/ if (args[ARGS_CORRELATION].is_set) { do { DATATYPE mean=0.0; int nrofaverages=0; do { if (project_args->channel_list!=NULL && !is_in_channellist(vectors->current_element+1, project_args->channel_list)) { array_advance(vectors); } else { mean+=array_scan(vectors); nrofaverages++; } } while (vectors->message==ARRAY_CONTINUE); mean/=nrofaverages; array_previousvector(vectors); do { array_write(vectors, READ_ELEMENT(vectors)-mean); } while (vectors->message==ARRAY_CONTINUE); } while (vectors->message!=ARRAY_ENDOFSCAN); } /*}}} */ /*{{{ Orthogonalize vectors if requested*/ if (project_args->orthogonalize_vectors_first) { array_make_orthogonal(vectors); if (vectors->message==ARRAY_ERROR) { ERREXIT(tinfo->emethods, "project_init: Error orthogonalizing projection vectors\n"); } } /*}}} */ if (!args[ARGS_NONORMALIZATION].is_set) { /*{{{ Normalize vectors*/ do { DATATYPE length=0.0; do { if (project_args->channel_list!=NULL && !is_in_channellist(vectors->current_element+1, project_args->channel_list)) { array_advance(vectors); } else { const DATATYPE hold=array_scan(vectors); length+=hold*hold; } } while (vectors->message==ARRAY_CONTINUE); length=sqrt(length); array_previousvector(vectors); if (length==0.0) { ERREXIT1(tinfo->emethods, "project_init: Vector %d has zero length !\n", MSGPARM(vectors->current_vector)); } array_scale(vectors, 1.0/length); } while (vectors->message!=ARRAY_ENDOFSCAN); /*}}} */ } /*{{{ Dump vectors if requested*/ if (args[ARGS_DUMPVECTORS].is_set) { FILE * const fp=fopen(args[ARGS_DUMPVECTORS].arg.s, "w"); if (fp==NULL) { ERREXIT1(tinfo->emethods, "project_init: Error opening output file >%s<.\n", MSGPARM(args[ARGS_DUMPVECTORS].arg.s)); } array_transpose(vectors); /* We want one vector to be one column */ array_dump(fp, vectors, ARRAY_MATLAB); array_transpose(vectors); fclose(fp); } /*}}} */ (*side_tinfo->methods->transform_exit)(side_tinfo); free_methodmem(side_tinfo); growing_buf_free(&buf); tinfo->methods->init_done=TRUE; }
/* This function not only seeks to the specified point, but also reads * the point into the buffer if necessary. The get_singlepoint function * then only transfers the data. */ LOCAL void read_synamps_seek_point(transform_info_ptr tinfo, long point) { struct read_synamps_storage *local_arg=(struct read_synamps_storage *)tinfo->methods->local_storage; switch(local_arg->SubType) { case NST_CONT0: case NST_DCMES: case NST_CONTINUOUS: case NST_SYNAMPS: { /*{{{ */ const int points_per_buf=local_arg->EEG.ChannelOffset/local_arg->bytes_per_sample; /* Note a value of 1 is fixed in read_synamps_init */ long const buffer_boundary=(point/points_per_buf)*points_per_buf; long const new_last_point_in_buffer=buffer_boundary+points_per_buf-1; /* This format is neither points fastest nor channels fastest, but * points fastest in blocks. No idea why they didn't do channels fastest, * it would have rendered the whole file in one order, no matter what buffer * size is used internally in programs. This way we MUST use the given buffers. */ if (new_last_point_in_buffer!=local_arg->last_point_in_buffer) { fseek(local_arg->SCAN,point2offset(tinfo,buffer_boundary),SEEK_SET); if (fread(local_arg->buffer,1,local_arg->BufferCount,local_arg->SCAN)!=local_arg->BufferCount) { ERREXIT(tinfo->emethods, "read_synamps_seek_point: Error reading data\n"); } local_arg->first_point_in_buffer=buffer_boundary; local_arg->last_point_in_buffer=new_last_point_in_buffer; /*{{{ Swap byte order if necessary*/ # ifndef LITTLE_ENDIAN {uint16_t *pdata=(uint16_t *)local_arg->buffer, *p_end=(uint16_t *)((char *)local_arg->buffer+local_arg->BufferCount); while (pdata<p_end) Intel_int16(pdata++); } # endif /*}}} */ } /*}}} */ } break; default: ERREXIT1(tinfo->emethods, "read_synamps_seek_point: Format `%s' is not yet supported\n", MSGPARM(neuroscan_subtype_names[local_arg->SubType])); break; } local_arg->current_point=point; }
/*{{{ read_synamps_get_singlepoint(transform_info_ptr tinfo, array *toarray) {*/ LOCAL int read_synamps_get_singlepoint(transform_info_ptr tinfo, array *toarray) { struct read_synamps_storage *local_arg=(struct read_synamps_storage *)tinfo->methods->local_storage; transform_argument *args=tinfo->methods->arguments; if (local_arg->current_point>=local_arg->EEG.NumSamples) return -1; read_synamps_seek_point(tinfo, local_arg->current_point); switch(local_arg->SubType) { case NST_DCMES: { /* DC-MES data is unsigned, and the marker channel is skipped: */ unsigned short *pdata=(unsigned short *)local_arg->buffer+local_arg->current_point-local_arg->first_point_in_buffer+1; int channel=0; do { *pdata^=0x8000; /* Exclusive or to convert to signed... */ if (args[ARGS_NOBADCHANS].is_set && local_arg->Channels[channel].bad) { toarray->message=ARRAY_CONTINUE; } else { array_write(toarray, NEUROSCAN_CONVSHORT(&local_arg->Channels[channel], *((signed short *)pdata))); } pdata+=local_arg->EEG.ChannelOffset/local_arg->bytes_per_sample; channel++; } while (toarray->message==ARRAY_CONTINUE); } break; case NST_CONT0: case NST_CONTINUOUS: case NST_SYNAMPS: { int channel=0; do { DATATYPE val; if (args[ARGS_NOBADCHANS].is_set && local_arg->Channels[channel].bad) { toarray->message=ARRAY_CONTINUE; } else { if (local_arg->bytes_per_sample==2) { int16_t * const pdata=((int16_t *)local_arg->buffer)+local_arg->current_point-local_arg->first_point_in_buffer+channel; # ifndef LITTLE_ENDIAN Intel_int16(pdata); # endif val=NEUROSCAN_CONVSHORT(&local_arg->Channels[channel],*pdata); } else if (local_arg->bytes_per_sample==4) { int32_t * const pdata=((int32_t *)local_arg->buffer)+local_arg->current_point-local_arg->first_point_in_buffer+channel; # ifndef LITTLE_ENDIAN Intel_int32(pdata); # endif val=NEUROSCAN_CONVSHORT(&local_arg->Channels[channel],*pdata); } else { ERREXIT(tinfo->emethods, "read_synamps: Unknown bytes_per_sample\n"); } array_write(toarray, val); } channel++; } while (toarray->message==ARRAY_CONTINUE); } break; default: ERREXIT1(tinfo->emethods, "read_synamps_get_singlepoint: Format `%s' is not yet supported\n", MSGPARM(neuroscan_subtype_names[local_arg->SubType])); break; } local_arg->current_point++; return 0; }
/* This subroutine encapsulates the coding of the different event codes * into a unified signed code */ LOCAL void read_synamps_push_keys(transform_info_ptr tinfo, long position, int TrigVal, int KeyPad, int KeyBoard, enum NEUROSCAN_ACCEPTVALUES Accept) { struct read_synamps_storage * const local_arg=(struct read_synamps_storage *)tinfo->methods->local_storage; int code; if (Accept!=0 && (Accept<NAV_DCRESET || Accept>NAV_STARTSTOP)) { TRACEMS2(tinfo->emethods, 0, "read_synamps_push_keys: Unknown Accept value %d at position %d!\n", MSGPARM(Accept), MSGPARM(position)); return; } code=TrigVal-KeyPad+neuroscan_accept_translation[Accept]; if (code==0) { /* At least in Edit 4.x, KeyPad F2 is written as KeyBoard=0 with everything else 0 too... */ code= -(((KeyBoard&0xf)+1)<<4); } if (code==0) { TRACEMS1(tinfo->emethods, 0, "read_synamps_push_keys: Trigger with trigcode 0 at position %d!\n", MSGPARM(position)); } else { push_trigger(&local_arg->triggers, position, code, NULL); } }
/*{{{ 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--; } } } }
/*{{{ 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; }
/*{{{ 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; }
/* 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; } }
/*{{{ get_mfxepoch(transform_info_ptr tinfo)*/ METHODDEF DATATYPE * get_mfxepoch(transform_info_ptr tinfo) { struct get_mfxepoch_storage *local_arg=(struct get_mfxepoch_storage *)tinfo->methods->local_storage; transform_argument *args=tinfo->methods->arguments; DATATYPE *newepoch; int again=FALSE; long epochlength; if (local_arg->epochs--==0) return NULL; do { again=FALSE; if ((newepoch=(DATATYPE *)mfx_getepoch(local_arg->fileptr, &epochlength, local_arg->beforetrig-local_arg->offset, local_arg->aftertrig+local_arg->offset, local_arg->trigname, args[ARGS_TRIGCODE].arg.i))==NULL) { /* MFX_READERR4 is the normal end-of-file 'error' */ TRACEMS1(tinfo->emethods, (mfx_lasterr==MFX_READERR4 ? 1 : 0), "get_mfxepoch: mfx error >%s<\n", MSGPARM(mfx_errors[mfx_lasterr])); /* If the error was due to the beforetrig time being too long, try to * skip this epoch and try the next one */ if (mfx_lasterr==MFX_NEGSEEK) { again=TRUE; mfx_seektrigger(local_arg->fileptr, local_arg->trigname, args[ARGS_TRIGCODE].arg.i); TRACEMS(tinfo->emethods, 1, "get_mfxepoch: Retrying...\n"); } } } while (again); if (newepoch!=NULL) { /* TOUCH TINFO ONLY IF GETEPOCH WAS SUCCESSFUL */ get_mfxinfo(local_arg->fileptr, tinfo); tinfo->z_label=NULL; tinfo->nr_of_points=epochlength; tinfo->length_of_output_region=epochlength*tinfo->nr_of_channels; tinfo->beforetrig=local_arg->beforetrig; tinfo->aftertrig=tinfo->nr_of_points-tinfo->beforetrig; tinfo->multiplexed=TRUE; tinfo->sfreq=1.0/(local_arg->fileptr)->fileheader.sample_period; tinfo->data_type=TIME_DATA; tinfo->itemsize=1; /* Still, mfx doesn't support tuple data */ tinfo->leaveright=0; tinfo->nrofaverages=1; } return newepoch; }
/*{{{ 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; }
/*{{{ 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; }
METHODDEF DATATYPE * read_freiburg(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 freiburg_channels_struct *in_channels=local_arg->in_channels; array myarray; FILE *infile; int i, point, channel; int trial_not_accepted; long length_of_data; short header[FREIBURG_HEADER_LENGTH/sizeof(short)]; char const *last_sep=strrchr(args[ARGS_IFILE].arg.s, PATHSEP); char const *last_component=(last_sep==NULL ? args[ARGS_IFILE].arg.s : last_sep+1); char comment[MAX_COMMENTLEN]; tinfo->nrofaverages=1; if (args[ARGS_CONTINUOUS].is_set) { /*{{{ Read an epoch from a continuous file*/ infile=local_arg->infile; if (local_arg->epochs--==0) return NULL; /*{{{ Configure myarray*/ myarray.element_skip=tinfo->itemsize=1; myarray.nr_of_vectors=tinfo->nr_of_points=local_arg->epochlength; myarray.nr_of_elements=tinfo->nr_of_channels=local_arg->nr_of_channels; if (array_allocate(&myarray)==NULL) { ERREXIT(tinfo->emethods, "read_freiburg: Error allocating data\n"); } tinfo->multiplexed=TRUE; /*}}} */ do { do { if (local_arg->segment_table.buffer_start!=NULL && local_arg->current_point%SEGMENT_LENGTH==0) { int const segment=local_arg->current_point/SEGMENT_LENGTH; long const nr_of_segments=local_arg->segment_table.current_length/sizeof(long); if (segment>=nr_of_segments) { array_free(&myarray); return NULL; } fseek(infile, ((long *)local_arg->segment_table.buffer_start)[segment], SEEK_SET); local_arg->no_last_values=TRUE; } if (freiburg_get_segment(tinfo, &myarray)!=0) { array_free(&myarray); return NULL; } } while (myarray.message!=ARRAY_ENDOFSCAN); } while (--local_arg->fromepoch>0); snprintf(comment, MAX_COMMENTLEN, "%s %s %02d/%02d/%04d,%02d:%02d:%02d", (local_arg->continuous_type==SLEEP_BT_TYPE ? "sleep_BT" : "sleep_KL"), last_component, local_arg->btfile.start_month, local_arg->btfile.start_day, local_arg->btfile.start_year, local_arg->btfile.start_hour, local_arg->btfile.start_minute, local_arg->btfile.start_second); tinfo->sfreq=local_arg->sfreq; /*}}} */ } else /*{{{ Read an epoch from a single (epoched or averaged) file*/ do { /* Return here if trial was not accepted */ trial_not_accepted=FALSE; if (local_arg->epochs--==0 || (local_arg->average_mode && local_arg->current_trigger>=1)) return NULL; if (local_arg->average_mode) { /*{{{ Prepare reading an averaged file*/ if((infile=fopen(args[ARGS_IFILE].arg.s,"rb"))==NULL) { ERREXIT1(tinfo->emethods, "read_freiburg: Can't open file %s\n", MSGPARM(args[ARGS_IFILE].arg.s)); } fseek(infile, 0, SEEK_END); length_of_data=ftell(infile)-FREIBURG_HEADER_LENGTH; local_arg->current_trigger++; snprintf(comment, MAX_COMMENTLEN, "Freiburg-avg %s", last_component); /*}}} */ } else { /*{{{ Build pathname of the single trial to read*/ /* A directory name was given. */ char const * const expnumber=args[ARGS_IFILE].arg.s+strlen(args[ARGS_IFILE].arg.s)-2; #ifdef __GNUC__ #define NEWFILENAME_SIZE (strlen(args[ARGS_IFILE].arg.s)+strlen(last_component)+20) #else #define NEWFILENAME_SIZE MAX_PATHLEN #endif char newfilename[NEWFILENAME_SIZE]; do { /* Files from which only the parameter part exists are rejected */ int div100=local_arg->current_trigger/100, mod100=local_arg->current_trigger%100; snprintf(newfilename, NEWFILENAME_SIZE, "%s%c%s%02d%c%c%s%02d%02d", args[ARGS_IFILE].arg.s, PATHSEP, last_component, div100, PATHSEP, tolower(expnumber[-1]), expnumber, div100, mod100); TRACEMS1(tinfo->emethods, 1, "read_freiburg: Constructed filename %s\n", MSGPARM(newfilename)); if((infile=fopen(newfilename,"rb"))==NULL) { if (local_arg->current_trigger==0) { ERREXIT1(tinfo->emethods, "read_freiburg: Can't open file %s\n", MSGPARM(newfilename)); } else { return NULL; } } fseek(infile, 0, SEEK_END); length_of_data=ftell(infile)-FREIBURG_HEADER_LENGTH; local_arg->current_trigger++; } while (length_of_data==0 || --local_arg->fromepoch>0); snprintf(comment, MAX_COMMENTLEN, "Freiburg-raw %s", last_component); /*}}} */ } /*{{{ Read the 64-Byte header*/ fseek(infile, 0, SEEK_SET); fread(header, 1, FREIBURG_HEADER_LENGTH, infile); for (i=0; i<18; i++) { # ifdef LITTLE_ENDIAN Intel_int16((uint16_t *)&header[i]); # endif TRACEMS2(tinfo->emethods, 3, "read_freiburg: Header %02d: %d\n", MSGPARM(i), MSGPARM(header[i])); } /*}}} */ if (local_arg->average_mode) { if ((length_of_data/sizeof(short))%local_arg->nr_of_channels!=0) { ERREXIT2(tinfo->emethods, "read_freiburg: length_of_data=%d does not fit with nr_of_channels=%d\n", MSGPARM(length_of_data), MSGPARM(local_arg->nr_of_channels)); } tinfo->nr_of_points=(length_of_data/sizeof(short))/local_arg->nr_of_channels; local_arg->sfreq=(args[ARGS_SFREQ].is_set ? args[ARGS_SFREQ].arg.d : 200.0); /* The most likely value */ } else { local_arg->nr_of_channels=header[14]; /* Note: In a lot of experiments, one point MORE is available in the data * than specified in the header, but this occurs erratically. We could only * check for this during decompression, but that's probably too much fuss. */ tinfo->nr_of_points=header[16]/header[15]; local_arg->sfreq=(args[ARGS_SFREQ].is_set ? args[ARGS_SFREQ].arg.d : 1000.0/header[15]); } tinfo->sfreq=local_arg->sfreq; /*{{{ Parse arguments that can be in seconds*/ local_arg->offset=(args[ARGS_OFFSET].is_set ? gettimeslice(tinfo, args[ARGS_OFFSET].arg.s) : 0); /*}}} */ tinfo->beforetrig= -local_arg->offset; tinfo->aftertrig=tinfo->nr_of_points+local_arg->offset; /*{{{ Configure myarray*/ myarray.element_skip=tinfo->itemsize=1; myarray.nr_of_vectors=tinfo->nr_of_points; myarray.nr_of_elements=tinfo->nr_of_channels=local_arg->nr_of_channels; if (array_allocate(&myarray)==NULL) { ERREXIT(tinfo->emethods, "read_freiburg: Error allocating data\n"); } tinfo->multiplexed=TRUE; /*}}} */ fseek(infile, FREIBURG_HEADER_LENGTH, SEEK_SET); if (local_arg->average_mode) { /*{{{ Read averaged epoch*/ for (point=0; point<tinfo->nr_of_points; point++) { #ifdef __GNUC__ short buffer[tinfo->nr_of_channels]; #else short buffer[MAX_NR_OF_CHANNELS]; #endif if ((int)fread(buffer, sizeof(short), tinfo->nr_of_channels, infile)!=tinfo->nr_of_channels) { ERREXIT1(tinfo->emethods, "read_freiburg: Error reading data point %d\n", MSGPARM(point)); } for (channel=0; channel<tinfo->nr_of_channels; channel++) { # ifdef LITTLE_ENDIAN Intel_int16((uint16_t *)&buffer[channel]); # endif array_write(&myarray, (DATATYPE)buffer[channel]); } } /*}}} */ } else { /*{{{ Read compressed single trial*/ # ifdef DISPLAY_ADJECTIVES char *adjektiv_ende=strchr(((char *)header)+36, ' '); if (adjektiv_ende!=NULL) *adjektiv_ende='\0'; printf("Single trial: nr_of_points=%d, nr_of_channels=%d, Adjektiv=%s\n", tinfo->nr_of_points, tinfo->nr_of_channels, ((char *)header)+36); # endif local_arg->infile=infile; do { if (freiburg_get_segment(tinfo, &myarray)!=0) { TRACEMS1(tinfo->emethods, 0, "read_freiburg: Decompression out of bounds for trial %d - skipped\n", MSGPARM(local_arg->current_trigger-1)); array_free(&myarray); trial_not_accepted=TRUE; break; } } while (myarray.message!=ARRAY_ENDOFSCAN); /*}}} */ } fclose(infile); } while (trial_not_accepted); /*}}} */ /*{{{ Look for a Freiburg channel setup for this number of channels*/ /* Force create_channelgrid to really allocate the channel info anew. * Otherwise, free_tinfo will free someone else's data ! */ tinfo->channelnames=NULL; tinfo->probepos=NULL; if (local_arg->channelnames!=NULL) { copy_channelinfo(tinfo, local_arg->channelnames, NULL); } else { while (in_channels->nr_of_channels!=0 && in_channels->nr_of_channels!=tinfo->nr_of_channels) in_channels++; if (in_channels->nr_of_channels==0) { TRACEMS1(tinfo->emethods, 1, "read_freiburg: Don't have a setup for %d channels.\n", MSGPARM(tinfo->nr_of_channels)); } else { copy_channelinfo(tinfo, in_channels->channelnames, NULL); } } create_channelgrid(tinfo); /* Create defaults for any missing channel info */ /*}}} */ if ((tinfo->comment=(char *)malloc(strlen(comment)+1))==NULL) { ERREXIT(tinfo->emethods, "read_freiburg: Error allocating comment memory\n"); } strcpy(tinfo->comment, comment); if (local_arg->zero_idiotism_warned==FALSE && local_arg->zero_idiotism_encountered) { TRACEMS(tinfo->emethods, 0, "read_freiburg: All-zero data points have been encountered and omitted!\n"); local_arg->zero_idiotism_warned=TRUE; } tinfo->z_label=NULL; tinfo->tsdata=myarray.start; tinfo->length_of_output_region=tinfo->nr_of_channels*tinfo->nr_of_points; tinfo->leaveright=0; tinfo->data_type=TIME_DATA; return tinfo->tsdata; }