/* * 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 //TW UPDATE #include #include #include #include #include #include #include #include #include #include #include #include static int setup_channel_mifdrqs(dataptr dz); static int check_formant_buffer(dataptr dz); static int preset_channels(dataptr dz); static int write_pitched_window(double fundamental,double *amptotal,dataptr dz); //TW UPDATES + AVOID WARNING static int write_unpitched_window(double *amptotal,dataptr dz); static int write_silent_window(dataptr dz); static int normalise_in_file(double normaliser,dataptr dz); static int do_specmax(dataptr dz); static int if_loud_enough_to_go_in_list_put_in_list(float *ampstore,int *locstore,float val,int location,dataptr dz); static int generate_mean_values(int *loc1, int *loc2,dataptr dz); static int pichwise_mean_of_frqs(double *outfrq,double frq1,double frq2); //TW UPDATE static int read_envel_from_envfile(float **env,float **envend,int *envlen,int fileno,dataptr dz); /****************************** SPECMAKE **************************** * * Construct an analfile, from pitchfile and formantdata only. */ int specmake(dataptr dz) { #define MAXANALAMP (1.0) int exit_status; double normaliser, amptotal, thisfrq, maxamptotal = 0.0; //TW UPDATE float *env = NULL, *envend; int envlen; if(dz->process==MAKE2) { if((exit_status = read_envel_from_envfile(&env,&envend,&envlen,2,dz))<0) return(exit_status); dz->wlength = min(dz->wlength,envlen); } dz->wanted = dz->infile->origchans; /* to reconstruct an analfile !! */ if((exit_status = setup_formant_params(dz->ifd[1],dz))<0) return(exit_status); dz->flbufptr[1] = dz->flbufptr[2] + dz->descriptor_samps; if((exit_status = setup_channel_mifdrqs(dz))<0) return(exit_status); if((exit_status = check_formant_buffer(dz))<0) return(exit_status); dz->flbufptr[0] = dz->bigfbuf; while(dz->total_windows < dz->wlength){ amptotal = 0.0; if((exit_status = preset_channels(dz))<0) return(exit_status); if((thisfrq = dz->pitches[dz->total_windows])>0.0) { if((exit_status = write_pitched_window(thisfrq,&total,dz))<0) return(exit_status); //TW UPDATE } else if(flteq(thisfrq,NOT_SOUND)) { amptotal = 0.0; if((exit_status = write_silent_window(dz))<0) return(exit_status); } else { //TW AVOID WARNING if((exit_status = write_unpitched_window(&total,dz))<0) return(exit_status); if(dz->process==MAKE2) normalise(env[dz->total_windows],amptotal,dz); } if(amptotal > maxamptotal) maxamptotal = amptotal; if((dz->flbufptr[0] += dz->wanted) >= dz->flbufptr[2]) { if((exit_status = write_exact_samps(dz->bigfbuf,dz->buflen,dz))<0) return(exit_status); dz->flbufptr[0] = dz->bigfbuf; } if((exit_status = move_along_formant_buffer(dz))<0) return(exit_status); if(exit_status!=CONTINUE) break; dz->total_windows++; } if(dz->flbufptr[0] != dz->bigfbuf) { if((exit_status = write_samps(dz->bigfbuf,(dz->flbufptr[0] - dz->bigfbuf),dz))<0) return(exit_status); } //TW UPDATE if(dz->process!=MAKE2) { if(maxamptotal > MAXANALAMP) normaliser = MAXANALAMP/maxamptotal; else normaliser = 1.0; if((exit_status = normalise_in_file(normaliser,dz))<0) return(exit_status); } dz->specenvamp = NULL; /* prevent SUPERFREE from attempting to free this pointer */ return(FINISHED); } /*************************** SETUP_CHANNEL_MIFDRQS ********************/ int setup_channel_mifdrqs(dataptr dz) { int cc; double thisfrq = 0.0; for(cc=0;ccclength;cc++) { dz->freq[cc] = (float)thisfrq; /* Set up midfrqs of PVOC channels */ thisfrq += dz->chwidth; } return(FINISHED); } /*************************** CHECK_FORMANT_BUFFER ********************/ int check_formant_buffer(dataptr dz) { if(dz->flbufptr[1] >= dz->flbufptr[3]) { if(fgetfbufEx(dz->flbufptr[2],dz->buflen2,dz->ifd[1],0)<0) { sprintf(errstr,"data miscount in check_formant_buffer()\n"); return(SYSTEM_ERROR); } dz->flbufptr[1] = dz->flbufptr[2]; } return(FINISHED); } /*************************** PRESET_CHANNELS ********************/ int preset_channels(dataptr dz) { int vc, cc; for(cc = 0, vc = 0; cc < dz->clength; cc++, vc+=2) { dz->flbufptr[0][AMPP] = 0.0f; dz->flbufptr[0][FREQ] = dz->freq[cc]; } return(FINISHED); } /*************************** WRITE_PITCHED_WINDOW ********************/ int write_pitched_window(double fundamental,double *amptotal,dataptr dz) { int exit_status; double thisamp, thisfrq = fundamental; int n = 1, vc, cc; dz->specenvamp = dz->flbufptr[1]; while(thisfrq < dz->nyquist) { if((exit_status = get_channel_corresponding_to_frq(&cc,thisfrq,dz))<0) return(exit_status); vc = cc * 2; if((exit_status = getspecenvamp(&thisamp,thisfrq,0,dz))<0) return(exit_status); if(thisamp > dz->flbufptr[0][vc]) { *amptotal -= dz->flbufptr[0][vc]; dz->flbufptr[0][AMPP] = (float)thisamp; dz->flbufptr[0][FREQ] = (float)thisfrq; *amptotal += thisamp; } n++; thisfrq = fundamental * (double)n; } return(FINISHED); } /********************************** NORMALISE_IN_FILE ***********************************/ int normalise_in_file(double normaliser,dataptr dz) { int exit_status; int vc; // int bufcnt = 0; int total_samps_to_write = dz->total_samps_written; int samps_to_write; float *bufend; //TW NEW MECHANISM writes renormalised vals from original file created (tempfile) into true outfile // true outfile gets the name the user originally input //seek eliminated if(sndcloseEx(dz->ifd[0]) < 0) { sprintf(errstr, "WARNING: Can't close input soundfile\n"); return(SYSTEM_ERROR); } dz->ifd[0] = -1; if(sndcloseEx(dz->ofd) < 0) { sprintf(errstr, "WARNING: Can't close output soundfile\n"); return(SYSTEM_ERROR); } dz->ofd = -1; if((dz->ifd[0] = sndopenEx(dz->outfilename,0,CDP_OPEN_RDWR)) < 0) { /*RWD Nov 2003, was RDONLY */ sprintf(errstr,"Failure to reopen file %s for renormalisation.\n",dz->outfilename); return(SYSTEM_ERROR); } sndseekEx(dz->ifd[0],0,0); if((exit_status = create_sized_outfile(dz->wordstor[0],dz))<0) { sprintf(errstr,"Failure to create file %s for renormalisation.\n",dz->wordstor[0]); return(exit_status); } if((exit_status = reset_peak_finder(dz)) < 0) return exit_status; dz->total_samps_written = 0; fprintf(stdout,"INFO: Normalising.\n"); fflush(stdout); while(total_samps_to_write>0) { if(fgetfbufEx(dz->bigfbuf,dz->buflen,dz->ifd[0],0)<0) { sprintf(errstr,"Sound read error.\n"); close_and_delete_tempfile(dz->outfilename,dz); return(SYSTEM_ERROR); } dz->flbufptr[0] = dz->bigfbuf; samps_to_write = min(dz->buflen,total_samps_to_write); bufend = dz->flbufptr[0] + samps_to_write; while(dz->flbufptr[0] < bufend) { for(vc = 0;vc < dz->wanted; vc+=2) dz->flbufptr[0][AMPP] = (float)(dz->flbufptr[0][AMPP] * normaliser); dz->flbufptr[0] += dz->wanted; } if(samps_to_write>=dz->buflen) { if((exit_status = write_exact_samps(dz->bigfbuf,samps_to_write,dz))<0) { close_and_delete_tempfile(dz->outfilename,dz); return(exit_status); } } else if(samps_to_write > 0) { if((exit_status = write_samps(dz->bigfbuf,samps_to_write,dz))<0) { close_and_delete_tempfile(dz->outfilename,dz); return(exit_status); } } total_samps_to_write -= samps_to_write; // bufcnt++; } close_and_delete_tempfile(dz->outfilename,dz); return(FINISHED); } /*************************** SPECSUM ***********************/ int specsum(dataptr dz) { int vc; switch(dz->vflag[SUM_IS_CROSS]) { case(TRUE): for(vc = 0; vc < dz->wanted; vc += 2) dz->flbufptr[0][vc] = (float)(dz->flbufptr[0][vc] + (dz->param[SUM_CROSS] * dz->flbufptr[1][vc])); break; case(FALSE): for(vc = 0; vc < dz->wanted; vc += 2) dz->flbufptr[0][vc] = (float)(dz->flbufptr[0][vc] + dz->flbufptr[1][vc]); break; default: sprintf(errstr,"unknown case in specsum()\n"); return(PROGRAM_ERROR); } return(FINISHED); } /*************************** SPECDIFF ***********************/ int specdiff(dataptr dz) { int vc; switch(dz->vflag[DIFF_SUBZERO]) { case(FALSE): switch(dz->vflag[DIFF_IS_CROSS]) { case(FALSE): for(vc = 0; vc < dz->wanted; vc += 2) dz->flbufptr[0][vc] = (float)max(0.0,dz->flbufptr[0][vc] - dz->flbufptr[1][vc]); break; case(TRUE): for(vc = 0; vc < dz->wanted; vc += 2) dz->flbufptr[0][vc] = (float)max(0.0,dz->flbufptr[0][vc] - (dz->flbufptr[1][vc] * dz->param[DIFF_CROSS])); break; } break; case(TRUE): switch(dz->vflag[DIFF_IS_CROSS]) { case(FALSE): for(vc = 0; vc < dz->wanted; vc += 2) dz->flbufptr[0][vc] = (float)(dz->flbufptr[0][vc] - dz->flbufptr[1][vc]); break; case(TRUE): for(vc = 0; vc < dz->wanted; vc += 2) dz->flbufptr[0][vc] = (float)(dz->flbufptr[0][vc] - (dz->flbufptr[1][vc] * dz->param[DIFF_CROSS])); break; } break; } return(FINISHED); } /**************************** SPECLEAF ****************************/ int specleaf(dataptr dz) { int exit_status; int n; int samps_read, minsams = dz->insams[0]; for(n=1;ninfilecnt;n++) minsams = min(minsams,dz->insams[n]); dz->wlength = minsams/dz->wanted; while(dz->total_windows < dz->wlength) { for(n = 0;n < dz->infilecnt;n++) { if((samps_read = fgetfbufEx(dz->bigfbuf,dz->buflen,dz->ifd[n],0))<=0) { if(samps_read<0) { sprintf(errstr,"Sound read error.\n"); return(SYSTEM_ERROR); } else { sprintf(errstr,"Accounting problem: specleaf()\n"); return(PROGRAM_ERROR); } } if((exit_status = write_samps(dz->bigfbuf,dz->buflen,dz))<0) return(exit_status); if((dz->total_windows += dz->iparam[LEAF_SIZE]) >= dz->wlength) break; } } return(FINISHED); } /***************************** SPECMAX *********************** * * NB file0 is always the largest. */ int specmax(dataptr dz) { int exit_status; int n, m, windows_in_buf, windows_read, samps_read, samps_to_write; int windows_to_process = dz->wlength; while(windows_to_process) { if((samps_read = fgetfbufEx(dz->bigfbuf,dz->buflen,dz->ifd[0],0))<=0) { if(samps_read<0) { sprintf(errstr,"Sound read error.\n"); return(SYSTEM_ERROR); } else { sprintf(errstr,"Buffer accounting problem: specmax()\n"); return(PROGRAM_ERROR); } } windows_read = samps_read/dz->wanted; samps_to_write = samps_read; for(n=1;ninfilecnt;n++) { if((samps_read = fgetfbufEx(dz->flbufptr[2],dz->buflen,dz->ifd[n],0))>0) { windows_in_buf = samps_read/dz->wanted; dz->flbufptr[0] = dz->bigfbuf; dz->flbufptr[1] = dz->flbufptr[2]; for(m=0;mflbufptr[0] += dz->wanted; dz->flbufptr[1] += dz->wanted; } } } if(samps_to_write > 0) { if((exit_status = write_samps(dz->bigfbuf,samps_to_write,dz))<0) return(exit_status); } windows_to_process -= windows_read; } return(FINISHED); } /****************** DO_SPECMAX *********************/ int do_specmax(dataptr dz) { int vc; for(vc=0;vcwanted;vc+=2) { if(dz->flbufptr[1][AMPP] > dz->flbufptr[0][AMPP]) { dz->flbufptr[0][AMPP] = dz->flbufptr[1][AMPP]; dz->flbufptr[0][FREQ] = dz->flbufptr[1][FREQ]; } } return(FINISHED); } /****************** SPECMEAN *********************/ int specmean(dataptr dz) { int exit_status; int vc, cc; int *loc1 = dz->iparray[MEAN_LOC1]; int *loc2 = dz->iparray[MEAN_LOC2]; /* SUBZERO ALL LOUDEST-VALS TO BE USED IN THIS PASS */ rectify_window(dz->flbufptr[0],dz); rectify_window(dz->flbufptr[1],dz); for(cc = 0; cc < dz->clength; cc++) { dz->windowbuf[1][cc] = -1.0f; dz->windowbuf[2][cc] = -1.0f; } if(dz->vflag[MEAN_ZEROED]) { /* zero out-of-range channels */ for(vc = 0; vc < dz->iparam[MEAN_BOT];vc += 2) dz->flbufptr[0][AMPP] = 0.0f; for(vc = dz->iparam[MEAN_TOP]; vc < dz->wanted; vc += 2) dz->flbufptr[0][AMPP] = 0.0f; return(FINISHED); } for(vc = dz->iparam[MEAN_BOT]; vc < dz->iparam[MEAN_TOP]; vc += 2) { if((exit_status = if_loud_enough_to_go_in_list_put_in_list(dz->windowbuf[1],loc1,dz->flbufptr[0][vc],vc,dz))<0) return(exit_status); if((exit_status = if_loud_enough_to_go_in_list_put_in_list(dz->windowbuf[2],loc2,dz->flbufptr[1][vc],vc,dz))<0) return(exit_status); dz->windowbuf[0][AMPP] = 0.0f; /* initialise each output to zero amp */ dz->windowbuf[0][FREQ] = dz->flbufptr[0][FREQ]; } return generate_mean_values(loc1,loc2,dz); /* SWITCH AMPLITUDES */ } /****************************** IF_LOUD_ENOUGH_TO_GO_IN_LIST_PUT_IN_LIST ******************************/ int if_loud_enough_to_go_in_list_put_in_list(float *ampstore,int *locstore,float val,int location,dataptr dz) { int n = 0; if(val < 0.0) /* eliminate any subzero amplitudes */ return(FINISHED); while(ampstore[n] >= val) { /* Move along until stored vals are less than input val */ if(++n >= dz->clength) return(FINISHED); } if(n < dz->clength-1) { /* If ness, shuffle existing vals */ memmove((char *)(ampstore + n),(char *)(ampstore + n + 1),(dz->clength - n - 1) * sizeof(float)); memmove((char *)(locstore + n),(char *)(locstore + n + 1),(dz->clength - n - 1) * sizeof(int)); } ampstore[n] = val; /* Store new value */ locstore[n] = location; /* store its location in original buffer */ return(FINISHED); } /*************************** GENERATE_MEAN_VALUES ****************************/ int generate_mean_values(int *loc1, int *loc2,dataptr dz) { int exit_status; double newfrq, newamp; int j, n, a, b; n = 0; while(n < dz->clength && dz->windowbuf[1][n] >= 0.0 && dz->windowbuf[2][n] >= 0.0) { a = loc1[n]; b = loc2[n]; switch(dz->mode) { case(MEAN_AMP_AND_PICH): newamp = (dz->flbufptr[0][a] + dz->flbufptr[1][b])/2.0; a++; b++; if((exit_status = pichwise_mean_of_frqs (&newfrq,fabs((double)dz->flbufptr[0][a]),fabs((double)dz->flbufptr[1][b])))<0) return(exit_status); break; case(MEAN_AMP_AND_FRQ): newamp = (dz->flbufptr[0][a] + dz->flbufptr[1][b])/2.0; a++; b++; newfrq = (fabs(dz->flbufptr[0][a]) + fabs(dz->flbufptr[1][b]))/2.0; break; case(AMP1_MEAN_PICH): newamp = dz->flbufptr[0][a]; a++; b++; if((exit_status = pichwise_mean_of_frqs (&newfrq,fabs((double)dz->flbufptr[0][a]),fabs((double)dz->flbufptr[1][b])))<0) return(exit_status); break; case(AMP1_MEAN_FRQ): newamp = dz->flbufptr[0][a]; a++; b++; newfrq = (fabs(dz->flbufptr[0][a]) + fabs(dz->flbufptr[1][b]))/2.0; break; case(AMP2_MEAN_PICH): newamp = dz->flbufptr[1][b]; a++; b++; if((exit_status = pichwise_mean_of_frqs (&newfrq,fabs((double)dz->flbufptr[0][a]),fabs((double)dz->flbufptr[1][b])))<0) return(exit_status); break; case(AMP2_MEAN_FRQ): newamp = dz->flbufptr[1][b]; a++; b++; newfrq = (fabs(dz->flbufptr[0][a]) + fabs(dz->flbufptr[1][b]))/2.0; break; case(MAXAMP_MEAN_PICH): newamp = max(dz->flbufptr[0][a],dz->flbufptr[1][b]); a++; b++; if((exit_status = pichwise_mean_of_frqs (&newfrq,fabs((double)dz->flbufptr[0][a]),fabs((double)dz->flbufptr[1][b])))<0) return(exit_status); break; case(MAXAMP_MEAN_FRQ): newamp = max(dz->flbufptr[0][a],dz->flbufptr[1][b]); a++; b++; newfrq = (fabs(dz->flbufptr[0][a]) + fabs(dz->flbufptr[1][b]))/2.0; break; default: sprintf(errstr,"unknown program mode in generate_mean_values()\n"); return(PROGRAM_ERROR); } j = (int)((newfrq + dz->halfchwidth)/dz->chwidth); /* TRUNCATE */ /*FIND APPROP CHAN */ if(j < dz->infile->channels) { j *= 2; if(newamp > dz->windowbuf[0][j]) { dz->windowbuf[0][j++] = (float)newamp; dz->windowbuf[0][j] = (float)newfrq; } } n++; } for(j = dz->iparam[MEAN_BOT]; j < dz->iparam[MEAN_TOP]; j++) dz->flbufptr[0][j] = dz->windowbuf[0][j]; return(FINISHED); } /****************************** PICHWISE_MEAN_OF_FRQS ******************************/ int pichwise_mean_of_frqs(double *outfrq,double frq1,double frq2) { double half_of_interval_in_octaves; if(frq1 == 0.0) { *outfrq = frq2; return(FINISHED); } if(frq2 == 0.0) { *outfrq = frq1; return(FINISHED); } half_of_interval_in_octaves = (LOG2(frq2/frq1))/2.0; *outfrq = pow(2.0,half_of_interval_in_octaves) * frq1; return(FINISHED); } /************************* SPECCROSS ***************************/ int speccross(dataptr dz) { int vc; double valdiff; switch(dz->vflag[CROSS_INTP]) { case(CROS_FULL): for(vc = 0; vc < dz->wanted; vc += 2) dz->flbufptr[0][vc] = dz->flbufptr[1][vc]; break; case(CROS_INTERP): for(vc = 0; vc < dz->wanted; vc += 2) { valdiff = dz->flbufptr[1][vc] - dz->flbufptr[0][vc]; valdiff *= dz->param[CROS_INTP]; dz->flbufptr[0][vc] = (float)(dz->flbufptr[0][vc] + valdiff); } break; default: sprintf(errstr,"Unknown flag value in speccross()\n"); return(PROGRAM_ERROR); } return(FINISHED); } //TW NEW UPDATE CODE BELOW /*************************** WRITE_UNPITCHED_WINDOW ********************/ #define NOISEBASEX (0.5) //TW AVOID WARNING int write_unpitched_window(double *amptotal,dataptr dz) { int exit_status; double thisamp, basefrq = 0.0, thisfrq; double rand_offset; double noisrange = 1.0 - NOISEBASEX; int n = 1, vc, cc; int ccnt = dz->wanted/2; n = 1; while(n <= ccnt) { rand_offset = (drand48() - (.5)) * dz->chwidth; thisfrq = basefrq + rand_offset; if(thisfrq < 0.0 || thisfrq > dz->nyquist) continue; if((exit_status = get_channel_corresponding_to_frq(&cc,thisfrq,dz))<0) return(exit_status); vc = cc * 2; if((exit_status = getspecenvamp(&thisamp,thisfrq,0,dz))<0) return(exit_status); if(thisamp > dz->flbufptr[0][vc]) { *amptotal -= dz->flbufptr[0][vc]; dz->flbufptr[0][AMPP] = (float)(thisamp * (drand48() * noisrange)); dz->flbufptr[0][FREQ] = (float)thisfrq; *amptotal += thisamp; } basefrq += dz->chwidth; n++; } return(FINISHED); } /*************************** WRITE_SILENT_WINDOW ********************/ int write_silent_window(dataptr dz) { int vc, cc; double thisfrq = 0.0; for(cc=0, vc =0; cc < dz->clength; cc++, vc += 2) { dz->flbufptr[0][AMPP] = (float)0.0; dz->flbufptr[0][FREQ] = (float)thisfrq; thisfrq += dz->chwidth; } return(FINISHED); } /*************************** READ_ENVEL_FROM_ENVFILE **************************/ int read_envel_from_envfile(float **env,float **envend,int *envlen,int fileno,dataptr dz) { int samps_to_read, secs_to_read; *envlen = dz->insams[fileno]; if(((secs_to_read = dz->insams[fileno]/F_SECSIZE)*F_SECSIZE)!=dz->insams[fileno]) secs_to_read++; samps_to_read = secs_to_read * F_SECSIZE; if((*env = (float *)malloc((size_t)(samps_to_read * sizeof(float))))==NULL) { sprintf(errstr,"INSUFFICIENT MEMORY for envelope array.\n"); return(MEMORY_ERROR); } if(fgetfbufEx(*env,samps_to_read,dz->ifd[fileno],0) < 0) { sprintf(errstr,"fgetfbufEx() Anomaly in read_envel_from_envfile()\n"); return(SYSTEM_ERROR); } if((*env = (float *)realloc(*env,(size_t)(dz->insams[fileno] * sizeof(float))))==NULL) { sprintf(errstr,"INSUFFICIENT MEMORY to reallocate envelope array.\n"); return(MEMORY_ERROR); } *envend = *env + *envlen; return(FINISHED); }