/* ebscuttr.cc Class definitions for ebstrans Copyright (C) 1993/94 C.Taegert-Kilger, Institut fuer Physiologie und Biokybernetik (IPB), Universitaet Erlangen, Deutschland Permission to use, copy, modify, distribute, and sell this software and its documentation for any purpose is hereby granted without fee, provided that the above copyright notice appear in all copies and related publications and that both that copyright notice and this permission notice appear in supporting documentation. The authors make no representations about the suitability of this software for any purpose. It is provided "as is" without express or implied warranty. Send your comments, suggestions or bug reports to ftpebs@uni-erlangen.de Or mail to Institut fuer Physiologie und Biokybernetik Markus Prosch Universitaetsstrasse 17 D-91054 Erlangen Germany $Id: ebscuttr.cc,v 1.2 1994/12/15 10:52:35 msprosch Exp $ */ #include "ebscuttr.h" #ifdef MSDOS #include #endif // Useful functions #define min(a,b) (a=b)? a : b // Useful transformation: time -> sample uint32 DetermineSample(EBSFile::EBSTm time,double sample_rate) { double ires; ires=time.fraction; ires+=time.second; ires+=time.minute/60; ires+=time.hour/3600; ires*=sample_rate; return ( (uint32) ires ); } // Try to evaluate parsed command as command help, copyright etc int EvaluateParserAsMessage(EBSParser* ebs_parser) { // Specific transfer switch (ebs_parser->command) { // Help case CUTCOMM_HELP: { fprintf(stdout,"%s",helpstring); return(1);}; // Copyright case CUTCOMM_COPYRIGHT: { fprintf(stdout,"%s",copyrightstring); return(1);}; // Else return 0 default: return 0; } } /* ----------------------------------------------------------- Methods for input params type ----------------------------------------------------------- */ // Open input file with a set of parameters EBSTransInParams::EBSTransInParams(EBSParser::InFile *in_file) :EBSFile(in_file->name,'r') { // Auxiliary variables uint32 i,ss_,ds_,ts_,lc; // Store file name P_TRACE("Input file open called with %s\n",in_file->name); filename_=new char[strlen(in_file->name)+1]; strcpy(filename_,in_file->name); P_TRACE("filename: %s\n",filename_); // Test for validity of input if (!Valid()) { WARNING(ERR_INV_INFILE, "Input file object not opened correctly",NULL); return; } // Samples P_TRACE("Getting sample rates\n"); const long unsigned int * n_samples; n_samples=GetNSamples(); P_TRACE("NSamples[]: %lx ", (unsigned long) n_samples); P_TRACE("NSamples: %lu",n_samples[0]); const double* sample_rate; sample_rate=GetSampleRate(); P_TRACE("Sample rate[]: %lx ", (unsigned long) sample_rate); P_TRACE("Sample rate: %f ",sample_rate[0]); // Fill channel translation if (in_file->channels) { lc=in_file->channels->GetLength(); n_outchannels=lc; // GetNChannels(); // Allocate memory for channels array channel_translator = new ChannelTranslator[n_outchannels]; // Fill channel translator AddInChannel( *(int*) in_file->channels->GetFirst()->GetContent(), 0,1); for (i=1; ichannels->GetContinued()->GetContent(), i,1); } else { lc=GetNChannels(); n_outchannels=lc; // GetNChannels(); // Allocate memory for channels array channel_translator = new ChannelTranslator[n_outchannels]; for (i=0; iss==0) { // try time ss_=min(*GetNSamples(),DetermineSample(in_file->st,*GetSampleRate())); } else { ss_=min(*GetNSamples(),(uint32) in_file->ss); } // Set target sample to 0 ts_=0; // Samples // try time P_TRACE("Determine samples\n"); uint32 res=DetermineSample(in_file->dt,*GetSampleRate()); if (res>0) { ds_=(uint32) res; } else { if (in_file->ds == ALL) ds_=*GetNSamples()-ss_; else ds_=(uint32) in_file->ds; } // Set data like this P_TRACE("Set data scheme \n"); SetDataScheme(ss_,ds_,ts_,0); P_TRACE("EBSTransInParams() ready\n"); }; // Modifier void EBSTransInParams::SetDataScheme(uint32 ss_, uint32 ds_,uint32 ts_, uint32 tc_) { // Store values if (ss_!=ALL) ss=ss_; if (ds_!=ALL) ds=ds_; if (ts_!=ALL) ts=ts_; if (tc_!=ALL) tc=tc_; // Store internally how many samples we have to transfer ds_i=(*GetNSamples()-ss-1) channel_translator[c_out-tc].multiplier=mul; P_TRACE("Multiplier for channel %u: %f\n",c_out,mul); } /* Destructor */ EBSTransInParams::~EBSTransInParams() // Close EBS file, free mem, etc. { delete channel_translator; // Free translation table delete filename_; } /* Add channel correspondence */ void EBSTransInParams::AddInChannel( int InChannel, int OutChannel, double multiplier) { int32 c_out; if (Valid()) { c_out=OutChannel; if (c_out < n_outchannels) { if (InChannel < (int32) GetNChannels()) { P_TRACE("Add channel translation: %i -> %i ",InChannel,OutChannel); channel_translator[c_out].source=InChannel; channel_translator[c_out].multiplier=multiplier; P_TRACE("...ok\n"); } else { char num[60]; sprintf(num,"%i in %s",InChannel,filename_); WARNING(ERR_INV_ARG,"Channel number too high: ",num); } } else { ERROR(ERR_INV_ARG,"Channel number for output out of range", NULL); }; }; }; // char* EBSTransInParams::GetFilename() { return filename_; }; // Number of channels int EBSTransInParams::GetNOutChannels() { return n_outchannels; } uint32 EBSTransInParams::GetNOutSamples() { return ds; } /* Get value of correspondence */ int EBSTransInParams::GetInChannel(int OutChannel) { int32 ic=OutChannel-tc; return (ic=0) ? (channel_translator[ic].source) : -1; }; /* Get value of correspondence */ int EBSTransInParams::GetOutChannel(int in_channel) { // Auxiliary variables int32 ch; int32 c_in; // Find in_channel in translation array for (ch=tc-1, c_in=-1; ch=0) ? (channel_translator[ic].multiplier) : 0; }; int EBSTransInParams::GetDefaultValue() { return 0; } int EBSTransInParams::GetTransformedValue( // Compute transformed value uint32 i,uint32 j) // for output channel i and output sample j { int s; uint32 nr; s=GetInChannel(i); nr=(j-ts < ds) ? j :(uint32)~0;// Allow this sample only if in range for // this input file if (s>=0 && nr!=(uint32)~0) return (int32)(Value(s,j+ss-ts) * GetMultiplier(i)); else return GetDefaultValue(); }; // Rounding routine int16 roundi16(double x) { return (x>0) ? (int32)(x+0.5) : (int32)(x-0.5); }; int EBSTransInParams::GetDataBlock( // Get data for all output channels: uint32 fch_, uint32 nch_, uint32 from_, // From output sample no uint32 n_, // get n samples int16* target) // and write to array[channels][time] { uint32 t,ch,ds_v,i; int32 c_orig; int32 from; // Compute new from from=from_-ts+ss; if (from<0) ERROR(ERR_UNKNOWN, "EBSTransInParams::GetSamples called with too small \"from_\"\n",NULL); ds_v=ds_i+ss-from; // Maximum of possible samples if (ds_v>n_) ds_v=n_; // Correct value // If time mode: // Get for time -> Get for channel // P_TRACE("EBS-Mode: %s\n",formatname(ebs_type)); // Write real values for (ch=0; chnfilters != f2->nfilters) return 0; for (i=0; infilters; i++) { if ((f1->filter[i].type != f2->filter[i].type) || (f1->filter[i].cutoff_freq != f2->filter[i].cutoff_freq) || (f1->filter[i].falloff_specified != f2->filter[i].falloff_specified) || (f1->filter[i].falloff_specified && (f1->filter[i].falloff != f2->filter[i].falloff))) return 0; } return 1; } /* Init transfer object with parsing, write to temporary file */ // Initializing input objects // ~~~~~~~~~~~~~~~~~~~~~~~~~~ int EBSTrans::CreateInputObjects() { // Auxiliary variables int i; // Count number of input files InitForNInfiles(params_parser->n_infiles); if (n_infiles==0) { WARNING(ERR_INV_INFILE,"No input files specified\n",NULL); return 0; } P_TRACE("N: %u; %s\n",n_infiles,params_parser->infile_array[0].name); // Open all input files for (i=0; in_infiles; i++) { // Open input file /* if (strcmp(params_parser->infile_array[i].name, params_parser->out_params.name)==0) { WARNING(ERR_WARNING,"Duplicate filename: ", params_parser->out_params.name); return 0; }*/ in_files[i]= new EBSTransInParams(&(params_parser->infile_array[i])); // Check validity if (!in_files[i]->Valid()) { WARNING(ERR_INV_INFILE, "Invalid input files specified: ", params_parser->infile_array[i].name); return 0; } P_TRACE("Input file opened: %s \n",params_parser->infile_array[i].name); }; // If this point is reached: Succesful return 1; }; // Compute ranges for channels & samples // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ int EBSTrans::ComputeRanges(int command) { if (command==CUTCOMM_A) { // Compute new number of channels & samples n_channels=GetMaxInChannels(); if (GetExactInChannels()==0) WARNING(ERR_WARNING,"Varying number of input channels specified",NULL); n_samples=GetSumSamples(); return 1; }; if (command==CUTCOMM_E) { n_channels=GetMaxInChannels(); n_samples=GetSumSamples(); return 1; } if (command==CUTCOMM_MS) { n_channels=GetSumInChannels(); if (GetExactInSamples()==0) WARNING(ERR_WARNING, "Varying number of samples specified",NULL); n_samples=GetMaxSamples(); return 1; } return 0; }; // Update input objects ranges appropriate to command // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ int EBSTrans::UpdateInputObjects(int command) { // Auxiliary variables uint32 ts_; int tc_,i; if (command == CUTCOMM_A || command == CUTCOMM_E) // If append: { // Adjust first target sample for each file ts_=0; for (i=0; in_infiles; i++) { in_files[i]->SetDataScheme(ALL,ALL,ts_); ts_+=in_files[i]->ds; } return 1; } // Merge: if (command == CUTCOMM_MS) { // Adjust first channel for each file tc_=0; for (i=0; in_infiles; i++) { in_files[i]->SetDataScheme(ALL,ALL,ALL,tc_); tc_+=in_files[i]->GetNOutChannels(); } return 1; } // Else: do nothing return 1; }; // Compute new starting time if any // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ void EBSTrans::ComputeStartingTime(int command) { P_TRACE("Getting time\n"); EBSTime time1; time1=in_files[0]->EBSTimeAtSampleNo(0,in_files[0]->ss); if (command==CUTCOMM_E || command==CUTCOMM_A || n_infiles==1) SetRecordingTime(time1); return; } // Create new event lists for input files // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ int EBSTrans::CreateInputFileEventLists() { // Auxiliary variables uint16 i; // Create new event lists for (i=0; iGetFilename())]; sprintf(c,"%u:%s",i+1,in_files[i]->GetFilename()); AppendFileEvents(in_files[i],c); delete c; } return 1; } // Determine output format, initialize data part, sample rate // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ int EBSTrans::InitializeData() { // Auxiliary variables uint32 i; // Initialize data part: // - Find format ebs_format=formatid(params_parser->out_params.format); if (ebs_format<0) { WARNING(ERR_INV_ARG, "Wrong ebs format specified: ",params_parser->out_params.format); return 0; } if (ebs_format != EBS_CIB_16 && ebs_format != EBS_TIB_16 && ebs_format != EBS_TIL_16 && ebs_format != EBS_CIL_16) { WARNING(ERR_INV_ARG, "Ebs format not supported: ", params_parser->out_params.format); return 0; } // - Do initialization InitDataPart( ebs_format, n_channels,n_samples); // Compute new sample rate double* sample_rate; sample_rate = new double [n_channels]; double r; r=GetExactSampleRate(); if (r==0) { WARNING(ERR_INCOMPATIBLE_DATA, "Sample rates do not match.\n",NULL); return 0; } for (i=0; iGetInChannel(ch); if (ch_orig>-1) { // Get filters for this channel const Filters* arr_filters; arr_filters= in_files[nf]->GetFilters(); // Test for non-existing filters if (!arr_filters) { filters[ch].nfilters=0; } else { hf=arr_filters[ch_orig]; // If empty as yet: Use value to fill if (filters[ch].nfilters==-1) filters[ch]=hf; // Else test for identity and issue warning if not else { if (!IsEqual(&hf,&filters[ch])) { WARNING(ERR_WARNING,"Filters do not match.",NULL); filters[ch].nfilters=0; } } } } } // Fill with 0 if not specified if (filters[ch].nfilters==-1) filters[ch].nfilters=0; } // Set filters SetFilters(filters); // Free filters array delete filters; return 1; }; // Transform location diagram & info // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ void EBSTrans::TransferLocationDiagrams() { if (n_infiles==1) { LocationDiagram const* ld; ChannelLocations const* cl; ChannelLocations cl2; ld=in_files[0]->GetLocationDiagram(); if (ld!=NULL) { P_TRACE("Valid location diagram found\n"); SetLocationDiagram(ld); // Get Channel locations of input file cl=in_files[0]->GetChannelLocations(); // If not == NULL: build new location diagram if (cl!=NULL) { // Initialize number and array cl2.nlocations=0; cl2.location = new ChannelLocation[cl->nlocations]; // Transfer electrode positions int32 icl, c_new; for (icl=0; iclnlocations; icl++) { // Find new channel for old one c_new = in_files[0]->GetOutChannel( cl->location[icl].channel); if (c_new>-1) { P_TRACE("Location for old %lu -> new %lu\n", (unsigned long) cl->location[icl].channel, (unsigned long) c_new); cl2.location[cl2.nlocations] = cl->location[icl]; cl2.location[cl2.nlocations].channel=c_new; cl2.nlocations++; } } // Transfer channel locations data SetChannelLocations(&cl2); delete cl2.location; } } } else { WARNING(ERR_WARNING,"Location diagrams are discarded",NULL); } } // Transfer channel groups // ~~~~~~~~~~~~~~~~~~~~~~~ void EBSTrans::TransferChannelGroups() { // Auxiliary variables int i, j, c, c2, n_chg, n_c; // Seek all input files for channel groups and transport these n_chg = 0; const ChannelGroups** in_cg; ChannelGroups new_cg; // Collect channel groups & lengths in_cg= new const ChannelGroups* [n_infiles]; for (i=0; iGetChannelGroups(); if (in_cg[i]) n_chg += in_cg[i]->ngroups; } // Allocate new channel groups array with number of groups new_cg.group = new ChannelGroup[n_chg]; // Recurse input files, start with target channel group 0 for (i=0, c=0; ingroups; j++, c++) { // Read group & constrain to included channels new_cg.group[c].description=in_cg[i]->group[j].description; new_cg.group[c].name=in_cg[i]->group[j].name; new_cg.group[c].channel= new uint32[in_cg[i]->group[j].nchannels]; new_cg.group[c].nchannels=0; // ... recurse channels of group : n_c=0; for (c2=0; c2group[j].nchannels; c2++) // Store output channel in nc if (n_c=in_files[i]-> GetOutChannel(in_cg[i]->group[j].channel[c2]) > -1) { new_cg.group[c].channel[new_cg.group[c].nchannels++]=n_c; } } } } // Store number of successfully read input channel groups new_cg.ngroups=c; // Store channel groups in file SetChannelGroups(&new_cg); for (i=0; iGetNChannels(); old_cd=in_files[f]->GetChannelDescription(); if (old_cd) { for (c=0; cGetOutChannel(c)) new_cd[c_t] = old_cd[c]; } } } SetChannelDescription(new_cd); delete new_cd; } else WARNING(ERR_WARNING,"Discarding channel descriptions",NULL); } // Transfer data from input files // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ int EBSTrans::TransferData(int command) { // Auxiliary variables uint32 iwf,n_dbl; n_dbl=0; char c_n_dbl[10]; // Message MESSAGE("Transferring data\n",NULL,NULL); // Case append if (command == CUTCOMM_A || command == CUTCOMM_E) { // Transfer data int16* databuf; uint32 size_alloc,size_block_samples; for (iwf=0; iwfds; P_TRACE("array sizes: %lx %lx\n", (unsigned long) size_alloc*sizeof(int16), (unsigned long) MAX_ARRAYLEN); if (size_alloc*sizeof(int16)<=MAX_ARRAYLEN) { databuf=new int16[n_channels * in_files[iwf]->ds]; if (databuf==NULL) ERROR(ERR_INSUFFICIENT_MEMORY, "Set MAX_ARRAYLEN in ebscuttr.h to lower value", NULL); in_files[iwf]->GetDataBlock( 0, n_channels, in_files[iwf]->ts, in_files[iwf]->ds, databuf); WriteDataBlock( in_files[iwf]->ts, in_files[iwf]->ds, 0,n_channels, databuf); delete [] databuf; } else { uint32 size_samples,size_next_samples,sample_pointer; // How many samples to write in one turn size_block_samples=MAX_ARRAYLEN / (sizeof(int16)*n_channels); databuf=new int16[size_block_samples*n_channels]; sample_pointer=0; size_samples=in_files[iwf]->ds; do { // Message sprintf(c_n_dbl,"%-8lu", (unsigned long) n_dbl++); MESSAGE("Transferring data block no.",c_n_dbl,"\n"); // Determine size of next block to write size_next_samples= (size_samples-sample_pointer < size_block_samples) ? size_samples-sample_pointer : size_block_samples; in_files[iwf]->GetDataBlock( 0, n_channels, in_files[iwf]->ts + sample_pointer , size_next_samples , databuf); WriteDataBlock( in_files[iwf]->ts + sample_pointer, size_next_samples, 0,n_channels, databuf); // Increase sample pointer by samples written sample_pointer+=size_next_samples; } while (sample_pointer < size_samples); delete [] databuf; } } // Data ready return(EndOfWritingData()==0); } if (command == CUTCOMM_MS) { // Transfer data int16* databuf; uint32 size_alloc,size_block_samples; for (iwf=0; iwfGetNOutChannels()*n_samples; P_TRACE("array sizes: %lx %lx\n", (unsigned long) size_alloc*sizeof(int16),(unsigned long) MAX_ARRAYLEN); if (size_alloc*sizeof(int16)<=MAX_ARRAYLEN) { databuf=new int16[size_alloc]; in_files[iwf]->GetDataBlock( in_files[iwf]->tc, in_files[iwf]->GetNOutChannels(), 0, n_samples, databuf); WriteDataBlock( 0, n_samples, in_files[iwf]->tc, in_files[iwf]->GetNOutChannels(), databuf); delete [] databuf; } else { uint32 size_samples,size_next_samples,sample_pointer; // How many samples to write in one turn size_block_samples=MAX_ARRAYLEN / (sizeof(int16)* in_files[iwf]->GetNOutChannels()); databuf=new int16[size_block_samples* in_files[iwf]->GetNOutChannels()]; sample_pointer=0; size_samples=n_samples; do { // Message sprintf(c_n_dbl,"%-8lu", (unsigned long) n_dbl++); MESSAGE("Transferring data block no.",c_n_dbl,"\n"); // Determine size of next block to write size_next_samples= (size_samples-sample_pointer < size_block_samples) ? size_samples-sample_pointer : size_block_samples; in_files[iwf]->GetDataBlock( in_files[iwf]->tc, in_files[iwf]->GetNOutChannels(), sample_pointer , size_next_samples , databuf); WriteDataBlock( sample_pointer, size_next_samples, in_files[iwf]->tc, in_files[iwf]->GetNOutChannels(), databuf); // Increase sample pointer by samples written sample_pointer+=size_next_samples; } while (sample_pointer < size_samples); delete [] databuf; } } // Data ready return(EndOfWritingData()==0); } return 0; } // Constructor which reads from command line parser // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ EBSTrans::EBSTrans(EBSParser* ebs_parser): EBSFile(ebs_parser->out_params.name,'w') { // Check if valid if (!Valid()) return; // Store command line param_string= new char [strlen(ebs_parser->program_name)+ strlen(ebs_parser->args_orig)+4 ]; strcpy(param_string,ebs_parser->program_name); strcat(param_string," "); strcat(param_string,ebs_parser->args_orig); // Store parsing object params_parser=ebs_parser; // Some basic initializations n_eventlists=0; // Check validity if (!Valid()) return; }; // Data deriving functions double EBSTrans::GetExactSampleRate() { if (params_parser->special_options.sample_rate > 0 ) return params_parser->special_options.sample_rate; else { uint32 i; double sr; sr=*in_files[0]->GetSampleRate(); for (i=1;(iGetSampleRate()) ? sr : 0); }; return sr; } }; int EBSTrans::DeriveUnitsAndRange() { int i,ch; char str_null[]=""; // Units // Allocate & initialize array for new units Unit* units = new Unit[n_channels]; const EBSFile::Unit **in_units; in_units = new const EBSFile::Unit* [n_infiles]; // Set default values for units for (i=0; ifilename_); // Get units in_units[i] = in_files[i]->GetUnits(); P_TRACE("... got them\n"); // Catch empty units if (!in_units[i]) WARNING(ERR_WARNING,"No units specified in ", in_files[i]->filename_); else { // For each channel: Check units (quotient: later) for (ch=0; chGetInChannel(ch); if (ch_orig>=0) { // Check with units if (units[ch].specified < 0) { units[ch].specified=in_units[i][ch_orig].specified; units[ch].unit=in_units[i][ch_orig].unit; } else { if (units[ch].specified != in_units[i][ch_orig].specified) WARNING(ERR_WARNING, "Specified units together with unspecified ones\n", NULL); if (units[ch].specified && in_units[i][ch_orig].specified) if (strcmp(units[ch].unit,in_units[i][ch_orig].unit)!=0) { char* errmess; errmess=new char[strlen(units[ch].unit)+ strlen(in_units[i][ch_orig].unit)+9]; strcpy(errmess,in_units[i][ch_orig].unit); strcat(errmess," with "); strcat(errmess,units[ch].unit); if (strcmp(units[ch].unit,"")==0 || strcmp(in_units[i][ch_orig].unit,"")==0) WARNING(ERR_WARNING,"Putting together with empty unit:", errmess); else ERROR(ERR_UNKNOWN,"Units do not match:",errmess); delete[] errmess; } } } } } } // Set all units to unspecified if necessary for (i=0; iGetPreferredIntegerRange(); P_TRACE("... done\n"); if (!pref_int_range_orig[i]) { ERROR(ERR_UNKNOWN,in_files[i]->filename_, ": No integer ranges spec.\n"); } } // Maximum & minimum of range * quotient (= maximal possible value) double *range_min= new double[n_channels]; double *range_max= new double [n_channels]; for (i=0; i New preferred integer range for (ch=0; chGetInChannel(ch); double ch_quotient; ch_quotient= (in_units[i]) ? in_units[i][ch_orig].quotient : 1; if (ch_orig>-1) { if (range_specified[ch]) { // Update preferred integer ranges pref_int_range[ch].min= (pref_int_range[ch].min< pref_int_range_orig[i][ch_orig].min) ? pref_int_range[ch].min : pref_int_range_orig[i][ch_orig].min; pref_int_range[ch].max= (pref_int_range[ch].max> pref_int_range_orig[i][ch_orig].max) ? pref_int_range[ch].max : pref_int_range_orig[i][ch_orig].max; // Update range of physical values range_min[ch]=min( range_min[ch], pref_int_range_orig[i][ch_orig].min * ch_quotient) * params_parser->special_options.mul_val; range_max[ch]=max( range_max[ch], pref_int_range_orig[i][ch_orig].max * ch_quotient)* params_parser->special_options.mul_val; } else { // Case first specification: // Set integer ranges pref_int_range[ch].min=pref_int_range_orig[i][ch_orig].min; pref_int_range[ch].max=pref_int_range_orig[i][ch_orig].max; P_TRACE("Integer ranges for channel %lu set to %li %li\n", (unsigned long) ch, (long) pref_int_range[ch].min, (long)pref_int_range[ch].max); // Compute physical ranges range_min[ch]=pref_int_range_orig[i][ch_orig].min* ch_quotient * params_parser->special_options.mul_val; range_max[ch]=pref_int_range_orig[i][ch_orig].max* ch_quotient * params_parser->special_options.mul_val; // Set RANGE SPECIFIED for this channel range_specified[ch]=1; } }; }; // for n_infiles // Set ranges for channel if not specified if (!range_specified[ch]) { range_max[ch]=2047; range_min[ch]=-2048; pref_int_range[ch].max=2047; pref_int_range[ch].min=-2048; } // Set ranges if extra options are given if (params_parser->special_options.int_range_max>0) pref_int_range[ch].max= params_parser->special_options.int_range_max; if (params_parser->special_options.int_range_min<0) pref_int_range[ch].min= params_parser->special_options.int_range_min; // Now we have got minimum and maximum values for each channel // -> new quotient: double f_max,f_min; f_max= (pref_int_range[ch].max==0) ? 1 : range_max[ch] / pref_int_range[ch].max; f_min= (pref_int_range[ch].min==0) ? 1 : range_min[ch] / pref_int_range[ch].min; units[ch].quotient= (f_max>f_min) ? f_max : f_min; P_TRACE("Quotient & ranges: %li %li %f\n", (long) pref_int_range[ch].min, (long) pref_int_range[ch].max, units[ch].quotient); }; // Compute multiplier for each channel in each input file P_TRACE("Finding multipliers (multiplied by %f)\n", params_parser->special_options.mul_val); for (i=0; iGetInChannel(ch); if (c_orig>-1) { if (in_units[i] != NULL) { P_TRACE("Multipliers: old %f, mul %f, trans %f\n", in_units[i][c_orig].quotient, params_parser->special_options.mul_val, units[ch].quotient); in_files[i]->SetMultiplierForChannel(ch, in_units[i][c_orig].quotient * params_parser->special_options.mul_val / units[ch].quotient ); } else { // Special case: No input units P_TRACE("m"); P_TRACE("Multipliers: %f\n", units[ch].quotient); in_files[i]->SetMultiplierForChannel(ch, params_parser->special_options.mul_val / units[ch].quotient); } } } } // Set units SetUnits(units); SetPreferredIntegerRange(pref_int_range); P_TRACE("Units & ranges done\n"); delete [] range_max; delete [] range_min; delete [] range_specified; delete [] pref_int_range_orig; delete [] pref_int_range; delete [] in_units; delete [] units; return(1); // For each channel :- // Get & check units; if not equal for valid channels: return 0 }; // Append new events created by start and end of input file void EBSTrans::AppendFileEvents(EBSTransInParams* in_file,char* desc) { int nc=0,i; Event* events; int count=0; // Count number of real input channels of in_file for (i=0; iGetInChannel(i) > -1) nc++; // Allocate memory for nc events, set events counter events = new Event[nc]; // Create new events for (i=0; iGetInChannel(i) > -1) { events[count].channel=i; events[count].position=in_file->ts; events[count].length=in_file->ds_i; events[count].description=desc; count++; }; } AppendEventlist("VALID",in_file->filename_,count,events); delete events; }; int EBSTrans::GetMaxInChannels() { int i, ch=0; for (i=0;iGetNOutChannels()); }; return ch; }; int EBSTrans::GetSumInChannels() { int i,ch=0; for (i=0;iGetNOutChannels(); }; return ch; }; int EBSTrans::GetExactInChannels() { int i,ch; ch=in_files[0]->GetNOutChannels(); for (i=1;iGetNOutChannels())? ch : 0; }; return ch; }; int EBSTrans::GetExactInSamples() { int i,ds; ds=in_files[0]->ds; for (i=1;ids)? ds : 0; }; return ds; }; uint32 EBSTrans::GetMaxSamples() { uint32 i,ds=0; for (i=0;ids); }; return ds; }; uint32 EBSTrans::GetSumSamples() { uint32 i,ds=0; for (i=0;ids; }; return ds; }; // Append a new event list int EBSTrans::AppendEventlist(char* name, char* description, uint32 nevents, Event* events) { if (n_eventlists==0) { n_eventlists++; return(SetEventlist(name,description,nevents,events)); }; n_eventlists++; return(AppEventlist(name,description,nevents,events)); }; void EBSTrans::GetInputEventLists() { int i,i1,i2,ne=0,e,ev,nevents,newlen,helplen,newpos;const EventList* el; Event* events; const Event* read_event; Event new_event; P_TRACE("Memory at start of GetInputEventList: %lu\n", (unsigned long) coreleft()); for (i=0; iGetNEventLists(); if (ne>0) { for (e=0; eGetEventList(e); P_TRACE("Memory after GetEventList: %lu\n", (unsigned long)coreleft()); events=(Event*) malloc(sizeof(Event) * el->nevents); in_files[i]->RewindEventList(e); nevents=0; for (ev=0; evnevents; ev++) { // If considered event is in range add it: read_event=in_files[i]->GetNextEvent(e); // Find out which channel i2=-1; for (i1=0; i1GetInChannel(i1) == read_event->channel)? i1: -1; // Found channel? if (i2>=0) // YES! { new_event=*read_event; // New position & length - first iteration: Cut head newpos=new_event.position-in_files[i]->ss; newlen=new_event.length; // If newpos<0: Cut length, set newpos to 0 newlen=(newpos<0) ? (newlen+newpos) : newlen; newpos=(newpos<0) ? 0 : newpos; helplen=in_files[i]->ds-newpos; newlen=(helplends)? newpos : -1; // Move by ts if (newpos>=0 && newlen>=0) { newpos+=in_files[i]->ts; new_event.position = newpos ; new_event.length = newlen; events[nevents]=new_event; nevents++; P_TRACE("Event: %s %lu %lu %lu\n", new_event.description, (unsigned long) new_event.channel, (unsigned long) new_event.position, (unsigned long) new_event.length); } } } // Write modified event list AppendEventlist(el->name,el->description,nevents,events); free(events); P_TRACE("Memory after GetEventList: %lu\n", (unsigned long)coreleft()); } } } P_TRACE("Memory at end of GetInputEventList: %lu\n", (unsigned long) coreleft()); } // Find out patient's new name etc. void EBSTrans::ComputeNewPatientsData() { if (n_infiles==0) return; int i; // Check consistency of names & write patient dependent data const char* j=in_files[0]->GetPatientName(); char no_name[]="No unique name (merged file)"; for (i=1; iGetPatientName(); if (!j_i || strcmp(j_i,j)!=0) j=no_name; } P_TRACE("Patient's name: %s\n",j); SetPatientName(j); // Birthday EBSTime th = in_files[0]->GetPatientBirthday(); EBSTime t_null; t_null.info = no_date_or_time; EBSFile::Sex j1=sex_unknown; int j2=1; for (i=1; iGetPatientBirthday()), EBSTimeToString(th))!=0) j2=0; if (j2) SetPatientBirthday(th); else SetPatientBirthday(t_null); P_TRACE("Patient's birthday set\n"); j1=in_files[0]->GetPatientSex(); for (i=1; iGetPatientSex()) j1=sex_unknown; SetPatientSex(j1); j=in_files[0]->GetPatientID(); char no_id[]="No unique id (merged file)"; for (i=1; iGetPatientID(); if (!j_i || strcmp(j_i,j)!=0) j=no_id; } SetPatientID(j); P_TRACE("Patient ID set to %s\n",j); }; // Find out institution void EBSTrans::ComputeNewInstitution() { int i,res,len=1; char* j; if (n_infiles==0) {} else { // First check if institution is the same j= new char [strlen(in_files[0]->GetInstitution())+2]; strcpy(j,in_files[0]->GetInstitution()); res=1; for (i=1; iGetInstitution())==0); if(res) { SetInstitution(j); } else { delete j; for (i=0; iGetInstitution()) + 15; j=(char*) malloc(len*sizeof(char)); strcpy(j,""); for (i=0; iGetInstitution()); strcat(j,"\n"); } SetInstitution(j); } P_TRACE("Institution set to %s\n",j); delete j; } }; // Create new processing history void EBSTrans::ComputeNewProcessingHistory() { // Check for number of input files if (n_infiles==0) return; int i,k,n; const ProcessingHistory* proc_hist; ProcessingHistory proc_hist_new; // Determine summed up number of lines proc_hist_new.nlines =0; // Add number of original lines for (i=0; i // GetProcessingHistory(); if (proc_hist) proc_hist_new.nlines+=proc_hist->nlines; // + number of original lines } // Add two lines for this file proc_hist_new.nlines+=3; // Create new lines array proc_hist_new.line = new char* [proc_hist_new.nlines]; // Initialize line counter n=0; // Add new history strings proc_hist_new.line[n++]=strdup(historystring); proc_hist_new.line[n++]=strdup(param_string); time_t atime; time(&atime); char* atime_c=ctime(&atime); P_TRACE("Time: %s",atime_c); proc_hist_new.line[n]=strdup(atime_c); proc_hist_new.line[n][strlen(proc_hist_new.line[n])-1]='\0'; n++; // Fill lines array char *linebuf; for (i=0; iGetProcessingHistory(); if (proc_hist != NULL) { linebuf = new char[strlen(in_files[i]->filename_) + 14]; strcpy(linebuf,">Input: "); strcat(linebuf,in_files[i]->filename_); proc_hist_new.line[n++]=linebuf; for (k=0; knlines;k++) { proc_hist_new.line[n]=new char[strlen(proc_hist->line[k])+4]; strcpy(proc_hist_new.line[n],"> "); strcat(proc_hist_new.line[n],proc_hist->line[k]); n++; } } } // Adjust processing history: Number of lines proc_hist_new.nlines=n; // Set new processing history SetProcessingHistory(&proc_hist_new); P_TRACE("New processing history with %u lines\n",proc_hist_new.nlines); // Dispose everything for (i=0;iGetShortDescription(); if (di) len+=strlen(di) + 15; } j=(char*) malloc(len*sizeof(char)); strcpy(j,""); for (i=0; iGetShortDescription(); if (di) { sprintf(num,"Part %u:\n",i+1); strcat(j,num); strcat(j,in_files[i]->GetShortDescription()); strcat(j,"\n"); } } SetShortDescription(j); free(j); for (i=0; iGetDescription(); if (di) len+= strlen(di)+15; } j=(char*) malloc(len*sizeof(char)); strcpy(j,""); for (i=0; iGetShortDescription(); if (di && !(strcmp(di,"")==0)) { char num[11]; sprintf(num,"File %u:\n",i+1); strcat(j,num); strcat(j,in_files[i]->GetDescription()); strcat(j,"\n"); } } SetDescription(j); P_TRACE("Description set to %s\n",j); free(j); } }; // Dispose everything necessary EBSTrans::~EBSTrans() { delete[] param_string; DeleteInFiles(); // Call necessary disposing functions }; void EBSTrans::InitForNInfiles(int n) // Alloc mem for n input files { // and initialize with NULL n_infiles = n; in_files = (EBSTransInParams**) malloc(n*sizeof(EBSTransInParams*)); for (int i=0; iParse(&args); delete p; // Command not found if (!res) return 0; // Command found return command; } // Parse other parameters in respect to command given int EBSParser::ParseParameters(int command_) { // Auxiliary variables int i, res; Parser* p; // Store command... command=command_; // Behave according to it if (command == CUTCOMM_HELP || command == CUTCOMM_COPYRIGHT) return(1); // Simple extract (cut) // Simple append if (command == CUTCOMM_A || command == CUTCOMM_E || command == CUTCOMM_MS) { // Create parsing object p=new ParserChoice( new List( // Parse a -t target f.. and ParserInParams(), // a -s source ... @ source ... new List( ParserOutParams(), // parameter, ParserSpecialOptions() )), 1,1); // use once, consume all res= p->Parse(&args); // Try evaluation P_TRACE("THIS: %lx\n", (long) this); if (!res) // If not possible: { WARNING(ERR_INV_ARG, "Invalid argument list for command append -a or -e .\n", NULL); return 0; // Return 0 } // Trace input parameters P_TRACE("Number of input files: %u\n",n_infiles); if (command == CUTCOMM_E && n_infiles>1) { WARNING(ERR_INV_ARG, "Too many input files for parameter -e\n",NULL); return 0; } P_TRACE("Special options: %f %f %i %i\n", special_options.mul_val, special_options.sample_rate, special_options.int_range_min, special_options.int_range_max); for (i=0; iInsertAfter(new_channel); return(1); }; }; /* +++ */ // Actual parser for tagged input parameters Parser* res =(Parser*) new ParserChoice( new List( new ParserFormat( (void*) p->infile_read.name , "%[a-zA-Z1-90_-./\\]" ,1), // file name is obligatory component new List( new ParserSelection( new ParserTag("ss", new ParserFormat( &p->infile_read.ss, "%li")), new ParserTag("st", ParserTime(&p->infile_read.st)) ), new List( new ParserSelection( new ParserTag("ds", new ParserFormat( &p->infile_read.ds, "%li")), new ParserTag("dt", ParserTime(&p->infile_read.dt)) ), new List( // Element: -c channel1,channel2,... (usage -1) or -q all or nothing new ParserTag("c", new ParserChannelList(&p->infile_read.channels)), new ParserConstant(":",NULL,1,1,-2) ))))); return res; } // Special List parser type for more than one input file /* Constructor */ EBSParser::ParserInputList::ParserInputList(EBSParser *parent_): ParserList( parent_->ParserInArgs(parent_), new ParserConstant("@",NULL,1), NULL,1) // Usage 1 { parent=parent_; }; /* Iterating function */ int EBSParser::ParserInputList::InputFn() { strcpy( parent->infile_array[parent->n_infiles].name, parent->infile_read.name); parent->infile_array[parent->n_infiles].ds=parent->infile_read.ds; parent->infile_array[parent->n_infiles].ss=parent->infile_read.ss; parent->infile_array[parent->n_infiles].dt=parent->infile_read.dt; parent->infile_array[parent->n_infiles].st=parent->infile_read.st; parent->infile_array[parent->n_infiles].channels=parent->infile_read.channels; parent->infile_read = parent->infile_default; P_TRACE("ParserInputList, InputFn(): n %lu, name %s, command %lu, addr %lx\n", (unsigned long) parent->n_infiles, parent->infile_array[parent->n_infiles].name, (unsigned long) parent->command, (unsigned long) parent); parent->n_infiles++; return(1); }; /* +++ */ // Parser for complete input files list Parser* EBSParser::ParserInParams() { ParserTag* p=new ParserTag("-s",(Parser*) new ParserInputList(this),1); return p; }; // Parser for one single input file Parser* EBSParser::ParserSingleInParams() { ParserTag* p=new ParserTag("-s",ParserInArgs(this),1); return p; }; // Parser for time structure Parser* EBSParser::ParserTime(EBSFile::EBSTm *tm) { tm->year=0; tm->month=0; tm->day=0; tm->hour=0; tm->minute=0; tm->second=0; tm->fraction=0; return new ParserBag( new List( new ParserFormat(&tm->hour,"%u",1), new List( new ParserTag(":",new ParserFormat(&tm->minute,"%u",1)), new List( new ParserTag(":",new ParserFormat(&tm->second,"%u",1)), new ParserFormat(&tm->fraction,"%lf",-1) )))); };