/* * Copyright (c) 1983-2023 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 * */ #include #include #include #include #include #include #include #include #include #include #include #include static int setup_lphp_filter(dataptr dz); static int calc_frqs(dataptr dz); static void randomise_frqs(dataptr dz); static int allocate_internal_params_lphp(int chans,dataptr dz); static void calculate_filter_poles_lphp(double signd,int filter_order,dataptr dz); static void initialise_filter_coeffs_lphp(int chans,dataptr dz); static int allocate_filter_internalparam_arrays(int fltcnt,dataptr dz); static int initialise_filter_params(dataptr dz); static int establish_order_of_filter(dataptr dz); static int initialise_fltbankv2(dataptr dz); /************************** FILTER_PREPROCESS **************************/ int filter_preprocess(dataptr dz) { int exit_status; int n; if(dz->process == FLTBANKV2) { if((exit_status = initialise_fltbankv2(dz))<0) return exit_status; } switch(dz->process) { case(EQ): case(FSTATVAR): case(FLTSWEEP): case(ALLPASS): break; case(LPHP): if((exit_status = setup_lphp_filter(dz))<0) return(exit_status); break; case(FLTBANKC): return calc_frqs(dz); case(FLTBANKN): if((exit_status = calc_frqs(dz))<0) return(exit_status); for(n=0;niparam[FLT_CNT];n++) dz->parray[FLT_AMP][n] = 1.0; /* fall thro */ case(FLTBANKU): case(FLTBANKV2): case(FLTBANKV): case(FLTITER): if((exit_status = allocate_filter_internalparam_arrays(dz->iparam[FLT_CNT],dz))<0) return(exit_status); if((exit_status = initialise_filter_params(dz))<0) return(exit_status); break; default: sprintf(errstr,"Unknown case in filter_preprocess()\n"); return(PROGRAM_ERROR); } return(FINISHED); } /********************************* SETUP_LPHP_FILTER *****************************/ int setup_lphp_filter(dataptr dz) { int exit_status; int filter_order; double signd = 1.0; if (dz->param[FLT_PASSFRQ] < dz->param[FLT_STOPFRQ]) /* low pass */ signd = -1.0; filter_order = establish_order_of_filter(dz); if((exit_status = allocate_internal_params_lphp(dz->infile->channels,dz))<0) return(exit_status); calculate_filter_poles_lphp(signd,filter_order,dz); initialise_filter_coeffs_lphp(dz->infile->channels,dz); return(FINISHED); } /***************************** CALC_FRQS **********************************/ int calc_frqs(dataptr dz) { double interval, one_over_total_steps; int n; switch(dz->mode) { case(FLT_EQUALSPAN): one_over_total_steps = 1.0/(double)dz->iparam[FLT_CNT]; for(n=0;niparam[FLT_CNT];n++) { interval = dz->param[FLT_HIFRQ]/dz->param[FLT_LOFRQ]; dz->parray[FLT_FRQ][n] = dz->param[FLT_LOFRQ] * pow(interval,(double)n * one_over_total_steps); } break; case(FLT_EQUALINT): dz->parray[FLT_FRQ][0] = dz->param[FLT_LOFRQ]; for(n=1;niparam[FLT_CNT];n++) dz->parray[FLT_FRQ][n] = dz->parray[FLT_FRQ][n-1] * dz->param[FLT_INTSIZE]; break; case(FLT_HARMONIC): /* offset = 0.0 */ case(FLT_LINOFFSET): dz->parray[FLT_FRQ][0] = dz->param[FLT_LOFRQ]; for(n=1;niparam[FLT_CNT];n++) dz->parray[FLT_FRQ][n] = (dz->param[FLT_LOFRQ] * (double)(n+1))+dz->param[FLT_OFFSET]; break; case(FLT_ALTERNATE): dz->parray[FLT_FRQ][0] = dz->param[FLT_LOFRQ]; for(n=1;niparam[FLT_CNT];n++) dz->parray[FLT_FRQ][n] = dz->param[FLT_LOFRQ] * (double)((n*2)+1); break; case(FLT_SUBHARM): /* dz->param[FLT_LOFRQ] already reset at top */ dz->parray[FLT_FRQ][0] = dz->param[FLT_HIFRQ]; for(n=1;niparam[FLT_CNT];n++) dz->parray[FLT_FRQ][n] = dz->param[FLT_HIFRQ]/(double)(n+1); break; default: sprintf(errstr,"Unknown mode in calc_frqs()\n"); return(PROGRAM_ERROR); } if(!flteq(dz->param[FLT_RANDFACT],0.0)) randomise_frqs(dz); return(FINISHED); } /************************ RANDOMISE_FRQS *******************************/ void randomise_frqs(dataptr dz) { int n; double thisrand, frqratio, interval; for(n=1;niparam[FLT_CNT]-1;n++) { thisrand = drand48(); /* RANGE 0 - 1 */ if(thisrand >= 0.5) { /* IF IN TOP 1/2 */ thisrand -= 0.5; /* REDUCE BY 1/2 */ thisrand *= dz->param[FLT_RANDFACT]; /* SCALE BY randfact */ frqratio = dz->parray[FLT_FRQ][n+1]/dz->parray[FLT_FRQ][n]; interval = log(frqratio) * thisrand; frqratio = exp(interval); dz->parray[FLT_FRQ][n] *= frqratio; /* SCATTER FRQ IN 1/2 INTERVAL ABOVE CURRENT VAL */ } else { thisrand *= dz->param[FLT_RANDFACT]; /* SCALE BY randfact */ frqratio = dz->parray[FLT_FRQ][n]/dz->parray[FLT_FRQ][n-1]; interval = log(frqratio) * (1.0 - thisrand); frqratio = exp(interval); dz->parray[FLT_FRQ][n] = dz->parray[FLT_FRQ][n-1] * frqratio; /* SCATTER FRQ IN 1/2 INTERVAL BELOW CURRENT VAL */ } } } /********************************* ALLOCATE_INTERNAL_PARAMS_LPHP *****************************/ //int allocate_internal_params_lphp(int chans,dataptr dz) //{ // if((dz->parray[FLT_DEN1] = (double *)malloc(dz->iparam[FLT_CNT] * sizeof(double)))==NULL // || (dz->parray[FLT_DEN2] = (double *)malloc(dz->iparam[FLT_CNT] * sizeof(double)))==NULL // || (dz->parray[FLT_CN] = (double *)malloc(dz->iparam[FLT_CNT] * sizeof(double)))==NULL // || (dz->parray[FLT_S1] = (double *)malloc(dz->iparam[FLT_CNT] * sizeof(double)))==NULL // || (dz->parray[FLT_E1] = (double *)malloc(dz->iparam[FLT_CNT] * sizeof(double)))==NULL // || (dz->parray[FLT_S2] = (double *)malloc(dz->iparam[FLT_CNT] * sizeof(double)))==NULL // || (dz->parray[FLT_E2] = (double *)malloc(dz->iparam[FLT_CNT] * sizeof(double)))==NULL) { // sprintf(errstr,"INSUFFICIENT MEMORY for arrays of filter parameters.\n"); // return(MEMORY_ERROR); // } // if(chans==2) { // if((dz->parray[FLT_S1S] = (double *)malloc(dz->iparam[FLT_CNT] * sizeof(double)))==NULL // || (dz->parray[FLT_E1S] = (double *)malloc(dz->iparam[FLT_CNT] * sizeof(double)))==NULL // || (dz->parray[FLT_S2S] = (double *)malloc(dz->iparam[FLT_CNT] * sizeof(double)))==NULL // || (dz->parray[FLT_E2S] = (double *)malloc(dz->iparam[FLT_CNT] * sizeof(double)))==NULL) { // sprintf(errstr,"INSUFFICIENT MEMORY for arrays of filter stereo parameters.\n"); // return(MEMORY_ERROR); // } // } // return(FINISHED); //} // // TW MULTICHAN 2010 int allocate_internal_params_lphp(int chans,dataptr dz) { int i; if((dz->parray[FLT_DEN1] = (double *)calloc(dz->iparam[FLT_CNT] * sizeof(double),sizeof(char)))==NULL || (dz->parray[FLT_DEN2] = (double *)calloc(dz->iparam[FLT_CNT] * sizeof(double),sizeof(char)))==NULL || (dz->parray[FLT_CN] = (double *)calloc(dz->iparam[FLT_CNT] * sizeof(double),sizeof(char)))==NULL || (dz->parray[FLT_S1_BASE] = (double *)calloc(dz->iparam[FLT_CNT] * sizeof(double),sizeof(char)))==NULL || (dz->parray[FLT_E1_BASE] = (double *)calloc(dz->iparam[FLT_CNT] * sizeof(double),sizeof(char)))==NULL || (dz->parray[FLT_S2_BASE] = (double *)calloc(dz->iparam[FLT_CNT] * sizeof(double),sizeof(char)))==NULL || (dz->parray[FLT_E2_BASE] = (double *)calloc(dz->iparam[FLT_CNT] * sizeof(double),sizeof(char)))==NULL) { sprintf(errstr,"INSUFFICIENT MEMORY for arrays of filter parameters.\n"); return(MEMORY_ERROR); } for(i = 1; i < chans;i++) { int index = i*FLT_LPHP_ARRAYS_PER_FILTER; if((dz->parray[FLT_S1_BASE + index] = (double *)calloc(dz->iparam[FLT_CNT] * sizeof(double),sizeof(char)))==NULL || (dz->parray[FLT_E1_BASE + index] = (double *)calloc(dz->iparam[FLT_CNT] * sizeof(double),sizeof(char)))==NULL || (dz->parray[FLT_S2_BASE + index] = (double *)calloc(dz->iparam[FLT_CNT] * sizeof(double),sizeof(char)))==NULL || (dz->parray[FLT_E2_BASE + index] = (double *)calloc(dz->iparam[FLT_CNT] * sizeof(double),sizeof(char)))==NULL) { sprintf(errstr,"INSUFFICIENT MEMORY for arrays of %d-channel filter parameters.\n",chans); return(MEMORY_ERROR); } } return(FINISHED); } /********************************* CALCULATE_FILTER_POLES_LPHP *****************************/ void calculate_filter_poles_lphp(double signd,int filter_order,dataptr dz) { double ss, xx, aa, tppwr, x1, x2, cc; double pii = 4.0 * atan(1.0); double tp = tan(dz->param[FLT_PASSFRQ]); int k; ss = pii / (double)(2 * filter_order); for (k = 0; k < dz->iparam[FLT_CNT]; k++ ) { //TW : RWD CORRECTION TALLIES WITH MY UPDATES xx = (double) ((2.0 * (k+1)) - 1.0); aa = -sin(xx * ss); tppwr = pow(tp,2.0); cc = 1.0 - (2.0 * aa * tp) + tppwr; x1 = 2.0 * (tppwr - 1.0)/cc ; x2 = (1.0 + (2.0 * aa * tp) + tppwr)/cc ; dz->parray[FLT_DEN1][k] = signd * x1; dz->parray[FLT_DEN2][k] = -x2 ; dz->parray[FLT_CN][k] = pow(tp,2.0)/cc ; } } /********************************* INITIALISE_FILTER_COEFFS_LPHP *****************************/ //void initialise_filter_coeffs_lphp(int chans,dataptr dz) //{ // int k; // for (k = 0 ; k < dz->iparam[FLT_CNT]; k++) { // dz->parray[FLT_S1][k] = 0.0; // dz->parray[FLT_S2][k] = 0.0; // dz->parray[FLT_E1][k] = 0.0; // dz->parray[FLT_E2][k] = 0.0; // } // if(chans==STEREO) { // for (k = 0 ; k < dz->iparam[FLT_CNT]; k++) { // dz->parray[FLT_S1S][k] = 0.0; // dz->parray[FLT_S2S][k] = 0.0; // dz->parray[FLT_E1S][k] = 0.0; // dz->parray[FLT_E2S][k] = 0.0; // } // } //} // // TW MULTICHAN 2010 void initialise_filter_coeffs_lphp(int chans,dataptr dz) { int k; int i,index; for (k = 0 ; k < dz->iparam[FLT_CNT]; k++) { dz->parray[FLT_S1_BASE][k] = 0.0; dz->parray[FLT_S2_BASE][k] = 0.0; dz->parray[FLT_E1_BASE][k] = 0.0; dz->parray[FLT_E2_BASE][k] = 0.0; } for(i=1;i < chans; i++){ index = i * FLT_LPHP_ARRAYS_PER_FILTER; for (k = 0 ; k < dz->iparam[FLT_CNT]; k++) { dz->parray[FLT_S1_BASE + index][k] = 0.0; dz->parray[FLT_S2_BASE + index][k] = 0.0; dz->parray[FLT_E1_BASE + index][k] = 0.0; dz->parray[FLT_E2_BASE + index][k] = 0.0; } } } /**************************** ALLOCATE_FILTER_INTERNALPARAM_ARRAYS *******************************/ int allocate_filter_internalparam_arrays(int fltcnt,dataptr dz) { int chans = dz->infile->channels; if((dz->parray[FLT_AMPL] = (double *)calloc(fltcnt * sizeof(double),sizeof(char)))==NULL || (dz->parray[FLT_A] = (double *)calloc(fltcnt * sizeof(double),sizeof(char)))==NULL || (dz->parray[FLT_B] = (double *)calloc(fltcnt * sizeof(double),sizeof(char)))==NULL || (dz->parray[FLT_WW] = (double *)calloc(fltcnt * sizeof(double),sizeof(char)))==NULL || (dz->parray[FLT_COSW] = (double *)calloc(fltcnt * sizeof(double),sizeof(char)))==NULL || (dz->parray[FLT_SINW] = (double *)calloc(fltcnt * sizeof(double),sizeof(char)))==NULL || (dz->parray[FLT_Y] = (double *)calloc(fltcnt * chans * sizeof(double),sizeof(char)))==NULL || (dz->parray[FLT_Z] = (double *)calloc(fltcnt * chans * sizeof(double),sizeof(char)))==NULL) { sprintf(errstr,"INSUFFICIENT MEMORY for arrays of filter parameters.\n"); return(MEMORY_ERROR); } if(dz->vflag[FLT_DBLFILT]) { if((dz->parray[FLT_D] = (double *)calloc(fltcnt * chans * sizeof(double),sizeof(char)))==NULL || (dz->parray[FLT_E] = (double *)calloc(fltcnt * chans * sizeof(double),sizeof(char)))==NULL) { sprintf(errstr,"INSUFFICIENT MEMORY for double filtering parameters.\n"); return(MEMORY_ERROR); } } return(FINISHED); } /************************ INITIALISE_FILTER_PARAMS ***************************/ int initialise_filter_params(dataptr dz) { int n, chno, k; int chans = dz->infile->channels; for(n=0;niparam[FLT_CNT];n++) { get_coeffs1(n,dz); get_coeffs2(n,dz); for(chno=0;chnovflag[FLT_DBLFILT]) { dz->parray[FLT_D][k] = 0.0; dz->parray[FLT_E][k] = 0.0; } dz->parray[FLT_Y][k] = 0.0; dz->parray[FLT_Z][k] = 0.0; } } return(FINISHED); } /********************************* ESTABLISH_ORDER_OF_FILTER *****************************/ int establish_order_of_filter(dataptr dz) { int filter_order; double tc, tp, tt, pii, xx, yy; double sr = (double)dz->infile->srate; if (dz->param[FLT_PASSFRQ] < dz->param[FLT_STOPFRQ]) /* low pass */ dz->param[FLT_MUL] = 2.0; else { dz->param[FLT_MUL] = -2.0; dz->param[FLT_PASSFRQ] = dz->nyquist - dz->param[FLT_PASSFRQ]; dz->param[FLT_STOPFRQ] = dz->nyquist - dz->param[FLT_STOPFRQ]; } pii = 4.0 * atan(1.0); dz->param[FLT_PASSFRQ] = pii * dz->param[FLT_PASSFRQ]/sr; tp = tan(dz->param[FLT_PASSFRQ]); dz->param[FLT_STOPFRQ] = pii * dz->param[FLT_STOPFRQ]/sr; tc = tan(dz->param[FLT_STOPFRQ]); tt = tc / tp ; tt = (tt * tt); dz->param[FLT_GAIN] = fabs(dz->param[FLT_GAIN]); dz->param[FLT_GAIN] = dz->param[FLT_GAIN] * log(10.0)/10.0 ; dz->param[FLT_GAIN] = exp(dz->param[FLT_GAIN]) - 1.0 ; xx = log(dz->param[FLT_GAIN])/log(tt) ; yy = floor(xx); if ((xx - yy) == 0.0 ) yy = yy - 1.0 ; filter_order = ((int)yy) + 1; if (filter_order <= 1) filter_order = 2; dz->iparam[FLT_CNT] = filter_order/2 ; filter_order = 2 * dz->iparam[FLT_CNT] ; fprintf(stdout,"INFO: Order of filter is %d\n", filter_order); fflush(stdout); dz->iparam[FLT_CNT] = min(dz->iparam[FLT_CNT],FLT_LBF); filter_order = 2 * dz->iparam[FLT_CNT]; return(filter_order); } /**************************** INITIALISE_FLTBANKV2 *******************************/ int initialise_fltbankv2(dataptr dz) { int n, k/*, z*/; memset((char *)dz->parray[FLT_INFRQ],0,dz->iparam[FLT_CNT] * sizeof(double)); memset((char *)dz->parray[FLT_INAMP],0,dz->iparam[FLT_CNT] * sizeof(double)); for(n = 1,k = 0; n < dz->iparam[FLT_ENTRYCNT];n+=2,k += dz->iparam[FLT_HARMCNT]) { dz->parray[FLT_INFRQ][k] = dz->parray[FLT_FBRK][n]; /* Get frqs of fundamentals into array, leaving space for harmonics */ dz->parray[FLT_INAMP][k] = dz->parray[FLT_FBRK][n+1]; /* Get amps of fundamentals into array, leaving space for harmonics */ } for(n = 1,k=0; n < dz->iparam[HRM_ENTRYCNT];n+=2,k++) { dz->parray[HARM_FRQ_CALC][k] = dz->parray[FLT_HBRK][n]; dz->parray[HARM_AMP_CALC][k] = dz->parray[FLT_HBRK][n+1]; } for(n=0;niparam[FLT_CNT];n+=dz->iparam[FLT_HARMCNT]) { // z = 0; for(k=0; k < dz->iparam[FLT_HARMCNT];k++) { /* calc vals for partials from basefrq vals */ dz->parray[FLT_INFRQ][n+k] = dz->parray[FLT_INFRQ][n] * dz->parray[HARM_FRQ_CALC][k]; dz->parray[FLT_INAMP][n+k] = dz->parray[FLT_INAMP][n] * dz->parray[HARM_AMP_CALC][k]; } } return(FINISHED); }