// ebscalc.cc #include "ebscalc.h" #include "convolute.h" #include "correlate.h" #include "lincorrelation.h" #include "fft.h" extern "C" { #include #include #include #include #include #include #include #include int unlink(char*); } static char *mystrdup(char const *todup) { if(todup == NULL) return NULL; char *p = new char[strlen(todup)+1]; strcpy(p, todup); return p; } int InCurvePointers(EBScurve*); // true = 1 , false = 0 int InFilePointers(EBSFile*); void InsertInFilePointers(EBScurve*); void AppendFilePointers(EBScurve*); struct ebsfile_pointer { EBSFile *ebsfile; curve_pointers *next_curve; ebsfile_pointer *next_file; unsigned long channels; // how many channels for that file unsigned long maxlength; // of samples in the channels (is not used // in the next version of EBS with variable channel length) }; // to hold selve created curves tmp and files to give the memory later free static curve_pointers *CurvePointers = NULL; static curve_pointers *OutPointers = NULL; static tmp_pointers *TmpPointers = NULL; static ebsfile_pointer *FilePointers = NULL; // just for testing and debugging (maybe remove later) void info(ebsfile_pointer *go) { curve_pointers *cgo; fprintf(stderr, "Info ueber FilePointers.\n"); while(go != NULL) { fprintf(stderr, "next_file %p\n", go->next_file); cgo = go->next_curve; while(cgo != NULL) { fprintf(stderr, "curve %p\n", cgo->curve); cgo = cgo->next_curve; } go = go->next_file; } } int EvaluateAll(void) { curve_pointers *gothrough1; ebsfile_pointer *gothrough2; // gothrough2 is a pointer to a chain of ebs files (were the output is // written to). // gothrough1 is a pointer to go through the channels of an ebs file. gothrough1 = OutPointers; // built evaluation tree in file and channel order. while(gothrough1 != NULL) { if(InFilePointers(gothrough1->curve->EbsFile)) { InsertInFilePointers(gothrough1->curve); } else { AppendFilePointers(gothrough1->curve); } gothrough1 = gothrough1->next_curve; } gothrough2 = FilePointers; info(gothrough2); EBScurve *wcurve; EBSFile *wfile; unsigned long i, chn; int err = 0; while(gothrough2 != NULL) { wfile = gothrough2->ebsfile; wcurve = gothrough2->next_curve->curve; gothrough1 = gothrough2->next_curve; wcurve->info(); // built all the attributes which are needed for the data part. // built and set samplerate double *samplerate = new double [gothrough2->channels]; gothrough1 = gothrough2->next_curve; for(i = 0; i < gothrough2->channels; i++) { samplerate[i] = gothrough1->curve->SampleRate; gothrough1 = gothrough1->next_curve; } if(wfile->SetSampleRate(samplerate) == -1) { fprintf(stderr, "Can't set the sample rate.\n"); delete [] samplerate; return -1; } delete [] samplerate; // built and set units chn = gothrough2->channels; wfile->SetNChannels(chn); // set the number of chn. for the new ebs file EBSFile::Unit nunits[chn]; gothrough1 = gothrough2->next_curve; for(i = 0; i < chn; i++) { if(gothrough1 == NULL) return 0; nunits[i].quotient = gothrough1->curve->ScaleFactor; nunits[i].unit = gothrough1->curve->SIUnit; nunits[i].specified = gothrough1->curve->UnitSpec; gothrough1 = gothrough1->next_curve; } wfile->SetUnits(nunits); // Achtung: folgendes kommt erst in der naechsten // Version von EBS // *********************************************************** // baue physikal und integer MIN / MAX auf // *********************************************************** // schreibe physical min, max / integer min, max // imin = (pmin + bias) / scale; // imax = (pmax + bias) / scale; // kommt erst in der naechsten EBS Version. // ********** // built BIAS // write the length and samplerate of the different channels // this is not used in this version of ebs // ********** // schreibe Laengenangaben fuer die verschiedenen Kanaele // *** don't write attributes below that line! *** if(wfile->InitDataPart(EBS_CIB_16, gothrough2->channels, gothrough2->maxlength) == -1) { fprintf(stderr, "InitDataPart failed!\n"); return -1; } err = 0; gothrough1 = gothrough2->next_curve; while(gothrough1 != NULL) { if(gothrough1->curve->Evaluated == 0) err += EvaluateCurve(gothrough1->curve); if(err == 0) err += gothrough1->curve.WriteCurve(gothrough2->maxlength); gothrough1->curve->Reference -= 1; LoseDependency(gothrough1->curve); if(err > 0) break; gothrough1 = gothrough1->next_curve; } if(err > 0) return err; // call end of writing data gothrough2->ebsfile->EndOfWritingData(); // for that EBS file gothrough2 = gothrough2->next_file; } return err; } int EBScurve::WriteCurve(unsigned long maxlength) { // write the curve to an ebs file EBSFile *ebsfile = EbsFile; EBStmp *tmp = Leaf; unsigned long channel = OutChannel; if(OutLength == ~0) OutLength = NumOfSamples - OutOffset; tmp->RewindSample(); unsigned long i; if(CurveType == EBS_IN_TIME) { ebsfile.SetNextDatumOnChn(channel, tmp->GetSample(OutOffset)+(short)(Bias/ScaleFactorCalc)); for(i = 1; i < OutLength; i++) ebsfile.SetNextDatumOnChn(channel, tmp->GetNextSample()+(short)(Bias/ScaleFactorCalc)); } else { // CurveType == EBS_IN_FREQUENCE Complex value; short svalue; for(i = 0; i < OutOffset; i++) tmp->GetNextComplex(); for(i = 0; i < OutLength; i++) { value = tmp->GetNextComplex(); // the abs. value of the complex number will be written svalue = (short)(sqrt(value.real()*value.real() +value.imag()*value.imag())*ScaleFactor);//* ebsfile.SetNextDatumOnChn(channel, svalue); } } tmp->CloseFile(); // this is needed in this version of ebs, where all channels must have // the same sample rate and the same length. // the channels who are shorter will be zero padded at the end for(i = 0; i < (maxlength - OutLength); i++) ebsfile.SetNextDatumOnChn(channel, 0); return 0; } int EvaluateCurve(EBScurve *curve) { #ifdef DEBUG fprintf(stderr, "Calculating curve >%s<. ", curve->Description); fprintf(stderr, "BindType: %d\n" , curve->CurveBindType); #endif if(curve->Evaluated == 1) { fprintf(stderr, " allready evaluated!\n"); return 0; } if(curve->CurveBindType == EBS_BIND_TO_CURVE) { EvaluateCurve(curve->Curve1); // Curve1 is now bound to a TMP_CLASS - make a copy of this // and bind curve to it EBStmp *tmp; tmp = new EBStmp; AddInTmpPointers(tmp); tmp->BindType = curve->Curve1->Leaf->BindType; tmp->FileName = mystrdup(curve->Curve1->Leaf->FileName); tmp->NumOfSamples = curve->Curve1->Leaf->NumOfSamples; tmp->ChannelNumber = curve->Curve1->Leaf->ChannelNumber; tmp->SampleOffset = curve->Curve1->Leaf->SampleOffset; tmp->CurveType = curve->Curve1->Leaf->CurveType; tmp->CutOffset = curve->CutOffset; tmp->AddCurve(curve); curve->CurveBindType = EBS_BIND_TO_TMP_CLASS; curve->Leaf = tmp; curve->Curve1->RemoveCurve(curve); LoseDependency(curve->Curve1); curve->Evaluated = 1; return 0; } else if(curve->CurveBindType == EBS_BIND_TO_EVALUATION) { EBScurve *Curve1, *Curve2; Curve1 = curve->Curve1; Curve2 = curve->Curve2; double SampleRate; unsigned long NumOfSamples; EvaluateCurve(Curve1); if(Curve2 != NULL) EvaluateCurve(Curve2); // determine the temp Leafs EBStmp *tmp1, *tmp2; if(Curve2 != NULL) { if(Curve1->SampleRate != Curve2->SampleRate) { if(Curve1->SampleRate > Curve2->SampleRate) { tmp2 = ChangeSampleRate(Curve2, Curve1->SampleRate); AddInTmpPointers(tmp2); tmp1 = Curve1->Leaf; } else { tmp1 = ChangeSampleRate(Curve1, Curve2->SampleRate); AddInTmpPointers(tmp1); tmp2 = Curve2->Leaf; } } else { tmp1 = Curve1->Leaf; tmp2 = Curve2->Leaf; } } else { tmp1 = Curve1->Leaf; tmp2 = NULL; } if(tmp1 == tmp2) { tmp2 = new EBStmp; AddInTmpPointers(tmp2); bcopy((char *)(tmp1), (char *)(tmp2), sizeof(EBStmp)); tmp2->Reference = 0; tmp2->Dependent = NULL; tmp2->IsFileOpen = 0; tmp2->FileName = mystrdup(tmp1->FileName); } tmp1->AddCurve(curve); if(tmp2 != NULL) tmp2->AddCurve(curve); SampleRate = curve->SampleRate; NumOfSamples = curve->NumOfSamples; // create a new tmp file, where the evaluation is written to. char tmpfilename[L_tmpnam]; tmpnam(tmpfilename); // creates a tmp file name after posix. FILE *tmpfile; tmpfile = fopen(tmpfilename, "wb"); if(tmpfile == NULL) { perror(tmpfilename); return -1; } // write tmp file header fputf4(SampleRate, tmpfile); fputi32(NumOfSamples, tmpfile); unsigned long Op = curve->Operator; int err; switch(Op) { case EBS_VECTOR_PLUS: case EBS_VECTOR_MINUS: case EBS_VECTOR_MULT: case EBS_VECTOR_DIV: err = curve.CalcVector(tmpfile, tmp1, tmp2); break; case EBS_CONCATENATION: err = curve.CalcConc(tmpfile, tmp1, tmp2); break; case EBS_CONVOLUTION: err = curve.CalcConv(tmpfile, tmp1, tmp2); break; case EBS_CORRELATION: err = curve.CalcCorr(tmpfile, tmp1, tmp2); break; case EBS_LINCORRELATION: err = curve.CalcLinCorr(tmpfile, tmp1, tmp2); break; case EBS_FFT: err = curve.CalcFFT(tmpfile, tmp1); break; case EBS_CONVOLUTION_WITH_FREQUENCE: err = curve.CalcConvFreq(tmpfile, tmp1, tmp2); break; default: err = -1; break; } fclose(tmpfile); tmp1->RemoveCurve(curve); if(tmp2 != NULL) tmp2->RemoveCurve(curve); if(err == -1) { unlink(tmpfilename); return err; } // remove dependencies (recursive) Curve1->RemoveCurve(curve); LoseDependency(Curve1); if(Curve2 != NULL) { Curve2->RemoveCurve(curve); LoseDependency(Curve2); } EBStmp *tmp; tmp = new EBStmp; tmp->BindType = EBS_BIND_TO_TMP_FILE; tmp->CurveType = curve->CurveType; tmp->FileName = mystrdup(tmpfilename); tmp->NumOfSamples = curve->NumOfSamples; tmp->CutOffset = curve->CutOffset; tmp->AddCurve(curve); curve->CurveBindType = EBS_BIND_TO_TMP_CLASS; curve->Leaf = tmp; curve->Evaluated = 1; AddInTmpPointers(tmp); return 0; } else if(curve->CurveBindType == EBS_BIND_TO_EBS_FILE) { EBStmp *tmp; tmp = new EBStmp; tmp->BindType = EBS_BIND_TO_EBS_FILE; tmp->FileName = mystrdup(curve->FileName); tmp->NumOfSamples = curve->NumOfSamples; tmp->ChannelNumber = curve->ChannelNumber; tmp->SampleOffset = curve->SampleOffset; tmp->CurveType = curve->CurveType; tmp->CutOffset = curve->CutOffset; tmp->AddCurve(curve); curve->CurveBindType = EBS_BIND_TO_TMP_CLASS; curve->Leaf = tmp; curve->Evaluated = 1; AddInTmpPointers(tmp); return 0; } else if(curve->CurveBindType == EBS_BIND_TO_TMP_FILE) { EBStmp *tmp; tmp = new EBStmp; tmp->BindType = EBS_BIND_TO_TMP_FILE; tmp->FileName = mystrdup(curve->FileName); tmp->NumOfSamples = curve->NumOfSamples; tmp->CurveType = curve->CurveType; tmp->CutOffset = curve->CutOffset; tmp->AddCurve(curve); curve->CurveBindType = EBS_BIND_TO_TMP_CLASS; curve->Leaf = tmp; curve->Evaluated = 1; AddInTmpPointers(tmp); return 0; } else if(curve->CurveBindType == EBS_BIND_TO_FUNCTION) { // create a new tmp file, where the function samples are written to. short Min, Max, value; Min = 0; Max = 0; char tmpfilename[L_tmpnam]; tmpnam(tmpfilename); // creates a tmp file name after posix. FILE *tmpfile; tmpfile = fopen(tmpfilename, "wb"); if(tmpfile == NULL) return -1; // write tmp file header fputf4(curve->SampleRate, tmpfile); fputi32(curve->NumOfSamples, tmpfile); unsigned long i = 0; while(i < curve->NumOfSamples) { value = curve->BindFunction(i); if(value > Max) Max = value; else if(value < Min) Min = value; fputi16(value, tmpfile); i++; } fclose(tmpfile); curve->Vmax = Max; curve->Vmin = Min; curve->CurveBindType = EBS_BIND_TO_TMP_CLASS; curve->Evaluated = 1; EBStmp *tmp; tmp = new EBStmp; tmp->BindType = EBS_BIND_TO_TMP_FILE; tmp->FileName = mystrdup(tmpfilename); tmp->NumOfSamples = curve->NumOfSamples; tmp->CurveType = curve->CurveType; tmp->CutOffset = curve->CutOffset; tmp->AddCurve(curve); curve->Leaf = tmp; AddInTmpPointers(tmp); return 0; } else if(curve->CurveBindType == EBS_BIND_TO_FUNCTION_C) { // create a new tmp file, where the function samples are written to. char tmpfilename[L_tmpnam]; tmpnam(tmpfilename); // creates a tmp file name after posix. FILE *tmpfile; tmpfile = fopen(tmpfilename, "wb"); if(tmpfile == NULL) return -1; // write tmp file header fputf4(curve->SampleRate, tmpfile); fputi32(curve->NumOfSamples, tmpfile); Complex value; unsigned long i = 0; while(i < curve->NumOfSamples) { value = curve->BindFunctionC(i); PutNextComplex(value, tmpfile); i++; } fclose(tmpfile); curve->Vmax = 0; curve->Vmin = 0; curve->CurveBindType = EBS_BIND_TO_TMP_CLASS; curve->Evaluated = 1; EBStmp *tmp; tmp = new EBStmp; tmp->BindType = EBS_BIND_TO_TMP_FILE; tmp->FileName = mystrdup(tmpfilename); tmp->NumOfSamples = curve->NumOfSamples; tmp->CurveType = curve->CurveType; tmp->CutOffset = curve->CutOffset; tmp->AddCurve(curve); curve->Leaf = tmp; AddInTmpPointers(tmp); return 0; } else if(curve->CurveBindType == EBS_BIND_TO_TMP_CLASS) { curve->Evaluated = 1; return 0; } else return -1; // unknown bind type return 0; } // this is a simple adjustment of bias and scalefactor out of // two other curves. // the unit and the scale factor for the evaluation curve is only taken // if the units of the both other curves are the same. // the scale factor is also taken if the both curves don't have a unit. // the taken scale factor is allways the bigger one of the both curves. // if the scale factor is not taken it is set to 1.0. void ScaleBiasAdjust(EBScurve *curve) { double bias1, bias2, bias; int spec1, spec2; double scale1, scale2, scale; char *SI1, *SI2; EBScurve *Curve1, *Curve2; Curve1 = curve->Curve1; Curve2 = curve->Curve2; bias1 = Curve1->Bias; scale1 = Curve1->ScaleFactor; spec1 = Curve1->UnitSpec; SI1 = Curve1->SIUnit; if(Curve2 == NULL) { bias = bias1; scale = scale1; if(spec1 == 1) { delete [] curve->SIUnit; curve->UnitSpec = 1; curve->SIUnit = mystrdup(SI1); } else { delete [] curve->SIUnit; curve->SIUnit = NULL; curve->UnitSpec = 0; } } else { bias2 = Curve2->Bias; scale2 = Curve2->ScaleFactor; spec2 = Curve2->UnitSpec; SI2 = Curve2->SIUnit; if((spec1 == 0) && (spec2 == 0)) { curve->UnitSpec = 0; delete [] curve->SIUnit; curve->SIUnit = NULL; if(scale1 > scale2) scale = scale1; else scale = scale2; bias = (bias1+bias2)/2; } else if(((spec1 == 0) && (spec2 != 0)) || ((spec1 != 0) && (spec2 == 0))) { curve->UnitSpec = 0; delete [] curve->SIUnit; curve->SIUnit = NULL; scale = 1.0; bias = 0; } else if((spec1 == 1) && (spec2 == 1) && (SI1 != NULL) && (SI2 != NULL)) { if(strcmp(SI1, SI2) == 0) { // equal curve->UnitSpec = 1; delete [] curve->SIUnit; curve->SIUnit = mystrdup(SI1); if(scale1 > scale2) scale = scale1; else scale = scale2; bias = (bias1+bias2)/2; fprintf(stderr, "!!!!!bias1 %f bias2 %f bias %f\n", bias1, bias2, bias); } else { // losing SI unit, because the units of the curves does not match curve->UnitSpec = 0; delete [] curve->SIUnit; curve->SIUnit = NULL; scale = 1.0; bias = 0; } } else { curve->UnitSpec = 0; delete [] curve->SIUnit; curve->SIUnit = NULL; scale = 1.0; bias = 0; } } curve->Bias = bias; curve->BiasCalc = bias; curve->ScaleFactor = scale; curve->ScaleFactorCalc = scale; return; } int EBScurve::CalcConc(FILE *tmpfile, EBStmp *tmp1, EBStmp *tmp2) { double bias, bias1, bias2; int spec, spec1, spec2; double scale, scale1, scale2; bias = BiasCalc; bias1 = Curve1->Bias; bias2 = Curve2->Bias; scale = ScaleFactorCalc; scale1 = Curve1->ScaleFactor; scale2 = Curve2->ScaleFactor; /* muss noch implementiert werden, je nachdem was im format vereinbart wird float vmin1, vmax1, vmin2, vmax2, vmin, vmax; vmin1 = (tmp1->Vmin1+bias1)*scale1; vmax1 = (tmp1->Vmax1+bias1)*scale1; vmin2 = (tmp2->Vmin1+bias2)*scale2; vmax2 = (tmp2->Vmax2+bias2)*scale2; if(vmin1Vmin = (short)(vmin/scale-bias); curve->Vmax = (short)(vmin/scale-bias); */ spec = UnitSpec; spec1 = Curve1->UnitSpec; spec2 = Curve2->UnitSpec; unsigned long nsample, nsample1, nsample2; nsample = NumOfSamples; nsample1 = Curve1->NumOfSamples; nsample2 = Curve2->NumOfSamples; int fill; fill = nsample - nsample1 - nsample2; unsigned long i; tmp1->RewindSample(); tmp2->RewindSample(); if((spec == spec1) && (spec1 == spec2)) { double sam; for(i = 0; i < nsample1; i++) { sam = tmp1->GetNextSample()*scale1+bias1; fputi16((short)((sam-bias)/scale), tmpfile); } for(i = 0; i < nsample2; i++) { sam = tmp2->GetNextSample()*scale2+bias2; fputi16((short)((sam-bias)/scale), tmpfile); } } else { for(i = 0; i < nsample1; i++) { fputi16(tmp1->GetNextSample(), tmpfile); } for(i = 0; i < nsample2; i++) { fputi16(tmp2->GetNextSample(), tmpfile); } } for(i = 0; i < fill; i++) // make a correction in length, because the length fputi16(0, tmpfile); // was determined a long time before tmp1->CloseFile(); tmp2->CloseFile(); return 0; } int EBScurve::CalcVector(FILE *tmpfile, EBStmp *tmp1, EBStmp *tmp2) { unsigned long Op = Operator; unsigned long nsample, nsample1, nsample2; nsample = NumOfSamples; nsample1 = Curve1->NumOfSamples; nsample2 = Curve2->NumOfSamples; double bias, bias1, bias2; int spec, spec1, spec2; double scale, scale1, scale2; bias = BiasCalc; bias1 = Curve1->Bias; bias2 = Curve2->Bias; scale = ScaleFactorCalc; scale1 = Curve1->ScaleFactor; scale2 = Curve2->ScaleFactor; spec = UnitSpec; spec1 = Curve1->UnitSpec; spec2 = Curve2->UnitSpec; unsigned long both, i; int fill; if(nsample1 < nsample2) { both = nsample1; fill = nsample - nsample2; } else { both = nsample2; fill = nsample - nsample1; } tmp1->RewindSample(); tmp2->RewindSample(); if((spec == spec1) && (spec1 == spec2)) { // calc with scale and bias double sam, sam1, sam2; for(i = 0; i < both; i++) { sam1 = tmp1->GetNextSample()*scale1+bias1; sam2 = tmp2->GetNextSample()*scale2+bias2; switch(Op) { case EBS_VECTOR_PLUS: sam = (sam1+sam2-bias)/scale; break; case EBS_VECTOR_MINUS: sam = (sam1-sam2-bias)/scale; break; case EBS_VECTOR_MULT: sam = (sam1*sam2-bias)/scale; break; case EBS_VECTOR_DIV: sam = (sam1/sam2-bias)/scale; break; default: #ifdef DEBUG fprintf(stderr, "CalcVector: unknown operation: %d\n", Op); #endif tmp1->CloseFile(); tmp2->CloseFile(); return -1; break; } fputi16((short)(sam), tmpfile); } // if one of the both channels is longer than the other one if(nsample1 > nsample2) for(i = both; i < nsample1; i++) { fputi16((short)((tmp1->GetNextSample()*scale1+bias1-bias)/scale), tmpfile); } if(nsample2 > nsample1) for(i = both; i < nsample2; i++) { fputi16((short)((tmp2->GetNextSample()*scale2+bias2-bias)/scale), tmpfile); } } else { // calc only in the 'short'(-type) area short sam, sam1, sam2; for(i = 0; i < both; i++) { sam1 = tmp1->GetNextSample(); sam2 = tmp2->GetNextSample(); switch(Op) { case EBS_VECTOR_PLUS: sam = sam1+sam2; break; case EBS_VECTOR_MINUS: sam = sam1-sam2; break; case EBS_VECTOR_MULT: sam = sam1*sam2; break; case EBS_VECTOR_DIV: sam = sam1/sam2; break; default: #ifdef DEBUG fprintf(stderr, "CalcVector: unknown operation: %d\n", Op); #endif tmp1->CloseFile(); tmp2->CloseFile(); return -1; break; } fputi16(sam, tmpfile); } // if one of the both channels is longer than the other one if(nsample1 > nsample2) for(i = both; i < nsample1; i++) { fputi16(tmp1->GetNextSample(), tmpfile); } if(nsample2 > nsample1) for(i = both; i < nsample2; i++) { fputi16(tmp2->GetNextSample(), tmpfile); } } for(i = 0; i < fill; i++) fputi16(0, tmpfile); tmp1->CloseFile(); tmp2->CloseFile(); return 0; } void LoseDependency(EBScurve *curve) { EBScurve *helpcurve; helpcurve = curve; if(helpcurve != NULL) { if(helpcurve->CurveBindType == EBS_BIND_TO_CURVE) { helpcurve->Curve1->RemoveCurve(curve); LoseDependency(helpcurve->Curve1); helpcurve->CurveBindType = EBS_NO_BINDING; if((helpcurve->Reference == 0) && (InCurvePointers(helpcurve))) { delete helpcurve; } } else if(helpcurve->CurveBindType == EBS_BIND_TO_EVALUATION) { EBScurve *helpcurve1, *helpcurve2; helpcurve1 = helpcurve->Curve1; helpcurve2 = helpcurve->Curve2; helpcurve1->RemoveCurve(curve); LoseDependency(helpcurve1); if(helpcurve2 != NULL) { helpcurve2->RemoveCurve(curve); LoseDependency(helpcurve2); } helpcurve->CurveBindType = EBS_NO_BINDING; if((helpcurve->Reference == 0) && (InCurvePointers(helpcurve))) delete helpcurve; } else if((helpcurve->CurveBindType == EBS_BIND_TO_TMP_FILE) && (helpcurve->Reference == 0)) { helpcurve->CurveBindType = EBS_NO_BINDING; helpcurve->Evaluated = 0; unlink(helpcurve->FileName); if(InCurvePointers(helpcurve)) delete helpcurve; } else if((helpcurve->CurveBindType == EBS_BIND_TO_TMP_CLASS) && (helpcurve->Reference == 0)) { helpcurve->CurveBindType = EBS_NO_BINDING; helpcurve->Evaluated = 0; helpcurve->Leaf->RemoveCurve(helpcurve); helpcurve->Leaf = NULL; if(InCurvePointers(helpcurve)) delete helpcurve; } } } EBStmp *ChangeSampleRate(EBScurve *curve, double SampleRate) { EBStmp *tmp; tmp = new EBStmp; // [L_tmpnam]; // beachte hierbei, dass die Laenge von curve die vorher evtl. etwas ungenau // ermittelt wurde durch die darauffolgende Operation nicht veraendert wird. // also z.B. bei calcconcat oder calcvector oder calccorrelation.... // => hier evtl schon Laengenanpassung vornehmen. fprintf(stderr, "+++++++ In change Sample Rate! +++++++\n"); fprintf(stderr, "curve rate: %f -> samplerate: %f\n", curve->SampleRate, SampleRate); fprintf(stderr, "Teiler: %f\n", SampleRate/curve->SampleRate); int c = 0; // gcd(&((int)(SampleRate)), &((int)(curve->SampleRate)), &c); fprintf(stderr, "gcd %d\n", c); double fac = SampleRate/curve->SampleRate; int faci = (int)(fac); double rest = fac-faci; fprintf(stderr, "fac %f faci %d rest %f\n,", fac, faci, rest); // tmpnam(tmp); // creates a tmp file name after posix. // erzeuge aus curve ein neues tmp file mit der angegebenen SampleRate // ******************************************************************* return tmp; } int InFilePointers(EBSFile *name) { ebsfile_pointer *help; help = FilePointers; while(help != NULL) { if(help->ebsfile == name) return 1; help = help->next_file; } return 0; } void InsertInFilePointers(EBScurve *curve) { ebsfile_pointer *help; curve_pointers *helpc, *helpf, *helpn; help = FilePointers; helpn = new curve_pointers; while(help != NULL) { if(help->ebsfile == curve->EbsFile) { help->channels += 1; if(curve->OutLength = ~0) { if((curve->NumOfSamples - curve->OutOffset) > help->maxlength) help->maxlength = curve->NumOfSamples - curve->OutOffset; } else if(curve->OutLength > help->maxlength) help->maxlength = curve->OutLength; helpf = help->next_curve; helpc = helpf; if(helpc->curve->OutChannel > curve->OutChannel) { help->next_curve = helpn; helpn->curve = curve; helpn->next_curve = helpc; return; } helpc = helpf->next_curve; while(helpc != NULL) { if(helpc->curve->OutChannel > curve->OutChannel) { helpn->next_curve = helpf->next_curve; helpf->next_curve = helpn; helpn->curve = curve; return; } helpf = helpf->next_curve; helpc = helpf->next_curve; } helpf->next_curve = helpn; helpn->curve = curve; helpn->next_curve = NULL; return; } help = help->next_file; } return; } void AppendFilePointers(EBScurve *curve) { ebsfile_pointer *help, *helpnf; curve_pointers *helpc; help = FilePointers; helpc = new curve_pointers; helpnf = new ebsfile_pointer; helpnf->ebsfile = curve->EbsFile; helpnf->next_curve = helpc; helpnf->next_file = NULL; helpnf->channels = 1; helpnf->maxlength = curve->OutLength; if(curve->OutLength == ~0) helpnf->maxlength = curve->NumOfSamples - curve->OutOffset; helpc->next_curve = NULL; helpc->curve = curve; if(help == NULL) { FilePointers = helpnf; return; } while(help->next_file != NULL) help = help->next_file; help->next_file = helpnf; return; } void ListAddIn(curve_pointers *&List, EBScurve *elem) { curve_pointers *help, *insert; help = List; if(help == NULL) { help = new curve_pointers; help->curve = elem; help->next_curve = NULL; List = help; } else { while(help->next_curve != NULL) help = help->next_curve; insert = new curve_pointers; insert->curve = elem; insert->next_curve = NULL; help->next_curve = insert; } } void ListAddIn(tmp_pointers *&List, EBStmp *elem) { tmp_pointers *help, *insert; help = List; if(help == NULL) { help = new tmp_pointers; help->tmp = elem; help->next_tmp = NULL; List = help; } else { while(help->next_tmp != NULL) help = help->next_tmp; insert = new tmp_pointers; insert->tmp = elem; insert->next_tmp = NULL; help->next_tmp = insert; } } int ListCurveIn(curve_pointers *List, EBScurve *elem) // true = 1 , false = 0 { curve_pointers *help; help = List; if(help == NULL) { return 0; // not found } if(help->curve == elem) { return 1; // found } while(help->next_curve != NULL) { if(help->next_curve->curve == elem) { return 1; // found } else help = help->next_curve; } return 0; // not found } int ListRemoveIn(curve_pointers *&List, EBScurve *elem) { curve_pointers *help, *help2; int out; help = List; if(help == NULL) { return 0; // not found } if(help->curve == elem) { help->curve = NULL; List = help->next_curve; delete help; return 1; // found and removed } else { out = 0; while(!out) { if(help->next_curve != NULL) { if(help->next_curve->curve == elem) { help2 = help->next_curve; help->next_curve = help2->next_curve; delete help2; out = 1; return 1; // found and removed } else help = help->next_curve; } else out = 1; } return 0; // not found } } int ListRemoveIn(tmp_pointers *&List, EBStmp *elem) { tmp_pointers *help, *help2; int out; help = List; if(help == NULL) { return 0; // not found } if(help->tmp == elem) { help->tmp = NULL; List = help->next_tmp; delete help; return 1; // found and removed } else { out = 0; while(!out) { if(help->next_tmp != NULL) { if(help->next_tmp->tmp == elem) { help2 = help->next_tmp; help->next_tmp = help2->next_tmp; delete help2; out = 1; return 1; // found and removed } else help = help->next_tmp; } else out = 1; } return 0; // not found } } void AddInTmpPointers(EBStmp *elem) { ListAddIn(TmpPointers, elem); } int RemoveInTmpPointers(EBStmp *elem) { return ListRemoveIn(TmpPointers, elem); } void AddInOutPointers(EBScurve *elem) { ListAddIn(OutPointers, elem); } void AddInCurvePointers(EBScurve *elem) { ListAddIn(CurvePointers, elem); } int InCurvePointers(EBScurve *elem) // true = 1 , false = 0 { return ListCurveIn(CurvePointers, elem); } int RemoveInCurvePointers(EBScurve *elem) { return ListRemoveIn(CurvePointers, elem); } void EBScurve::AddCurve(EBScurve *elem) { ListAddIn(Dependent, elem); Reference += 1; } int EBScurve::RemoveCurve(EBScurve *elem) { if(ListRemoveIn(Dependent, elem) == 1) { Reference -= 1; return 1; } else return 1; } EBScurve::EBScurve(char *description) { Evaluated = 0; Description = description; SampleRate = 0.0; ScaleFactor = 1.0; ScaleFactorCalc = 1.0; Vmin = 0; Vmax = 0; Bias = 0.0; BiasCalc = 0.0; UnitSpec = 0; SIUnit = NULL; NumOfSamples = 0; CurveBindType = EBS_NO_BINDING; CurveType = EBS_IN_TIME; Reference = 0; Dependent = NULL; ZeroOffset = 0; Lag = 0; // initialize file part FileName = NULL; ChannelNumber = 0; SampleOffset = 0; // initialize function part BindFunction = NULL; BindFunctionC = NULL; // initialize evaluation part Curve1 = NULL; Curve2 = NULL; // Value = 0; Operator = EBS_NO_OPERATOR; CutOffset = 0; EbsFile = NULL; Leaf = NULL; } EBScurve::~EBScurve(void) // destructor { delete [] FileName; FileName = NULL; CurveBindType = EBS_NO_BINDING; delete [] SIUnit; SIUnit = NULL; } void EBScurve::SetSIUnit(char *SI) { if(SI == NULL) { // delete the SI Unit UnitSpec = 0; delete [] SIUnit; SIUnit = NULL; } else { UnitSpec = 1; delete [] SIUnit; SIUnit = mystrdup(SI); } return; } int EBScurve::BindTo(char* filename, unsigned long channel, unsigned long offset, unsigned long length) { EBSFile fillebs(filename, 'r'); if(fillebs.Valid() == 0) return -1; if((fillebs.GetNChannels()-1) < channel) return -1; if(fillebs.GetNSamples() == NULL) return -1; if(fillebs.GetNSamples()[channel] < (offset + length)) return -1; if(fillebs.GetSampleRate() == NULL) return -1; else SampleRate = fillebs.GetSampleRate()[channel]; EBSFile::Unit const *munits = fillebs.GetUnits(); ScaleFactor = 1.0; if(munits != NULL) if(munits[channel].specified == 1) { // specified? ScaleFactor = munits[channel].quotient; delete [] SIUnit; SIUnit = mystrdup(munits[channel].unit); UnitSpec = 1; } else { delete [] SIUnit; SIUnit = NULL; UnitSpec = 0; } ScaleFactorCalc = ScaleFactor; // here must be insert the program part for the bias adjustment // if it is added to the EBS-FORMAT Bias = 0.0; BiasCalc = Bias; // or the program part for reading the physical and converter min, max EBSFile::PreferredIntegerRange const *prange = fillebs.GetPreferredIntegerRange(); Vmin = 0; Vmax = 0; if(prange != NULL) { Vmin = prange[channel].min; Vmax = prange[channel].max; } NumOfSamples = length; CurveBindType = EBS_BIND_TO_EBS_FILE; FileName = mystrdup(filename); ChannelNumber = channel; SampleOffset = offset; return 0; } int EBScurve::BindTo(char* filename) { FILE *TEST; int nan, nancount; TEST = fopen(filename, "rb"); if(TEST == NULL) return -1; nan = 0; nancount = 0; SampleRate = fgetf4(TEST, &nan); if(nan != 0) { fclose(TEST); return -1; } NumOfSamples = fgeti32(TEST); fclose(TEST); CurveBindType = EBS_BIND_TO_TMP_FILE; FileName = mystrdup(filename); return 0; } int EBScurve::BindTo(GFun Functionname) { BindFunction = Functionname; CurveBindType = EBS_BIND_TO_FUNCTION; CurveType = EBS_IN_TIME; return 0; } int EBScurve::BindTo(CFun Functionname) { BindFunctionC = Functionname; CurveBindType = EBS_BIND_TO_FUNCTION_C; CurveType = EBS_IN_FREQUENCE; return 0; } int EBScurve::Output(EBSFile *name, unsigned long channel, unsigned long offset, unsigned long length) { if(offset > NumOfSamples) return -1; if((offset+length > NumOfSamples) && (length != ~0)) return -1; if(EbsFile != NULL) { #ifdef DEBUG fprintf(stderr, "Error: you trying to bind a curve with Output() to a\n"); fprintf(stderr, " EBS file which is allready bound to one.\n"); #endif return -1; } EbsFile = name; OutChannel = channel; OutLength = length; // ~0 means to end of channel OutOffset = offset; AddInOutPointers(this); this->Reference += 1; return 0; } // newcurve is afterwards a simplified copy of curve, // where all bindings to curves which are selve bound to a curve // or a evalution are eleminated. void Simplify(EBScurve *newcurve, EBScurve *curve) { EBScurve *helpcurve; int out; helpcurve = curve; out = 0; while(!out) { if(helpcurve->CurveBindType == EBS_BIND_TO_CURVE) { newcurve->Curve1 = helpcurve->Curve1; newcurve->CurveBindType = EBS_BIND_TO_CURVE; helpcurve->RemoveCurve(newcurve); helpcurve->Curve1->AddCurve(newcurve); if((helpcurve->Reference == 0) && (InCurvePointers(helpcurve))) { (helpcurve->Curve1)->RemoveCurve(helpcurve); RemoveInCurvePointers(helpcurve); delete helpcurve; } helpcurve = newcurve->Curve1; } else if(helpcurve->CurveBindType == EBS_BIND_TO_EVALUATION) { helpcurve->RemoveCurve(newcurve); newcurve->Curve1 = helpcurve->Curve1; newcurve->Curve2 = helpcurve->Curve2; newcurve->Operator = helpcurve->Operator; newcurve->CurveBindType = EBS_BIND_TO_EVALUATION; helpcurve->Curve1->AddCurve(newcurve); if(helpcurve->Curve2 != NULL) helpcurve->Curve2->AddCurve(newcurve); if((helpcurve->Reference == 0) && (InCurvePointers(helpcurve))) { helpcurve->Curve1->RemoveCurve(helpcurve); if(helpcurve->Curve2 != NULL) helpcurve->Curve2->RemoveCurve(helpcurve); RemoveInCurvePointers(helpcurve); delete helpcurve; } out = 1; } else out = 1; } } EBScurve& Cut(EBScurve& curve, unsigned long offset, unsigned long length) { EBScurve *newcurve; newcurve = new EBScurve; #ifdef DEBUG fprintf(stderr, "Function Cut() called.\n"); #endif newcurve->Description = "Created by EBScalc Cut"; AddInCurvePointers(newcurve); // write newcurve in the list of curves if(offset > curve.NumOfSamples) offset = 0; if(length == ~0) length = curve.NumOfSamples - offset; if(offset+length>curve.NumOfSamples) length = curve.NumOfSamples - offset; CopyCurve(&curve, newcurve); // copies the main things of curve to newcurve newcurve->CurveBindType = EBS_BIND_TO_CURVE; newcurve->Curve1 = &curve; newcurve->NumOfSamples = length; // maybe curve is selve bound to other curve or a evaluation. Simplify(newcurve, &curve); newcurve->CutOffset += offset; return *newcurve; } EBScurve& operator+(EBScurve& curve, double value) { /* Vorgehensweise: Erzeuge eine neue curve und uebernehme alle wichtigen Parameter aus der gegebenen curve. Anschliessend fuehre die Addition aus. Der Rueckgabewert ist ein Pointer auf die neue curve. */ EBScurve *newcurve; newcurve = new EBScurve; #ifdef DEBUG fprintf(stderr, "Operator+ called.\n"); #endif newcurve->Description = "Created by EBScalc+"; AddInCurvePointers(newcurve); // write newcurve in the list of curves CopyCurve(&curve, newcurve); // copies the main things of curve to newcurve newcurve->CurveBindType = EBS_BIND_TO_CURVE; newcurve->Curve1 = &curve; // maybe curve is selve bound to other curve or a evaluation. Simplify(newcurve, &curve); (newcurve->Bias) += value; // that is what really changes return *newcurve; } EBScurve& operator-(EBScurve& curve, double value) { /* Vorgehensweise: Erzeuge eine neue curve und uebernehme alle wichtigen Parameter aus der gegebenen curve. Anschliessend fuehre die Addition aus. Der Rueckgabewert ist ein Pointer auf die neue curve. */ EBScurve *newcurve; newcurve = new EBScurve; #ifdef DEBUG fprintf(stderr, "Operator- called.\n"); #endif newcurve->Description = "Created by EBScalc-"; AddInCurvePointers(newcurve); // write newcurve in the list of curves CopyCurve(&curve, newcurve); // copies the main things of curve to newcurve newcurve->CurveBindType = EBS_BIND_TO_CURVE; newcurve->Curve1 = &curve; // maybe curve is selve bound to other curve or a evaluation. Simplify(newcurve, &curve); (newcurve->Bias) -= value; // that is what really changes return *newcurve; } EBScurve& operator*(EBScurve& curve, double value) { /* Vorgehensweise: Erzeuge eine neue curve und uebernehme alle wichtigen Parameter aus der gegebenen curve. Anschliessend fuehre die Addition aus. Der Rueckgabewert ist ein Pointer auf die neue curve. */ EBScurve *newcurve; newcurve = new EBScurve; #ifdef DEBUG fprintf(stderr, "Operator* called.\n"); #endif newcurve->Description = "Created by EBScalc*"; AddInCurvePointers(newcurve); // write newcurve in the list of curves CopyCurve(&curve, newcurve); // copies the main things of curve to newcurve newcurve->CurveBindType = EBS_BIND_TO_CURVE; newcurve->Curve1 = &curve; // maybe curve is selve bound to other curve or a evaluation. Simplify(newcurve, &curve); (newcurve->ScaleFactor) *= value; // that is what really changes return *newcurve; } EBScurve& operator/(EBScurve& curve, double value) { /* Vorgehensweise: Erzeuge eine neue curve und uebernehme alle wichtigen Parameter aus der gegebenen curve. Anschliessend fuehre die Addition aus. Der Rueckgabewert ist ein Pointer auf die neue curve. */ EBScurve *newcurve; newcurve = new EBScurve; #ifdef DEBUG fprintf(stderr, "Operator/ called.\n"); #endif newcurve->Description = "Created by EBScalc/"; AddInCurvePointers(newcurve); // write newcurve in the list of curves CopyCurve(&curve, newcurve); // copies the main things of curve to newcurve newcurve->CurveBindType = EBS_BIND_TO_CURVE; newcurve->Curve1 = &curve; // maybe curve is selve bound to other curve or a evaluation. Simplify(newcurve, &curve); (newcurve->ScaleFactor) /= value; // that is what really changes return *newcurve; } // determines the number of samples and the rate a curve will have // which is a evaluation out of two other curves void DetermineLengthRate(unsigned long& length, double& rate, EBScurve *curve1, EBScurve *curve2) { unsigned long length1, length2, testlength; double rate1, rate2; length1 = curve1->NumOfSamples; length2 = curve2->NumOfSamples; rate1 = curve1->SampleRate; rate2 = curve2->SampleRate; if((length1 > length2) && (rate1 >= rate2)) { length = length1; rate = rate1; return; } else if((length2 > length1) && (rate2 >= rate1)) { length = length2; rate = rate2; return; } else if(rate1 > rate2) { testlength = (unsigned long)((rate1/rate2)*length2+0.5); rate = rate1; if(testlength > length1) length = testlength; else length = length1; return; } else if(rate2 > rate1) { testlength = (unsigned long)((rate2/rate1)*length1+0.5); rate = rate2; if(testlength > length2) length = testlength; else length = length2; return; } else { rate = rate1; length = length1; } } EBScurve& operator+(EBScurve& curve1, EBScurve& curve2) { /* Vorgehensweise: Erzeuge eine neue curve und kennzeichne diese als Summe aus den beiden gegebenen Curves. Optimierungen sind nicht moeglich. Der Rueckgabewert ist ein Pointer auf die neue curve. */ EBScurve *newcurve; newcurve = new EBScurve; #ifdef DEBUG fprintf(stderr, "Operator+ c+c called.\n"); #endif newcurve->Description = "Created by EBScalc+ c+c"; AddInCurvePointers(newcurve); // write newcurve in the list of curves newcurve->CurveBindType = EBS_BIND_TO_EVALUATION; newcurve->Operator = EBS_VECTOR_PLUS; newcurve->Curve1 = &curve1; newcurve->Curve2 = &curve2; curve1.AddCurve(newcurve); curve2.AddCurve(newcurve); unsigned long samplelength; double samplerate; DetermineLengthRate(samplelength, samplerate, &curve1, &curve2); newcurve->SampleRate = samplerate; newcurve->NumOfSamples = samplelength; ScaleBiasAdjust(newcurve); return *newcurve; } EBScurve& operator-(EBScurve& curve1, EBScurve& curve2) { /* Vorgehensweise: Erzeuge eine neue curve und kennzeichne diese als Summe aus den beiden gegebenen Curves. Optimierungen sind nicht moeglich. Der Rueckgabewert ist ein Pointer auf die neue curve. */ EBScurve *newcurve; newcurve = new EBScurve; #ifdef DEBUG fprintf(stderr, "Operator- c-c called.\n"); #endif newcurve->Description = "Created by EBScalc- c-c"; AddInCurvePointers(newcurve); // write newcurve in the list of curves newcurve->CurveBindType = EBS_BIND_TO_EVALUATION; newcurve->Operator = EBS_VECTOR_MINUS; newcurve->Curve1 = &curve1; newcurve->Curve2 = &curve2; curve1.AddCurve(newcurve); curve2.AddCurve(newcurve); unsigned long samplelength; double samplerate; DetermineLengthRate(samplelength, samplerate, &curve1, &curve2); newcurve->SampleRate = samplerate; newcurve->NumOfSamples = samplelength; ScaleBiasAdjust(newcurve); return *newcurve; } EBScurve& operator*(EBScurve& curve1, EBScurve& curve2) { /* Vorgehensweise: Erzeuge eine neue curve und kennzeichne diese als Summe aus den beiden gegebenen Curves. Optimierungen sind nicht moeglich. Der Rueckgabewert ist ein Pointer auf die neue curve. */ EBScurve *newcurve; newcurve = new EBScurve; #ifdef DEBUG fprintf(stderr, "Operator* c*c called.\n"); #endif newcurve->Description = "Created by EBScalc* c*c"; AddInCurvePointers(newcurve); // write newcurve in the list of curves newcurve->CurveBindType = EBS_BIND_TO_EVALUATION; newcurve->Operator = EBS_VECTOR_MULT; newcurve->Curve1 = &curve1; newcurve->Curve2 = &curve2; curve1.AddCurve(newcurve); curve2.AddCurve(newcurve); unsigned long samplelength; double samplerate; DetermineLengthRate(samplelength, samplerate, &curve1, &curve2); newcurve->SampleRate = samplerate; newcurve->NumOfSamples = samplelength; ScaleBiasAdjust(newcurve); return *newcurve; } EBScurve& operator/(EBScurve& curve1, EBScurve& curve2) { /* Vorgehensweise: Erzeuge eine neue curve und kennzeichne diese als Summe aus den beiden gegebenen Curves. Optimierungen sind nicht moeglich. Der Rueckgabewert ist ein Pointer auf die neue curve. */ EBScurve *newcurve; newcurve = new EBScurve; #ifdef DEBUG fprintf(stderr, "Operator/ c/c called.\n"); #endif newcurve->Description = "Created by EBScalc/ c/c"; AddInCurvePointers(newcurve); // write newcurve in the list of curves newcurve->CurveBindType = EBS_BIND_TO_EVALUATION; newcurve->Operator = EBS_VECTOR_DIV; newcurve->Curve1 = &curve1; newcurve->Curve2 = &curve2; curve1.AddCurve(newcurve); curve2.AddCurve(newcurve); unsigned long samplelength; double samplerate; DetermineLengthRate(samplelength, samplerate, &curve1, &curve2); newcurve->SampleRate = samplerate; newcurve->NumOfSamples = samplelength; ScaleBiasAdjust(newcurve); return *newcurve; } double EBScurve::operator[](unsigned long pos) { if(pos > NumOfSamples) return 0; if(this->Evaluated == 0) EvaluateCurve(this); short value = this->Leaf->GetSample(pos); return (value*ScaleFactor+Bias); } EBScurve& Concat(EBScurve& curve1, EBScurve& curve2) { /* Vorgehensweise: Erzeuge eine neue curve und kennzeichne diese als Konkatenation aus den beiden gegebenen Curves. Optimierungen sind nicht moeglich. Der Rueckgabewert ist ein Pointer auf die neue curve. */ EBScurve *newcurve; newcurve = new EBScurve; #ifdef DEBUG fprintf(stderr, "Concat for curve1, curve2 called.\n"); #endif newcurve->Description = "Created by EBScalc Concat"; AddInCurvePointers(newcurve); // write newcurve in the list of curves newcurve->CurveBindType = EBS_BIND_TO_EVALUATION; newcurve->Operator = EBS_CONCATENATION; newcurve->Curve1 = &curve1; newcurve->Curve2 = &curve2; curve1.AddCurve(newcurve); curve2.AddCurve(newcurve); unsigned long length1, length2, testlength; double rate1, rate2; length1 = curve1.NumOfSamples; length2 = curve2.NumOfSamples; rate1 = curve1.SampleRate; rate2 = curve2.SampleRate; if(rate1 > rate2) { newcurve->SampleRate = rate1; testlength = (unsigned long)((rate1/rate2)*length2+0.5); newcurve->NumOfSamples = length1+testlength; } else if(rate2 > rate1) { newcurve->SampleRate = rate2; testlength = (unsigned long)((rate2/rate1)*length1+0.5); newcurve->NumOfSamples = length2+testlength; } else newcurve->NumOfSamples = length1 + length2; ScaleBiasAdjust(newcurve); return *newcurve; } EBScurve& FFT(EBScurve& curve, unsigned long position, unsigned long size) { EBScurve *newcurve; newcurve = new EBScurve; #ifdef DEBUG fprintf(stderr, "FFT for curve called.\n"); #endif newcurve->Description = "Created by EBScalc fft"; AddInCurvePointers(newcurve); // write newcurve in the list of curves newcurve->CurveBindType = EBS_BIND_TO_EVALUATION; newcurve->Operator = EBS_FFT; newcurve->CurveType = EBS_IN_FREQUENCE; newcurve->Curve1 = &curve; newcurve->Curve2 = NULL; newcurve->FFTPos = position; if(position > curve.NumOfSamples) position = curve.NumOfSamples; if(size == ~0) size = curve.NumOfSamples; if((position + size) > curve.NumOfSamples) size = curve.NumOfSamples - position; newcurve->SampleRate = curve.SampleRate; newcurve->FFTSize = size; newcurve->NumOfSamples = pot2(size); // because of fft newcurve->Bias = curve.Bias; newcurve->BiasCalc = curve.BiasCalc; newcurve->ScaleFactor = curve.ScaleFactor; newcurve->ScaleFactorCalc = curve.ScaleFactorCalc; curve.AddCurve(newcurve); return *newcurve; } EBScurve& Correlation(EBScurve& curve1, EBScurve& curve2, unsigned long lag) { /* Vorgehensweise: Erzeuge eine neue curve und kennzeichne diese als Correlation aus den beiden gegebenen Curves. Optimierungen sind nicht moeglich. Der Rueckgabewert ist ein Pointer auf die neue curve. */ #ifdef DEBUG fprintf(stderr, "Function correlation called.\n"); #endif EBScurve *newcurve; newcurve = new EBScurve; newcurve->Description = "Created by EBScalc correlation"; AddInCurvePointers(newcurve); // write newcurve in the list of curves newcurve->CurveBindType = EBS_BIND_TO_EVALUATION; newcurve->Operator = EBS_CORRELATION; newcurve->Curve1 = &curve1; newcurve->Curve2 = &curve2; curve1.AddCurve(newcurve); curve2.AddCurve(newcurve); // take the higher samplerate and longer samplelength double samplerate; unsigned long samplelength; DetermineLengthRate(samplelength, samplerate, &curve1, &curve2); newcurve->SampleRate = samplerate; newcurve->NumOfSamples = samplelength; if(lag == ~0) // correlation of lags lag = samplelength/2; newcurve->Lag = lag; ScaleBiasAdjust(newcurve); return *newcurve; } EBScurve& LinCorrelation(EBScurve& curve1, EBScurve& curve2) { /* Vorgehensweise: Erzeuge eine neue curve und kennzeichne diese als Correlation aus den beiden gegebenen Curves. Optimierungen sind nicht moeglich. Der Rueckgabewert ist ein Pointer auf die neue curve. */ EBScurve *newcurve; newcurve = new EBScurve; #ifdef DEBUG fprintf(stderr, "Function linear correlation called.\n"); #endif newcurve->Description = "Created by EBScalc lin correlation"; AddInCurvePointers(newcurve); // write newcurve in the list of curves newcurve->CurveBindType = EBS_BIND_TO_EVALUATION; newcurve->Operator = EBS_LINCORRELATION; newcurve->Curve1 = &curve1; newcurve->Curve2 = &curve2; curve1.AddCurve(newcurve); curve2.AddCurve(newcurve); // take the higher samplerate and longer samplelength double samplerate; unsigned long samplelength; DetermineLengthRate(samplelength, samplerate, &curve1, &curve2); newcurve->SampleRate = samplerate; newcurve->NumOfSamples = samplelength; ScaleBiasAdjust(newcurve); return *newcurve; } EBScurve& Convolution(EBScurve& curve1, EBScurve& curve2, unsigned long zero) { /* Vorgehensweise: Erzeuge eine neue curve und kennzeichne diese als Convolution aus den beiden gegebenen Curves. Optimierungen sind nicht moeglich. Der Rueckgabewert ist ein Pointer auf die neue curve. */ EBScurve *newcurve; newcurve = new EBScurve; #ifdef DEBUG fprintf(stderr, "Function convolution called.\n"); #endif newcurve->Description = "Created by EBScalc convolution"; AddInCurvePointers(newcurve); // write newcurve in the list of curves newcurve->CurveBindType = EBS_BIND_TO_EVALUATION; newcurve->Operator = EBS_CONVOLUTION; newcurve->Curve1 = &curve1; newcurve->Curve2 = &curve2; curve1.AddCurve(newcurve); curve2.AddCurve(newcurve); newcurve->ZeroOffset = zero; double samplerate; unsigned long samplelength; DetermineLengthRate(samplelength, samplerate, &curve1, &curve2); newcurve->SampleRate = samplerate; newcurve->NumOfSamples = samplelength; ScaleBiasAdjust(newcurve); return *newcurve; } EBScurve& ConvolutionWithFrequence(EBScurve& curve1, EBScurve& curve2) { /* Vorgehensweise: Erzeuge eine neue curve und kennzeichne diese als Convolution aus den beiden gegebenen Curves. Optimierungen sind nicht moeglich. Der Rueckgabewert ist ein Pointer auf die neue curve. */ EBScurve *newcurve; newcurve = new EBScurve; #ifdef DEBUG fprintf(stderr, "Operator convolution with frequence called.\n"); #endif newcurve->Description = "Created by EBScalc convolution w.freq."; AddInCurvePointers(newcurve); // write newcurve in the list of curves newcurve->CurveBindType = EBS_BIND_TO_EVALUATION; newcurve->Operator = EBS_CONVOLUTION_WITH_FREQUENCE; newcurve->Curve1 = &curve1; newcurve->Curve2 = &curve2; curve1.AddCurve(newcurve); curve2.AddCurve(newcurve); newcurve->SampleRate = curve1.SampleRate; newcurve->NumOfSamples = curve1.NumOfSamples; newcurve->Bias = curve1.Bias; newcurve->BiasCalc = curve1.BiasCalc; newcurve->ScaleFactor = curve1.ScaleFactor; newcurve->ScaleFactorCalc = curve1.ScaleFactorCalc; delete [] newcurve->SIUnit; newcurve->SIUnit = mystrdup(curve1.SIUnit); newcurve->UnitSpec = curve1.UnitSpec; return *newcurve; } EBScurve& EBScurve::operator=(EBScurve& newcurve) { /* Vorgehensweise: Ueberpruefe, ob sich jemand schon auf das Element auf der linken Seite bezieht (Reference >0). Falls nein, dann copiere alle Aenderungen nach linker Seite und loesche rechte Seite falls die rechte Seite mit new erzeugt wurde. Andernfalls wird der Destructor beim Verlassen des Gueltigkeitsbereiches automatisch aufgerufen. Falls ja, dann ist dort die Lage des Objektes auf der linken Seite bekannt, also uebergebe an das Objekt der linken Seite ein neues Objekt. */ #ifdef DEBUG fprintf(stderr, "Operator= called.\n", this, &newcurve); #endif if(this == &newcurve) // f1 = f1; return *this; if(Reference == 0) { // no one is interested on the curve of the left side // lose binding if there is one for the left side if(CurveBindType == EBS_BIND_TO_CURVE) { Curve1->RemoveCurve(this); if((this->Curve1->Reference == 0) && (InCurvePointers(this->Curve1))) { RemoveInCurvePointers(this->Curve1); delete this->Curve1; } } else if(CurveBindType == EBS_BIND_TO_EVALUATION) { Curve1->RemoveCurve(this); if(Curve2 != NULL) Curve2->RemoveCurve(this); if((this->Curve1->Reference == 0) && (InCurvePointers(this->Curve1))) { RemoveInCurvePointers(this->Curve1); delete this->Curve1; } if(this->Curve2 != NULL) if((this->Curve2->Reference == 0) && (InCurvePointers(this->Curve2))) { RemoveInCurvePointers(this->Curve2); delete this->Curve2; } } char *rescdesc = this->Description; delete [] FileName; FileName = NULL; UnitSpec = 0; delete [] SIUnit; SIUnit = NULL; // make a full copy of newcurve to this bcopy((char *)(&newcurve), (char *)(this), sizeof(EBScurve)); this->Description = rescdesc; this->FileName = NULL; this->SIUnit = mystrdup(newcurve.SIUnit); this->EbsFile = NULL; newcurve.AddCurve(this); CurveBindType = EBS_BIND_TO_CURVE; Curve1 = &newcurve; Curve2 = NULL; Reference = 0; Dependent = NULL; Simplify(this, &newcurve); return *this; } else if((Reference == 1) && (this == newcurve.Curve1) && (newcurve.CurveBindType == EBS_BIND_TO_CURVE)) { // f1 = f1 + x; // the curve is interested on herself CopyCurve(&newcurve, this); newcurve.RemoveCurve(this); (newcurve.Curve1)->RemoveCurve(&newcurve); // this->RemoveCurve(newcurve); if((newcurve.Reference == 0) && (InCurvePointers(&newcurve))) { RemoveInCurvePointers(&newcurve); delete &newcurve; } return *this; } else { // f1 = f2 + f3; f2 = f3 + y; (Referenz > 0,1) // there are curve(s) which are interested on the curve of the left side // tell all the curves who depend on this, that there is a new copy // of this and overwrite this with the object of the right side EBScurve *newcurve2; newcurve2 = new EBScurve; AddInCurvePointers(newcurve2); ChangeBindings(&newcurve, newcurve2); return *this; } } void EBScurve::ChangeBindings(EBScurve *newcurve, EBScurve *newcurve2) { // there are curves which are dependend on 'this' // copy 'this' to newcurve2 // copy newcurve to 'this // tell all curves who depend on 'this', that they now depend to newcurve2 // remove the dependency of 'this' to another curve(s) if there is one // and set therefore the dependence to newcurve2 if(this->CurveBindType == EBS_BIND_TO_CURVE) { this->Curve1->RemoveCurve(this); this->Curve1->AddCurve(newcurve2); if((this->Curve1->Reference == 0) && (InCurvePointers(this->Curve1))) { RemoveInCurvePointers(this->Curve1); delete this->Curve1; } } else if(this->CurveBindType == EBS_BIND_TO_EVALUATION) { this->Curve1->RemoveCurve(this); this->Curve1->AddCurve(newcurve2); if(this->Curve2 != NULL) { this->Curve2->RemoveCurve(this); this->Curve2->AddCurve(newcurve2); } if((this->Curve1->Reference == 0) && (InCurvePointers(this->Curve1))) { RemoveInCurvePointers(this->Curve1); delete this->Curve1; } if(this->Curve2 != NULL) if((this->Curve2->Reference == 0) && (InCurvePointers(this->Curve2))) { RemoveInCurvePointers(this->Curve2); delete this->Curve2; } } // rescue description of 'this' char *rescdesc = this->Description; // make a full copy of this to newcurve2 // make a full copy of newcurve to this bcopy((char *)(this), (char *)(newcurve2), sizeof(EBScurve)); bcopy((char *)(newcurve), (char *)(this), sizeof(EBScurve)); // reinsert description in 'this' and delete the description in newcurve2 this->Description = rescdesc; newcurve2->Description = "Created by EBScalc="; this->FileName = mystrdup(newcurve->FileName); this->SIUnit = mystrdup(newcurve->SIUnit); this->EbsFile = newcurve2->EbsFile; newcurve2->EbsFile = NULL; newcurve->AddCurve(this); // this could be reversed later this->CurveBindType = EBS_BIND_TO_CURVE; this->Curve1 = newcurve; this->Curve2 = NULL; this->Reference = 0; this->Dependent = NULL; // simplify... if((newcurve->CurveBindType == EBS_BIND_TO_CURVE) && (newcurve->Curve1 == this)) { // f3 = f2; f2 = f2 + 2; (f2) // the curve depends on her selve newcurve->RemoveCurve(this); newcurve2->RemoveCurve(newcurve); newcurve2->AddCurve(this); this->Curve1 = newcurve2; if((newcurve->Reference == 0) && (InCurvePointers(newcurve))) { RemoveInCurvePointers(newcurve); delete newcurve; } } else if((newcurve->CurveBindType == EBS_BIND_TO_EVALUATION) && ((newcurve->Curve1 == this) || (newcurve->Curve2 == this))) { // the curve depends on her selve newcurve->RemoveCurve(this); if(newcurve->Curve1 == this) { newcurve2->RemoveCurve(newcurve); newcurve2->AddCurve(this); this->Curve1 = newcurve2; } else { newcurve->Curve1->RemoveCurve(newcurve); newcurve->Curve1->AddCurve(this); this->Curve1 = newcurve->Curve1; } if(newcurve->Curve2 == this) { newcurve2->RemoveCurve(newcurve); newcurve2->AddCurve(this); this->Curve2 = newcurve2; } else { if(newcurve->Curve2 != NULL) { newcurve->Curve2->RemoveCurve(newcurve); newcurve->Curve2->AddCurve(this); this->Curve2 = newcurve->Curve2; } } if((newcurve->Reference == 0) && (InCurvePointers(newcurve))) { RemoveInCurvePointers(newcurve); delete newcurve; } this->CurveBindType = EBS_BIND_TO_EVALUATION; } else Simplify(this, newcurve); // tell all dependent of 'this' that something has changed curve_pointers *help; help = newcurve2->Dependent; while(help != NULL) { if(help->curve->Curve1 == this) help->curve->Curve1 = newcurve2; else if(help->curve->Curve2 == this) help->curve->Curve2 = newcurve2; else if(help->curve == this) ; else { #ifdef DEBUG fprintf(stderr, "Error in tell dependent: expected %p but get %p.\n", this, help->curve->Curve1); #endif help->curve->info(); } help = help->next_curve; } } void CopyCurve(EBScurve *curve, EBScurve *newcurve) { newcurve->SampleRate = curve->SampleRate; newcurve->ScaleFactor = curve->ScaleFactor; newcurve->ScaleFactorCalc = curve->ScaleFactorCalc; newcurve->Vmin = curve->Vmin; newcurve->Vmax = curve->Vmax; newcurve->Bias = curve->Bias; newcurve->BiasCalc = curve->BiasCalc; newcurve->NumOfSamples = curve->NumOfSamples; newcurve->CurveType = curve->CurveType; newcurve->CutOffset = curve->CutOffset; delete [] newcurve->SIUnit; newcurve->SIUnit = NULL; newcurve->UnitSpec = curve->UnitSpec; if(curve->UnitSpec == 1) { newcurve->SIUnit = mystrdup(curve->SIUnit); } curve->AddCurve(newcurve); // curve knows that newcurve depends on it } void EBScurve::info(void) // prints information over a curve { fprintf(stderr, "Description of curve: %s\n", Description); fprintf(stderr, "Samplerate: %f\n", SampleRate); fprintf(stderr, "Unit specified? %d pointer %p\n", UnitSpec, SIUnit); fprintf(stderr, "SIUnit: %s\n", SIUnit); fprintf(stderr, "Scalefactor: %f\n", ScaleFactor); fprintf(stderr, "ScalefactorCalc: %f\n", ScaleFactorCalc); fprintf(stderr, "Vmin: %d / Vmax: %d\n", Vmin, Vmax); fprintf(stderr, "Bias: %f\n", Bias); fprintf(stderr, "BiasCalc: %f\n", BiasCalc); fprintf(stderr, "Number of Samples: %d\n", NumOfSamples); fprintf(stderr, "Curve type: %d 1 in time / 2 in frequence\n", CurveType); fprintf(stderr, "Curve bind type: %d\n", CurveBindType); fprintf(stderr, "Operator: %d\n", Operator); fprintf(stderr, "FileName: %s\n", FileName); fprintf(stderr, "References: %d\n", Reference); fprintf(stderr, "Leaf: %p\n", Leaf); fprintf(stderr, "This pointer: %p\n", this); fprintf(stderr, "Bound to pointer1: %p\n", Curve1); fprintf(stderr, "Bound to pointer2: %p\n", Curve2); fprintf(stderr, "Following curves depend on this one:\n>"); curve_pointers *help; help = Dependent; while(help != NULL) { fprintf(stderr, " %p ", help->curve); help = help->next_curve; } fprintf(stderr, "<\n"); fprintf(stderr, "----------------------------------------\n"); } void InfoInCurvePointers(void) { curve_pointers *help; help = CurvePointers; fprintf(stderr, "Which curves are in CurvePointers?\n"); while(help != NULL) { help->curve->info(); help = help->next_curve; } } // ************************************ // some definition for the class EBStmp // ************************************ void ToOpenClose(void) { unsigned long i = 0; tmp_pointers *help; help = TmpPointers; while(help != NULL) { if(help->tmp->IsFileOpen == 1) i++; help = help->next_tmp; } if(i > MAXOPEN) { help = TmpPointers; while(help != NULL) { if(help->tmp->IsFileOpen == 1) { help->tmp->CloseFile(); return; } help = help->next_tmp; } } } void EBStmp::JumpToFirstPosition(void) { if(BindType == EBS_BIND_TO_EBS_FILE) { SamPosition = SampleOffset + CutOffset; } else { // EBS_BIND_TO_TMP_FILE fseek(FFile, 0, SEEK_SET); int nan; fgetf4(FFile, &nan); fgeti32(FFile); fseek(FFile, 2*(SampleOffset + CutOffset), SEEK_CUR); SamPosition = 0; } } int EBStmp::OpenFile(void) { // fprintf(stderr, "open for %p\n", this); if(IsFileOpen == 1) return 0; // find out if there are already to many EBStmps are opened // and close one if needed ToOpenClose(); if(BindType == EBS_BIND_TO_EBS_FILE) { EFile = new EBSFile(FileName, 'r'); if(EFile->Valid() == 1) { IsFileOpen = 1; } else { delete EFile; EFile = NULL; SamPosition = ~0; // not yet set return -1; } SamPosition = ~0; // not yet set return 0; } else if(BindType == EBS_BIND_TO_TMP_FILE) { FFile = fopen(FileName, "rb"); if(FFile == NULL) { return -1; } IsFileOpen = 1; SamPosition = ~0; // not yet set return 0; } else { SamPosition = ~0; // not yet set return -1; } } void EBStmp::CloseFile(void) { // ebs oder tmp file if(IsFileOpen == 1) { if(BindType == EBS_BIND_TO_EBS_FILE) delete EFile; else fclose(FFile); } IsFileOpen = 0; } void EBStmp::AddCurve(EBScurve *elem) { ListAddIn(Dependent, elem); Reference += 1; } int EBStmp::RemoveCurve(EBScurve *elem) { int ret; if(ListRemoveIn(Dependent, elem) == 1) { Reference -= 1; ret = 1; } else ret = 0; if(Reference <= 0) { // delete this, if no one whants anything from it RemoveInTmpPointers(this); delete this; } return ret; } EBStmp::EBStmp(void) // constructor { // init Reference = 0; Dependent = NULL; NumOfSamples = 0; SamPosition = 0; BindType = EBS_NO_BINDING; CurveType = EBS_IN_TIME; IsFileOpen = 0; CutOffset = 0; ChannelNumber = 0; SampleOffset = 0; FileName = NULL; FFile = NULL; EFile = NULL; } int EBStmp::FileInTmpPointers() { tmp_pointers *help; help = TmpPointers; if(FileName == NULL) return 1; while(help != NULL) { if(help->tmp == this) { help = help->next_tmp; continue; } if(help->tmp->BindType == EBS_BIND_TO_TMP_FILE) if(help->tmp->FileName != NULL) if(strcmp(help->tmp->FileName, FileName) == 0) { return 1; } help = help->next_tmp; } return 0; } EBStmp::~EBStmp(void) // Destructor { if(IsFileOpen == 1) { if(BindType == EBS_BIND_TO_EBS_FILE) delete EFile; else fclose(FFile); } IsFileOpen = 0; // look in all Leafs, if tmp file is still needed if(BindType == EBS_BIND_TO_TMP_FILE) { if(!FileInTmpPointers()) unlink(FileName); delete [] FileName; } else delete [] FileName; } // return first sample and rewind for GetNextSample short EBStmp::GetFirstSample(void) { short value; if(IsFileOpen == 0) OpenFile(); JumpToFirstPosition(); // next is first sample if(BindType == EBS_BIND_TO_EBS_FILE) { value = EFile->Value(ChannelNumber, SamPosition); SamPosition += 1; return value; } else { // EBS_BIND_TO_TMP_FILE value = fgeti16(FFile); SamPosition += 1; return value; } } short EBStmp::GetNextSample(void) { short value; if(IsFileOpen == 0) OpenFile(); if(SamPosition == ~0) JumpToFirstPosition(); if(BindType == EBS_BIND_TO_EBS_FILE) { value = EFile->Value(ChannelNumber, SamPosition); SamPosition += 1; return value; } else { // EBS_BIND_TO_TMP_FILE value = fgeti16(FFile); SamPosition += 1; return value; } } void EBStmp::RewindSample(void) { SamPosition = ~0; } short EBStmp::GetSample(unsigned long pos) { unsigned long i; if(IsFileOpen == 0) OpenFile(); if(SamPosition == ~0) JumpToFirstPosition(); if((SamPosition+1) == pos) return GetNextSample(); else { if(BindType == EBS_BIND_TO_EBS_FILE) { SamPosition = SampleOffset+pos+1; return EFile->Value(ChannelNumber, SampleOffset+pos); } else { // EBS_BIND_TO_TMP_FILE fseek(FFile, 2*(pos-SamPosition), SEEK_CUR); SamPosition = pos; return fgeti16(FFile); } } } Complex EBStmp::GetNextComplex() { int nan; Complex value(-1, -1); if(IsFileOpen == 0) OpenFile(); if(SamPosition == ~0) JumpToFirstPosition(); if((BindType == EBS_BIND_TO_TMP_FILE) && (CurveType == EBS_IN_FREQUENCE)) { value = Complex(fgetf4(FFile, &nan), fgetf4(FFile, &nan)); SamPosition += 1; return value; } else { #ifdef DEBUG fprintf(stderr, "Error: GetNextComplex() for a curve in time called.\n"); #endif return value; } } void PutNextComplex(Complex value, FILE *tmpfile) { fputf4(value.real(), tmpfile); fputf4(value.imag(), tmpfile); }