| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043 |
- /*
- * 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 <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <osbind.h>
- #include <math.h>
- #include <float.h>
- #include <float.h>
- #include <sfsys.h>
- #include <cdplib.h>
- #include <pvoc.h>
- #include <paudition.h>
- 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<PARTIALS_IN_TEST_TONE;m++) {
- cc = (int)((thisfrq + halfchwidth)/chwidth);
- if((vc = cc)!=0)
- vc = cc * 2;
- if(vc != lastvc) {
- sampbuf[vc] = testpamp[m];
- sampbuf[vc+1] = (float)thisfrq;
- }
- lastvc = vc;
- if((thisfrq = thisfrq * 2.0) > 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<winLen; i++)
- *(win+i) = (float)((double).54 + (double).46*cos((double)(ftmp*((float)i+.5))));
- *(win+winLen) = 0.0f;}
- else{ *(win) = 1.0f;
- for (i=1; i<=winLen; i++)
- *(win+i) =(float)((double).54 + (double).46*cos((double)(ftmp*(float)i)));
- }
- return;
- }
- /****************************** FLOAT_ARRAY ******************************/
- int pvoc_float_array(int nnn,float **ptr)
- { /* set up a floating point array length nnn. */
- *ptr = (float *) calloc(nnn,sizeof(float));
- if(*ptr==NULL){
- fprintf(stdout,"ERROR: insufficient memory for PVOC\n");
- fflush(stdout);
- return(0);
- }
- return(1);
- }
- /****************************** PVOC_PROCESS_ADDON ******************************/
- int pvoc_process_addon(int ifd,int ofd,int chans,int origrate,float arate,int Mlen,int Dfac)
- {
- int num_overflows = 0;
- float *input, /* pointer to start of input buffer */
- *output, /* pointer to start of output buffer */
- *anal, /* pointer to start of analysis buffer */
- *syn, /* pointer to start of synthesis buffer */
- // *banal, /* pointer to anal[1] (for FFT calls) */
- *bsyn, /* pointer to syn[1] (for FFT calls) */
- // *nextIn, /* pointer to next empty word in input */
- *nextOut, /* pointer to next empty word in output */
- *analWindow, /* pointer to center of analysis window */
- *synWindow, /* pointer to center of synthesis window */
- *maxAmp, /* pointer to start of max amp buffer */
- *avgAmp, /* pointer to start of avg amp buffer */
- *avgFrq, /* pointer to start of avg frq buffer */
- *env, /* pointer to start of spectral envelope */
- *i0, /* pointer to amplitude channels */
- *i1, /* pointer to frequency channels */
- *oldInPhase, /* pointer to start of input phase buffer */
- *oldOutPhase, /* pointer to start of output phase buffer */
- maxsample = 0.0, minsample = 0.0;
- int M = 0, /* length of analWindow impulse response */
- D = 0, /* decimatin factor */
- I = 0, /* interpolation factor (default will be I=D)*/
- pvoc_chans = chans - 2,
- analWinLen, /* half-length of analysis window */
- synWinLen; /* half-length of synthesis window */
- int outCount, /* number of samples written to output */
- ibuflen, /* length of input buffer */
- obuflen, /* length of output buffer */
- nI = 0, /* current input (analysis) sample */
- nO, /* current output (synthesis) sample */
- nMaxOut; /* last output (synthesis) sample */
- int /* isr,*/ /* sampling rate */
- endsamp = VERY_BIG_INT;
- float mag, /* magnitude of analysis data */
- phase, /* phase of analysis data */
- // RoverTwoPi, /* R/D divided by 2*Pi */
- TwoPioverR, /* 2*Pi divided by R/I */
- F = (float)0, /* fundamental frequency (determines pvoc_chans) */
- sum, /* scale factor for renormalizing windows */
- // rIn, /* decimated sampling rate */
- rOut, /* pre-interpolated sampling rate */
- R; /* input sampling rate */
- int i,j,k, /* index variables */
- Dd, /* number of new inputs to read (Dd <= D) */
- Ii, /* number of new outputs to write (Ii <= I) */
- N2, /* pvoc_chans/2 */
- NO, /* synthesis NO = pvoc_chans / P */
- NO2, /* NO/2 */
- IO, /* synthesis IO = I / P */
- IOi, /* synthesis IOi = Ii / P */
- Mf = 0, /* flag for even M */
- #ifdef SINGLE_SAMP
- rv, /* return value from fgetfloat */
- #endif
- flag = 0; /* end-of-input flag */
- #if defined(__SC__) && defined(SOFT_FP)
- extern int _8087;
- _8087 = 0;
- #endif
- {
- char *mem;
- if((mem = malloc(64*SECSIZE)) == 0
- ||sndsetbuf(ifd, mem, 64) < 0) {
- fprintf(stdout, "ERROR: Can't set big input buffer for PVOC.\n");
- return(0);
- }
- }
- // isr = origrate;
- M = Mlen;
- D = Dfac;
- R = ((float) D * arate);
- if(flteq(R,0.0)) {
- fprintf(stdout, "ERROR: Problem: zero sampling rate in PVOC\n");
- return(0);
- }
- N2 = pvoc_chans / 2;
- F = (float)(R /(float)pvoc_chans);
- Mf = 1 - M%2;
- if (M < 7) {
- fprintf(stdout,"WARNING: analWindow impulse response is too small\n");
- fflush(stdout);
- }
- ibuflen = 4 * M;
- obuflen = 4 * M;
- I = D;
- NO = pvoc_chans; /* synthesis transform will be NO points */
- NO2 = NO/2;
- IO = I;
- /* set up analysis window: The window is assumed to be symmetric
- with M total points. After the initial memory allocation,
- analWindow always points to the midpoint of the window
- (or one half sample to the right, if M is even); analWinLen
- is half the true window length (rounded down). Any low pass
- window will work; a Hamming window is generally fine,
- but a Kaiser is also available. If the window duration is
- longer than the transform (M > 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<obuflen; i++) {
- if (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<lowerbnd))
- return(0);
- return(1);
- }
|