/* * 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 aint with the CDP System; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /* floatsam vesion */ #include #include #include #include #include #include #include #include #include #include #include #include #define maxtime scalefact #include #include #include #ifndef HUGE #define HUGE 3.40282347e+38F #endif //#ifdef unix #define round(x) lround((x)) //#endif static int copygrain_from_elsewhere(int len,int k,int *obufposition,dataptr dz); static int store_the_grain_time(int grainstart,int *graincnt,int crosbuf,double samptotime,int init,dataptr dz); static int retime_grain(int ibufpos,int thisgap,int grainstart,int origgap,int bufno,int *obufpos, int chans,int crosbuf,int *grainadjusted,int store_end,int is_first_grain,dataptr dz); static int keep_non_omitted_grains(int ibufpos,int bufno,int grainstart,int *graincnt, int *obufpos,int crosbuf,int chans,int is_first_grain,dataptr dz); static int do_the_reordered_grains(int ibufpos,int bufno,int grainstart,int *graincnt, int *obufpos,int crosbuf,int chans,int is_first_grain,int is_last_grain,dataptr dz); static int synchronise_the_grain(int ibufpos,int *graincnt,int bufno,int gapcnt,int *obufpos, int grainstart,int crosbuf,int chans,int *grainadjusted,int is_first_grain,dataptr dz); static int do_final_reorder_grains(int graincnt,int *obufpos,dataptr dz); //TW REVISED static int output_final_grain(int grainstart,int start_splice,int bufno,int splicestart_bufno,int is_first_grain, int *obufpos,int grainlen,int crosbuf,dataptr dz); static int do_rerhythm_grain(int ibufpos,int *graincnt,int bufno,int gapcnt,int *obufpos,int grainstart, int crosbuf,int chans,int *grainadjusted,int is_first_grain,dataptr dz); static void swap_array_adresses_and_lens_for_reordr(int n,int m,dataptr dz); static int copy_grain_to_buf(int ibufpos,int bufno,int grainstart,int crosbuf,int chans,int n,dataptr dz); //TW REVISED static int retime_pre_firstgrain_material (int new_grainstart,int *obufposition,int chans,int crosbuf,dataptr dz); static int output_grain_link(int thisgap,int abs_halfsplice,int *obufposition,dataptr dz); static int copy_start_of_grain(int grainstart,int start_splice,int bufno,int splicestart_bufno, int *obufpos,int crosbuf,dataptr dz); static int read_dn_halfsplice(int *obufposition,int len,dataptr dz); static int create_an_upsplice_from_pregrain_material(int obufpos,int chans,dataptr dz); static int duplicate_grain(int ibufpos,int bufno,int gapcnt,int *obufpos,int grainstart, int crosbuf,int chans,int *grainadjusted,int is_first_grain,dataptr dz); static int prepare_final_grain(int ibufpos,int *start_splice,int bufno,int *splicestart_bufno, int grainstart,int *grainlen,int crosbuf,int chans,dataptr dz); static int read_up_halfsplice(int *obufposition,int len,dataptr dz); static int store_up_halfsplice(int storeno,int start,int bufno,int chans,int splicelen,dataptr dz); static int store_dn_halfsplice(int start,int bufno,int chans,int splicelen,dataptr dz); //TW REVISED static int duplicate_last_grain(int ibufpos,int bufno,int *obufpos,int grainstart, int crosbuf,int chans,int is_first_grain,dataptr dz); static int store_upsplice_of_next_grain(int ibufpos,int bufno,int abs_halfsplice,int chans,dataptr dz); static int copy_last_grain_to_buf(int ibufpos,int bufno,int grainstart,int crosbuf,int chans,int n,dataptr dz); static int copy_up_halfsplice_to_grainstore(int len,int storeno,int storelen,int *storepos,dataptr dz); static int copy_dn_halfsplice_to_grainstore(int len,int storeno,int storelen,int storepos,dataptr dz); static int copy_midgrain_to_store(int mid_grainlen,int bufno,int storelen,int grainstart, int *storepos,int crosbuf,int storeno,dataptr dz);; static int put_grain_into_store(int is_last_grain,int ibufpos,int bufno,int grainstart, int crosbuf,int chans,int graincnt,dataptr dz); static int save_abs_sampletime_of_grain(int grainstart,int *graincnt,int crosbuf,dataptr dz); static int do_seek_and_read(int *seekbufs, int *seeksamps,int grainno,dataptr dz); static int test_buffer_overflows(float *obuf,int *obufpos,int *ibufpos,int n,int maxlen,int *crosbuf,dataptr dz); static int do_the_reversing_process(int graincnt,int *obufposition,int chans,dataptr dz); static int output_up_halfsplice(int *ibufpos,int *obufpos,int chans,int splicelen,int *crosbuf,dataptr dz); static int output_dn_halfsplice(int *ibufpos,int *obufpos,int chans,int splicelen,int *crosbuf,dataptr dz); static int copy_midgrain_to_output(int mid_grainlen,int *ibufpos,int *obufpos,int *crosbuf,int chans,dataptr dz); static int insert_EOF_sampletime_in_samptime_list(int graincnt,dataptr dz); static void adjust_for_last_grain(int *graincnt,int *grainpos,dataptr dz); static int clear_outbuf(dataptr dz); static int output_whole_grain(int n,int *obufpos,int *seeksamps,int *seekbufs, int halfsplice,int abs_splicelen,int chans,dataptr dz); static int adjust_firstgrain_upsplice(int *ibufpos,int *startsplice,int n,int chans); static int do_grain_repitching(int *actual_grainlen,int bufno,int grainstart, int new_grainlen,int orig_grainlen,int chans,int crosbuf,double pichratio,dataptr dz); static int test_for_bufcros(int *thishere,float **b,int bufno,int crosbuf,dataptr dz); static int save_nextgrain_upsplice_elsewhere(int ibufpos,int bufno,int abs_halfsplice,int halfsplice, int chans,dataptr dz); static int copygrain_from_grainbuf_to_outbuf(int *obufpos,int grainlen,dataptr dz); static int retrieve_upsplice_for_nextgrain(int abs_halfsplice,dataptr dz); static int save_origgrain_length_and_store_nextgrains_upsplice(int *orig_grainlen,int ibufpos,int bufno, int grainstart,int abs_halfsplice,int halfsplice,int crosbuf,int chans,int is_last_grain,dataptr dz); //TW REVISED static int create_repitched_and_retimed_grain(int bufno,int grainstart,int orig_grainlen, int *new_grainlen,double pichratio,double timeratio,int *obufpos,int *is_first_grain, int *grainadjusted,int abs_halfsplice,int chans,int crosbuf,dataptr dz); static int repitch_main_body_of_grain(int bufno,int grainstart,int new_grainlen,int orig_grainlen, double pichratio,int chans,int crosbuf,int halfsplice,int abs_halfsplice,dataptr dz); //TW REVISED static int retime_main_body_of_grain(int grainstart,int bufno,double pichratio, double timeratio,int chans,int crosbuf,int *grainadjusted, int orig_grainlen,int *new_grainlen,dataptr dz); static int repitching_process(int ibufpos,int bufno,int grainstart,int abs_halfsplice,int halfsplice, int *graincnt,int *obufpos,int *orig_grainlen,int *new_grainlen,int *grainadjusted, int *is_first_grain,int is_last_grain,int chans,int crosbuf,dataptr dz); static int repitching_and_retiming_process(int ibufpos,int bufno,int grainstart,int abs_halfsplice, int halfsplice,int *graincnt,int *obufpos,int *orig_grainlen,int *new_grainlen, int *grainadjusted,int *is_first_grain,int is_last_grain,int chans,int crosbuf,dataptr dz); static int do_in_situ_halfsplice_on_stored_grain(int bufpos,int chans,int splicelen,int grainstorelen,dataptr dz); static int locate_zero_crossings(int local_minima_cnt,dataptr dz); static int which_minimum_to_eliminate(int minsegstartpos,int *pos,int maxseg,int segcnt,int *eliminate_pos,dataptr dz); static int eliminate_excess_minima(int *local_minima_cnt,int *pos,dataptr dz); static int find_all_local_minima(int peakcnt,int *local_minima_cnt,dataptr dz); static int find_all_positive_peaks(int startsearch,int endsearch,int *peakcnt,dataptr dz); static int eliminate_spurious_minima(int *local_minima_cnt,int *minimum_element_len,dataptr dz); static void hhshuflup(int k,int setlen,int *perm); static void hhprefix(int m,int setlen,int *perm); static void hhinsert(int m,int t,int setlen,int *perm); static void do_repet_restricted_perm(int *arr, int *perm, int arrsiz, int allowed, int endval); static int rand_ints_with_restricted_repeats(int element_cnt,int max_elements_needed,int arrsiz,int fullperms,int **pattern,dataptr dz); static int extract_rrr_env_from_sndfile(int paramno,dataptr dz); static void get_rrrenv_of_buffer(int samps_to_process,int envwindow_sampsize,float **envptr,float *buffer); static float getmaxsampr(int startsamp, int sampcnt,float *buffer); static int do_envgrain_write(int startsearch,int endsearch,int *last_total_samps_read,int *obufpos,dataptr dz); static int do_envgrain_zerowrite(int startsearch,int endsearch,int *obufpos,dataptr dz); static int do_envgrain_addwrite(int startsearch,int endsearch,int *last_total_samps_read,int *obufpos,dataptr dz); static int do_envgrain_zerowrite_dblbuf(int startsearch,int endsearch,int *obufpos,dataptr dz); /************************** DO_THE_GRAIN **********************/ int do_the_grain(int ibufpos,int *graincnt,int bufno,int gapcnt,int *obufpos,int grainstart, int crosbuf,int chans,int *grainadjusted,double samptotime, int *is_first_grain,dataptr dz) { int exit_status; int is_last_grain = FALSE; int newgapcnt, orig_grainlen, new_grainlen; int abs_splicelen = dz->iparam[GR_ABS_SPLICELEN]; int abs_halfsplice = abs_splicelen/2; /* guaranteed to fall on stereo boundary */ int halfsplice = dz->iparam[GR_SPLICELEN]/2; int store_end; static int init = 1; switch(dz->process) { case(GRAIN_COUNT): (*graincnt)++; break; case(GRAIN_GET): case(GRAIN_ALIGN): if((exit_status = store_the_grain_time(grainstart,graincnt,crosbuf,samptotime,init,dz))<0) return(exit_status); init = 0; break; case(GRAIN_REPITCH): if((exit_status = repitching_process(ibufpos,bufno,grainstart,abs_halfsplice,halfsplice,graincnt, obufpos,&orig_grainlen,&new_grainlen,grainadjusted,is_first_grain,is_last_grain,chans,crosbuf,dz))<0) return(exit_status); if((exit_status = retrieve_upsplice_for_nextgrain(abs_halfsplice,dz))<0) return(exit_status); break; case(GRAIN_REMOTIF): if((exit_status = repitching_and_retiming_process(ibufpos,bufno,grainstart,abs_halfsplice,halfsplice,graincnt, obufpos,&orig_grainlen,&new_grainlen,grainadjusted,is_first_grain,is_last_grain,chans,crosbuf,dz))<0) return(exit_status); if((exit_status = retrieve_upsplice_for_nextgrain(abs_halfsplice,dz))<0) return(exit_status); break; case(GRAIN_RERHYTHM): if((exit_status = do_rerhythm_grain (ibufpos,graincnt,bufno,gapcnt,obufpos,grainstart,crosbuf,chans,grainadjusted,*is_first_grain,dz))<0) return(exit_status); break; case(GRAIN_OMIT): if((exit_status = keep_non_omitted_grains (ibufpos,bufno,grainstart,graincnt,obufpos,crosbuf,chans,*is_first_grain,dz))<0) return(exit_status); break; case(GRAIN_REORDER): if((exit_status = do_the_reordered_grains (ibufpos,bufno,grainstart,graincnt,obufpos,crosbuf,chans,*is_first_grain,is_last_grain,dz))<0) return(exit_status); break; case(GRAIN_DUPLICATE): if((exit_status = duplicate_grain (ibufpos,bufno,gapcnt,obufpos,grainstart,crosbuf,chans,grainadjusted,*is_first_grain,dz))<0) return(exit_status); break; case(GRAIN_TIMEWARP): newgapcnt = round((double)(gapcnt/chans) * dz->param[GR_TSTRETCH]) * chans; store_end = TRUE; if((exit_status = retime_grain (ibufpos,newgapcnt,grainstart,gapcnt,bufno,obufpos,chans,crosbuf,grainadjusted,store_end,*is_first_grain,dz))<0) return(exit_status); break; case(GRAIN_REVERSE): if(*is_first_grain) { fprintf(stdout,"INFO: Searching for grains\n"); fflush(stdout); } if((exit_status = save_abs_sampletime_of_grain(grainstart,graincnt,crosbuf,dz))<0) return(exit_status); break; case(GRAIN_POSITION): if((exit_status = synchronise_the_grain (ibufpos,graincnt,bufno,gapcnt,obufpos,grainstart,crosbuf,chans,grainadjusted,*is_first_grain,dz))<0) return(exit_status); if(exit_status!=CONTINUE) return(FINISHED); break; default: sprintf(errstr,"Unknown case in do_the_grain()\n"); return(PROGRAM_ERROR); } *is_first_grain = FALSE; return(CONTINUE); } /************************** STORE_THE_GRAIN_TIME **********************/ int store_the_grain_time(int grainstart,int *graincnt,int crosbuf,double samptotime,int init,dataptr dz) { int previous_total_ssampsread = dz->total_samps_read - dz->ssampsread; int sampcnt = grainstart + previous_total_ssampsread; if(init) { if(*graincnt == 0) { sprintf(errstr,"No grains found.\n"); return(GOAL_FAILED); } if((dz->parray[GR_SYNCTIME] = (double *)malloc(*graincnt * sizeof(double)))==NULL) { sprintf(errstr,"INSUFFICIENT MEMORY to store sync times.\n"); return(MEMORY_ERROR); } dz->iparam[GR_SYNCCNT] = *graincnt; *graincnt = 0; } else if(dz->parray[GR_SYNCTIME] == NULL) { sprintf(errstr,"No grains found.\n"); return(GOAL_FAILED); } if(crosbuf) sampcnt -= dz->buflen; dz->parray[GR_SYNCTIME][(*graincnt)++] = (double)sampcnt * samptotime; if(*graincnt > dz->iparam[GR_SYNCCNT]) { sprintf(errstr,"Error in memory asignment for storing grain times.\n"); return(PROGRAM_ERROR); } return(FINISHED); } /************************* KEEP_NON_OMITTED_GRAINS *************************/ int keep_non_omitted_grains (int ibufpos,int bufno,int grainstart,int *graincnt,int *obufpos,int crosbuf,int chans,int is_first_grain,dataptr dz) { int exit_status; int start_splice; int abs_splicelen = dz->iparam[GR_ABS_SPLICELEN]; int abs_halfsplice = abs_splicelen/2; /* guaranteed to fall on stereo boundary */ int halfsplice = dz->iparam[GR_SPLICELEN]/2; int splicestart_bufno = bufno; /* Write previously stored up_splice to THIS grain */ if(*graincntiparam[GR_KEEP] &&!is_first_grain) { if((exit_status = read_up_halfsplice(obufpos,abs_halfsplice,dz))<0) return(exit_status); } start_splice = ibufpos - abs_halfsplice; /* ALWAYS KEEP up_splice to NEXT grain */ if(start_splice < 0) { splicestart_bufno = !bufno; start_splice += dz->buflen; } if((exit_status = store_up_halfsplice(1,start_splice,splicestart_bufno,chans,halfsplice,dz))<0) return(exit_status); if(*graincntiparam[GR_KEEP]) { start_splice -= abs_halfsplice; if(start_splice < 0) { splicestart_bufno = !bufno; start_splice += dz->buflen; } if((exit_status = store_dn_halfsplice(start_splice,splicestart_bufno,chans,halfsplice,dz))<0) return(exit_status); if((exit_status = copy_start_of_grain(grainstart,start_splice,bufno,splicestart_bufno,obufpos,crosbuf,dz))<0) return(exit_status); if((exit_status = read_dn_halfsplice(obufpos,abs_halfsplice,dz))<0) return(exit_status); } if(++(*graincnt)>=dz->iparam[GR_OUT_OF]) *graincnt = 0; return(FINISHED); } /************************* DO_THE_REORDERED_GRAINS *************************/ int do_the_reordered_grains(int ibufpos,int bufno,int grainstart,int *graincnt, int *obufpos,int crosbuf,int chans,int is_first_grain,int is_last_grain,dataptr dz) { int exit_status; int n, m, k; int len; int abs_halfsplice = dz->iparam[GR_ABS_SPLICELEN]/2; /* guaranteed to fall on stereo boundary */ if(*graincnt > dz->iparam[GR_REOLEN]) { /* WE'RE BEYOND PERMUTE-SET: LOOKING AT GRAINS NOT USED */ if(*graincnt == dz->iparam[GR_REOSTEP]-1) { /* IF looking at very last unused grain */ if((exit_status = store_upsplice_of_next_grain(ibufpos,bufno,abs_halfsplice,chans,dz))<0) return(exit_status);/* store startsplice of nextgrain, found at end of final skipped grain */ *graincnt = -1; /* and reset grain counter to indicate end of skipped-over grains */ } /* Otherwise, completely ignore skipped over grain */ } else if(*graincnt == dz->iparam[GR_REOLEN]) { /* WE'VE REACHED THE END OF THE PERMUTABLE SET */ for(n=0;niparam[GR_REOCNT];n++) { k = dz->iparray[GR_REOSET][n]; /* write permuted set to outbuf */ len = dz->lparray[GR_THIS_LEN][k]; if((exit_status = copygrain_from_elsewhere(len,k,obufpos,dz))<0) return(exit_status); } if(dz->iparam[GR_REOSTEP] < dz->iparam[GR_REOLEN]) { /* IF NEXT PERMUTE SET BEGINS BEFORE END OF THIS */ for(n=0,m=dz->iparam[GR_REOSTEP];m < dz->iparam[GR_REOLEN];n++,m++) swap_array_adresses_and_lens_for_reordr(n,m,dz); /* recycle the buffer storage */ *graincnt = dz->iparam[GR_REOLEN] - dz->iparam[GR_REOSTEP]; /* & reduce graincnt to no. of reused grains */ if((exit_status = put_grain_into_store(is_last_grain,ibufpos,bufno,grainstart,crosbuf,chans,*graincnt,dz))<0) return(exit_status); /* Store the current grain */ } else if(dz->iparam[GR_REOSTEP] == dz->iparam[GR_REOLEN]) { /* IF IT BEGINS AT END OF THIS ONE */ *graincnt = 0; /* reset grain counter to zero, for next set */ if((exit_status = put_grain_into_store(is_last_grain,ibufpos,bufno,grainstart,crosbuf,chans,*graincnt,dz))<0) return(exit_status); /* Store the current grain */ } else if (dz->iparam[GR_REOSTEP] == dz->iparam[GR_REOLEN]+1) {/* IF IT BEGINS AT 1st GRAIN BEYOND THIS SET */ if((exit_status = store_upsplice_of_next_grain(ibufpos,bufno,abs_halfsplice,chans,dz))<0) return(exit_status);/* store startsplice of nextgrain, found at end of final skipped grain */ *graincnt = -1; /* and reset grain counter to indicate end of skipped-over grains */ } /* IF IT BEGINS BEYOND THAT : DO NOTHING */ } else { /* WE'RE AT START OF, OR WITHIN, PERMUTABLE SET */ if(is_first_grain) { if((exit_status = create_an_upsplice_from_pregrain_material(*obufpos,chans,dz))<0) return(exit_status); /* Generate upsplice to 1st grain, of correct size */ memset((char *)dz->sampbuf[2],0,(size_t)dz->buflen * sizeof(float)); *obufpos = 0; } if((exit_status = put_grain_into_store(is_last_grain,ibufpos,bufno,grainstart,crosbuf,chans,*graincnt,dz))<0) return(exit_status); /* Store the current grain */ } (*graincnt)++; return(FINISHED); } /*********************** SYNCHRONISE_THE_GRAIN ***************************/ int synchronise_the_grain(int ibufpos,int *graincnt,int bufno,int gapcnt,int *obufpos, int grainstart,int crosbuf,int chans,int *grainadjusted,int is_first_grain,dataptr dz) { int exit_status; int newgapcnt; int store_end = TRUE; if(*graincnt >= dz->iparam[GR_SYNCCNT]) return(FINISHED); newgapcnt = round(dz->parray[GR_SYNCTIME][*graincnt]); if(*graincnt==0) { if((exit_status = retime_pre_firstgrain_material(newgapcnt,obufpos,chans,crosbuf,dz))<0) return(exit_status); (*graincnt)++; } newgapcnt = round(dz->parray[GR_SYNCTIME][*graincnt]); if((exit_status = retime_grain(ibufpos,newgapcnt,grainstart,gapcnt, bufno,obufpos,chans,crosbuf,grainadjusted,store_end,is_first_grain,dz))<0) return(exit_status); (*graincnt)++; return(CONTINUE); } /************************* DEAL_WITH_LAST_GRAINS *************************/ //TW REVISED int deal_with_last_grains (int ibufpos,int bufno,int *graincnt,int grainstart,int *grainadjusted, int *obufpos,int crosbuf,int chans,double samptotime,int *is_first_grain,dataptr dz) { int exit_status; int is_last_grain = TRUE; int abs_splicelen = dz->iparam[GR_ABS_SPLICELEN]; int abs_halfsplice = abs_splicelen/2; /* guaranteed to fall on stereo boundary */ int halfsplice = dz->iparam[GR_SPLICELEN]/2; int n, start_splice, grainlen, orig_grainlen, new_grainlen; int splicestart_bufno; switch(dz->process) { case(GRAIN_COUNT): if(!dz->vflag[LOSE_LAST_GRAIN]) (*graincnt)++; sprintf(errstr,"%d grains found at this gate level.\n",*graincnt); break; case(GRAIN_GET): if(!dz->vflag[LOSE_LAST_GRAIN]) { if((exit_status = store_the_grain_time(grainstart,graincnt,crosbuf,samptotime,0,dz))<0) return(exit_status); } for(n=0;n < *graincnt;n++) fprintf(dz->fp,"%lf\n",dz->parray[GR_SYNCTIME][n]); break; case(GRAIN_REVERSE): if((exit_status = save_abs_sampletime_of_grain(grainstart,graincnt,crosbuf,dz))<0) return(exit_status); if(*graincnt <= 1) { sprintf(errstr,"No grains found.\n"); return(DATA_ERROR); } fprintf(stdout,"INFO: Reversing grain order\n"); fflush(stdout); if((exit_status = do_the_reversing_process(*graincnt,obufpos,chans,dz))<0) return(exit_status); break; case(GRAIN_ALIGN): if(!dz->vflag[LOSE_LAST_GRAIN]) { if((exit_status = store_the_grain_time(grainstart,graincnt,crosbuf,samptotime,0,dz))<0) return(exit_status); } if(dz->iparam[GR_SYNCCNT] != *graincnt) dz->iparam[GR_SYNCCNT] = *graincnt; break; case(GRAIN_REORDER): if(!dz->vflag[LOSE_LAST_GRAIN]) { if((exit_status = do_the_reordered_grains (ibufpos,bufno,grainstart,graincnt,obufpos,crosbuf,chans,*is_first_grain,is_last_grain,dz))<0) return(exit_status); } if((exit_status = do_final_reorder_grains(*graincnt,obufpos,dz))<0) return(exit_status); break; case(GRAIN_RERHYTHM): case(GRAIN_TIMEWARP): case(GRAIN_POSITION): if(!dz->vflag[LOSE_LAST_GRAIN]) { if((exit_status = prepare_final_grain (ibufpos,&start_splice,bufno,&splicestart_bufno,grainstart,&grainlen,crosbuf,chans,dz))<0) return(exit_status); if(exit_status==FINISHED) break; if((exit_status = output_final_grain //TW REVISED (grainstart,start_splice,bufno,splicestart_bufno,*is_first_grain,obufpos,grainlen,crosbuf,dz))<0) return(exit_status); } break; case(GRAIN_OMIT): if(!dz->vflag[LOSE_LAST_GRAIN] && *graincntiparam[GR_KEEP]) { if((exit_status = prepare_final_grain (ibufpos,&start_splice,bufno,&splicestart_bufno,grainstart,&grainlen,crosbuf,chans,dz))<0) return(exit_status); if(exit_status==FINISHED) break; if((exit_status = output_final_grain //TW REVISED (grainstart,start_splice,bufno,splicestart_bufno,*is_first_grain,obufpos,grainlen,crosbuf,dz))<0) return(exit_status); } break; case(GRAIN_DUPLICATE): if(!dz->vflag[LOSE_LAST_GRAIN]) { if((exit_status = duplicate_last_grain //TW REVISED (ibufpos,bufno,obufpos,grainstart,crosbuf,chans,*is_first_grain,dz))<0) return(exit_status); } break; case(GRAIN_REPITCH): if(!dz->vflag[LOSE_LAST_GRAIN]) { if((exit_status = repitching_process(ibufpos,bufno,grainstart,abs_halfsplice,halfsplice,graincnt, obufpos,&orig_grainlen,&new_grainlen,grainadjusted,is_first_grain,is_last_grain,chans,crosbuf,dz))<0) return(exit_status); } break; case(GRAIN_REMOTIF): if(!dz->vflag[LOSE_LAST_GRAIN]) { if((exit_status = repitching_and_retiming_process(ibufpos,bufno,grainstart,abs_halfsplice,halfsplice,graincnt, obufpos,&orig_grainlen,&new_grainlen,grainadjusted,is_first_grain,is_last_grain,chans,crosbuf,dz))<0) return(exit_status); } break; default: sprintf(errstr,"Unknown case in deal_with_last_grains()\n"); return(PROGRAM_ERROR); } return(FINISHED); } /************************* DO_FINAL_REORDER_GRAINS *************************/ int do_final_reorder_grains(int graincnt,int *obufpos,dataptr dz) { int exit_status; int n, k; int len; if(graincnt > 0 && graincnt <= dz->iparam[GR_REOCNT]) { /* There are grains still to permute */ for(n=0;niparam[GR_REOCNT];n++) { if((k = dz->iparray[GR_REOSET][n])>=graincnt) /* If required grain doesn't exist, finish */ return(FINISHED); len = dz->lparray[GR_THIS_LEN][k]; if((exit_status = copygrain_from_elsewhere(len,k,obufpos,dz))<0) return(exit_status); } } return(FINISHED); } /************************* DO_RERHYTHM_GRAIN *************************/ int do_rerhythm_grain(int ibufpos,int *graincnt,int bufno,int gapcnt, int *obufpos,int grainstart,int crosbuf,int chans,int *grainadjusted,int is_first_grain,dataptr dz) { int exit_status; int newgapcnt, n; int store_end; double *ratio = dz->parray[GR_RATIO]; switch(dz->mode) { case(GR_NO_REPEATS): store_end = TRUE; newgapcnt = round((double)(gapcnt/chans) * ratio[*graincnt]) * chans; if((exit_status = retime_grain (ibufpos,newgapcnt,grainstart,gapcnt,bufno,obufpos,chans,crosbuf,grainadjusted,store_end,is_first_grain,dz))<0) return(exit_status); if(++(*graincnt)>=dz->iparam[GR_RATIOCNT]) *graincnt = 0; break; case(GR_REPEATS): store_end = FALSE; if(is_first_grain && dz->iparam[GR_RATIOCNT]>1) { if((exit_status = create_an_upsplice_from_pregrain_material(*obufpos,chans,dz))<0) return(exit_status); } for(n=0; niparam[GR_RATIOCNT]-1; n++) { newgapcnt = round((double)(gapcnt/chans) * ratio[n]) * chans; if((exit_status = retime_grain (ibufpos,newgapcnt,grainstart,gapcnt,bufno,obufpos,chans,crosbuf,grainadjusted,store_end,is_first_grain,dz))<0) return(exit_status); is_first_grain = FALSE; } store_end = TRUE; newgapcnt = round((double)(gapcnt/chans) * ratio[n]) * chans; if((exit_status = retime_grain (ibufpos,newgapcnt,grainstart,gapcnt,bufno,obufpos,chans,crosbuf,grainadjusted,store_end,is_first_grain,dz))<0) return(exit_status); break; default: sprintf(errstr,"Unknown case in do_rerhythm_grain()\n"); return(PROGRAM_ERROR); } return(FINISHED); } /************************* DUPLICATE_GRAIN *************************/ int duplicate_grain(int ibufpos,int bufno,int gapcnt,int *obufpos,int grainstart, int crosbuf,int chans,int *grainadjusted,int is_first_grain,dataptr dz) { int exit_status; int newgapcnt = gapcnt, n; int store_end = FALSE; int dupl = (int)dz->iparam[GR_DUPLS]; if(is_first_grain && dupl>1) { if((exit_status = create_an_upsplice_from_pregrain_material(*obufpos,chans,dz))<0) return(exit_status); } for(n=0; niparam[GR_DUPLS]; if(is_first_grain && dupl>1) { if((exit_status = create_an_upsplice_from_pregrain_material(*obufpos,chans,dz))<0) return(exit_status); } if((exit_status = prepare_final_grain (ibufpos,&start_splice,bufno,&splicestart_bufno,grainstart,&grainlen,crosbuf,chans,dz))<0) return(exit_status); if(exit_status==FINISHED) return(FINISHED); for(n=0; nsampbuf[2]; float *buf = dz->extrabuf[k+SPLBUF_OFFSET]; for(n=0;n= dz->buflen) { if((exit_status = write_samps(obuf,dz->buflen,dz))<0) return(exit_status); obufpos = 0; } } *obufposition = obufpos; return(FINISHED); } /************************* SWAP_ARRAY_ADRESSES_AND_LENS_FOR_REORDR ************************* * * The arrays still needed are now pointed to by the lower-indexed lparrays. * The arrays NO intER required get swapped, to be pointed to by the higher-indexed lparrays, * hence are overwritten as the process proceeds. * * This works (I hope) even where an index is swapped over more than once!! */ void swap_array_adresses_and_lens_for_reordr(int n,int m,dataptr dz) { int n_bufno = n + SPLBUF_OFFSET; int m_bufno = m + SPLBUF_OFFSET; float *tempadr = dz->extrabuf[n_bufno]; int temp_arraylen = dz->lparray[GR_ARRAYLEN][n]; int templen = dz->lparray[GR_THIS_LEN][n]; dz->extrabuf[n_bufno] = dz->extrabuf[m_bufno]; dz->extrabuf[m_bufno] = tempadr; dz->lparray[GR_ARRAYLEN][n] = dz->lparray[GR_ARRAYLEN][m]; dz->lparray[GR_ARRAYLEN][m] = temp_arraylen; dz->lparray[GR_THIS_LEN][n] = dz->lparray[GR_THIS_LEN][m]; dz->lparray[GR_THIS_LEN][m] = templen; } /************************* COPY_GRAIN_TO_BUF *************************/ int copy_grain_to_buf(int ibufpos,int bufno,int grainstart,int crosbuf,int chans,int storeno,dataptr dz) { int exit_status; int grainlen = ibufpos - grainstart; int storepos = 0, mid_grainlen; int abs_splicelen = dz->iparam[GR_ABS_SPLICELEN]; int abs_halfsplice = abs_splicelen/2; int halfsplice = dz->iparam[GR_SPLICELEN]/2; int splicestart; int grainbufno = storeno + SPLBUF_OFFSET; int splicestart_bufno = bufno; if(crosbuf) grainlen += dz->buflen; if(grainlen > dz->lparray[GR_ARRAYLEN][storeno]) { if((dz->extrabuf[grainbufno] = (float *)realloc(dz->extrabuf[grainbufno],grainlen * sizeof(float)))==NULL) { sprintf(errstr,"INSUFFICIENT MEMORY to enlarge grain store.\n"); return(MEMORY_ERROR); } dz->lparray[GR_ARRAYLEN][storeno] = grainlen; } dz->lparray[GR_THIS_LEN][storeno] = grainlen; if((exit_status = copy_up_halfsplice_to_grainstore(abs_halfsplice,grainbufno,grainlen,&storepos,dz))<0) return(exit_status); splicestart = ibufpos - abs_halfsplice; if(splicestart < 0) { splicestart += dz->buflen; splicestart_bufno = !bufno; } if((exit_status = store_up_halfsplice(1,splicestart,splicestart_bufno,chans,halfsplice,dz))<0) return(exit_status); splicestart -= abs_halfsplice; if(splicestart < 0) { splicestart += dz->buflen; splicestart_bufno = !bufno; } if((exit_status = store_dn_halfsplice(splicestart,splicestart_bufno,chans,halfsplice,dz))<0) return(exit_status); mid_grainlen = grainlen - dz->iparam[GR_ABS_SPLICELEN]; if((exit_status = copy_midgrain_to_store(mid_grainlen,bufno,grainlen,grainstart,&storepos,crosbuf,grainbufno,dz))<0) return(exit_status); if((exit_status = copy_dn_halfsplice_to_grainstore(abs_halfsplice,grainbufno,grainlen,storepos,dz))<0) return(exit_status); return(FINISHED); } /************************* COPY_LAST_GRAIN_TO_BUF *************************/ int copy_last_grain_to_buf(int ibufpos,int bufno,int grainstart,int crosbuf,int chans,int storeno,dataptr dz) { int exit_status; int storepos = 0, mid_grainlen; int splicelen, abs_splicelen = dz->iparam[GR_ABS_SPLICELEN]; int abs_halfsplice = abs_splicelen/2; int splicestart; int splicestart_bufno = bufno; int grainbufno = storeno + SPLBUF_OFFSET; int storelen; int grainlen = ibufpos - grainstart; if(crosbuf) grainlen += dz->buflen; if((storelen = grainlen + abs_halfsplice) dz->lparray[GR_ARRAYLEN][storeno]) { if((dz->extrabuf[grainbufno] = (float *)realloc(dz->extrabuf[grainbufno],storelen * sizeof(float)))==NULL) { sprintf(errstr,"INSUFFICIENT MEMORY to enlarge grain store.\n"); return(MEMORY_ERROR); } dz->lparray[GR_ARRAYLEN][storeno] = storelen; } dz->lparray[GR_THIS_LEN][storeno] = storelen; if((exit_status = copy_up_halfsplice_to_grainstore(abs_halfsplice,grainbufno,storelen,&storepos,dz))<0) return(exit_status); if((mid_grainlen = grainlen - abs_halfsplice) < 0) mid_grainlen = 0; /* HENCE mid_grainlen >= 0 */ abs_splicelen = min(grainlen,abs_halfsplice); splicelen = abs_splicelen/chans; /* HENCE abs_splicelen <= grainlen */ splicestart = ibufpos - abs_splicelen; /* splicestart >= grainstart, BECAUSE abs_splicelen <= grainlen */ if(splicestart < 0) { splicestart += dz->buflen; splicestart_bufno = !bufno; } if((exit_status = store_dn_halfsplice(splicestart,splicestart_bufno,chans,splicelen,dz))<0) return(exit_status); /* forces an abs_halfsplice length unit, regardless of input splicelen */ if(mid_grainlen > 0) { if((exit_status = copy_midgrain_to_store(mid_grainlen,bufno,storelen,grainstart,&storepos,crosbuf,grainbufno,dz))<0) return(exit_status); } if((exit_status = copy_dn_halfsplice_to_grainstore(abs_halfsplice,grainbufno,storelen,storepos,dz))<0) return(exit_status); return(FINISHED); } /************************ RETIME_PRE_FIRSTGRAIN_MATERIAL ***************************/ int retime_pre_firstgrain_material (int new_grainstart,int *obufposition,int chans,int crosbuf,dataptr dz) { int exit_status; /*float *b = dz->sampbuf[bufno];*/ /* RWD: not used */ float *obuf = dz->sampbuf[2]; double *splicetab = dz->parray[GR_SPLICETAB]; int excess, n, k; int m; int obufpos = *obufposition; int abs_splicelen = dz->iparam[GR_ABS_SPLICELEN]/2; int splicelen = abs_splicelen/chans; if(crosbuf) { sprintf(errstr,"1st grain starts beyond end of sound buffer: Can't proceed.\n"); return(DATA_ERROR); } excess = new_grainstart - obufpos; if(excess > 0) { memmove((char *)dz->extrabuf[2],(char *)obuf,(size_t)dz->buflen * sizeof(float)); if(excess >= dz->buflen) { memset((char *)obuf,0,(size_t)dz->buflen * sizeof(float)); while(excess >= dz->buflen) { if((exit_status = write_samps(obuf,dz->buflen,dz))<0) return(exit_status); excess -= dz->buflen; } } for(n=0;nextrabuf[2][m]; if(n >= dz->buflen) { if((exit_status = write_samps(obuf,dz->buflen,dz))<0) return(exit_status); n = 0; } } new_grainstart = n; } else if(excess < 0) { for(n=0, m = excess; n < new_grainstart; n++, m++) obuf[n] = obuf[m]; /* Move data backwards */ while(n < obufpos) obuf[n++] = 0; /* rezero samples beyond new_grainstart */ k = 0; for(n=0;n= dz->buflen) { sprintf(errstr,"Buffer accounting problem: retime_pre_firstgrain_material()\n"); return(PROGRAM_ERROR); } } } *obufposition = new_grainstart; /* reset obuf pointer to (new) END of pre-grain material */ return(FINISHED); } /************************* OUTPUT_GRAIN_LINK *************************/ int output_grain_link(int thisgap,int abs_halfsplice,int *obufposition,dataptr dz) { int exit_status; int n, m; float *obuf = dz->sampbuf[2]; int obufpos = *obufposition; for(n = 0, m = -(thisgap - abs_halfsplice); n < thisgap; n++,m++) { if(n < abs_halfsplice) obuf[obufpos] = dz->extrabuf[0][n]; else obuf[obufpos] = 0; if(++obufpos >= dz->buflen) { if((exit_status = write_samps(obuf,dz->buflen,dz))<0) return(exit_status); obufpos = 0; } } *obufposition = obufpos; return(FINISHED); } /************************* COPY_START_OF_GRAIN *************************/ int copy_start_of_grain (int grainstart,int start_splice,int bufno,int splicestart_bufno,int *obufpos,int crosbuf,dataptr dz) { int exit_status; if(crosbuf) { if(splicestart_bufno != bufno) { if((exit_status = copygrain(grainstart,start_splice,!bufno,obufpos,dz))<0) return(exit_status); } else { if((exit_status = crosbuf_grain_type3(grainstart,start_splice,bufno,obufpos,dz))<0) return(exit_status); } } else { if((exit_status = copygrain(grainstart,start_splice,bufno,obufpos,dz))<0) return(exit_status); } return(FINISHED); } /************************** PREPARE_FINAL_GRAIN ******************************/ int prepare_final_grain(int ibufpos,int *start_splice,int bufno,int *splicestart_bufno, int grainstart,int *grainlen,int crosbuf,int chans,dataptr dz) { int exit_status; int abs_splicelen = dz->iparam[GR_ABS_SPLICELEN]; int abs_halfsplice = abs_splicelen/2; /* guaranteed to fall on stereo boundary */ int halfsplice = abs_halfsplice/chans; *grainlen = ibufpos - grainstart; if(crosbuf) *grainlen += dz->buflen; if(*grainlen < abs_splicelen) { fprintf(stdout,"INFO: Final grain omitted: too short\n"); fflush(stdout); return(FINISHED); } *start_splice = ibufpos - abs_halfsplice; *splicestart_bufno = bufno; if(*start_splice < 0) { *splicestart_bufno = !bufno; *start_splice += dz->buflen; } if((exit_status = store_dn_halfsplice(*start_splice,*splicestart_bufno,chans,halfsplice,dz))<0) return(exit_status); return(CONTINUE); } /************************** OUTPUT_FINAL_GRAIN ******************************/ //TW REVISED int output_final_grain(int grainstart,int start_splice,int bufno,int splicestart_bufno,int is_first_grain, int *obufpos,int grainlen,int crosbuf,dataptr dz) { int exit_status; int abs_splicelen = dz->iparam[GR_ABS_SPLICELEN]; int abs_halfsplice = abs_splicelen/2; /* guaranteed to fall on stereo boundary */ if(!is_first_grain) { if((exit_status = read_up_halfsplice(obufpos,abs_halfsplice,dz))<0) return(exit_status); } if(grainlen > 0) { if((exit_status = copy_start_of_grain(grainstart,start_splice,bufno,splicestart_bufno,obufpos,crosbuf,dz))<0) return(exit_status); } if((exit_status = read_dn_halfsplice(obufpos,abs_halfsplice,dz))<0) return(exit_status); return(FINISHED); } /**************************** READ_DN_HALFSPLICE ****************************/ int read_dn_halfsplice(int *obufposition,int len,dataptr dz) { int exit_status; int n, j = 0; float *b = dz->extrabuf[0]; float *obuf = dz->sampbuf[2]; int obufpos = *obufposition; for(n=0;n < len;n++) { obuf[obufpos++] = b[j++]; if(obufpos >= dz->buflen) { if((exit_status = write_samps(obuf,dz->buflen,dz))<0) return(exit_status); obufpos = 0; } } *obufposition = obufpos; return(FINISHED); } /**************************** READ_UP_HALFSPLICE ****************************/ int read_up_halfsplice(int *obufposition,int len,dataptr dz) { int exit_status; int n, j = 0; float *b = dz->extrabuf[1]; float *obuf = dz->sampbuf[2]; int obufpos = *obufposition; for(n=0;n < len;n++) { obuf[obufpos++] = b[j++]; if(obufpos >= dz->buflen) { if((exit_status = write_samps(obuf,dz->buflen,dz))<0) return(exit_status); obufpos = 0; } } *obufposition = obufpos; return(FINISHED); } /**************************** COPY_UP_HALFSPLICE_TO_GRAINSTORE ****************************/ int copy_up_halfsplice_to_grainstore(int len,int storeno,int storelen,int *storepos,dataptr dz) { char *goaladdress = (char *)dz->extrabuf[storeno]; if(len > storelen) { sprintf(errstr,"Buffer anomaly: copy_up_halfsplice_to_grainstore()\n"); return(PROGRAM_ERROR); } memmove(goaladdress,(char *)dz->extrabuf[1],len * sizeof(float)); *storepos = len; return(FINISHED); } /**************************** COPY_DN_HALFSPLICE_TO_GRAINSTORE ****************************/ int copy_dn_halfsplice_to_grainstore(int len,int storeno,int storelen,int storepos,dataptr dz) { char *goaladdress = (char *)(dz->extrabuf[storeno] + storepos); if(storepos + len > storelen) { sprintf(errstr,"Buffer anomaly: copy_dn_halfsplice_to_grainstore()\n"); return(PROGRAM_ERROR); } memmove(goaladdress,(char *)dz->extrabuf[0],len * sizeof(float)); return(FINISHED); } /**************************** CREATE_AN_UPSPLICE_FROM_PREGRAIN_MATERIAL ****************************/ int create_an_upsplice_from_pregrain_material(int obufpos,int chans,dataptr dz) { int n, k; int m, j = 0, empty_space; double ratio; float *obuf = dz->sampbuf[2]; float *splicebuf = dz->extrabuf[1]; int abs_halfsplice = dz->iparam[GR_ABS_SPLICELEN]/2; int halfsplice = abs_halfsplice/chans; int splicelen; double *splicetab = dz->parray[GR_SPLICETAB]; if(obufpos >= abs_halfsplice) { k = obufpos - abs_halfsplice; for(n=0;n= dz->buflen) { sprintf(errstr,"Error in buffer accounting: create_an_upsplice_from_pregrain_material()\n"); return(PROGRAM_ERROR); } } } else { splicelen = obufpos/chans; empty_space = abs_halfsplice - obufpos; for(n=0;n= dz->buflen) { sprintf(errstr,"Error in buffer accounting: create_an_upsplice_from_pregrain_material()\n"); return(PROGRAM_ERROR); } } } return(FINISHED); } /************************* RETIME_GRAIN *************************/ int retime_grain(int ibufpos,int thisgap,int grainstart,int origgap,int bufno, int *obufpos,int chans,int crosbuf,int *grainadjusted,int store_end,int is_first_grain,dataptr dz) { int exit_status; int grainend, start_splice, gapchange; int abs_splicelen = dz->iparam[GR_ABS_SPLICELEN]; int abs_halfsplice = abs_splicelen/2; /* guaranteed to fall on stereo boundary */ int halfsplice = dz->iparam[GR_SPLICELEN]/2; int splicestart_bufno = bufno; start_splice = ibufpos - abs_halfsplice; if(start_splice < 0) { splicestart_bufno = !bufno; start_splice += dz->buflen; } if(!is_first_grain) { if((exit_status = read_up_halfsplice(obufpos,abs_halfsplice,dz))<0) return(exit_status); } if(store_end) { if((exit_status = store_up_halfsplice(1,start_splice,splicestart_bufno,chans,halfsplice,dz))<0) return(exit_status); } if((gapchange = thisgap - origgap)>=0) { start_splice -= abs_halfsplice; if(start_splice < 0) { splicestart_bufno = !bufno; start_splice += dz->buflen; } if((exit_status = store_dn_halfsplice(start_splice,splicestart_bufno,chans,halfsplice,dz))<0) return(exit_status); if((exit_status = copy_start_of_grain(grainstart,start_splice,bufno,splicestart_bufno,obufpos,crosbuf,dz))<0) return(exit_status); if((exit_status = output_grain_link(abs_halfsplice+gapchange,abs_halfsplice,obufpos,dz))<0) return(exit_status); } else { if(thisgap < dz->iparam[GR_ABS_SPLICEX2]) { grainend = grainstart + dz->iparam[GR_ABS_SPLICEX2]; (*grainadjusted)++; } else grainend = grainstart + thisgap; start_splice = grainend - abs_splicelen; /* NB Ensures 1 grain stops before other starts */ splicestart_bufno = bufno; if(crosbuf) { if(start_splice >= dz->buflen) start_splice -= dz->buflen; else splicestart_bufno = !bufno; } if((exit_status = store_dn_halfsplice(start_splice,splicestart_bufno,chans,halfsplice,dz))<0) return(exit_status); if((exit_status = copy_start_of_grain(grainstart,start_splice,bufno,splicestart_bufno,obufpos,crosbuf,dz))<0) return(exit_status); if((exit_status = output_grain_link(abs_halfsplice,abs_halfsplice,obufpos,dz))<0) return(exit_status); } return(FINISHED); } /**************************** STORE_UP_HALFSPLICE *************************** * * GIVE IT bufno where splice STARTS!!! */ int store_up_halfsplice(int storeno,int start,int bufno,int chans,int splicelen,dataptr dz) { int n, remain; int m; float *b = dz->sampbuf[bufno]; float *obuf = dz->extrabuf[storeno]; int k = start, j = 0; double *splicetab = dz->parray[GR_SPLICETAB]; int true_halfsplice = dz->iparam[GR_SPLICELEN]/2; if((remain = true_halfsplice - splicelen)<0) { sprintf(errstr,"Invalid splicelen in store_up_halfsplice()\n"); return(PROGRAM_ERROR); } else if(remain==0) { for(n=0;n= dz->buflen) { b = dz->sampbuf[!bufno]; k = 0; } } } else { for(n=0;n= dz->buflen) { b = dz->sampbuf[!bufno]; k = 0; } } } return(FINISHED); } /**************************** STORE_DN_HALFSPLICE *************************** * * GIVE IT bufno where splice STARTS!!! */ int store_dn_halfsplice(int start,int bufno,int chans,int splicelen,dataptr dz) { int n, k = start, j = 0; int m; float *b = dz->sampbuf[bufno]; float *obuf = dz->extrabuf[0]; double *splicetab = dz->parray[GR_SPLICETAB]; int true_halfsplice = dz->iparam[GR_SPLICELEN]/2; int remain = true_halfsplice - splicelen; if(remain < 0) { sprintf(errstr,"Invalid splicelen: store_dn_halfsplice()\n"); return(PROGRAM_ERROR); } else if(remain==0) { for(n=splicelen-1;n>=0;n--) { for(m=0;m= dz->buflen) { b = dz->sampbuf[!bufno]; k = 0; } } } else { for(n=splicelen-1;n>=0;n--) { for(m=0;m= dz->buflen) { b = dz->sampbuf[!bufno]; k = 0; } } for(n=0;n storelen) { sprintf(errstr,"Buffer anomaly: copy_midgrain_to_store()\n"); return(PROGRAM_ERROR); } if(crosbuf) { if(grainstart + mid_grainlen <= dz->buflen) { b2 = dz->sampbuf[!bufno] + grainstart; b = dz->extrabuf[storeno] + *storepos; memmove((char *)b,(char *)b2,mid_grainlen * sizeof(float)); *storepos += mid_grainlen; } else { partbuf = dz->buflen - grainstart; partbuf_samps = partbuf; b2 = dz->sampbuf[!bufno] + grainstart; b = dz->extrabuf[storeno] + *storepos; memmove((char *)b,(char *)b2,partbuf_samps * sizeof(float)); *storepos += partbuf; partbuf = mid_grainlen - partbuf; partbuf_samps = partbuf; b2 = dz->sampbuf[bufno]; b = dz->extrabuf[storeno] + *storepos; memmove((char *)b,(char *)b2, partbuf_samps * sizeof(float)); *storepos += partbuf; } } else { b2 = dz->sampbuf[bufno] + grainstart; b = dz->extrabuf[storeno] + *storepos; memmove((char *)b,(char *)b2,mid_grainlen * sizeof(float)); *storepos += mid_grainlen; } return(FINISHED); } /**************************** STORE_UPSPLICE_OF_NEXT_GRAIN ***************************/ int store_upsplice_of_next_grain(int ibufpos,int bufno,int abs_halfsplice,int chans,dataptr dz) { int splicestart_bufno = bufno; int halfsplice = abs_halfsplice/chans; int splicestart = ibufpos - abs_halfsplice; if(splicestart < 0) { splicestart += dz->buflen; splicestart_bufno = !bufno; } return store_up_halfsplice(1,splicestart,splicestart_bufno,chans,halfsplice,dz); } /**************************** PUT_GRAIN_INTO_STORE ***************************/ int put_grain_into_store (int is_last_grain,int ibufpos,int bufno,int grainstart,int crosbuf,int chans,int graincnt,dataptr dz) { if(is_last_grain) return copy_last_grain_to_buf(ibufpos,bufno,grainstart,crosbuf,chans,graincnt,dz); return copy_grain_to_buf(ibufpos,bufno,grainstart,crosbuf,chans,graincnt,dz); } /**************************** SAVE_ABS_SAMPLETIME_OF_GRAIN ***************************/ int save_abs_sampletime_of_grain(int grainstart,int *graincnt,int crosbuf,dataptr dz) { int samps_read_before_thisbuf = dz->total_samps_read - dz->ssampsread; dz->lparray[GR_ABS_POS][*graincnt] = grainstart + samps_read_before_thisbuf; if(crosbuf) dz->lparray[GR_ABS_POS][*graincnt] -= dz->buflen; (*graincnt)++; if(*graincnt >= dz->iparam[GR_ARRAYSIZE]) { dz->iparam[GR_ARRAYSIZE] += BIGARRAY; if((dz->lparray[GR_ABS_POS] = (int *)realloc(dz->lparray[GR_ABS_POS],dz->iparam[GR_ARRAYSIZE] * sizeof(int)))==NULL) { sprintf(errstr,"INSUFFICIENT MEMORY to enlarge positions store.\n"); return(MEMORY_ERROR); } } return(FINISHED); } /**************************** DO_THE_REVERSING_PROCESS ***************************/ int do_the_reversing_process(int graincnt,int *obufposition,int chans,dataptr dz) { int exit_status; int obufpos = 0, seeksamps = 0, n, seekbufs = 0; int abs_splicelen = dz->iparam[GR_ABS_SPLICELEN]; int abs_halfsplice = abs_splicelen/2; int halfsplice = abs_halfsplice/chans; int *grainpos; if((exit_status = insert_EOF_sampletime_in_samptime_list(graincnt,dz))<0) return(exit_status); grainpos = dz->lparray[GR_ABS_POS]; for(n=0;nssampsread) */ if(sndseekEx(dz->ifd[0],0,0) < 0) { sprintf(errstr,"seek error at start of do_the_reversing_process()\n"); return(SYSTEM_ERROR); } if((exit_status = read_samps(dz->sampbuf[0],dz))<0) return(exit_status); if((exit_status = do_seek_and_read(&seekbufs,&seeksamps,graincnt-1,dz))<0) return(exit_status); /* seek to a buffer containing (WHOLE) final grain */ for(n=graincnt-1;n>=0;n--) { if((exit_status = output_whole_grain (n,&obufpos,&seeksamps,&seekbufs,halfsplice,abs_splicelen,chans,dz))<0) return(exit_status); } *obufposition = obufpos; return(FINISHED); } /**************************** DO_SEEK_AND_READ ***************************/ int do_seek_and_read(int *seekbufs,int *seeksamps,int grainno,dataptr dz) { int exit_status; int new_seekbufs = dz->lparray[GR_ABS_POS][grainno]/dz->buflen; if(new_seekbufs != *seekbufs) { *seekbufs = new_seekbufs; if((sndseekEx(dz->ifd[0],(*seekbufs) * dz->buflen,0))<0) { sprintf(errstr,"seek error in do_seek_and_read()\n"); return(SYSTEM_ERROR); } if((exit_status = read_samps(dz->sampbuf[0],dz))<0) return(exit_status); *seeksamps = *seekbufs * dz->buflen; } return(FINISHED); } /**************************** OUTPUT_UP_HALFSPLICE ****************************/ int output_up_halfsplice(int *ibufpos,int *obufpos,int chans,int splicelen,int *crosbuf,dataptr dz) { int exit_status; int n, remain; int m; float *b = dz->sampbuf[0]; float *obuf = dz->sampbuf[2]; int i = *ibufpos; int j = *obufpos; double *splicetab = dz->parray[GR_SPLICETAB]; int true_halfsplice = dz->iparam[GR_SPLICELEN]/2; if((remain = true_halfsplice - splicelen)<0) { sprintf(errstr,"Invalid splicelen in output_up_halfsplice()\n"); return(PROGRAM_ERROR); } else if(remain==0) { for(n=0;n= dz->buflen) { if((exit_status = write_samps(obuf,dz->buflen,dz))<0) return(exit_status); j = 0; } } for(n=0;nsampbuf[0]; float *obuf = dz->sampbuf[2]; int i = *ibufpos; int j = *obufpos; double *splicetab = dz->parray[GR_SPLICETAB]; int true_halfsplice = dz->iparam[GR_SPLICELEN]/2; if((remain = true_halfsplice - splicelen)<0) { sprintf(errstr,"Invalid splicelen in output_dn_halfsplice()\n"); return(PROGRAM_ERROR); } else if(remain==0) { for(n=splicelen-1,k=0;n>=0;n--,k++) { for(m=0;m=0;n--,k++) { for(m=0;m= dz->buflen) { if((exit_status = write_samps(obuf,dz->buflen,dz))<0) return(exit_status); j = 0; } } } *ibufpos = i; *obufpos = j; return(FINISHED); } /**************************** DO_IN_SITU_HALFSPLICE_ON_STORED_GRAIN ****************************/ int do_in_situ_halfsplice_on_stored_grain(int bufpos,int chans,int splicelen,int grainstorelen,dataptr dz) { int n, k, remain; int m; float *obuf = dz->extrabuf[2]; double *splicetab = dz->parray[GR_SPLICETAB]; int true_halfsplice = dz->iparam[GR_SPLICELEN]/2; int abs_halfsplice = true_halfsplice * chans; if(bufpos + abs_halfsplice > grainstorelen) { sprintf(errstr,"Grainstore buffer overflow: do_in_situ_halfsplice_on_stored_grain()\n"); return(PROGRAM_ERROR); } if((remain = true_halfsplice - splicelen)<0) { sprintf(errstr,"Invalid splicelen in do_in_situ_halfsplice_on_stored_grain()\n"); return(PROGRAM_ERROR); } else if(remain==0) { for(n=splicelen-1,k=0;n>=0;n--,k++) { for(m=0;m=0;n--,k++) { for(m=0;m= dz->buflen) { if((exit_status = write_samps(obuf,dz->buflen,dz))<0) return(exit_status); *obufpos = 0; } if(*ibufpos >= dz->ssampsread && n < maxlen) { if(*crosbuf) { sprintf(errstr,"double crosbuf: test_buffer_overflows()\n"); return(PROGRAM_ERROR); } if((exit_status = read_samps(dz->sampbuf[0],dz))<0) return(exit_status); *crosbuf = TRUE; *ibufpos = 0; } return(FINISHED); } /**************************** COPY_MIDGRAIN_TO_OUTPUT ***************************/ int copy_midgrain_to_output(int mid_grainlen,int *ibufpos,int *obufpos,int *crosbuf,int chans,dataptr dz) { int exit_status; int n; int m; float *b = dz->sampbuf[0], *obuf = dz->sampbuf[2]; int i = *ibufpos; int j = *obufpos; mid_grainlen /= chans; for(n=0; n dz->iparam[GR_ARRAYSIZE]) { if((dz->lparray[GR_ABS_POS] = (int *)realloc(dz->lparray[GR_ABS_POS],(graincnt+1) * sizeof(int)))==NULL) { sprintf(errstr,"INSUFFICIENT MEMORY to enlarge positions store.\n"); return(MEMORY_ERROR); } } dz->lparray[GR_ABS_POS][graincnt] = dz->insams[0]; return(FINISHED); } /**************************** ADJUST_FOR_LAST_GRAIN ***************************/ void adjust_for_last_grain(int *graincnt,int *grainpos,dataptr dz) { int lastgap; if(dz->vflag[LOSE_LAST_GRAIN]) /* get rid of last grain if flagged */ (*graincnt)--; else if((lastgap = grainpos[*graincnt] - grainpos[(*graincnt)-1]) < dz->iparam[GR_ABS_SPLICELEN]) { fprintf(stdout,"WARNING: Loosing last grain: too short.\n"); fflush(stdout); (*graincnt)--; } else if(lastgap > dz->buflen) { /* truncate last grain if too int */ fprintf(stdout,"WARNING: Last grain truncated: too int.\n"); fflush(stdout); grainpos[*graincnt] = grainpos[(*graincnt)-1] + dz->buflen; } } /**************************** CLEAR_OUTBUF ***************************/ int clear_outbuf(dataptr dz) { memset((char *)dz->sampbuf[2],0,dz->buflen * sizeof(float)); return(FINISHED); } /**************************** OUTPUT_WHOLE_GRAIN ***************************/ int output_whole_grain(int n,int *obufpos,int *seeksamps,int *seekbufs, int halfsplice,int abs_splicelen,int chans,dataptr dz) { int exit_status; int crosbuf = FALSE; int ibufpos; int mid_grainlen; int startsplice; int endsplice; startsplice = endsplice = halfsplice; if((ibufpos = dz->lparray[GR_ABS_POS][n] - *seeksamps)<0) { /* IF current grain NOT in current buffer */ if(*seeksamps==0) { /* IF at start of file */ if((exit_status = adjust_firstgrain_upsplice(&ibufpos,&startsplice,n,chans))<0) return(exit_status); } else { /* ELSE: change current buffer */ if((exit_status = do_seek_and_read(seekbufs,seeksamps,n,dz))<0) return(exit_status); ibufpos = dz->lparray[GR_ABS_POS][n] - *seeksamps; } } if((exit_status = output_up_halfsplice(&ibufpos,obufpos,chans,startsplice,&crosbuf,dz))<0) return(exit_status); mid_grainlen = (dz->lparray[GR_ABS_POS][n+1] - dz->lparray[GR_ABS_POS][n]) - abs_splicelen; if(crosbuf) { (*seekbufs)++; (*seeksamps) += dz->buflen; } crosbuf = FALSE; if(mid_grainlen > 0) { if((exit_status = copy_midgrain_to_output(mid_grainlen,&ibufpos,obufpos,&crosbuf,chans,dz))<0) return(exit_status); if(crosbuf) { (*seekbufs)++; (*seeksamps) += dz->buflen; } } crosbuf = FALSE; if((exit_status = output_dn_halfsplice(&ibufpos,obufpos,chans,endsplice,&crosbuf,dz))<0) return(exit_status); if(crosbuf) { (*seekbufs)++; (*seeksamps) += dz->buflen; } return(FINISHED); } /**************************** ADJUST_FIRSTGRAIN_UPSPLICE ***************************/ int adjust_firstgrain_upsplice(int *ibufpos,int *startsplice,int n,int chans) { if(n!=0) { /* MUST be 1st grain */ sprintf(errstr,"Grain accounting error: adjust_firstgrain_upsplice()\n"); return(PROGRAM_ERROR); } *startsplice += *ibufpos/chans; /* shorten startsplice by deficit of [stereo] samples */ *ibufpos = 0; /* reset output read to start of file */ return(FINISHED); } /************************* DO_GRAIN_REPITCHING *************************/ /* RWD 4:2002 : NB modified to allow n-channels */ int do_grain_repitching(int *actual_grainlen,int bufno,int grainstart,int new_grainlen,int orig_grainlen, int chans,int crosbuf,double pichratio,dataptr dz) { int exit_status; int m; int k = 0, here, thishere; double dpoint = 0.0, frac; //TW CHANGED // float /*thisval[2],*/ nextval[2], diff[2]; float /*thisval[2],*/ nextval, diff; float *b, *b2, *grainbuf = dz->extrabuf[2]; float *thisval; thisval = (float *) malloc(chans * sizeof(float)); if(thisval==NULL) { sprintf(errstr,"INSUFFICIENT MEMORY to enlarge positions store.\n"); return MEMORY_ERROR; } if(crosbuf) b = dz->sampbuf[!bufno]; else b = dz->sampbuf[bufno]; orig_grainlen /= chans; while(k < new_grainlen) { here = (int)dpoint; /* truncate */ frac = dpoint - (double)here; thishere = (here*chans); thishere += grainstart; if((exit_status = test_for_bufcros(&thishere,&b,bufno,crosbuf,dz))<0) { free(thisval); return(exit_status); } if(exit_status == TRUE) /* changed buffer */ grainstart -= dz->buflen; for(m=0;m orig_grainlen) break; } *actual_grainlen = k; free(thisval); return(FINISHED); } /************************* TEST_FOR_BUFCROS *************************/ int test_for_bufcros(int *thishere,float **b,int bufno,int crosbuf,dataptr dz) { if(*thishere >= dz->buflen) { if(crosbuf==FALSE) { sprintf(errstr,"Buffer accounting problem: test_for_bufcros()\n"); return(PROGRAM_ERROR); } *b = dz->sampbuf[bufno]; *thishere -= dz->buflen; return(TRUE); } return(FALSE); } /************************* SAVE_NEXTGRAIN_UPSPLICE_ELSEWHERE *************************/ int save_nextgrain_upsplice_elsewhere (int ibufpos,int bufno,int abs_halfsplice,int halfsplice,int chans,dataptr dz) { int splicestart_bufno = bufno; int start_splice = ibufpos - abs_halfsplice; if(start_splice < 0) { splicestart_bufno = !bufno; start_splice += dz->buflen; } return store_up_halfsplice(0,start_splice,splicestart_bufno,chans,halfsplice,dz); } /************************* COPYGRAIN_FROM_GRAINBUF_TO_OUTBUF *************************/ int copygrain_from_grainbuf_to_outbuf(int *obufpos,int grainlen,dataptr dz) { int exit_status; int remain = dz->buflen - *obufpos; float *there = dz->sampbuf[2] + *obufpos; float *here = dz->extrabuf[2]; while(grainlen >= remain) { memmove((char *)there,(char *)here,remain * sizeof(float)); if((exit_status = write_samps(dz->sampbuf[2],dz->buflen,dz))<0) return(exit_status); *obufpos = 0; there = dz->sampbuf[2]; here += remain; grainlen -= remain; remain = dz->buflen; } if(grainlen) { memmove((char *)there,(char *)here,grainlen * sizeof(float)); *obufpos += grainlen; } return(FINISHED); } /************************* RETRIEVE_UPSPLICE_FOR_NEXTGRAIN *************************/ int retrieve_upsplice_for_nextgrain(int abs_halfsplice,dataptr dz) { memmove((char *)dz->extrabuf[1],(char *)dz->extrabuf[0],abs_halfsplice * sizeof(float)); return(FINISHED); } /************************* RETIME_MAIN_BODY_OF_GRAIN *************************/ //TW REVISED int retime_main_body_of_grain(int grainstart,int bufno,double pichratio, double timeratio,int chans,int crosbuf,int *grainadjusted, int orig_grainlen,int *new_grainlen,dataptr dz) { int exit_status; int abs_splicelen = dz->iparam[GR_ABS_SPLICELEN]; int abs_halfsplice = abs_splicelen/2; /* guaranteed to fall on stereo boundary */ int halfsplice = dz->iparam[GR_SPLICELEN]/2; *new_grainlen = round((double)(orig_grainlen/chans) * timeratio) * chans; if(*new_grainlen < dz->iparam[GR_ABS_SPLICEX2]) { *new_grainlen = dz->iparam[GR_ABS_SPLICEX2]; (*grainadjusted)++; } *new_grainlen -= abs_halfsplice; orig_grainlen -= abs_halfsplice; if((exit_status = repitch_main_body_of_grain(bufno,grainstart,*new_grainlen,orig_grainlen, pichratio,chans,crosbuf,halfsplice,abs_halfsplice,dz))<0) return(exit_status); return(FINISHED); } /************************* REPITCH_MAIN_BODY_OF_GRAIN *************************/ int repitch_main_body_of_grain(int bufno,int grainstart,int new_grainlen,int orig_grainlen, double pichratio,int chans,int crosbuf,int halfsplice,int abs_halfsplice,dataptr dz) { int exit_status; int actual_grainlen; int splicelen; int splicestart; float *grainbuf; if(new_grainlen > dz->iparam[GR_STORESIZE]) { if((dz->extrabuf[2] = (float *)realloc(dz->extrabuf[2],new_grainlen * sizeof(float)))==NULL) { sprintf(errstr,"INSUFFICIENT MEMORY to enlarge grain store.\n"); return(MEMORY_ERROR); } dz->iparam[GR_STORESIZE] = (int)new_grainlen; } grainbuf = dz->extrabuf[2]; memset((char *)grainbuf,0,new_grainlen * sizeof(float)); if((exit_status = do_grain_repitching (&actual_grainlen,bufno,grainstart,new_grainlen,orig_grainlen,chans,crosbuf,pichratio,dz))<0) return(exit_status); splicelen = halfsplice; splicestart = actual_grainlen - abs_halfsplice; if(splicestart < 0) { splicelen += splicestart/chans; splicestart = 0; } return do_in_situ_halfsplice_on_stored_grain(splicestart,chans,splicelen,new_grainlen,dz); } /************************* CREATE_REPITCHED_AND_RETIMED_GRAIN *************************/ //TW REVISED int create_repitched_and_retimed_grain (int bufno,int grainstart,int orig_grainlen,int *new_grainlen, double pichratio,double timeratio,int *obufpos,int *is_first_grain, int *grainadjusted,int abs_halfsplice,int chans,int crosbuf,dataptr dz) { int exit_status; if((exit_status = retime_main_body_of_grain(grainstart,bufno,pichratio,timeratio, chans,crosbuf,grainadjusted,orig_grainlen,new_grainlen,dz))<0) return(exit_status); if(!(*is_first_grain)) { if((exit_status = read_up_halfsplice(obufpos,abs_halfsplice,dz))<0) return(exit_status); } *is_first_grain = FALSE; return copygrain_from_grainbuf_to_outbuf(obufpos,*new_grainlen,dz); } /************************* SAVE_ORIGGRAIN_LENGTH_AND_STORE_NEXTGRAINS_UPSPLICE *************************/ int save_origgrain_length_and_store_nextgrains_upsplice(int *orig_grainlen,int ibufpos,int bufno, int grainstart,int abs_halfsplice,int halfsplice,int crosbuf,int chans,int is_last_grain,dataptr dz) { *orig_grainlen = ibufpos - grainstart; if(crosbuf) *orig_grainlen += dz->buflen; if((*orig_grainlen - abs_halfsplice)<0) { if(!is_last_grain) { sprintf(errstr,"Anomalous too short grain: save_origgrain_length_and_store_nextgrains_upsplice()\n"); return(PROGRAM_ERROR); } else { fprintf(stdout,"WARNING: Last grain omitted: too short.\n"); return(CONTINUE); } } return save_nextgrain_upsplice_elsewhere(ibufpos,bufno,abs_halfsplice,halfsplice,chans,dz); } /************************* REPITCHING_PROCESS *************************/ int repitching_process(int ibufpos,int bufno,int grainstart,int abs_halfsplice,int halfsplice,int *graincnt, int *obufpos,int *orig_grainlen,int *new_grainlen,int *grainadjusted, int *is_first_grain,int is_last_grain,int chans,int crosbuf,dataptr dz) { int exit_status; double timeratio = 1.0, pichratio; int n; if(*is_first_grain && (exit_status = create_an_upsplice_from_pregrain_material(*obufpos,chans,dz))<0) return(exit_status); if((exit_status = save_origgrain_length_and_store_nextgrains_upsplice (orig_grainlen,ibufpos,bufno,grainstart,abs_halfsplice,halfsplice,crosbuf,chans,is_last_grain,dz))<0) return(exit_status); if(exit_status==CONTINUE) /* last grain too short */ return(FINISHED); switch(dz->mode) { case(GR_REPEATS): for(n=0;niparam[GR_RATIOCNT];n++) { pichratio = dz->parray[GR_RATIO][n]; if((exit_status = create_repitched_and_retimed_grain (bufno,grainstart,*orig_grainlen,new_grainlen,pichratio,timeratio,obufpos, is_first_grain,grainadjusted,abs_halfsplice,chans,crosbuf,dz))<0) return(exit_status); } break; case(GR_NO_REPEATS): pichratio = dz->parray[GR_RATIO][*graincnt]; if((exit_status = create_repitched_and_retimed_grain (bufno,grainstart,*orig_grainlen,new_grainlen,pichratio,timeratio,obufpos, is_first_grain,grainadjusted,abs_halfsplice,chans,crosbuf,dz))<0) return(exit_status); if(++(*graincnt)>=dz->iparam[GR_RATIOCNT]) *graincnt = 0; break; default: sprintf(errstr,"Unknown case: repitching_process()\n"); return(PROGRAM_ERROR); } return(FINISHED); } /************************* REPITCHING_AND_RETIMING_PROCESS *************************/ int repitching_and_retiming_process(int ibufpos,int bufno,int grainstart,int abs_halfsplice, int halfsplice,int *graincnt,int *obufpos,int *orig_grainlen,int *new_grainlen,int *grainadjusted, int *is_first_grain,int is_last_grain,int chans,int crosbuf,dataptr dz) { int exit_status; double timeratio, pichratio; int n; if(*is_first_grain && (exit_status = create_an_upsplice_from_pregrain_material(*obufpos,chans,dz))<0) return(exit_status); if((exit_status = save_origgrain_length_and_store_nextgrains_upsplice (orig_grainlen,ibufpos,bufno,grainstart,abs_halfsplice,halfsplice,crosbuf,chans,is_last_grain,dz))<0) return(exit_status); if(exit_status==CONTINUE) /* last grain too short */ return(FINISHED); switch(dz->mode) { case(GR_REPEATS): for(n=0;niparam[GR_RATIOCNT];n+=2) { pichratio = dz->parray[GR_RATIO][n]; timeratio = dz->parray[GR_RATIO][n+1]; if((exit_status = create_repitched_and_retimed_grain (bufno,grainstart,*orig_grainlen,new_grainlen,pichratio,timeratio,obufpos, is_first_grain,grainadjusted,abs_halfsplice,chans,crosbuf,dz))<0) return(exit_status); } break; case(GR_NO_REPEATS): pichratio = dz->parray[GR_RATIO][(*graincnt)++]; timeratio = dz->parray[GR_RATIO][(*graincnt)++]; if((exit_status = create_repitched_and_retimed_grain (bufno,grainstart,*orig_grainlen,new_grainlen,pichratio,timeratio,obufpos, is_first_grain,grainadjusted,abs_halfsplice,chans,crosbuf,dz))<0) return(exit_status); if(*graincnt >= dz->iparam[GR_RATIOCNT]) *graincnt = 0; break; default: sprintf(errstr,"Unknown case: repitching_and_retiming_process()\n"); return(PROGRAM_ERROR); } return(FINISHED); } /****************************** TIMESTRETCH_ITERATIVE ****************************/ int timestretch_iterative(dataptr dz) { int exit_status, do_slow = 0, do_regu; float *ibuf = dz->sampbuf[0]; float *obuf = dz->sampbuf[1]; // double *peak = dz->parray[0]; int *pos = dz->lparray[0]; int peakcnt, startsearch, endsearch, local_minima_cnt, minimum_element_len; int stretchable_len, required_segsection_len, total_segsection_length; int element_cnt, max_elements_needed; int arrsiz, fullperms, patternsize; int *pattern; int finished; int n, k=0, outpos, startseg, startpos, endpos, seglen; int abspos, new_abspos; int ascatter = 0, pscatter = 0, jitter = 0; double gain = 1.0, trans = 1.0, d, part, time, diff; float val, nextval; double z = (dz->param[RRR_END] - dz->param[RRR_START]) * dz->param[RRR_REPET]; double starttime_of_iter, davg_step; int total_slolen, total_slo_incr, slo_incr, min_step, j, avg_step, gap, maxsamp = 0; int *seg_step = NULL, *seg_len = NULL; int thiselementcnt, regusegscnt, okcnt, *seg_ok = NULL; if(dz->vflag[0] == 0) z += dz->param[RRR_START]; if(dz->vflag[1] == 0) z += dz->duration - dz->param[RRR_END]; //2010 dz->tempsize = (int)round(z * dz->infile->srate) * dz->infile->channels; fprintf(stdout,"INFO: Generating output.\n"); fflush(stdout); if(sloom) display_virtual_time(0,dz); if(dz->brksize[RRR_ASCAT] || !flteq(dz->param[RRR_ASCAT],0.0)) { ascatter = 1; jitter = 1; } if(dz->brksize[RRR_PSCAT] || !flteq(dz->param[RRR_PSCAT],0.0)) { pscatter = 1; jitter = 1; } if((exit_status = read_samps(dz->sampbuf[0],dz))<0) return(exit_status); dz->sampbuf[0][dz->insams[0]] = dz->sampbuf[0][dz->insams[0] - 1]; /* wrap around point for interpolation */ startsearch = (int)round(dz->param[RRR_START] * dz->infile->srate); endsearch = (int)round(dz->param[RRR_END] * dz->infile->srate); /* FIND ALL POSITIVE PEAKS : always look only at +ve vals, so all zero-crossings eventually found will be from +ve to -ve */ peakcnt = 0; if((exit_status = find_all_positive_peaks(startsearch,endsearch,&peakcnt,dz)) < 0) return(exit_status); /* FIND ALL POSITIVE-PEAK MINIMA : overwriting the arrays peak-vals & peak-position with minima-vals & minima-positions */ local_minima_cnt = 0; if((exit_status = find_all_local_minima(peakcnt,&local_minima_cnt,dz)) < 0) return(exit_status); /* ELIMINATE SPURIOUS MINIMA */ if((exit_status = eliminate_spurious_minima(&local_minima_cnt,&minimum_element_len,dz)) < 0) return (exit_status); fprintf(stdout,"INFO: Original number of segments found = %d\n",local_minima_cnt - 1); fflush(stdout); /* CHECK MINIMA FOUND AGAINST INPUT ESTIMATE */ if((local_minima_cnt - 1) >= 2 * dz->iparam[RRR_GET]) { if((exit_status = eliminate_excess_minima(&local_minima_cnt,pos,dz)) < 0) return (exit_status); fprintf(stdout,"INFO: Reduced to = %d\n",local_minima_cnt - 1); fflush(stdout); } /* SEARCH FOR ZERO CROSSINGS AFTER MINIMA */ if((exit_status = locate_zero_crossings(local_minima_cnt,dz)) < 0) return (exit_status); /* CALCULATE HOW int STRETCHED SECTION SHOULD BE */ stretchable_len = pos[local_minima_cnt-1] - pos[0]; required_segsection_len = (int)round((double)stretchable_len * dz->param[RRR_STRETCH]); /* CALCULATE HOW MANY ELEMENTS TO USE */ element_cnt = local_minima_cnt - 1; max_elements_needed = (int)round(ceil((double)required_segsection_len/(double)minimum_element_len)); max_elements_needed *= 2; /* required no of elements is set to a value greater than possibly required */ /* CALCULATE HOW MANY PERMUTATIONS NEEDED */ arrsiz = element_cnt * dz->iparam[RRR_REPET]; /* if elements can be repeated N times, perm-array can contain N copies of values */ fullperms = max_elements_needed / arrsiz; if(fullperms * arrsiz < max_elements_needed) /* total number of permutations to generate must include any part permutation */ fullperms++; patternsize = fullperms * arrsiz; if((pattern = (int *)malloc(patternsize * sizeof(int)))==NULL) { sprintf(errstr,"Insufficient memory to generate segment permutation.\n"); return(MEMORY_ERROR); } /* GENERATE RANDOM PATTERN */ if((exit_status = rand_ints_with_restricted_repeats(element_cnt,max_elements_needed,arrsiz,fullperms,&pattern,dz)) < 0) return(exit_status); if(dz->brksize[RRR_SLOW]) { maxsamp = (int)round(dz->maxtime * (double)dz->infile->srate); if((seg_step = (int *)malloc(element_cnt * sizeof(int)))==NULL) { sprintf(errstr,"Insufficient memory to store steps between segment if slowed.\n"); return(MEMORY_ERROR); } if(dz->brksize[RRR_REGU]) { if((seg_len = (int *)malloc(element_cnt * sizeof(int)))==NULL) { sprintf(errstr,"Insufficient memory to store orig segment lengths, if slowed.\n"); return(MEMORY_ERROR); } if((seg_ok = (int *)malloc(element_cnt * sizeof(int)))==NULL) { sprintf(errstr,"Insufficient memory to store segment flags, if regularised.\n"); return(MEMORY_ERROR); } } } /* COPY SOUND START TO OUTBUF */ outpos = 0; if(dz->vflag[0] == 0) { memcpy((char *)obuf,(char *)ibuf,pos[0] * sizeof(float)); outpos = pos[0]; } /* GENERATE OUTPUT SEQUENCE OF ELEMENTS */ total_segsection_length = 0; finished = 0; time = 0.0; abspos = dz->total_samps_written + outpos; if(dz->brksize[RRR_SLOW]) maxsamp += abspos; starttime_of_iter = (double)abspos/(double)dz->infile->srate; do { for(n=0; n < patternsize; n++) { if(n % element_cnt == 0) { do_slow = 0; do_regu = 0; if(dz->brksize[RRR_SLOW]) { time = (double)abspos/(double)dz->infile->srate; time -= starttime_of_iter; if((exit_status = read_value_from_brktable(time,RRR_SLOW,dz))<0) return(exit_status); if(dz->brksize[RRR_REGU] > 0) { if((exit_status = read_value_from_brktable(time,RRR_REGU,dz))<0) return(exit_status); } } if(dz->param[RRR_SLOW] > 1.0) { // If segments are to be slowed (by intervening silence) do_slow = 1; while(do_slow) { thiselementcnt = min(element_cnt,patternsize-n); // SAFETY (should be whole number of element_cnts in patternsize) total_slolen = (int)round(stretchable_len * dz->param[RRR_SLOW]); // Sample duration of all segs, once slowed by intervening gaps total_slo_incr = total_slolen - stretchable_len; // Total added silence, in samples slo_incr = (int)round((double)total_slo_incr/(double)thiselementcnt); // Silence to be inserted after to each element if(slo_incr <= 0) { do_slow = 0; break; } // Regularisation of rhythm of output cannot be done until there is if(dz->param[RRR_REGU] > 0.0) { // maniupulable silence between segments, which only occues after SLOW applied do_regu = 1; while(do_regu) { total_slo_incr = slo_incr * thiselementcnt; // Total added silence, after accounting for rounding min_step = dz->insams[0] + 1; avg_step = 0; for(j = 0,k=n; j < thiselementcnt;j++,k++){ startseg = pattern[k]; startpos = pos[startseg]; endpos = pos[startseg+1]; seglen = endpos - startpos; seg_len[j] = seglen; // Find actual length of each segment seg_step[j] = seg_len[j] + slo_incr; // Find step between start of one seg & next (when intervening silence added) BEFORE REGULARISING seg_ok[j] = 1; // Mark as a valid segment to regularise min_step = min(min_step,seg_step[j]); // Find the minimim step avg_step += seg_step[j]; // Find the average step } regusegscnt = 0; okcnt = thiselementcnt; davg_step = (double)avg_step/(double)okcnt; // Once regularised, step between seg entries will be set to the average value for(j=0; j < thiselementcnt; j++) { // If length of a segment is > average, this can't be done if(seg_len[j] > davg_step) { // So mark any such segment as not valid for the averaging process seg_ok[j] = 0; avg_step -= seg_len[j]; // and remove it from the calculation of the average step okcnt--; davg_step = (double)avg_step/(double)okcnt; } else regusegscnt++; // Count all the averagable segments } if(regusegscnt < 2) // If less than 2 valid segs, no averaging can be done do_regu = 0; break; } if(do_regu) { avg_step = (int)round((double)avg_step/(double)regusegscnt); for(j=0; j < thiselementcnt; j++) { // For all valid segments if(seg_ok[j]) // (partially) adjust step between it and next to the average step seg_step[j] = ((int)round((avg_step - seg_step[j]) * dz->param[RRR_REGU])) + seg_step[j]; } } } break; } if(do_slow) { if(do_regu) { for(j=0; j < thiselementcnt; j++) // Find the gap left after each segment seg_step[j] -= seg_len[j]; } else { // If seg_entries NOT to be regularised for(j=0; j < thiselementcnt; j++) // Set silent gap between segs all to same val seg_step[j] = slo_incr; } } } } startseg = pattern[n]; startpos = pos[startseg]; endpos = pos[startseg+1]; seglen = endpos - startpos; if(jitter) { time = (double)abspos/(double)dz->infile->srate; if((exit_status = read_values_from_all_existing_brktables(time,dz))<0) return(exit_status); k = startpos; d = (double)startpos; part = 0.0; if(ascatter) { /* generate random value for seg gain, within given range */ gain = drand48() * dz->param[RRR_ASCAT]; gain = 1.0 - gain; } if(pscatter) { trans = (drand48() * 2.0) - 1.0; if(trans >= 0.0) /* randomly chose up or down transposition */ trans = 1.0; else trans = -1.0; /* generate random semitone step within given range */ trans *= (drand48() * dz->param[RRR_PSCAT]); trans /= 12; /* convert to transposition ratio = step in sample-reading */ trans = pow(2.0,trans); } while(k < endpos) { val = ibuf[k]; nextval = ibuf[k+1]; diff = nextval - val; z = val + (diff * part); z *= gain; d += trans; k = (int)d; /* TRUNCATE */ part = d - (double)k; obuf[outpos] = (float)z; if(++outpos >= dz->buflen) { if((exit_status = write_samps(obuf,dz->buflen,dz))<0) return(exit_status); outpos = 0; } } } else { for(k = startpos; k < endpos; k++) { obuf[outpos] = ibuf[k]; if(++outpos >= dz->buflen) { if((exit_status = write_samps(obuf,dz->buflen,dz))<0) return(exit_status); outpos = 0; } } } new_abspos = dz->total_samps_written + outpos; if(do_slow) { k = n % element_cnt; gap = seg_step[k]; for(j=0;j= dz->buflen) { if((exit_status = write_samps(obuf,dz->buflen,dz))<0) return(exit_status); outpos = 0; } } new_abspos = dz->total_samps_written + outpos; } abspos = new_abspos; // If reach end of slowing curve, but still patterns left, exit pattern generation if(dz->brksize[RRR_SLOW] && abspos >= maxsamp) finished = 1; // If reach end of patterns if((total_segsection_length += seglen) >= required_segsection_len || (n == patternsize - 1)) { // Should be equivalent!! // If not at end of slowing pattern, generate more random perms, and restart loop (n = 0) if(dz->brksize[RRR_SLOW] && abspos < maxsamp) { if((exit_status = rand_ints_with_restricted_repeats(element_cnt,max_elements_needed,arrsiz,fullperms,&pattern,dz)) < 0) return(exit_status); } else finished = 1; } if(finished) break; } } while(!finished); if(!finished) { sprintf(errstr,"Insufficient segments generated at output stage.\n"); return(PROGRAM_ERROR); } /* COPY SOUND END TO OUTBUF */ if(dz->vflag[1] == 0) { for(n = pos[local_minima_cnt - 1]; n < dz->insams[0];n++) { obuf[outpos] = ibuf[n]; if(++outpos >= dz->buflen) { if((exit_status = write_samps(obuf,dz->buflen,dz))<0) return(exit_status); /*memset((char *)obuf,0,dz->bigbufsize);*/ memset(obuf,0,sizeof(float)* dz->buflen); /*RWD ?? */ outpos = 0; } } } if(outpos > 0) { if((exit_status = write_samps(obuf,outpos,dz))<0) return(exit_status); } return(FINISHED); } /****************************** RAND_INTS_WITH_RESTRICTED_REPEATS ****************************/ int rand_ints_with_restricted_repeats(int element_cnt,int max_elements_needed,int arrsiz,int fullperms,int **pattern,dataptr dz) { int n, m, i, k=0, j; int endcnt, endval, allowed, checkpart; int patterncnt = 0; int *arr, *arr2, *perm; if((arr = (int *)malloc(arrsiz * sizeof(int)))==NULL) { sprintf(errstr,"Insufficient memory for permutation array 1.\n"); return(MEMORY_ERROR); } if((perm = (int *)malloc(arrsiz * sizeof(int)))==NULL) { sprintf(errstr,"Insufficient memory for permutation array 2.\n"); return(MEMORY_ERROR); } if((arr2 = (int *)malloc(dz->iparam[RRR_REPET] * sizeof(int)))==NULL) { sprintf(errstr,"Insufficient memory for permutation array 3.\n"); return(MEMORY_ERROR); } n = 0; for(j=0;jiparam[RRR_REPET];j++) { /* fill array with REPET copies of values. */ for(i=0;iiparam[RRR_REPET]; /* number of permissible repetitions of this val at start of 1st perm */ checkpart = arrsiz - dz->iparam[RRR_REPET]; /* items at end of array to test for repetitions */ n = 0; while(n < fullperms) { do_repet_restricted_perm(arr,perm,arrsiz,allowed,endval); j = 0; for(m = 0;m = checkpart) /* save last checkable stretch of perm */ arr2[j++] = arr[perm[m]]; } if(n < fullperms -1) { j--; endval = arr2[j--]; /* note the val at end of perm */ endcnt = 1; /* and count it */ for(k = j; k>= 0; k--) { if(arr2[k] == endval) /* check adjacent vals, for repetition of value: count */ endcnt++; else /* if no more repetitions, finish counting */ break; } allowed = dz->iparam[RRR_REPET] - endcnt; /* get number of permissible repets at start of next perm */ } n++; } return FINISHED; } /****************************** DO_REPET_RESTRICTED_PERM ****************************/ void do_repet_restricted_perm(int *arr, int *perm, int arrsiz, int allowed, int endval) { int n, t; int checklen = allowed + 1; int done = 0; while(!done) { for(n=0;n k;n--) { *i = *(i-1); i--; } } /****************************** ELIMINATE_SPURIOUS_MINIMA ***********************************/ int eliminate_spurious_minima(int *local_minima_cnt,int *minimum_element_len,dataptr dz) { int exit_status; int *seg; int *segpos, badseg; int n, m, segcnt = (*local_minima_cnt) - 1, temp,eliminate_pos; double *peak = dz->parray[0]; int *pos = dz->lparray[0]; int maxseg, minseg, minsegstartpos; if((seg = (int *)malloc(segcnt * sizeof(int)))==NULL) { sprintf(errstr,"Insufficient memory (A) to check for spurious local minima\n"); return(MEMORY_ERROR); } if((segpos = (int *)malloc(segcnt * sizeof(int)))==NULL) { sprintf(errstr,"Insufficient memory (B) to check for spurious local minima\n"); return(MEMORY_ERROR); } for(;;) { /* RECURSIVELY ELIMINATE TOO-SHORT GAPS */ for(n = 0; n < segcnt; n++) seg[n] = pos[n+1] - pos[n]; for(n = 0; n < segcnt; n++) segpos[n] = n; for(n=0;n < segcnt-1; n++) { /* BUBBLE SORT THE GAPS BETWEEN LOCAL MINIMA TO DESCENDING SIZE ORDER */ for(m=n+1;m < segcnt; m++) { if(seg[n] < seg[m]) { temp = seg[n]; seg[n] = seg[m]; seg[m] = temp; temp = segpos[n]; /* AND KEEP TRACK OF WHERE THESE NEWLY ORDERED GAPS ARE */ segpos[n] = segpos[m]; segpos[m] = temp; } } } maxseg = seg[0]; minseg = seg[segcnt-1]; badseg = 0; /* Compare minimum seg with maximum seg */ if((double)minseg < (double)maxseg * dz->param[RRR_RANGE]) { badseg = 1; } if(!badseg) { /* No more anomalous segs found, exit loop */ *minimum_element_len = minseg; break; } if(segcnt-1 < 3) { sprintf(errstr,"Insufficient valid local minima found during elimination of spurious minima. Are the search times incorrect??\n"); return(DATA_ERROR); } minsegstartpos = segpos[segcnt-1]; /* Find positions of minimum seg start */ if((exit_status = which_minimum_to_eliminate(minsegstartpos,pos,maxseg,segcnt,&eliminate_pos,dz)) < 0) return(exit_status); for(n=eliminate_pos ; n < (*local_minima_cnt)-1;n++) { peak[n] = peak[n+1]; /* Eliminate unwanted val, by moving values in array above it down 1 position */ pos[n] = pos[n+1]; /* If BAD minimum is at current end of array, it just gets ignored as result of "local_minima_cnt--" */ } (*local_minima_cnt)--; /* Reduce count of minima, and count of segs between minima */ segcnt--; } return(FINISHED); } /****************************** FIND_ALL_POSITIVE_PEAKS ***********************************/ int find_all_positive_peaks(int startsearch,int endsearch,int *peakcnt,dataptr dz) { double *peak = dz->parray[0], thispeak; int *pos = dz->lparray[0]; float *ibuf = dz->sampbuf[0]; int thissamp = startsearch, thispos; while(ibuf[thissamp] <= 0) { /* skip values below zero */ if(++thissamp >= endsearch) break; } if(thissamp >= endsearch) { sprintf(errstr,"Cannot locate any peaks in the signal. Are the search times incorrect??\n"); return(DATA_ERROR); } thispeak = ibuf[thissamp]; thispos = thissamp; thissamp++; while(thissamp < endsearch) { if(ibuf[thissamp] >= 0.0) { if(ibuf[thissamp] > thispeak) { /* search for (positive) peak val */ thispeak = ibuf[thissamp]; thispos = thissamp; } } else { peak[*peakcnt] = thispeak; /* once signal becomes -ve3, store last found peak */ pos[*peakcnt] = thispos; (*peakcnt)++; while(ibuf[thissamp] < 0) { /* then skip over -ve part of signal */ if(++thissamp >= endsearch) break; } thispeak = ibuf[thissamp]; /* once dignal is +ve again, set up an initial value for peak */ thispos = thissamp; } thissamp++; } if(*peakcnt > 0) { /* check for peak found near end, before signal goes -ve once more */ if((thispos != pos[(*peakcnt)-1]) && (thispeak > 0.0)) { peak[*peakcnt] = thispeak; pos[*peakcnt] = thispos; (*peakcnt)++; } } if(*peakcnt < 3) { sprintf(errstr,"Insufficient signal peaks found. Are the search times incorrect??\n"); return(DATA_ERROR); } return(FINISHED); } /****************************** FIND_ALL_LOCAL_MINIMA ***********************************/ int find_all_local_minima(int peakcnt,int *local_minima_cnt,dataptr dz) { int thispeak; double *peak = dz->parray[0]; int *pos = dz->lparray[0]; /* double peakmin = peak[0];*/ int finished = 0; *local_minima_cnt = 0; thispeak = 1; while(thispeak < peakcnt) { while(peak[thispeak] <= peak[thispeak-1]) { /* while peaks are falling, look for local peak minimum */ if(++thispeak >= peakcnt) { finished = 1; break; } } if(finished) break; peak[*local_minima_cnt] = peak[thispeak-1]; /* store value and position of local mimimum */ pos[*local_minima_cnt] = pos[thispeak-1]; (*local_minima_cnt)++; while(peak[thispeak] >= peak[thispeak-1]) { /* skip over rising sequence of peaks */ if(++thispeak >= peakcnt) { break; } } } if(*local_minima_cnt < 3) { sprintf(errstr,"Insufficient local minima found in inital search. Are the search times incorrect??\n"); return(DATA_ERROR); } return(FINISHED); } /****************************** LOCATE_ZERO_CROSSINGS ***********************************/ int locate_zero_crossings(int local_minima_cnt,dataptr dz) { int finished = 0; int n; float *ibuf = dz->sampbuf[0]; double *peak = dz->parray[0]; int *pos = dz->lparray[0]; for(n=0;n= 0.0) { /* advance position from minimum +ve peak until value crosses zero */ if(++pos[n] >= dz->insams[0]) { finished = 1; if(peak[n] > 0.0) { /* if end of file does not go to zero, Warn */ fprintf(stdout,"WARNING: End_of_sound segment doesn't fall to zero level, & may cause clicks in output. (Dovetail end of sound?)\n"); fflush(stdout); } break; } peak[n] = ibuf[pos[n]]; } if(finished) break; } return(FINISHED); } /****************************** WHICH_MINIMUM_TO_ELIMINATE *********************************** * * Too short segment can be eliminated by deleting minimum at its start, or at its end. * Eliminating the minimum will make the preceding (or following) segment larger. * Deduce which of the two minima to delete. */ int which_minimum_to_eliminate(int minsegstartpos,int *pos,int maxseg,int segcnt,int *eliminate_pos,dataptr dz) { int newpreseg, newpostseg, later_seg, prior_seg; double ratio, ratio2, presegratio=0, postsegratio=0; if(minsegstartpos == 0) { /* if minseg is at start of sequence */ if(pos[2] - pos[0] > maxseg) /* losing end min of seg makes next seg bigger: if bigger than maxseg, eliminate start min instead */ *eliminate_pos = minsegstartpos; /* effectively erasing the first seg */ else /* else lose end min, making following seg larger */ *eliminate_pos = minsegstartpos + 1; } else if(minsegstartpos + 1 == segcnt) { /* if minseg is at end of sequence */ if(pos[minsegstartpos+1] - pos[minsegstartpos-1] > maxseg) *eliminate_pos = minsegstartpos + 1; /* if losing start min of seg makes prior seg > maxseg, eliminate end min instead */ else /* else element start min, making previous seg larger */ *eliminate_pos = minsegstartpos; /* ELSE we're not dealing with segs at ends of sequence */ } else { newpreseg = (pos[minsegstartpos+1] - pos[minsegstartpos-1]); /* Find length new seg created by eliminating start min of shortest seg */ newpostseg = (pos[minsegstartpos+2] - pos[minsegstartpos]); /* Find length new seg created by eliminating end min of shortest seg */ if(newpreseg > maxseg || newpostseg > maxseg) { /* if either new seg is > maxseg */ if(newpostseg <= maxseg) /* If ONLY preseg inter than maxseg, choose to make postseg, elim end min */ *eliminate_pos = minsegstartpos + 1; else if(newpreseg <= maxseg) /* If ONLY postseg > maxseg, choose to make postseg, elim start min */ *eliminate_pos = minsegstartpos; /* else if BOTH > maxseg, choose smaller */ else if(newpreseg > newpostseg) /* if new preseg is larger, keep postseg, eliminate end min */ *eliminate_pos = minsegstartpos + 1; else /* if new preseg is smaller, keep preseg, eliminate start min */ *eliminate_pos = minsegstartpos; } else { /* both preseg and postseg are less than maxseg, choose seg that tallies best with local seg environment */ if(segcnt <=3) { /* with only 3 segs, any deletion affects (increases sizeof) maxseg */ /* Thus newly created seg, wherever it is, will be > sizeof orig maxseg, and will have been dealt with above */ sprintf(errstr,"Programming error xxxx.\n"); return(PROGRAM_ERROR); } /* find the maximum size ratio between new newpreseg and its adjacent segs */ later_seg = pos[minsegstartpos+2] - pos[minsegstartpos+1]; ratio = (double)newpreseg/(double)later_seg; if(ratio < 1.0) ratio = 1.0/ratio; if(minsegstartpos - 2 > 0) { prior_seg = pos[minsegstartpos-1] - pos[minsegstartpos-2]; ratio2 = (double)newpreseg/(double)prior_seg; if(ratio2 < 1.0) ratio2 = 1.0/ratio2; ratio = max(ratio,ratio2); } presegratio = ratio; /* find the maximum size ratio between new newpostseg and its adjacent segs */ ratio = 0.0; prior_seg = pos[minsegstartpos] - pos[minsegstartpos-1]; ratio = (double)newpostseg/(double)prior_seg; if(ratio < 1.0) ratio = 1.0/ratio; if(minsegstartpos + 3 < segcnt) { later_seg = pos[minsegstartpos+3] - pos[minsegstartpos+2]; ratio2 = (double)newpostseg/(double)later_seg; if(ratio2 < 1.0) ratio2 = 1.0/ratio2; ratio = max(ratio,ratio2); } postsegratio = ratio; } if(postsegratio < presegratio) /* if newpostseg makes better sense, eliminate end min */ *eliminate_pos = minsegstartpos + 1; else /* else newporeseg makes better sense, elminate start min */ *eliminate_pos = minsegstartpos; } return FINISHED; } /****************************** ELIMINATE_EXCESS_MINIMA *********************************** * * If no of segments found is >> anticipated segments, Group segments together in 'best' arrangement. */ int eliminate_excess_minima(int *local_minima_cnt,int *pos,dataptr dz) { int n, m, j, bestgroup = 0; /* if found-segs is exact multiple of anticipated-segs, bestgrouping starts at position 0 */ int more_than_possible = dz->insams[0]; /* i.e. too large to be reached by calculation */ int segcnt = (*local_minima_cnt) - 1; /* Number of segs found e.g. 19 */ int grouping_cnt = segcnt/dz->iparam[RRR_GET]; /* How many segs to join-as-a-group, to make no of segs tally with anticipated value */ /* if get=4 19/4 --> 4 by integer truncation */ int remnant = (int)(segcnt - (grouping_cnt * dz->iparam[RRR_GET])); /* How many segments are then spare at start or end of sequence of segs */ /* e.g. 19 - 16 = 3 */ int diff, mindiff = more_than_possible; int grouped_len, max_grouped_len, min_grouped_len; for(n=0;niparam[RRR_SKIP]; /* Number of iterate units to skip before utilising any of them */ if(((envcnt = dz->insams[0]/dz->iparam[RRR_SAMP_WSIZENU]) * dz->iparam[RRR_SAMP_WSIZENU])!=dz->insams[0]) envcnt++; if((dz->env=(float *)malloc((envcnt+20) * sizeof(float)))==NULL) { sprintf(errstr,"INSUFFICIENT MEMORY for envelope array.\n"); return(MEMORY_ERROR); } if((exit_status = extract_rrr_env_from_sndfile(RRR_SAMP_WSIZENU,dz))<0) return(exit_status); if((trofpnt = (int *)malloc(envcnt * sizeof(int)))==NULL) { sprintf(errstr,"INSUFFICIENT MEMORY TO ANALYSE ENVELOPE.\n"); return(MEMORY_ERROR); } trofpnt[0] = 0; lastenval = dz->env[0]; n = 1; while(n < envcnt) { /* GET FIRST ENVELOPE TROUGH */ if(dz->env[n] > lastenval) { trofpnt[0] = 0; lastenval = dz->env[n]; n++; break; } else if (dz->env[n] < lastenval) { trofpnt[0] = n; lastenval = dz->env[n]; n++; break; } lastenval = dz->env[n]; n++; } if(n >= envcnt) { sprintf(errstr,"NO PEAKS FOUND IN ENVELOPE\n"); return(GOAL_FAILED); } while(n < envcnt) { /* GET ENVELOPE TROUGHS */ if(dz->env[n] > lastenval) { trofpntcnt = lasttrofpntcnt + 1; } else if (dz->env[n] < lastenval) { trofpnt[trofpntcnt] = n; lasttrofpntcnt = trofpntcnt; } lastenval = dz->env[n]; n++; } if(trofpntcnt < 2) { sprintf(errstr,"NO SIGNIFICANT PEAKS FOUND IN ENVELOPE\n"); return(GOAL_FAILED); } for(m = 0, n=1;n 2 && peakwidth < 6) { /* IF PEAK WIDTH IS WITHIN LIMITS FOR AN ITERATE-UNIT */ could_be_rrr_flap = 0; for(k = trofpnt[m]; k < trofpnt[n]; k++) { /* AND PEAK IS ABOVE GATE */ if(dz->env[k] > dz->param[RRR_GATE]) { could_be_rrr_flap = 1; break; } } if(could_be_rrr_flap) { if(rrr_cnt == 0) /* IF (skipped unwanted flaps &) NO FLAPS HERE YET */ rrr_start = m; /* MARK START OF A POSSIBLE FLAP */ rrr_cnt++; /* COUNT FLAPS */ } } else { could_be_rrr_flap = 0; /* MARK NON-FLAP */ } if (!could_be_rrr_flap) { if(rrr_cnt >= dz->iparam[RRR_GET]) { /* IF END OF FLAPS, AND WE HAVE ENOUGH ADJACENT FLAPS */ /* SET PARAMS FOR ZER-CROSSING SEARCH */ dz->iparam[RRR_START] = trofpnt[rrr_start] * dz->iparam[RRR_SAMP_WSIZENU]; dz->iparam[RRR_START] -= dz->iparam[RRR_SAMP_WSIZENU]/ 2; /* Start search before first flap segment */ dz->iparam[RRR_START] = max(0,dz->iparam[RRR_START]); dz->iparam[RRR_END] = trofpnt[m] * dz->iparam[RRR_SAMP_WSIZENU];; dz->iparam[RRR_END] += dz->iparam[RRR_SAMP_WSIZENU]/ 2; /* End search after last flap segment */ dz->iparam[RRR_END] = min(dz->insams[0],dz->iparam[RRR_END]); dz->param[RRR_START] = (double)dz->iparam[RRR_START]/dz->infile->srate; dz->param[RRR_END] = (double)dz->iparam[RRR_END]/dz->infile->srate; // dz->iparam[RRR_GET] = rrr_cnt; // EXPERIMENTAL!! FORCES zero-cross algo to get better result // if algo finds 8 zcs and there are really rrr_cnt=4, as 8 >= 2 * 4 , it groups the zcs in pairs to give 4 zcs // However, if algo finds 7 zcs and there are really rrr_cnt=4 // 7 < (2*4), so it doesn't group the zcs in twos, so 7 zcs are kept, probalby too many... // With this mod 7 > 2*(rrr_cnt-1 = 3) so it groups the number of zcs in 2s (and throws 1 away) to give 3 zcs: better result dz->iparam[RRR_GET] = rrr_cnt - 1; gotrrr = 1; break; } else { rrr_cnt = -dz->iparam[RRR_SKIP]; } } } if(gotrrr == 0) { sprintf(errstr,"NO ITERATIVE LOCATION FOUND\n"); return(GOAL_FAILED); } else { fprintf(stdout,"INFO: searching between %.04lf and %.04lf secs: where %d peaks found\n",dz->param[RRR_START],dz->param[RRR_END],rrr_cnt); fflush(stdout); } return timestretch_iterative(dz); } /************************* EXTRACT_RRR_ENV_FROM_SNDFILE *******************************/ int extract_rrr_env_from_sndfile(int paramno,dataptr dz) { int n; float *envptr; int bufcnt; if(((bufcnt = dz->insams[0]/dz->buflen)*dz->buflen)!=dz->insams[0]) bufcnt++; envptr = dz->env; for(n = 0; n < bufcnt; n++) { if((dz->ssampsread = fgetfbufEx(dz->sampbuf[0], dz->buflen,dz->ifd[0],0)) < 0) { sprintf(errstr,"Can't read samples from soundfile: extract_rrr_env_from_sndfile()\n"); return(SYSTEM_ERROR); } if(sloom) display_virtual_time(dz->total_samps_read,dz); get_rrrenv_of_buffer(dz->ssampsread,dz->iparam[paramno],&envptr,dz->sampbuf[0]); } dz->envend = envptr; return(FINISHED); } /************************* GET_RRRENV_OF_BUFFER *******************************/ void get_rrrenv_of_buffer(int samps_to_process,int envwindow_sampsize,float **envptr,float *buffer) { int start_samp = 0; float *env = *envptr; while(samps_to_process >= envwindow_sampsize) { *env++ = getmaxsampr(start_samp,envwindow_sampsize,buffer); start_samp += envwindow_sampsize; samps_to_process -= envwindow_sampsize; } if(samps_to_process) /* Handle any final short buffer */ *env++ = getmaxsampr(start_samp,samps_to_process,buffer); *envptr = env; } /*************************** GETMAXSAMPR ******************************/ float getmaxsampr(int startsamp, int sampcnt,float *buffer) { int i, endsamp = startsamp + sampcnt; float thisval, thismaxsamp = 0.0f; for(i = startsamp; ithismaxsamp) thismaxsamp = thisval; } return(thismaxsamp); } /********************************** GRAB_NOISE_AND_EXPAND ********************************** * * Locate noise, then expand it by random-reads from zero-cross to zero-cross */ int grab_noise_and_expand(dataptr dz) { int exit_status; float *ibuf = dz->sampbuf[0], *obuf = dz->sampbuf[1]; int phase, initialphase, isnoise = -1, finished = 0; int j, k, n, m, waveset_cnt; int lastzcross = 0, sampstart, sampend, len, temp, orig_buflen; int brkpntcnt = 0, got_noise = 0; double maxsamp, gate = dz->param[SSS_GATE]; int abovegate = 0; if((dz->lparray[0] = (int *)malloc(dz->insams[0] * sizeof(int)))==NULL) { sprintf(errstr,"INSUFFICIENT MEMORY.\n"); return(DATA_ERROR); } fprintf(stdout,"INFO: Searching for noise.\n"); fflush(stdout); orig_buflen = dz->buflen; dz->buflen = dz->insams[0]; if((exit_status = read_samps(ibuf,dz))<0) return(exit_status); else if(dz->ssampsread <= 0) { sprintf(errstr,"Failed to read sound from input file\n"); return(DATA_ERROR); } dz->buflen = orig_buflen; /* ESTABLISH INITIAL PHASE OF SIGNAL */ n = 0; while(ibuf[n]==0) { if(++n >= dz->ssampsread) { sprintf(errstr,"FAILED TO FIND ANY WAVECYCLES IN FILE.\n"); return(DATA_ERROR); } } if(ibuf[n] > 0) initialphase = 1; else initialphase = -1; for(;;) { /* FIND A WAVECYCLE */ maxsamp = 0.0; if(initialphase == 1) { while(ibuf[n] > 0) { maxsamp = max(maxsamp,ibuf[n]); if(++n >= dz->ssampsread) { finished = 1; break; } } while(ibuf[n] <= 0) { maxsamp = max(maxsamp,-ibuf[n]); if(++n >= dz->ssampsread) { finished = 1; break; } } } else { while(ibuf[n] < 0) { maxsamp = max(maxsamp,-ibuf[n]); if(++n >= dz->ssampsread) { finished = 1; break; } } while(ibuf[n] >= 0) { maxsamp = max(maxsamp,ibuf[n]); if(++n >= dz->ssampsread) { finished = 1; break; } } } if(finished) break; if(maxsamp < gate) isnoise = 0; else { abovegate = 1; dz->lparray[0][brkpntcnt] = n; /* MEASURE WAVE-CYCLE LENGTH, AND TEST FOR NOISE */ /* IF SIGNAL SWITCHES FROM NOISE to NOT-NOISE or vice versa, STORE THAT POSITION */ if(dz->lparray[0][brkpntcnt] - lastzcross < dz->iparam[NOISE_MINFRQ]) { if(brkpntcnt == 0) /* if noise-start pos, move to search for noise-end position */ brkpntcnt = 1; else if(dz->lparray[0][1] - dz->lparray[0][0] >= dz->iparam[MAX_NOISLEN]) { got_noise = 1; break; } isnoise = 1; } else { if(isnoise == 1) { /* if at end of noise ... */ /* if enough noise present ... break */ if(dz->lparray[0][1] - dz->lparray[0][0] > dz->iparam[MIN_NOISLEN]) { got_noise = 1; break; } else { /* if NOT ENOUGH noise present, delete noise pos data, start again */ dz->lparray[0][0] = dz->lparray[0][1]; brkpntcnt = 0; } } isnoise = 0; } } lastzcross = n; /* store position of last waveset end... */ } /* CHECK THAT ANY NOISE : non-NOISE SWITCHES FOUND */ if(!abovegate) { sprintf(errstr,"NO SIGNAL IS ABOVE THE GATE LEVEL\n"); return(GOAL_FAILED); } if(!got_noise) { if(gate > 0) sprintf(errstr,"NO NOISE FOUND WITH GATE-LEVEL %lf\n",gate); else sprintf(errstr,"NO NOISE FOUND\n"); return(GOAL_FAILED); } fprintf(stdout,"INFO: Generating output.\n"); fflush(stdout); sampstart = dz->lparray[0][0]; sampend = dz->lparray[0][1]; waveset_cnt = 0; if(ibuf[sampstart] > 0) { initialphase = 1; phase = 1; dz->lparray[0][waveset_cnt++] = sampstart; } else if (ibuf[sampstart] < 0) { initialphase = -1; phase = -1; dz->lparray[0][waveset_cnt++] = sampstart; } else phase = 0; /* STORE ZERO-CROSS-PAIR POSITIONS */ for(n = sampstart+1;n < sampend; n++) { switch(phase) { case(0): if(ibuf[n] > 0) { phase = 1; initialphase = 1; dz->lparray[0][waveset_cnt++] = n; } else if(ibuf[n] < 0) { phase = -1; initialphase = -1; dz->lparray[0][waveset_cnt++] = n; } break; case(1): if(ibuf[n] < 0) { if(initialphase == -1) dz->lparray[0][waveset_cnt++] = n; phase = -1; } break; case(-1): if(ibuf[n] > 0) { if(initialphase == 1) dz->lparray[0][waveset_cnt++] = n; phase = 1; } break; } } j = 0; if(!dz->vflag[0]) { for(n=0;n= dz->buflen) { if((exit_status = write_samps(obuf,dz->buflen,dz))<0) return(exit_status); j = 0; } } } for(;;) { n = (int)floor(drand48() * waveset_cnt); /* RANDOM READS TO AND FROM ZERO-CROSSINGS */ do { m = (int)floor(drand48() * waveset_cnt); } while (m == n); if((len = dz->lparray[0][m] - dz->lparray[0][n]) < 0) { temp = m; m = n; n = temp; len = -len; } if(j + len >= dz->iparam[SSS_DUR]) /* HALT AT A ZERO CROSSING */ break; for(k= dz->lparray[0][n]; k < dz->lparray[0][m];k++) { obuf[j++] = ibuf[k]; if(j >= dz->buflen) { if((exit_status = write_samps(obuf,dz->buflen,dz))<0) return(exit_status); dz->iparam[SSS_DUR] -= dz->buflen; j = 0; } } } if(!dz->vflag[0]) { for(n=sampend;ninsams[0];n++) { obuf[j++] = ibuf[n]; if(j >= dz->buflen) { if((exit_status = write_samps(obuf,dz->buflen,dz))<0) return(exit_status); j = 0; } } } if(j > 0) { if((exit_status = write_samps(obuf,j,dz))<0) return(exit_status); } return(FINISHED); } /************************** GREV **********************/ int grev(dataptr dz) { int exit_status, finished, start_negative; int n, j=0, k, minpeakloc, envcnt, last_total_samps_read, startsearch, endsearch, obufpos; int lastobufpos, step, expansion, lastgrainlen=0, nu_gp_dur; double maxsamp0, maxsamp1, peakav, minpeakav, time; int firsttrof, up, gotmaxsamp0, crossed_zero_to_positive, crossed_zero_to_negative, gp=0, read_brk = 0; float *e, *ibuf = dz->sampbuf[0], *obuf = dz->sampbuf[1]; int *pa; double convertor = 1.0 / dz->infile->srate; if(((envcnt = dz->insams[0]/dz->iparam[GREV_SAMP_WSIZE]) * dz->iparam[GREV_SAMP_WSIZE])!=dz->insams[0]) envcnt++; if((dz->env=(float *)malloc((envcnt + 12) * sizeof(float)))==NULL) { sprintf(errstr,"INSUFFICIENT MEMORY for envelope array.\n"); return(MEMORY_ERROR); } e = dz->env; if((pa =(int *)malloc((envcnt + 12) * sizeof(int)))==NULL) { sprintf(errstr,"INSUFFICIENT MEMORY for peak positions array.\n"); return(MEMORY_ERROR); } if((exit_status = extract_rrr_env_from_sndfile(GREV_SAMP_WSIZE,dz))<0) /* Get envel of whole sound */ return(exit_status); dz->total_samps_read = 0; display_virtual_time(0,dz); envcnt = dz->envend - dz->env; n = 0; k = 0; pa[k++] = 0; while(flteq(e[n],e[0])) { n++; if(n >= envcnt) { sprintf(errstr,"NO PEAKS IN THE FILE\n"); return(GOAL_FAILED); } } if(e[n] < e[0]) { firsttrof = 1; up = -1; } else { firsttrof = 0; up = 1; } /* KEEP ONLY THE PEAKS AND TROUGHS OF THE ENVELOPE, AND THEIR LOCATIONS */ while (n env[k] = dz->env[n-1]; pa[k] = (n-1) * dz->iparam[GREV_SAMP_WSIZE]; k++; up = -1; } break; case(-1): if(e[n] > e[n-1]) { dz->env[k] = dz->env[n-1]; pa[k] = (n-1) * dz->iparam[GREV_SAMP_WSIZE]; k++; up = 1; } break; } n++; } if((envcnt = k) <= 3) { sprintf(errstr,"INSUFFICIENT PEAKS IN THE FILE.\n"); return(GOAL_FAILED); } /* KEEP ONLY THE (DEEP ENOUGH) TROUGHS OF THE ENVELOPE */ switch(firsttrof) { case(0): /* if trof at start */ k = 1; /* set item at 0 NOT to be overwritten (as it is first trof) (set k=1) */ j = 1; /* search for good trofs between peaks, from (j=)1 */ break; case(1): /* if trof not at start */ k = 0; /* set item at 0 to be overwritten by 1st trof found (k=0) */ j = 0; /* search for good trofs between peaks, from (j=)0 */ break; } for(n=j;nenv[n] + dz->env[n+2]; if(peakav * dz->param[GREV_TROFRAC] >= dz->env[n+1]) { /* NB TROF_FAC alreday PRE-MULTIPLIED by 2.0 */ pa[k] = pa[n+1]; k++; } } if((envcnt = k) <= 3) { sprintf(errstr,"INSUFFICIENT VALID TROUGHS IN THE FILE.\n"); return(GOAL_FAILED); } /* SEARCH WAVEFORM FOR ZERO_CROSSING AT MORE ACCURATE TROUGH */ fprintf(stdout,"INFO: Number of grains found = %d\n",envcnt); fflush(stdout); if((sndseekEx(dz->ifd[0],0,0))<0) { sprintf(errstr,"seek error 1\n"); return(SYSTEM_ERROR); } last_total_samps_read = 0; k = (int)round((double)dz->iparam[GREV_SAMP_WSIZE] * 0.5); /* search around size of envel window */ startsearch = max(pa[0] - k, 0); endsearch = min(pa[0] + k,dz->insams[0]); dz->total_samps_read = 0; while(startsearch > dz->buflen) { dz->total_samps_read += dz->buflen; startsearch -= dz->buflen; } if(dz->total_samps_read > 0) { if((sndseekEx(dz->ifd[0],dz->total_samps_read,0))<0) { sprintf(errstr,"seek error 2\n"); return(SYSTEM_ERROR); } last_total_samps_read = dz->total_samps_read; endsearch -= last_total_samps_read; } if((exit_status = read_samps(ibuf,dz))<0) return(exit_status); n = 0; finished = 0; while(n= dz->ssampsread) { last_total_samps_read = dz->total_samps_read; endsearch -= dz->buflen; j -= dz->buflen; if((exit_status = read_samps(ibuf,dz))<0) return(exit_status); if(dz->ssampsread == 0) { finished = 1; break; } } if(!crossed_zero_to_negative) { /* before signal crosses to negative */ if(start_negative) { if(ibuf[j] <= 0.0) { j++; continue; } start_negative = 0; } if(!gotmaxsamp0) { /* First time only, look for first maxsamp */ if(ibuf[j] > maxsamp0) /* (after first time, it gets val passed back from 2nd maxsamp */ maxsamp0 = ibuf[j]; } if (ibuf[j] < 0.0) { /* if not crossed zero to -ve, look for, and mark, zero-cross to -ve */ crossed_zero_to_negative = j + last_total_samps_read; gotmaxsamp0 = 1; } } else if (ibuf[j] >= 0) { /* if crossed zero to neg and we're now crossing back to +ve */ crossed_zero_to_positive = 1; if(ibuf[j] > maxsamp1) /* look for 2nd maxsamp */ maxsamp1 = ibuf[j]; } else if (crossed_zero_to_positive) { /* having crossed from -ve to +ve, we're now -ve again, in a new cycle */ if((peakav = maxsamp0 + maxsamp1) < minpeakav) { minpeakav = peakav; minpeakloc = crossed_zero_to_negative; } maxsamp0 = maxsamp1; crossed_zero_to_positive = 0; crossed_zero_to_negative = 0; } j++; } while(j < endsearch || minpeakloc < 0); if(minpeakloc < 0) { if (finished) { /* deal with endcases where waveform fails to cross zero (twice) */ if(crossed_zero_to_negative > 0) pa[n++] = crossed_zero_to_negative; envcnt = n; break; } else { sprintf(errstr,"FAILED TO FIND ONE OF THE LOCAL MINIMA.\n"); return(PROGRAM_ERROR); } } pa[n] = minpeakloc; n++; startsearch = max(pa[n] - k, 0); endsearch = min(pa[n] + k,dz->insams[0]); if(startsearch >= dz->total_samps_read) { while(startsearch >= dz->total_samps_read) { last_total_samps_read = dz->total_samps_read; if((exit_status = read_samps(ibuf,dz))<0) return(exit_status); if(last_total_samps_read >= dz->total_samps_read) { envcnt = n; break; } } } startsearch -= last_total_samps_read; endsearch -= last_total_samps_read; while(startsearch < 0) { /* very tiny windows may cause backtracking in file */ last_total_samps_read -= dz->buflen; if((sndseekEx(dz->ifd[0],last_total_samps_read,0))<0) { sprintf(errstr,"seek error 3\n"); return(SYSTEM_ERROR); } if((exit_status = read_samps(ibuf,dz))<0) return(exit_status); dz->total_samps_read = last_total_samps_read + dz->ssampsread; startsearch += dz->buflen; endsearch += dz->buflen; } } if((sndseekEx(dz->ifd[0],0,0))<0) { sprintf(errstr,"seek error 4\n"); return(SYSTEM_ERROR); } dz->total_samps_read = 0; last_total_samps_read = 1; /* Value 1 forces first seek and read */ obufpos = 0; switch(dz->mode) { case(GREV_REVERSE): if(!dz->brksize[GREV_GPCNT]) gp = dz->iparam[GREV_GPCNT]; for(n = envcnt - (2 * gp); n>0; n-=gp) { startsearch = pa[n]; if(dz->brksize[GREV_GPCNT]) { time = (double)startsearch * convertor; if((exit_status = read_values_from_all_existing_brktables(time,dz))<0) return(exit_status); gp = (int)round(dz->param[GREV_GPCNT]); } endsearch = pa[n + gp]; if((exit_status = do_envgrain_write(startsearch,endsearch,&last_total_samps_read,&obufpos,dz))<0) return(exit_status); } break; case(GREV_REPEAT): if(!dz->brksize[GREV_GPCNT]) gp = dz->iparam[GREV_GPCNT]; if(dz->brksize[GREV_REPETS] || dz->brksize[GREV_GPCNT]) read_brk = 1; for(n = 0; n<=(envcnt-gp); n+=gp) { startsearch = pa[n]; if(read_brk) { time = (double)startsearch * convertor; if((exit_status = read_values_from_all_existing_brktables(time,dz))<0) return(exit_status); } if(dz->brksize[GREV_GPCNT]) gp = (int)round(dz->param[GREV_GPCNT]); if(dz->brksize[GREV_REPETS]) dz->iparam[GREV_REPETS] = (int)round(dz->param[GREV_REPETS]); endsearch = pa[n + gp]; for(k = 0;k < dz->iparam[GREV_REPETS];k++) { if((exit_status = do_envgrain_write(startsearch,endsearch,&last_total_samps_read,&obufpos,dz))<0) return(exit_status); } } break; case(GREV_DELETE): if(!dz->brksize[GREV_GPCNT]) gp = dz->iparam[GREV_GPCNT]; if(dz->brksize[GREV_KEEP] || dz->brksize[GREV_GPCNT]) read_brk = 1; for(n = 0; n<=(envcnt-gp); n+=gp) { startsearch = pa[n]; if(read_brk) { time = (double)startsearch * convertor; if((exit_status = read_values_from_all_existing_brktables(time,dz))<0) return(exit_status); } if(dz->brksize[GREV_GPCNT]) gp = (int)round(dz->param[GREV_GPCNT]); if(dz->brksize[GREV_KEEP]) dz->iparam[GREV_KEEP] = (int)round(dz->param[GREV_KEEP]); endsearch = pa[n + gp]; if((n % dz->iparam[GREV_OUTOF]) < dz->iparam[GREV_KEEP]) { if((exit_status = do_envgrain_write(startsearch,endsearch,&last_total_samps_read,&obufpos,dz))<0) return(exit_status); } } break; case(GREV_OMIT): if(!dz->brksize[GREV_GPCNT]) gp = dz->iparam[GREV_GPCNT]; if(dz->brksize[GREV_KEEP] || dz->brksize[GREV_GPCNT]) read_brk = 1; for(n = 0; n<=(envcnt-gp); n+=gp) { startsearch = pa[n]; if(read_brk) { time = (double)startsearch * convertor; if((exit_status = read_values_from_all_existing_brktables(time,dz))<0) return(exit_status); } if(dz->brksize[GREV_GPCNT]) gp = (int)round(dz->param[GREV_GPCNT]); if(dz->brksize[GREV_KEEP]) dz->iparam[GREV_KEEP] = (int)round(dz->param[GREV_KEEP]); endsearch = pa[n + gp]; if((n % dz->iparam[GREV_OUTOF]) < dz->iparam[GREV_KEEP]) { if((exit_status = do_envgrain_write(startsearch,endsearch,&last_total_samps_read,&obufpos,dz))<0) return(exit_status); } else { if((exit_status = do_envgrain_zerowrite(startsearch,endsearch,&obufpos,dz))<0) return(exit_status); } } break; case(GREV_TSTRETCH): if(!dz->brksize[GREV_GPCNT]) gp = dz->iparam[GREV_GPCNT]; if(dz->brksize[GREV_TSTR] || dz->brksize[GREV_GPCNT]) read_brk = 1; for(n = 0; n<=envcnt-1; n++) { startsearch = pa[n]; if(read_brk) { time = (double)startsearch * convertor; if((exit_status = read_values_from_all_existing_brktables(time,dz))<0) return(exit_status); } if(dz->brksize[GREV_GPCNT]) gp = (int)round(dz->param[GREV_GPCNT]); endsearch = pa[n + 1]; lastobufpos = obufpos + dz->total_samps_written; if((exit_status = do_envgrain_addwrite(startsearch,endsearch,&last_total_samps_read,&obufpos,dz))<0) return(exit_status); step = obufpos + dz->total_samps_written - lastobufpos; expansion = (int)round((double)step * dz->param[GREV_TSTR]) - step; if(expansion > 0) { if((exit_status = do_envgrain_zerowrite_dblbuf(0,expansion,&obufpos,dz))<0) return(exit_status); } else obufpos += expansion; } break; case(GREV_GET): if(!dz->brksize[GREV_GPCNT]) gp = dz->iparam[GREV_GPCNT]; else read_brk = 1; for(n = 0; n<=(envcnt-gp); n+=gp) { startsearch = pa[n]; if(read_brk) { time = (double)startsearch * convertor; if((exit_status = read_values_from_all_existing_brktables(time,dz))<0) return(exit_status); } if(dz->brksize[GREV_GPCNT]) gp = (int)round(dz->param[GREV_GPCNT]); fprintf(dz->fp,"%d\n",startsearch); } break; case(GREV_PUT): if(!dz->brksize[GREV_GPCNT]) gp = dz->iparam[GREV_GPCNT]; else read_brk = 1; for(n = 0; n<=(envcnt-gp); n+=gp) { startsearch = pa[n]; if(read_brk) { time = (double)startsearch * convertor; if((exit_status = read_values_from_all_existing_brktables(time,dz))<0) return(exit_status); } if(dz->brksize[GREV_GPCNT]) gp = (int)round(dz->param[GREV_GPCNT]); endsearch = pa[n + gp]; if(n > 0) { if(n >= dz->itemcnt) break; nu_gp_dur = (int)round(dz->parray[GR_SYNCTIME][n] - dz->parray[GR_SYNCTIME][n-1]); obufpos += (nu_gp_dur - lastgrainlen); if(obufpos <= -dz->buflen) { sprintf(errstr,"BACKTRACK TOO LARGE\n"); return(GOAL_FAILED); } } if((exit_status = do_envgrain_write(startsearch,endsearch,&last_total_samps_read,&obufpos,dz))<0) return(exit_status); lastgrainlen = endsearch - startsearch; } break; } if(obufpos > 0) { if((exit_status = write_samps(obuf,obufpos,dz))<0) return(exit_status); } return(FINISHED); } /************************** DO_ENVGRAIN_WRITE **********************/ int do_envgrain_write(int startsearch,int endsearch,int *last_total_samps_read,int *obufpos,dataptr dz) { int exit_status; int step, n, m, limit = dz->buflen; float *ibuf = dz->sampbuf[0], *obuf = dz->sampbuf[1]; if(startsearch > dz->total_samps_read || startsearch < *last_total_samps_read) { step = (startsearch / dz->buflen) * dz->buflen; if((sndseekEx(dz->ifd[0],step,0))<0) { sprintf(errstr,"seek error 5\n"); return(SYSTEM_ERROR); } *last_total_samps_read = step; if((exit_status = read_samps(ibuf,dz))<0) return(exit_status); dz->total_samps_read = *last_total_samps_read + dz->ssampsread; } startsearch -= *last_total_samps_read; endsearch -= *last_total_samps_read; m = *obufpos; if(dz->mode == GREV_PUT) { limit *= 2; while(m >= limit) { if((exit_status = write_samps(obuf,dz->buflen,dz))<0) return(exit_status); memcpy((char *)dz->sampbuf[1],(char *)dz->sampbuf[2],dz->buflen * sizeof(float)); memset((char *)dz->sampbuf[2],0,dz->buflen * sizeof(float)); m -= dz->buflen; } } for(n=startsearch;n = dz->buflen) { *last_total_samps_read = dz->total_samps_read; if((exit_status = read_samps(ibuf,dz))<0) return(exit_status); n = 0; endsearch -= dz->buflen; } obuf[m++] = ibuf[n]; if(m >= limit) { if((exit_status = write_samps(obuf,dz->buflen,dz))<0) return(exit_status); if(dz->mode == GREV_PUT) { /* deals with bufptr < 0 */ memcpy((char *)dz->sampbuf[1],(char *)dz->sampbuf[2],dz->buflen * sizeof(float)); memset((char *)dz->sampbuf[2],0,dz->buflen * sizeof(float)); m = dz->buflen; } else m = 0; } } *obufpos = m; return(FINISHED); } /************************** DO_ENVGRAIN_ZEROWRITE **********************/ int do_envgrain_zerowrite(int startsearch,int endsearch,int *obufpos,dataptr dz) { int exit_status; int n, m; float *obuf = dz->sampbuf[1]; m = *obufpos; for(n=startsearch;n = dz->buflen) { if((exit_status = write_samps(obuf,dz->buflen,dz))<0) return(exit_status); m = 0; } obuf[m++] = 0.0; } *obufpos = m; return(FINISHED); } /************************** DO_ENVGRAIN_ZEROWRITE_DBLBUF **********************/ int do_envgrain_zerowrite_dblbuf(int startsearch,int endsearch,int *obufpos,dataptr dz) { int exit_status; int n, m; float *obuf = dz->sampbuf[1], *obuf2 = dz->sampbuf[2]; m = *obufpos; for(n=startsearch;n = dz->buflen * 2) { if((exit_status = write_samps(obuf,dz->buflen,dz))<0) return(exit_status); memcpy((char *)obuf,(char *)obuf2,dz->buflen * sizeof(float)); memset((char *)obuf2,0,dz->buflen * sizeof(float)); m -= dz->buflen; } obuf[m++] = 0.0; } *obufpos = m; return(FINISHED); } /************************** DO_ENVGRAIN_ADDWRITE **********************/ int do_envgrain_addwrite(int startsearch,int endsearch,int *last_total_samps_read,int *obufpos,dataptr dz) { int exit_status; int step, n, m; float *ibuf = dz->sampbuf[0], *obuf = dz->sampbuf[1], *obuf2 = dz->sampbuf[2]; if(*obufpos < 0) { sprintf(errstr,"GRAIN TOO LARGE TO BACKTRACK IN BUFFER.\n"); return(GOAL_FAILED); } if(startsearch > dz->total_samps_read || startsearch < *last_total_samps_read) { step = (startsearch / dz->buflen) * dz->buflen; if((sndseekEx(dz->ifd[0],step,0))<0) { sprintf(errstr,"seek error 6\n"); return(SYSTEM_ERROR); } *last_total_samps_read = step; if((exit_status = read_samps(ibuf,dz))<0) return(exit_status); dz->total_samps_read = *last_total_samps_read + dz->ssampsread; } startsearch -= *last_total_samps_read; endsearch -= *last_total_samps_read; m = *obufpos; for(n=startsearch;n = dz->buflen) { *last_total_samps_read = dz->total_samps_read; if((exit_status = read_samps(ibuf,dz))<0) return(exit_status); n = 0; endsearch -= dz->buflen; } obuf[m++] += ibuf[n]; if(m >= dz->buflen * 2) { if((exit_status = write_samps(obuf,dz->buflen,dz))<0) return(exit_status); memcpy((char *)obuf,(char *)obuf2,dz->buflen * sizeof(float)); memset((char *)obuf2,0,dz->buflen * sizeof(float)); m -= dz->buflen; } } *obufpos = m; return(FINISHED); } /****************************** TIMESTRETCH_ITERATIVE ****************************/ int timestretch_iterative3(dataptr dz) { int exit_status; float *obuf = dz->sampbuf[0]; int *pos = dz->lparray[0]; int peakcnt, startsearch, endsearch, local_minima_cnt, minimum_element_len; int n,z = 0, outpos, samps_to_write; char *outfilename; int namelen = strlen(dz->wordstor[0]); if((outfilename = (char *)malloc(namelen + 4))==NULL) { sprintf(errstr,"Insufficient memory\n"); return(MEMORY_ERROR); } strcpy(outfilename,dz->wordstor[0]); fprintf(stdout,"INFO: Generating output.\n"); fflush(stdout); if(sloom) display_virtual_time(0,dz); if((exit_status = read_samps(dz->sampbuf[0],dz))<0) return(exit_status); dz->sampbuf[0][dz->insams[0]] = dz->sampbuf[0][dz->insams[0] - 1]; /* wrap around point for interpolation */ startsearch = (int)round(dz->param[RRR_START] * dz->infile->srate); endsearch = (int)round(dz->param[RRR_END] * dz->infile->srate); /* FIND ALL POSITIVE PEAKS : always look only at +ve vals, so all zero-crossings eventually found will be from +ve to -ve */ peakcnt = 0; if((exit_status = find_all_positive_peaks(startsearch,endsearch,&peakcnt,dz)) < 0) return(exit_status); /* FIND ALL POSITIVE-PEAK MINIMA : overwriting the arrays peak-vals & peak-position with minima-vals & minima-positions */ local_minima_cnt = 0; if((exit_status = find_all_local_minima(peakcnt,&local_minima_cnt,dz)) < 0) return(exit_status); /* ELIMINATE SPURIOUS MINIMA */ if((exit_status = eliminate_spurious_minima(&local_minima_cnt,&minimum_element_len,dz)) < 0) return (exit_status); fprintf(stdout,"INFO: Original number of iterated segments found = %d\n",local_minima_cnt - 1); fflush(stdout); /* CHECK MINIMA FOUND AGAINST INPUT ESTIMATE */ if((local_minima_cnt - 1) >= 2 * dz->iparam[RRR_GET]) { if((exit_status = eliminate_excess_minima(&local_minima_cnt,pos,dz)) < 0) return (exit_status); fprintf(stdout,"INFO: Reduced to = %d\n",local_minima_cnt - 1); fflush(stdout); } /* SEARCH FOR ZERO CROSSINGS AFTER MINIMA */ if(local_minima_cnt > 999) { sprintf(errstr,"Found more than 999 segments. Process terminated.\n"); return(GOAL_FAILED); } if((exit_status = locate_zero_crossings(local_minima_cnt,dz)) < 0) return (exit_status); /* COPY SOUND START TO OUTBUF */ outpos = 0; if (pos[0] > 0) { fprintf(stdout,"INFO: Cutting start of sound\n"); fflush(stdout); } if((exit_status = write_samps(obuf,pos[0],dz))<0) return(exit_status); outpos = pos[0]; for (n = 1; n < local_minima_cnt; n++) { if((exit_status = headwrite(dz->ofd,dz))<0) { return(exit_status); } if(sndcloseEx(dz->ofd) < 0) { fprintf(stdout,"WARNING: Can't close output soundfile %s\n",outfilename); fflush(stdout); } z++; strcpy(outfilename,dz->wordstor[0]); if(!sloom) insert_new_number_at_filename_end(outfilename,n,0); else insert_new_number_at_filename_end(outfilename,n,1); if((exit_status = create_sized_outfile(outfilename,dz))<0) { sprintf(errstr,"WARNING: Can't create output soundfile %s\n",outfilename); return(SYSTEM_ERROR); } if(n==1) { fprintf(stdout,"INFO: Cutting each iterated segment\n"); fflush(stdout); } obuf = dz->sampbuf[0] + outpos; samps_to_write = pos[n] - pos[n-1]; if((exit_status = write_samps(obuf,samps_to_write,dz))<0) return(exit_status); outpos = pos[n]; } if((exit_status = headwrite(dz->ofd,dz))<0) { free(outfilename); return(exit_status); } if(sndcloseEx(dz->ofd) < 0) { fprintf(stdout,"WARNING: Can't close output soundfile %s\n",outfilename); fflush(stdout); } z++; if(pos[n-1] < dz->insams[0]) { fprintf(stdout,"INFO: Cutting end of sound\n"); fflush(stdout); strcpy(outfilename,dz->wordstor[0]); if(!sloom) insert_new_number_at_filename_end(outfilename,n,0); else insert_new_number_at_filename_end(outfilename,n,1); if((exit_status = create_sized_outfile(outfilename,dz))<0) { sprintf(errstr,"WARNING: Can't create output soundfile %s\n",outfilename); return(SYSTEM_ERROR); } obuf = dz->sampbuf[0] + outpos; samps_to_write = dz->insams[0] - pos[n-1]; if((exit_status = write_samps(obuf,samps_to_write,dz))<0) return(exit_status); z++; } fprintf(stdout,"INFO: Total no of outfiles = %d\n",z); fflush(stdout); return(FINISHED); }