| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579 |
- /*
- * Copyright (c) 1983-2013 Trevor Wishart and Composers Desktop Project Ltd
- * http://www.trevorwishart.co.uk
- * http://www.composersdesktop.com
- *
- This file is part of the CDP System.
-
- The CDP System is free software; you can redistribute it
- and/or modify it under the terms of the GNU Lesser General Public
- License as published by the Free Software Foundation; either
- version 2.1 of the License, or (at your option) any later version.
-
- The CDP System is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public
- License along with the CDP System; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
- 02111-1307 USA
- *
- */
- /*
- * Take a set of amp-frq data in the correct range,
- * and use cubic spline to replot curve to cover
- * every 1/64 tone over whole range.
- * Where, frq ratio between adjacent chans becomes < 1/64 tone
- * use chan centre frqs.
- */
- #define PSEUDOCENT (1.0009) // approx 1/64th of a tone
- #include <stdio.h>
- #include <stdlib.h>
- #include <structures.h>
- #include <tkglobals.h>
- #include <pnames.h>
- #include <filetype.h>
- #include <processno.h>
- #include <modeno.h>
- #include <logic.h>
- #include <globcon.h>
- #include <cdpmain.h>
- #include <math.h>
- #include <mixxcon.h>
- #include <osbind.h>
- #include <science.h>
- #include <ctype.h>
- #include <sfsys.h>
- #include <string.h>
- #include <srates.h>
- int sloom = 0;
- int sloombatch = 0;
- const char* cdp_version = "6.1.0";
- char errstr[2400]; //RWD added
- //CDP LIB REPLACEMENTS
- static int allocate_output_array(double **outarray, int *outcnt, double chwidth, double halfchwidth, double nyquist);
- //static int get_tk_cmdline_word(int *cmdlinecnt,char ***cmdline,char *q);
- static int handle_the_special_data(FILE *fpi, double **parray, double **secondderiv, double **x, double **y, int *itemcnt);
- static int test_the_special_data(double *parray, int itemcnt, double nyquist);
- static int smooth(double *x,double *y,double *secondderiv,double *outarray,int *outcnt,double chwidth,double halfchwidth,double nyquist,int arraycnt);
- //static int smooth(double *parray,double *outarray,int *outcnt, double chwidth, double halfchwidth,double nyquist);
- static int spline(double *parray,int itemcnt,double *secondderiv,double *x,double *y);
- static int splint(double thisfrq,double *thisamp,int *hi,int arraycnt,double *secondderiv, double *x, double *y);
- static int dove(double *parray,int itemcnt,double *outarray,int outcnt);
- static int get_float_with_e_from_within_string(char **str,double *val);
- /**************************************** MAIN *********************************************/
- int main(int argc,char *argv[])
- {
- FILE *fpi, *fpo;
- int k, OK = 0, dovetail = 0;
- int exit_status, srate, pointcnt, clength;
- double chwidth, halfchwidth, nyquist, *parray, *secondderiv, *x, *y, *outarray;
- int itemcnt, outcnt, arraycnt;
- char temp[200], temp2[200];
- if(argc < 5 || argc > 6) {
- usage1();
- return(FAILED);
- }
- if((fpi = fopen(argv[1],"r")) == NULL) {
- fprintf(stdout,"CANNOT OPEN DATAFILE %s\n",argv[1]);
- fflush(stdout);
- return(FAILED);
- }
- if((exit_status = handle_the_special_data(fpi,&parray,&secondderiv,&x,&y,&itemcnt))<0) {
- return(FAILED);
- }
- arraycnt = itemcnt/2;
- if(sscanf(argv[3],"%d",&pointcnt) != 1) {
- fprintf(stdout,"CANNOT READ POINTCNT (%s)\n",argv[3]);
- fflush(stdout);
- return(FAILED);
- }
- OK = 0;
- k = 1;
- while(k < pointcnt) {
- k *= 2;
- if(k == pointcnt){
- OK= 1;
- break;
- }
- }
- if(!OK) {
- fprintf(stdout,"ANALYSIS POINTS PARAMETER MUST BE A POWER OF TWO.\n");
- fflush(stdout);
- return(FAILED);
- }
- if(sscanf(argv[4],"%d",&srate) != 1) {
- fprintf(stdout,"CANNOT READ SAMPLE RATE (%s)\n",argv[3]);
- fflush(stdout);
- return(FAILED);
- }
- if(srate < 44100 || BAD_SR(srate)) {
- fprintf(stdout,"INVALID SAMPLE RATE ENTERED (44100,48000,88200,96000 only).\n");
- fflush(stdout);
- return(DATA_ERROR);
- }
- if(argc == 6) {
- if(strcmp(argv[5],"-s")) {
- fprintf(stdout,"UNKNOWN FINAL PARAMETER (%s).\n",argv[5]);
- fflush(stdout);
- return(DATA_ERROR);
- }
- dovetail = 1;
- }
- clength = (pointcnt + 2)/2;
- nyquist = (double)(srate / 2);
- chwidth = nyquist/(double)clength;
- halfchwidth = chwidth / 2;
- if((exit_status = test_the_special_data(parray,itemcnt,nyquist))<0)
- return(FAILED);
- if((exit_status = allocate_output_array(&outarray,&outcnt,chwidth,halfchwidth,nyquist))<0)
- return(FAILED);
- if((fpo = fopen(argv[2],"w")) == NULL) {
- fprintf(stdout,"CANNOT OPEN OUTPUT DATAFILE %s\n",argv[2]);
- fflush(stdout);
- return(FAILED);
- }
- if((exit_status = spline(parray,itemcnt,secondderiv,x,y))<0)
- return(FAILED);
- if((exit_status = smooth(x,y,secondderiv,outarray,&outcnt,chwidth,halfchwidth,nyquist,arraycnt)) < 0)
- return(FAILED);
- if(dovetail) {
- if((exit_status = dove(parray,itemcnt,outarray,outcnt)) < 0)
- return(FAILED);
- }
- k = 0;
- for(k = 0;k < outcnt;k+=2) {
- sprintf(temp,"%lf",outarray[k]);
- sprintf(temp2,"%lf",outarray[k+1]);
- strcat(temp2,"\n");
- strcat(temp,"\t");
- strcat(temp,temp2);
- fputs(temp,fpo);
- }
- if(fclose(fpo)<0) {
- fprintf(stdout,"WARNING: Failed to close output data file %s.\n",argv[2]);
- fflush(stdout);
- }
- return(SUCCEEDED);
- }
- /******************************** USAGE1 ********************************/
- int usage1(void)
- {
- fprintf(stderr,
- "USAGE: cubicspline datafile outdatafile pointcnt srate [-s]\n"
- "\n"
- "Generate smoothed curve from input data re spectrum.\n"
- "\n"
- "DATAFILE textfile of frq/amp pairs.\n"
- "OUTDATAFILE textfile of smoothed data.\n"
- "POINTCNT no of analysis points required in handling data.\n"
- "SRATE samplerate of eventual sound output.\n"
- "-s if spectral amp falls to zero before the nyquist,\n"
- " keep zeroed end of spectrum at zero.\n."
- "\n");
- return(USAGE_ONLY);
- }
- /************************** HANDLE_THE_SPECIAL_DATA **********************************/
- int handle_the_special_data(FILE *fpi, double **parray, double **secondderiv, double **x, double **y,int *itemcnt)
- {
- int cnt, linecnt;
- int arraycnt;
- double *p, dummy;
- char temp[200], *q;
- cnt = 0;
- p = &dummy;
- while(fgets(temp,200,fpi)==temp) {
- q = temp;
- if(*q == ';') // Allow comments in file
- continue;
- while(get_float_with_e_from_within_string(&q,p))
- cnt++;
- }
- if(ODD(cnt)) {
- fprintf(stdout,"Data not paired correctly in input data file\n");
- fflush(stdout);
- return(DATA_ERROR);
- }
- if(cnt == 0) {
- fprintf(stdout,"No data in input data file\n");
- fflush(stdout);
- return(DATA_ERROR);
- }
- if((*parray = (double *)malloc(cnt * sizeof(double)))==NULL) {
- fprintf(stdout,"INSUFFICIENT MEMORY for input data.\n");
- fflush(stdout);
- return(MEMORY_ERROR);
- }
- arraycnt = cnt/2;
- if((*secondderiv = (double *)malloc(cnt/2 * sizeof(double)))==NULL) {
- fprintf(stdout,"INSUFFICIENT MEMORY for storing slope of input data.\n");
- fflush(stdout);
- return(MEMORY_ERROR);
- }
- if((*x = (double *)malloc(cnt/2 * sizeof(double)))==NULL) {
- fprintf(stdout,"INSUFFICIENT MEMORY for storing x-coords of input data.\n");
- fflush(stdout);
- return(MEMORY_ERROR);
- }
- if((*y = (double *)malloc(cnt/2 * sizeof(double)))==NULL) {
- fprintf(stdout,"INSUFFICIENT MEMORY for storing y-coords of input data.\n");
- fflush(stdout);
- return(MEMORY_ERROR);
- }
- fseek(fpi,0,0);
- linecnt = 1;
- p = *parray;
- while(fgets(temp,200,fpi)==temp) {
- q = temp;
- if(*q == ';') // Allow comments in file
- continue;
- while(get_float_with_e_from_within_string(&q,p)) {
- p++;
- }
- linecnt++;
- }
- if(fclose(fpi)<0) {
- fprintf(stdout,"WARNING: Failed to close input data file.\n");
- fflush(stdout);
- }
- *itemcnt = cnt;
- return(FINISHED);
- }
- /************************** TEST_THE_SPECIAL_DATA **********************************/
- int test_the_special_data(double *parray, int itemcnt, double nyquist)
- {
- double *p;
- int isamp = 0, linecnt = 1;
- p = parray;
- while(linecnt <= itemcnt/2) {
- if(isamp) {
- if(*p < 0.0 || *p > 1.0) {
- fprintf(stdout,"Amp (%lf) out of range (0-1) at line %d in datafile.\n",*p,linecnt);
- fflush(stdout);
- return(DATA_ERROR);
- }
- } else {
- if(*p < 0.0 || *p > nyquist) {
- fprintf(stdout,"Frq (%lf) out of range (0 - %lf) at line %d in datafile.\n",*p,nyquist,linecnt);
- fflush(stdout);
- return(DATA_ERROR);
- }
- }
- if(!isamp)
- linecnt++;
- isamp = !isamp;
- p++;
- }
- return(FINISHED);
- }
- /************************** ALLOCATE_OUTPUT_ARRAY **********************************/
- int allocate_output_array(double **outarray,int *outcnt,double chwidth,double halfchwidth,double nyquist)
- {
- int outsize = 1; // Count initial halfwidht channel
- double lastlofrq, lofrq = halfchwidth;
- while(lofrq <= nyquist) {
- outsize++;
- lastlofrq = lofrq;
- lofrq *= PSEUDOCENT;
- if(lofrq - lastlofrq >= chwidth) // Once chan separation is > chwidth
- lofrq = lastlofrq + chwidth; // Just set 1 value per channel
- }
- outsize += 64; // SAFETY
- outsize *= 2;
- if((*outarray = (double *)malloc(outsize * sizeof(double)))==NULL) {
- fprintf(stdout,"INSUFFICIENT MEMORY for input data.\n");
- fflush(stdout);
- return(MEMORY_ERROR);
- }
- *outcnt = outsize;
- return( FINISHED);
- }
- /************************** SMOOTH **********************************
- static int smooth(double *parray,double *outarray,int *outcnt,double chwidth,double halfchwidth,double nyquist)
- {
- int k = 0;
- double lastlofrq, lofrq = halfchwidth;
- outarray[k] = 1.0;
- outarray[k+1] = 0.0;
- k = 2;
- while(lofrq <= nyquist) {
- k += 2;
- if(k > *outcnt) {
- fprintf(stdout,"OUT OF MEMORY IN OUTPUT ARRAY.\n");
- fflush(stdout);
- return(MEMORY_ERROR);
- }
- outarray[k] = 0.0;
- outarray[k+1] = lofrq;
- lastlofrq = lofrq;
- lofrq *= PSEUDOCENT;
- if(lofrq - lastlofrq >= chwidth) { // Once chan separation is < HEREH
- lofrq = lastlofrq + chwidth; // Just set 1 value per channel
- outarray[k] = 1.0;
- }
- }
- *outcnt = k;
- return( FINISHED);
- }
- */
- /************************************ SPLINE ************************************
- *
- * This function returns the second derivative at all points of the curve.
- *
- * We assume that the curve is flat (first derivative = 0) at start and end points
- */
- int spline(double *parray,int itemcnt,double *secondderiv,double *x,double *y)
- {
- double firstderivstt = 0.0, firstderivend = 0.0;
- double *u, sig, ppp, qend, uend;
- int i, k, arraylen = itemcnt/2;
- if((u = (double *)malloc(arraylen * sizeof(double)))==NULL) {
- fprintf(stdout,"INSUFFICIENT MEMORY for slope calculations 1.\n");
- fflush(stdout);
- return(MEMORY_ERROR);
- }
- for(i=0,k=0;k<itemcnt;k+=2,i++) {
- x[i] = parray[k]; // FRQ is the independent, monotonically increasing variable
- y[i] = parray[k+1];
- }
- secondderiv[0] = -0.5;
- u[0] = (3.0/(x[1] - x[0])) * (((y[1] - y[0])/(x[1] - x[0])) - firstderivstt);
- for(i = 1;i < arraylen-1; i++) {
- sig = (x[i] - x[i-1])/(x[i+1] - x[i-1]);
- ppp = (sig * secondderiv[i-1]) + 2.0;
- secondderiv[i] = (sig - 1.0)/ppp;
- u[i] = ((y[i+1] - y[i])/(x[i+1] - x[i])) - ((y[i] - y[i-1])/(x[i] - x[i-1]));
- u[i] = (((6.0 * u[i])/(x[i+1] - x[i-1])) - (sig * u[i-1]))/ppp;
- }
- // i = arraylen-1; = last entry in array
- qend = 0.5;
- uend = (3.0/(x[i] - x[i-1])) * (firstderivend - ((y[i] - y[i-1])/(x[i] - x[i-1])));
- secondderiv[i] = (uend - (qend * u[i-1]))/((qend * secondderiv[i-1]) + 1.0);
- for(k = i-1;k >= 0;k--) {
- secondderiv[k] = (secondderiv[k] * secondderiv[k+1]) + u[k];
- }
- free(u);
- return(FINISHED);
- }
- /************************************ SPLINT ************************************
- *
- * This function returns the value at a specified frq on curve, using cspline interp (2nd-deriv) data..
- */
- int splint(double thisfrq,double *thisamp,int *hi,int arraycnt,double *secondderiv, double *x, double *y)
- {
- int klo, khi = *hi;
- double fullstep, a, b, amp, jjj, kkk;
- /* Establish which input values bracket 'thisfrq' */
- while(x[khi] <= thisfrq) {
- khi++;
- if(khi >= arraycnt) {
- *thisamp = y[arraycnt - 1];
- return(FINISHED);
- }
- }
- klo = khi - 1;
- if(klo < 0) {
- *thisamp = y[0];
- return(FINISHED);
- }
- fullstep = x[khi] - x[klo];
- a = (x[khi] - thisfrq)/fullstep;
- b = (thisfrq - x[klo])/fullstep;
- amp = a * y[klo];
- amp += b * y[khi];
- jjj = a * a * a;
- jjj -= a;
- jjj *= secondderiv[klo];
- kkk = b * b * b;
- kkk -= b;
- kkk *= secondderiv[khi];
- jjj += kkk;
- jjj *= fullstep * fullstep;
- jjj /= 6.0;
-
- amp += jjj;
- if(amp < 0.0)
- amp = 0.0;
- if(amp > 1.0) {
- fprintf(stdout,"INFO: SMOOTHED DATA CLIPPED\n");
- fflush(stdout);
- amp = 1.0;
- }
- *thisamp = amp;
- *hi = khi;
- return(FINISHED);
- }
- /************************** SMOOTH **********************************/
- int smooth(double *x,double *y,double *secondderiv,double *outarray,int *outcnt,double chwidth,double halfchwidth,double nyquist,int arraycnt)
- {
- int exit_status;
- int k = 0, hi = 0;
- double lastlofrq, lofrq = halfchwidth, thisamp;
- outarray[k] = 0.0;
- outarray[k+1] = 0.0;
- k = 2;
- while(lofrq < nyquist) {
- k += 2;
- if(k > *outcnt) {
- fprintf(stdout,"OUT OF MEMORY IN OUTPUT ARRAY.\n");
- fflush(stdout);
- return(MEMORY_ERROR);
- }
- if((exit_status = splint(lofrq,&thisamp,&hi,arraycnt,secondderiv,x,y))<0)
- return(FAILED);
- outarray[k] = lofrq;
- outarray[k+1] = thisamp;
- lastlofrq = lofrq;
- lofrq *= PSEUDOCENT;
- if(lofrq - lastlofrq >= chwidth) // Once chan separation is < PSEUDOCENT
- lofrq = lastlofrq + chwidth; // Just set 1 value per channel
- }
- k += 2;
- outarray[k++] = nyquist;
- outarray[k++] = 0.0;
- *outcnt = k;
- if(outarray[0] == 0.0 && outarray[2] == 0.0) { // Eliminate any duplication of zero start frq
- k = 0;
- hi = 2;
- while(hi < *outcnt) {
- outarray[k] = outarray[hi];
- k++;
- hi++;
- }
- *outcnt = k;
- }
- return(FINISHED);
- }
- /************************** DOVE **********************************/
- int dove(double *parray,int itemcnt,double *outarray,int outcnt)
- {
- double *amp, *frq, *inarrayend = parray + itemcnt, *outarrayend = outarray + outcnt, tailstartfrq;
- amp = inarrayend - 1;
- if(!flteq(*amp,0.0)) // Input spectrum never falls to zero
- return(FINISHED);
- while(amp > parray) { // Search back from end of (orig) spectrum, until spectral vals are >0
- if(!flteq(*amp,0.0))
- break;
- amp -= 2;
- }
- if(amp <= parray) // (original) spectrum is everywhere zero
- return(FINISHED);
- frq = amp - 1;
- tailstartfrq = *frq; // Note frq at which (original) spectrum finally falls to zero
- frq = outarray; // Parse frq vals in output array
- while(frq < outarrayend) {
- if(*frq >= tailstartfrq) {
- amp = frq - 1; // Note where outfrq exceeds tailstartfrq of input, and step to amp BEFORE it
- break;
- }
- frq += 2;
- }
- if(frq >= outarrayend) { // Output frq never exceeds input frq: should be impossible
- fprintf(stdout,"DOVETAILING FAILED.\n");
- fflush(stdout);
- return(PROGRAM_ERROR);
- }
- while(amp < outarrayend) { // Search for point where output first touches zero
- if(flteq(*amp,0.0))
- break;
- amp += 2;
- }
- if(amp >= outarrayend) {
- fprintf(stdout,"NO DOVETAILING OCCURED.\n");
- fflush(stdout);
- }
- while(amp < outarrayend) { // Set tail to zero
- *amp = 0.0;
- amp += 2;
- }
- return(FINISHED);
- }
- /************************** GET_FLOAT_WITH_E_FROM_WITHIN_STRING **************************
- * takes a pointer TO A POINTER to a string. If it succeeds in finding
- * a float it returns the float value (*val), and it's new position in the
- * string (*str).
- */
- int get_float_with_e_from_within_string(char **str,double *val)
- {
- char *p, *valstart;
- int decimal_point_cnt = 0, has_digits = 0, has_e = 0, lastchar = 0;
- p = *str;
- while(isspace(*p))
- p++;
- valstart = p;
- switch(*p) {
- case('-'): break;
- case('.'): decimal_point_cnt=1; break;
- default:
- if(!isdigit(*p))
- return(FALSE);
- has_digits = TRUE;
- break;
- }
- p++;
- while(!isspace(*p) && *p!=NEWLINE && *p!=ENDOFSTR) {
- if(isdigit(*p))
- has_digits = TRUE;
- else if(*p == 'e') {
- if(has_e || !has_digits)
- return(FALSE);
- has_e = 1;
- } else if(*p == '-') {
- if(!has_e || (lastchar != 'e'))
- return(FALSE);
- } else if(*p == '.') {
- if(has_e || (++decimal_point_cnt>1))
- return(FALSE);
- } else
- return(FALSE);
- lastchar = *p;
- p++;
- }
- if(!has_digits || sscanf(valstart,"%lf",val)!=1)
- return(FALSE);
- *str = p;
- return(TRUE);
- }
|