/* * 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 * */ /* PEDITAUD * * Hear a pitchfile being edited in the PDISPLAY routine in SoundLoom. */ #include #include #include #include #include #include #include #include #include #include #include char errstr[2400]; #define NOT_PITCH (-1.0) #define ENDOFSTR ('\0') #define ANALFILE_OUT (1) #define SNDFILE_OUT (0) #define WINDOW_AMP (0.5) #define PARTIALS_IN_TEST_TONE (6) #define PARTIAL_DECIMATION (.25) #define VERY_TINY_AMP (0.00000000000000000001) /* 10^-20 */ #define FLTERR (0.000002) static int headwrite(int ofd,int origstype,int origrate,float arate,int Mlen,int Dfac); static int get_data_from_pitchfile(float **pitches,int infilesize,int ifd); static int setup_amplitudes(int clength,double halfchwidth,double chwidth,float **testpamp,float **totpamp,float **chbot); static void do_finish(int n,int ifd,int ofd,float *bigbuf) ; static int make_buffer(float **bigbuf,int *big_fsize, int wanted); static int gen_testdata(int ofd,float *bigbuf,float *bigbufend,int big_fsize, int wlength,int clength,int wanted,int *total_samps_written,float *pitches, double chwidth,double halfchwidth,float *chbot,double nois_chanamp,float *testpamp,float *totpamp, double nyquist,double pre_totalamp); static void gen_silence_in_sampbuf(float *sampbuf,double chwidth,double halfchwidth,int clength, float *chbot,double nois_chanamp); static void gen_nois_in_sampbuf(float *sampbuf,double chwidth,double halfchwidth,int clength, float *chbot,double nois_chanamp); static void gen_tone_in_sampbuf(double thisfrq,float *sampbuf,float *testpamp,float *totpamp, double nyquist,double pre_totalamp,double chwidth,double halfchwidth,int wanted); static int pvoc_process_addon(int ifd,int ofd,int chans,int origrate,float arate,int Mlen,int Dfac); static void hamming(float *win,int winLen,int even); static int pvoc_float_array(int nnn,float **ptr); /*static int lcm(int a, int b);*/ static void preset_sampbuf(float *sampbuf,double halfchwidth, int clength, float *chbot); static void normalise(double post_totalamp,double pre_totalamp,int wanted,float *sampbuf); static int flteq(double f1,double f2); static int outfloats(float *nextOut,float *maxsample,float *minsample,int *num_overflows,int todo, int ofd); #define MONO (1) const char* cdp_version = "7.1.0"; int main(int argc,char *argv[]) { float *pitches, *testpamp, *totpamp, *chbot; float *bigbuf = NULL, *bigbufend; int big_fsize, total_samps_written = 0; int ofd = -1, ifd; int wlength; int origchans, origstype, origrate; float arate; int Mlen, Dfac; int srate, chans; double chwidth, halfchwidth, nyquist, nois_chanamp, gain = 1.0, pre_totalamp; int wanted, clength; if(argc==2 && (strcmp(argv[1],"--version") == 0)) { fprintf(stdout,"%s\n",cdp_version); fflush(stdout); return 0; } if(argc != 12) { fprintf(stdout,"ERROR: Incorrect call to program which writes the sound.\n"); fflush(stdout); return 1; } /* initialise SFSYS */ if( sflinit("paudition") < 0 ) { fprintf(stdout,"ERROR: Cannot initialise soundfile system.\n"); fflush(stdout); return 1; } /* open input file */ if((ifd = sndopenEx(argv[1],0,CDP_OPEN_RDONLY))<0) { fprintf(stdout,"INFO: Cannot open intermediate pitch data file: %s\n",argv[1]); fflush(stdout); do_finish(0,ifd,ofd,bigbuf); } wlength = sndsizeEx(ifd); if(sscanf(argv[4],"%d",&origchans)!=1) { fprintf(stdout,"ERROR: Cannot read original-channels data,\n"); fflush(stdout); do_finish(1,ifd,ofd,bigbuf); return 1; } if(sscanf(argv[5],"%d",&origstype)!=1) { fprintf(stdout,"ERROR: Cannot read original-sample-type data,\n"); fflush(stdout); do_finish(1,ifd,ofd,bigbuf); return 1; } if(sscanf(argv[6],"%d",&origrate)!=1) { fprintf(stdout,"ERROR: Cannot read original-sample-rate data,\n"); fflush(stdout); do_finish(1,ifd,ofd,bigbuf); return 1; } if(sscanf(argv[7],"%f",&arate)!=1) { fprintf(stdout,"ERROR: Cannot read analysis-rate data,\n"); fflush(stdout); do_finish(1,ifd,ofd,bigbuf); return 1; } if(sscanf(argv[8],"%d",&Mlen)!=1) { fprintf(stdout,"ERROR: Cannot read Mlen data,\n"); fflush(stdout); do_finish(1,ifd,ofd,bigbuf); return 1; } if(sscanf(argv[9],"%d",&Dfac)!=1) { fprintf(stdout,"ERROR: Cannot read Decimation Factor data,\n"); fflush(stdout); do_finish(1,ifd,ofd,bigbuf); return 1; } if(sscanf(argv[10],"%d",&srate)!=1) { fprintf(stdout,"ERROR: Cannot read sample-rate data,\n"); fflush(stdout); do_finish(1,ifd,ofd,bigbuf); return 1; } if(sscanf(argv[11],"%d",&chans)!=1) { fprintf(stdout,"ERROR: Cannot read channel data,\n"); fflush(stdout); do_finish(1,ifd,ofd,bigbuf); return 1; } //TW COMMENT: this is temporary analysis file if((ofd = sndcreat_formatted(argv[2],-1,SAMP_FLOAT, chans,srate,CDP_CREATE_NORMAL)) < 0) { fprintf(stdout,"ERROR: Can't create file %s (It may already exist)\n", argv[2]); fflush(stdout); do_finish(1,ifd,ofd,bigbuf); return 1; } wanted = origchans ; /* floatsams to read */ clength = wanted / 2; /* channels to process */ nyquist = (double)origrate/2.0; chwidth = nyquist/(double)(clength - 1); halfchwidth = chwidth/2.0; if(!get_data_from_pitchfile(&pitches,wlength,ifd)) { do_finish(2,ifd,ofd,bigbuf); return 1; } sndcloseEx(ifd); pre_totalamp = WINDOW_AMP * gain; nois_chanamp = pre_totalamp/(double)clength; if(!setup_amplitudes(clength,halfchwidth,chwidth,&testpamp,&totpamp,&chbot)) { do_finish(3,ifd,ofd,bigbuf); return 1; } if(!make_buffer(&bigbuf,&big_fsize,wanted)) { do_finish(3,ifd,ofd,bigbuf); return 1; } bigbufend = bigbuf + big_fsize; if(!gen_testdata(ofd,bigbuf,bigbufend,big_fsize,wlength,clength,wanted,&total_samps_written, pitches,chwidth,halfchwidth,chbot,nois_chanamp,testpamp,totpamp,nyquist,pre_totalamp)) { do_finish(4,ifd,ofd,bigbuf); return 1; } chans = origchans; if (!headwrite(ofd,origstype,origrate,arate,Mlen,Dfac)) { fprintf(stdout,"ERROR: Failed to write valid header to output file.\n"); fflush(stdout); do_finish(4,ifd,ofd,bigbuf); return 1; } Mfree(bigbuf); sndcloseEx(ofd); if((ifd = sndopenEx(argv[2],0,CDP_OPEN_RDONLY))<0) { fprintf(stdout,"INFO: Cannot open intermediate analysis data file: %s\n",argv[2]); fflush(stdout); do_finish(0,ifd,ofd,bigbuf); return 1; } //TW COMMENT as this is a temporary sndfile: may as well leave it as SAMP_SHORT if((ofd = sndcreat_formatted(argv[3],-1,SAMP_SHORT, MONO,origrate,CDP_CREATE_NORMAL)) < 0) { fprintf(stdout,"ERROR: Can't create output soundfile %s\n", argv[3]); fflush(stdout); do_finish(5,ifd,ofd,bigbuf); return 1; } if(!pvoc_process_addon(ifd,ofd,chans,origrate,arate,Mlen,Dfac)) { do_finish(6,ifd,ofd,bigbuf); return 1; } do_finish(6,ifd,ofd,bigbuf); return 1; } /***************************** HEADWRITE *******************************/ int headwrite(int ofd,int origstype,int origrate,float arate,int Mlen,int Dfac) { if(sndputprop(ofd,"original sampsize", (char *)&origstype, sizeof(int)) < 0){ fprintf(stdout,"ERROR: Failure to write original sample size. headwrite()\n"); fflush(stdout); return(0); } if(sndputprop(ofd,"original sample rate", (char *)&origrate, sizeof(int)) < 0){ fprintf(stdout,"ERROR: Failure to write original sample rate. headwrite()\n"); fflush(stdout); return(0); } if(sndputprop(ofd,"arate",(char *)&arate,sizeof(float)) < 0){ fprintf(stdout,"ERROR: Failed to write analysis sample rate. headwrite()\n"); fflush(stdout); return(0); } if(sndputprop(ofd,"analwinlen",(char *)&Mlen,sizeof(int)) < 0){ fprintf(stdout,"ERROR: Failure to write analysis window length. headwrite()\n"); fflush(stdout); return(0); } if(sndputprop(ofd,"decfactor",(char *)&Dfac,sizeof(int)) < 0){ fprintf(stdout,"ERROR: Failure to write decimation factor. headwrite()\n"); fflush(stdout); return(0); } return(1); } /********************* GET_DATA_FROM_PITCHFILE *************************/ int get_data_from_pitchfile(float **pitches,int wanted,int ifd) { int samps_read; if((*pitches = (float *)malloc(wanted * sizeof(float)))==NULL) { fprintf(stdout,"ERROR: Insufficient memory to reread pitchdata.\n"); fflush(stdout); return 0; } if((samps_read = fgetfbufEx(*pitches, wanted,ifd,0))<0) { fprintf(stdout,"ERROR: Cannot reread pitchdata.\n"); fflush(stdout); return 0; } if(samps_read!=wanted) { fprintf(stdout,"ERROR: Problem rereading pitch data.\n"); fflush(stdout); return 0; } return(1); } /****************************** SETUP_AMPLITUDES ***************/ int setup_amplitudes(int clength,double halfchwidth,double chwidth,float **testpamp,float **totpamp,float **chbot) { int n, cc; if((*testpamp = (float *)malloc(PARTIALS_IN_TEST_TONE * sizeof(float)))==NULL) { fprintf(stdout,"ERROR: Insufficient memory A.\n"); fflush(stdout); return 0; } if((*totpamp = (float *)malloc(PARTIALS_IN_TEST_TONE * sizeof(float)))==NULL) { fprintf(stdout,"ERROR: Insufficient memory B.\n"); fflush(stdout); return 0; } (*totpamp)[0] = (*testpamp)[0] = 0.5f; for(n = 1; n < PARTIALS_IN_TEST_TONE; n++) /* ACTUAL PARTIAL AMPS */ (*testpamp)[n] = (float)((*testpamp)[n-1] * PARTIAL_DECIMATION); for(n = 1; n < PARTIALS_IN_TEST_TONE; n++) /* SUM OF PARTIAL AMPS */ (*totpamp)[n] = (float)((*totpamp)[n-1] + (*testpamp)[n]); if((*chbot = (float *)malloc(clength * sizeof(float)))==NULL) { fprintf(stdout,"ERROR: Insufficient memory C.\n"); fflush(stdout); return 0; } (*chbot)[0] = 0.0f; (*chbot)[1] = (float)halfchwidth; for(cc = 2 ;cc < clength; cc++) (*chbot)[cc] = (float)((*chbot)[cc-1] + chwidth); return 1; } /****************************** DO_FINISH *********************************/ void do_finish(int n,int ifd,int ofd,float *bigbuf) { switch(n) { case(2): sndcloseEx(ofd); case(1): sndcloseEx(ifd); case(0): // sffinish(); break; case(4): Mfree(bigbuf); case(3): sndcloseEx(ofd); // sffinish(); break; case(6): sndcloseEx(ofd); case(5): sndcloseEx(ifd); // sffinish(); break; } } /****************************** MAKE_BUFFER *********************************/ int make_buffer(float **bigbuf,int *big_fsize, int wanted) { size_t bigbufsize = (size_t) Malloc(-1); *big_fsize = bigbufsize/sizeof(float); if((*big_fsize = ((*big_fsize)/wanted) * wanted)<=0) { fprintf(stdout,"ERROR: Insufficient memory E.\n"); fflush(stdout); return 0; } if((*bigbuf = (float*)Malloc(*big_fsize * sizeof(float)))==NULL) { fprintf(stdout,"ERROR: Insufficient memory F.\n"); fflush(stdout); return 0; } memset((char *)(*bigbuf),0,(*big_fsize * sizeof(float))); return 1; } /************************* GEN_TESTDATA *************************/ int gen_testdata(int ofd,float *bigbuf,float *bigbufend,int big_fsize, int wlength,int clength,int wanted,int *total_samps_written,float *pitches, double chwidth,double halfchwidth,float *chbot,double nois_chanamp,float *testpamp,float *totpamp, double nyquist,double pre_totalamp) { double thisfrq; int n = 0, samps_to_write, samps_written; float *sampbuf = bigbuf; int cc, vc; while(n < wlength) { thisfrq = (double)pitches[n]; if(thisfrq < NOT_PITCH) /* NO SOUND FOUND : GENERATE SILENCE */ gen_silence_in_sampbuf(sampbuf,chwidth,halfchwidth,clength,chbot,nois_chanamp); else if(thisfrq < 0.0) /* NO PITCH FOUND : GENERATE NOISE */ gen_nois_in_sampbuf(sampbuf,chwidth,halfchwidth,clength,chbot,nois_chanamp); else { /* GENERATE TESTTONE AT FOUND PITCH */ preset_sampbuf(sampbuf,halfchwidth,clength,chbot); gen_tone_in_sampbuf(thisfrq,sampbuf,testpamp,totpamp,nyquist,pre_totalamp,chwidth,halfchwidth,wanted); } if(n==0) { for(cc = 0, vc = 0; cc < clength; cc++, vc += 2) sampbuf[vc] = 0.0f; } if((sampbuf += wanted) >= bigbufend) { if((samps_written = fputfbufEx(bigbuf,big_fsize,ofd))<0) { fprintf(stdout,"ERROR: Can't write to analysis file.\n"); fflush(stdout); return 0; } *total_samps_written += big_fsize; memset((char *)bigbuf,0,big_fsize * sizeof(float)); sampbuf = bigbuf; } n++; } if(sampbuf != bigbuf) { samps_to_write = (sampbuf - bigbuf); *total_samps_written += samps_to_write; if((samps_written = fputfbufEx(bigbuf,samps_to_write,ofd))<0) { fprintf(stdout,"ERROR: Can't write to analysis file.\n"); fflush(stdout); return 0; } } return 1; } /*************************** GEN_SILENCE_IN_SAMPBUF *********************/ void gen_silence_in_sampbuf(float *sampbuf,double chwidth,double halfchwidth,int clength, float *chbot,double nois_chanamp) { int cc, vc, clength_less_1 = clength - 1; sampbuf[0] = (float)nois_chanamp; sampbuf[1] = (float)(drand48() * halfchwidth); for(cc = 1, vc = 2; cc < clength_less_1; cc++, vc += 2) { sampbuf[vc+1] = (float)((drand48() * chwidth) + chbot[cc]); sampbuf[vc] = 0.0f; } sampbuf[vc+1] = (float)((drand48() * halfchwidth) + chbot[cc]); sampbuf[vc] = 0.0f; } /*************************** GEN_NOIS_IN_SAMPBUF *********************/ void gen_nois_in_sampbuf(float *sampbuf,double chwidth,double halfchwidth,int clength, float *chbot,double nois_chanamp) { int cc, vc, clength_less_1 = clength - 1; sampbuf[0] = (float)nois_chanamp; sampbuf[1] = (float)(drand48() * halfchwidth); for(cc = 1, vc = 2; cc < clength_less_1; cc++, vc += 2) { sampbuf[vc+1] = (float)((drand48() * chwidth) + chbot[cc]); sampbuf[vc] = (float)nois_chanamp; } sampbuf[vc+1] = (float)((drand48() * halfchwidth) + chbot[cc]); sampbuf[vc] = (float)nois_chanamp; } /********************** GEN_TONE_IN_SAMPBUF ***************************/ void gen_tone_in_sampbuf(double thisfrq,float *sampbuf,float *testpamp,float *totpamp, double nyquist,double pre_totalamp,double chwidth,double halfchwidth,int wanted) { int cc, vc, m, ampadjusted = 0; int lastvc = -1; double post_totalamp; for(m=0;m nyquist) { post_totalamp = (double)totpamp[m]; normalise(post_totalamp,pre_totalamp,wanted,sampbuf); ampadjusted = 1; break; } } if(!ampadjusted) { post_totalamp = (double)totpamp[PARTIALS_IN_TEST_TONE-1]; normalise(post_totalamp,pre_totalamp,wanted,sampbuf); } } /******************************** NORMALISE ***************************/ void normalise(double post_totalamp,double pre_totalamp,int wanted,float *sampbuf) { double normaliser; int vc; if(post_totalamp < VERY_TINY_AMP) return; normaliser = pre_totalamp/post_totalamp; for(vc = 0; vc < wanted; vc += 2) { if(sampbuf[vc] > 0.0f) sampbuf[vc] = (float)(sampbuf[vc] * normaliser); } } /****************************** HAMMING ******************************/ void hamming(float *win,int winLen,int even) { float Pi,ftmp; int i; /*********************************************************** Pi = (float)((double)4.*atan((double)1.)); ***********************************************************/ Pi = (float)PI; ftmp = Pi/winLen; if (even) { for (i=0; i N), then the window is multiplied by a sin(x)/x function to meet the condition: analWindow[Ni] = 0 for i != 0. In either case, the window is renormalized so that the phase vocoder amplitude estimates are properly scaled. The maximum allowable window duration is ibuflen/2. */ if(!pvoc_float_array(M+Mf,&analWindow)) return(0); analWindow += (analWinLen = M/2); hamming(analWindow,analWinLen,Mf); for (i = 1; i <= analWinLen; i++) *(analWindow - i) = *(analWindow + i - Mf); if (M > pvoc_chans) { if (Mf) *analWindow *=(float) ((double)pvoc_chans*sin((double)PI*.5/pvoc_chans)/(double)(PI*.5)); for (i = 1; i <= analWinLen; i++) *(analWindow + i) *=(float) ((double)pvoc_chans * sin((double) (PI*(i+.5*Mf)/pvoc_chans) / (PI*(i+.5*Mf)))); for (i = 1; i <= analWinLen; i++) *(analWindow - i) = *(analWindow + i - Mf); } sum = 0.0f; for (i = -analWinLen; i <= analWinLen; i++) sum += *(analWindow + i); sum = (float)(2.0/sum); /*factor of 2 comes in later in trig identity*/ for (i = -analWinLen; i <= analWinLen; i++) *(analWindow + i) *= sum; /* set up synthesis window: For the minimal mean-square-error formulation (valid for N >= M), the synthesis window is identical to the analysis window (except for a scale factor), and both are even in length. If N < M, then an interpolating synthesis window is used. */ if(!pvoc_float_array(M+Mf,&synWindow)) return(0); synWindow += (synWinLen = M/2); if (M <= pvoc_chans){ hamming(synWindow,synWinLen,Mf); for (i = 1; i <= synWinLen; i++) *(synWindow - i) = *(synWindow + i - Mf); for (i = -synWinLen; i <= synWinLen; i++) *(synWindow + i) *= sum; sum = 0.0f; for (i = -synWinLen; i <= synWinLen; i+=I) sum += *(synWindow + i) * *(synWindow + i); sum = (float)(1.0/ sum); for (i = -synWinLen; i <= synWinLen; i++) *(synWindow + i) *= sum; } else { hamming(synWindow,synWinLen,Mf); for (i = 1; i <= synWinLen; i++) *(synWindow - i) = *(synWindow + i - Mf); if (Mf) *synWindow *= (float)((double)IO * sin((double) (PI*.5/IO)) / (double)(PI*.5)); for (i = 1; i <= synWinLen; i++) *(synWindow + i) *=(float) ((double)IO * sin((double) (PI*(i+.5*Mf)/IO)) /(double) (PI*(i+.5*Mf))); for (i = 1; i <= synWinLen; i++) *(synWindow - i) = *(synWindow + i - Mf); sum = (float)(1.0/sum); for (i = -synWinLen; i <= synWinLen; i++) *(synWindow + i) *= sum; } /* set up input buffer: nextIn always points to the next empty word in the input buffer (i.e., the sample following sample number (n + analWinLen)). If the buffer is full, then nextIn jumps back to the beginning, and the old values are written over. */ if(!pvoc_float_array(ibuflen,&input)) return(0); // nextIn = input; /* set up output buffer: nextOut always points to the next word to be shifted out. The shift is simulated by writing the value to the standard output and then setting that word of the buffer to zero. When nextOut reaches the end of the buffer, it jumps back to the beginning. */ if(!pvoc_float_array(obuflen,&output)) return(0); nextOut = output; /* set up analysis buffer for (N/2 + 1) channels: The input is real, so the other channels are redundant. oldInPhase is used in the conversion to remember the previous phase when calculating phase difference between successive samples. */ if(!pvoc_float_array(pvoc_chans+2,&anal)) return(0); // banal = anal + 1; if(!pvoc_float_array(N2+1,&oldInPhase)) return(0); if(!pvoc_float_array(N2+1,&maxAmp)) return(0); if(!pvoc_float_array(N2+1,&avgAmp)) return(0); if(!pvoc_float_array(N2+1,&avgFrq)) return(0); if(!pvoc_float_array(N2+1,&env)) return(0); /* set up synthesis buffer for (pvoc_chans/2 + 1) channels: (This is included only for clarity.) oldOutPhase is used in the re- conversion to accumulate angle differences (actually angle difference per second). */ if(!pvoc_float_array(NO+2,&syn)) return(0); bsyn = syn + 1; if(!pvoc_float_array(NO2+1,&oldOutPhase)) return(0); /* initialization: input time starts negative so that the rightmost edge of the analysis filter just catches the first non-zero input samples; output time is always T times input time. */ outCount = 0; // rIn = (float)(R/(float)D); rOut = (float)(R/(float)I); // RoverTwoPi = (float)(rIn/TWOPI); TwoPioverR = (float)(TWOPI/rOut); nI = -(analWinLen / D) * D; /* input time (in samples) */ nO = nI; /* output time (in samples) */ Dd = analWinLen + nI + 1; /* number of new inputs to read */ Ii = 0; /* number of new outputs to write */ IOi = 0; flag = 1; /* main loop: If endsamp is not specified it is assumed to be very large and then readjusted when fgetfloat detects the end of input. */ while(nI < (endsamp + analWinLen)){ #ifdef SINGLE_SAMP for (i = 0; i < pvoc_chans+2; i++){ /* synthesis only */ if ((rv = fgetfloat((anal+i),ifd)) <= 0){ return 1; } } #else if((i = fgetfbufEx(anal, pvoc_chans+2, ifd,0)) < 0) { sfperror("pvoc: read error: "); return(0); } if(i < pvoc_chans+2) return 1; #endif /* reconversion: The magnitude and angle-difference-per-second in syn (assuming an intermediate sampling rate of rOut) are converted to real and imaginary values and are returned in syn. This automatically incorporates the proper phase scaling for time modifications. */ if (NO <= pvoc_chans){ for (i = 0; i < NO+2; i++) *(syn+i) = *(anal+i); } else { for (i = 0; i <= pvoc_chans+1; i++) *(syn+i) = *(anal+i); for (i = pvoc_chans+2; i < NO+2; i++) *(syn+i) = 0.0f; } for(i=0, i0=syn, i1=syn+1; i<= NO2; i++,i0+=2,i1+=2) { mag = *i0; *(oldOutPhase + i) += *i1 - ((float) i * F); phase = *(oldOutPhase + i) * TwoPioverR; *i0 = (float)((double)mag * cos((double)phase)); *i1 = (float)((double)mag * sin((double)phase)); } /* synthesis: The synthesis subroutine uses the Weighted Overlap-Add technique to reconstruct the time-domain signal. The (pvoc_chans/2 + 1) phase vocoder channel outputs at time n are inverse Fourier transformed, windowed, and added into the output array. The subroutine thinks of output as a shift register in which locations are referenced modulo obuflen. Therefore, the main program must take care to zero each location which it "shifts" out (to standard output). The subroutines reals and fft together perform an efficient inverse FFT. */ if(reals_(syn,bsyn,NO2,2)<0) { fprintf(stdout,"ERROR: %s\n",errstr); fflush(stdout); return 0; } if(fft_(syn,bsyn,1,NO2,1,2)<0) { fprintf(stdout,"ERROR: %s\n",errstr); fflush(stdout); return 0; } j = nO - synWinLen - 1; while (j < 0) j += obuflen; j = j % obuflen; k = nO - synWinLen - 1; while (k < 0) k += NO; k = k % NO; for (i = -synWinLen; i <= synWinLen; i++) { /*overlap-add*/ if (++j >= obuflen) j -= obuflen; if (++k >= NO) k -= NO; *(output + j) += *(syn + k) * *(synWindow + i); } #ifdef SINGLE_SAMP for (i = 0; i < IOi; i++) { /* shift out next IOi values */ fputfloat(nextOut,ofd); *(nextOut++) = 0.; if (nextOut >= (output + obuflen)) nextOut -= obuflen; outCount++; } #else for (i = 0; i < IOi;) { /* shift out next IOi values */ int jj; int todo = min(IOi-i, output+obuflen-nextOut); if(!outfloats(nextOut,&maxsample,&minsample,&num_overflows,todo, ofd)) return(0); i += todo; outCount += todo; for(jj = 0; jj < todo; jj++) *nextOut++ = 0.0f; if (nextOut >= (output + obuflen)) nextOut -= obuflen; } #endif if(flag /* flag means do this operation only once */ && (nI > 0) && (Dd < D)) { /* EOF detected */ flag = 0; endsamp = nI + analWinLen - (D - Dd); } nI += D; /* increment time */ nO += IO; /* Dd = D except when the end of the sample stream intervenes */ Dd = min(D, max(0, D+endsamp-nI-analWinLen)); if (nO > (synWinLen + I)) Ii = I; else if (nO > synWinLen) Ii = nO - synWinLen; else { Ii = 0; for (i=nO+synWinLen; i 0) *(output+i) = 0.0f; } } IOi = Ii; } /* End of main while loop */ nMaxOut = endsamp; while (outCount <= nMaxOut){ #ifdef SINGLE_SAMP outCount++; fputfloat(nextOut++,ofd); if (nextOut >= (output + obuflen)) nextOut -= obuflen; #else int todo = min(nMaxOut-outCount, output+obuflen-nextOut); if(todo == 0) break; if(!outfloats(nextOut,&maxsample,&minsample,&num_overflows,todo, ofd)) return(0); outCount += todo; nextOut += todo; if (nextOut >= (output + obuflen)) nextOut -= obuflen; #endif } return(1); } /************************************ OUTFLOATS ************************************ *TW 2002 no longer need to do conversion to floats: this func is now just checking for clipping * * ORIGINALLY (MCA) Converted floats -> shorts explicitly, since we are compiled with * hardware FP(probably), and the sound filing system is not! * (even without this, it should be more efficient!) */ int outfloats(float *nextOut,float *maxsample,float *minsample,int *num_overflows,int todo, int ofd) { static float *sbuf = 0; static int sblen = 0; float *sp; int cnt; float val; if(sblen < todo) { if(sbuf != 0) free(sbuf); if((sbuf = (float *)malloc(todo*sizeof(float))) == 0) { fprintf(stdout, "ERROR: PVOC can't allocate output buffer\n"); fflush(stdout); return(0); } sblen = todo; } sp = sbuf; #ifdef NOOVERCHK for(cnt = 0; cnt < todo; cnt++) *sp++ = *nextOut++; #else for(cnt = 0; cnt < todo; cnt++) { val = *nextOut++; if(val >= 1.0 || val <= -1.0) { (*num_overflows)++; if(val > 0.0f) { if(val > *maxsample) *maxsample = val; val = 1.0f; } if(val < 0.0f) { if(val < *minsample) *minsample = val; val = -1.0f; } } *sp++ = val; } #endif if(fputfbufEx(sbuf, todo, ofd) < todo) { fprintf(stdout,"ERROR: PVOC write error"); fflush(stdout); return(0); } return(1); } /**************************** PRESET_SAMPBUF ****************************** * * Preset all frqs to centre of channels. */ void preset_sampbuf(float *sampbuf,double halfchwidth, int clength, float *chbot) { int cc, vc , clength_less_1 = clength -1; sampbuf[1] = (float)(halfchwidth/2.0); for(cc = 1, vc = 2; cc < clength_less_1; cc++, vc += 2) sampbuf[vc+1] = (float)(chbot[cc] + halfchwidth); sampbuf[vc+1]=(float)(chbot[clength_less_1]+(halfchwidth/2.0)); } /**************************** FLTEQ *******************************/ int flteq(double f1,double f2) { double upperbnd, lowerbnd; upperbnd = f2 + FLTERR; lowerbnd = f2 - FLTERR; if((f1>upperbnd) || (f1