/*{{{ write_rec(transform_info_ptr tinfo) {*/ METHODDEF DATATYPE * write_rec(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=local_arg->outfptr; short *inbuf; array myarray; if (tinfo->itemsize!=1) { ERREXIT(tinfo->emethods, "write_rec: Only itemsize=1 is supported.\n"); } if (args[ARGS_CLOSE].is_set) { write_rec_open_file(tinfo); outfptr=local_arg->outfptr; } /*{{{ Write epoch*/ tinfo_array(tinfo, &myarray); /* We read the data point by point, i.e. channels fastest */ array_transpose(&myarray); /* Within the record, writing is non-interlaced, ie points fastest */ do { do { inbuf=local_arg->outbuf+local_arg->samples_per_record*myarray.current_element+local_arg->current_sample; *inbuf= (short int)rint(array_scan(&myarray)/local_arg->resolution); if (!local_arg->overflow_has_occurred && (*inbuf<local_arg->digmin || *inbuf>local_arg->digmax)) { TRACEMS(tinfo->emethods, 0, "write_rec: Some output values exceed digitization bits!\n"); local_arg->overflow_has_occurred=TRUE; } #ifndef LITTLE_ENDIAN Intel_int16(inbuf); #endif } while (myarray.message==ARRAY_CONTINUE); if (++local_arg->current_sample>=local_arg->samples_per_record) { if ((int)fwrite(local_arg->outbuf, sizeof(short), tinfo->nr_of_channels*local_arg->samples_per_record, outfptr)!=tinfo->nr_of_channels*local_arg->samples_per_record) { ERREXIT(tinfo->emethods, "write_rec: Write error on data file.\n"); } /* If nr_of_records was -1 (can only happen while appending), * leave it that way */ if (local_arg->nr_of_records>=0) local_arg->nr_of_records++; local_arg->current_sample=0L; } } while (myarray.message!=ARRAY_ENDOFSCAN); /*}}} */ if (args[ARGS_CLOSE].is_set) write_rec_close_file(tinfo); return tinfo->tsdata; /* Simply to return something `useful' */ }
/*{{{ change_byteorder(char *structure, struct_member *smp) {*/ void change_byteorder(char *structure, struct_member *smp) { struct_member *in_smp; for (in_smp=smp+1; in_smp->length!=0; in_smp++) { if (in_smp->control_byteorder) { switch(in_smp->length) { case 2: Intel_int16((uint16_t *)(structure+in_smp->offset_this_compiler)); break; case 4: Intel_int32((uint32_t *)(structure+in_smp->offset_this_compiler)); break; case 8: Intel_int64((uint64_t *)(structure+in_smp->offset_this_compiler)); break; } } } }
/* 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; }
/*{{{ 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' */ }
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; }
/*{{{ 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; }
/*{{{ write_vitaport_exit(transform_info_ptr tinfo) {*/ METHODDEF void write_vitaport_exit(transform_info_ptr tinfo) { struct write_vitaport_storage *local_arg=(struct write_vitaport_storage *)tinfo->methods->local_storage; int channel, NoOfChannels=local_arg->fileheader.knum; long point; long const channellen=local_arg->total_points*sizeof(uint16_t); long const hdlen=local_arg->fileheader.hdlen; uint16_t checksum=0; local_arg->fileheaderII.dlen=hdlen+NoOfChannels*channellen; /*{{{ Write the file headers*/ # ifdef LITTLE_ENDIAN change_byteorder((char *)&local_arg->fileheader, sm_vitaport_fileheader); change_byteorder((char *)&local_arg->fileheaderII, sm_vitaportII_fileheader); change_byteorder((char *)&local_arg->fileext, sm_vitaportII_fileext); # endif write_struct((char *)&local_arg->fileheader, sm_vitaport_fileheader, local_arg->outfile); write_struct((char *)&local_arg->fileheaderII, sm_vitaportII_fileheader, local_arg->outfile); write_struct((char *)&local_arg->fileext, sm_vitaportII_fileext, local_arg->outfile); /*}}} */ for (channel=0; channel<NoOfChannels; channel++) { /*{{{ Write a channel header*/ /* This is the factor as we'd like to have it... */ float factor=((float)(local_arg->channelmax[channel]> -local_arg->channelmin[channel] ? local_arg->channelmax[channel] : -local_arg->channelmin[channel]))/SHRT_MAX; if (strncmp(local_arg->channelheaders[channel].kname, VP_MARKERCHANNEL_NAME, 6)==0) { strcpy(local_arg->channelheaders[channel].kunit, "mrk"); local_arg->channelheaders[channel].datype=VP_DATYPE_MARKER; /* Since the marker channel is read without the conversion factors, * set the conversion to 1.0 for this channel */ local_arg->channelheaders[channel].mulfac=local_arg->channelheaders[channel].divfac=1; local_arg->channelheaders[channel].offset=0; } else { float const logdiff=log(factor)-TARGET_LOG_SHORTVAL; local_arg->channelheaders[channel].offset=0; if (logdiff<0) { /*{{{ Factor is small: Better to fix divfac and calculate mulfac after that*/ double const divfac=exp(-logdiff); if (divfac>SHRT_MAX) { local_arg->channelheaders[channel].divfac=SHRT_MAX; } else { local_arg->channelheaders[channel].divfac=(unsigned short)divfac; } /* The +1 takes care that we never get below the `ideal' factor computed above. */ local_arg->channelheaders[channel].mulfac=(unsigned short)(factor*local_arg->channelheaders[channel].divfac+1); if (local_arg->channelheaders[channel].mulfac==0) { local_arg->channelheaders[channel].mulfac=1; local_arg->channelheaders[channel].divfac=(unsigned short)(1.0/factor-1); } /*}}} */ } else { /*{{{ Factor is large: Better to fix mulfac and calculate divfac after that*/ double const mulfac=exp(logdiff); if (mulfac>SHRT_MAX) { local_arg->channelheaders[channel].mulfac=SHRT_MAX; } else { local_arg->channelheaders[channel].mulfac=(unsigned short)mulfac; } /* The -1 takes care that we never get below the `ideal' factor computed above. */ local_arg->channelheaders[channel].divfac=(unsigned short)(local_arg->channelheaders[channel].mulfac/factor-1); if (local_arg->channelheaders[channel].divfac==0) { local_arg->channelheaders[channel].mulfac=(unsigned short)(factor+1); local_arg->channelheaders[channel].divfac=1; } /*}}} */ } } /* Now see which factor we actually got constructed */ factor=((float)local_arg->channelheaders[channel].mulfac)/local_arg->channelheaders[channel].divfac; local_arg->channelheadersII[channel].doffs=channel*channellen; local_arg->channelheadersII[channel].dlen=channellen; # ifdef LITTLE_ENDIAN change_byteorder((char *)&local_arg->channelheaders[channel], sm_vitaport_channelheader); change_byteorder((char *)&local_arg->channelheadersII[channel], sm_vitaportIIrchannelheader); # endif write_struct((char *)&local_arg->channelheaders[channel], sm_vitaport_channelheader, local_arg->outfile); write_struct((char *)&local_arg->channelheadersII[channel], sm_vitaportIIrchannelheader, local_arg->outfile); # ifdef LITTLE_ENDIAN change_byteorder((char *)&local_arg->channelheaders[channel], sm_vitaport_channelheader); change_byteorder((char *)&local_arg->channelheadersII[channel], sm_vitaportIIrchannelheader); # endif /*}}} */ } fwrite(&checksum, sizeof(checksum), 1, local_arg->outfile); TRACEMS(tinfo->emethods, 1, "write_vitaport_exit: Copying channels to output file...\n"); /* We close and re-open the channel file because buffering is much more * efficient at least with DJGPP if the file is either only read or written */ fclose(local_arg->channelfile); if ((local_arg->channelfile=fopen(local_arg->channelfilename, "rb"))==NULL) { ERREXIT1(tinfo->emethods, "write_vitaport_exit: Can't open temp file %s\n", MSGPARM(local_arg->channelfilename)); } for (channel=0; channel<NoOfChannels; channel++) { /*{{{ Copy a channel to the target file */ float const factor=((float)local_arg->channelheaders[channel].mulfac)/local_arg->channelheaders[channel].divfac; unsigned short const offset=local_arg->channelheaders[channel].offset; for (point=0; point<local_arg->total_points; point++) { DATATYPE dat; int16_t s; fseek(local_arg->channelfile, (point*NoOfChannels+channel)*sizeof(DATATYPE), SEEK_SET); if (fread(&dat, sizeof(DATATYPE), 1, local_arg->channelfile)!=1) { ERREXIT(tinfo->emethods, "write_vitaport_exit: Error reading temp file.\n"); } s= (int16_t)rint(dat/factor)-offset; # ifdef LITTLE_ENDIAN Intel_int16((uint16_t *)&s); # endif if (fwrite(&s, sizeof(s), 1, local_arg->outfile)!=1) { ERREXIT(tinfo->emethods, "write_vitaport_exit: Write error.\n"); } } /*}}} */ } fclose(local_arg->channelfile); unlink(local_arg->channelfilename); if (local_arg->triggers.current_length!=0) { long tagno, n_events; uint32_t length, trigpoint; int const nevents=local_arg->triggers.current_length/sizeof(struct trigger); struct vitaport_idiotic_multiplemarkertablenames *markertable_entry; /* Try to keep a security space of at least 20 free events */ for (markertable_entry=markertable_names; markertable_entry->markertable_name!=NULL && markertable_entry->idiotically_fixed_length<nevents+20; markertable_entry++); if (markertable_entry->markertable_name==NULL) { if ((markertable_entry-1)->idiotically_fixed_length<=nevents) { /* Drop the requirement for at least 20 free events */ markertable_entry--; } else { /* No use... */ ERREXIT1(tinfo->emethods, "write_vitaport_exit: %d events wouldn't fit into the fixed-length VITAGRAPH marker tables!\nBlame the Vitaport people!\n", MSGPARM(nevents)); } } n_events=markertable_entry->idiotically_fixed_length; fwrite(markertable_entry->markertable_name, 1, VP_TABLEVAR_LENGTH, local_arg->outfile); length=n_events*sizeof(length); #ifdef LITTLE_ENDIAN Intel_int32((uint32_t *)&length); #endif fwrite(&length, sizeof(length), 1, local_arg->outfile); for (tagno=0; tagno<n_events; tagno++) { if (tagno<nevents) { struct trigger * const intrig=((struct trigger *)local_arg->triggers.buffer_start)+tagno; /* Trigger positions are given in ms units */ trigpoint=(long)rint(intrig->position*1000.0/local_arg->sfreq); /* Make trigpoint uneven if code%2==1 */ trigpoint=trigpoint-trigpoint%2+(intrig->code-1)%2; } else { trigpoint= -1; } #ifdef LITTLE_ENDIAN Intel_int32((uint32_t *)&trigpoint); #endif fwrite(&trigpoint, sizeof(trigpoint), 1, local_arg->outfile); } for (; tagno<n_events; tagno++) { trigpoint= -1; #ifdef LITTLE_ENDIAN Intel_int32((uint32_t *)&trigpoint); #endif fwrite(&trigpoint, sizeof(trigpoint), 1, local_arg->outfile); } } fclose(local_arg->outfile); /*{{{ Free memory*/ free_pointer((void **)&local_arg->channelfilename); free_pointer((void **)&local_arg->channelmax); free_pointer((void **)&local_arg->channelmin); free_pointer((void **)&local_arg->channelheaders); free_pointer((void **)&local_arg->channelheadersII); if (local_arg->triggers.buffer_start!=NULL) { clear_triggers(&local_arg->triggers); growing_buf_free(&local_arg->triggers); } /*}}} */ tinfo->methods->init_done=FALSE; }