/* * Copyright (c) 1983-2023 Trevor Wishart and Composers Desktop Project Ltd * http://www.trevorwishart.co.uk * http://www.composersdesktop.com * This file is part of the CDP System. The CDP System is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. The CDP System is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with the CDP System; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include #include #include #include #include #include #include #include #include #include #include #include #include //#ifdef unix #define round(x) lround((x)) //#endif int drunk(int here,int *obufpos,int *thisbuf,int thisdur,double pregain,int *endwrite,int outbufspace,dataptr dz); int do_pause(int here,int *obufpos,int *endwrite,int *thisbuf,int thisdur,double pregain,int outbufspace,dataptr dz); int get_thisdur(int *thisdur,int *goalpcnt,int *pcnt,dataptr dz); int get_pos_and_dur_for_pause(int *here,int *thisdur,int *thisbuf,int *ibufpos,double pregain,dataptr dz); int get_pos(int *here,int thisdur,dataptr dz); void do_pregain(double pregain,dataptr dz); int is_paus(int *goalpcnt,int *pcnt,dataptr dz); int convert_time_to_samplecnts(int paramno,dataptr dz); int convert_sec_steps_to_grain_steps(dataptr dz); int adjust_bufs(int here,int *ibufpos,int *thisbuf,double pregain,dataptr dz); int do_intermediate_write(int *endwrite,int *obufpos,dataptr dz); int make_drnk_splicetab(dataptr dz); void setup_paus_params(dataptr dz); int get_maxvalue(int paramno,double *maxval,dataptr dz); double get_pregain(dataptr dz); int do_start_splice(int chans,float *obuf,int *obufpos,float *ibuf,int *ibufpos,int *thisbuf,double pregain, int *endwrite,int outbufspace,dataptr dz); int do_end_splice(int chans,float *obuf,int *obufpos,float *ibuf,int *ibufpos,int *thisbuf,double pregain,dataptr dz); int bounce_off_file_end_if_necessary(int *here,int thisdur,int chans,int splicelen,dataptr dz); int get_pausdur(int *here,int splicelen,int chans,int *thisdur,dataptr dz); int get_step(int chans,dataptr dz); int get_new_pos(int here,int ambitus,int locus,int step); int get_new_locus_pos(int here,int ambitus,int locus,int step); /*************************** DO_DRUNKEN_WALK *************************/ int do_drunken_walk(dataptr dz) { int exit_status; int here = 0, ibufpos, obufpos = 0, samps_processed = 0; double outsamptime; double pregain = 1.0; int thisdur, endwrite = 0; int thisbuf; int is_a_pause; int goalpcnt = -1; /* total events needed before pause: initialisation value -1 */ int pcnt = 0; /* count of events since last pause: initial val 0 > -1 */ int chans = dz->infile->channels; int finished = FALSE; int outbufspace = dz->sampbuf[3] - dz->sampbuf[1]; display_virtual_time(0,dz); if((exit_status = read_samps(dz->sampbuf[0],dz))<0) return(exit_status); if(dz->vflag[IS_DRNK_OVERLAP]) { pregain = get_pregain(dz); do_pregain(pregain,dz); } while(samps_processed < dz->iparam[DRNK_TOTALDUR]) { outsamptime = (double)((obufpos + dz->total_samps_written)/chans); if((exit_status = read_values_from_all_existing_brktables(outsamptime,dz))<0) return(exit_status); while((is_a_pause = get_thisdur(&thisdur,&goalpcnt,&pcnt,dz))==TRUE) { setup_paus_params(dz); if((exit_status = get_pos_and_dur_for_pause(&here,&thisdur,&thisbuf,&ibufpos,pregain,dz))<0) return(exit_status); if((exit_status = do_pause(ibufpos,&obufpos,&endwrite,&thisbuf,thisdur,pregain,outbufspace,dz))<0) return(exit_status); if((samps_processed = dz->total_samps_written + endwrite) >= dz->iparam[DRNK_TOTALDUR]) { finished = TRUE; break; } outsamptime = (double)((obufpos + dz->total_samps_written)/chans); if((exit_status = read_values_from_all_existing_brktables(outsamptime,dz))<0) return(exit_status); } if(finished) break; if((exit_status = get_pos(&here,thisdur,dz))<0) return(exit_status); if((exit_status = adjust_bufs(here,&ibufpos,&thisbuf,pregain,dz))<0) return(exit_status); if((exit_status = drunk(ibufpos,&obufpos,&thisbuf,thisdur,pregain,&endwrite,outbufspace,dz))<0) return(exit_status); if(obufpos >= dz->buflen) { if((exit_status = do_intermediate_write(&endwrite,&obufpos,dz))<0) return(exit_status); } samps_processed = dz->total_samps_written + endwrite; } if(endwrite > 0) { if((exit_status = write_samps(dz->sampbuf[1],endwrite,dz))<0) return(exit_status); } display_virtual_time(dz->total_samps_written,dz); return(FINISHED); } /**************************** DRUNK **************************/ int drunk(int ibufpos,int *obufpos,int *thisbuf,int thisdur,double pregain,int *endwrite,int outbufspace,dataptr dz) { int exit_status; int n, overlap, copyblk; int chans = dz->infile->channels; int splicelen = dz->iparam[DRNK_SPLICELEN] * chans; int outbpos; float *ibuf = dz->sampbuf[0], *thisin; float *obuf = dz->sampbuf[1]; int available_insamps; if((exit_status = do_start_splice(chans,obuf,obufpos,ibuf,&ibufpos,thisbuf,pregain,endwrite,outbufspace,dz))<0) return(exit_status); outbpos = *obufpos; copyblk = thisdur - splicelen; available_insamps = dz->ssampsread - ibufpos; while(available_insamps < copyblk) { thisin = ibuf+ibufpos; for(n=0;n= outbufspace) { *endwrite = outbpos; if((exit_status = do_intermediate_write(endwrite,&outbpos,dz))<0) return(exit_status); } obuf[outbpos++] += thisin[n]; } if((exit_status = read_samps(dz->sampbuf[0],dz))<0) return(exit_status); if(dz->vflag[IS_DRNK_OVERLAP]) do_pregain(pregain,dz); (*thisbuf)++; ibufpos = 0; copyblk -= available_insamps; available_insamps = dz->ssampsread; } if(copyblk > 0) { thisin = ibuf+ibufpos; for(n=0;n= outbufspace) { *endwrite = outbpos; if((exit_status = do_intermediate_write(endwrite,&outbpos,dz))<0) return(exit_status); } obuf[outbpos++] += thisin[n]; } ibufpos += copyblk; } if((exit_status = do_end_splice(chans,obuf,&outbpos,ibuf,&ibufpos,thisbuf,pregain,dz))<0) return(exit_status); *endwrite = outbpos; outbpos -= splicelen; if(dz->vflag[IS_DRNK_OVERLAP]) { overlap = round((double)(thisdur/chans) * dz->param[DRNK_OVERLAP]) * chans; outbpos -= overlap; } *obufpos = outbpos; return(FINISHED); } /**************************** DO_PAUSE **************************/ int do_pause(int ibufpos,int *obufpos,int *endwrite,int *thisbuf,int thisdur,double pregain, int outbufspace,dataptr dz) { int exit_status; int n, copyblk, write_block; int outbpos; int chans = dz->infile->channels; int splicelen = dz->iparam[DRNK_SPLICELEN] * chans; float *ibuf = dz->sampbuf[0], *thisin; float *obuf = dz->sampbuf[1], *thisout; int available_insamps, available_outspace; /* ?? */ if((exit_status = do_start_splice(chans,obuf,obufpos,ibuf,&ibufpos,thisbuf,pregain,endwrite,outbufspace,dz))<0) return(exit_status); outbpos = *obufpos; copyblk = thisdur - splicelen; write_block = dz->sampbuf[3] - dz->sampbuf[1]; /* writeable block = outbuf + overflow */ available_outspace = write_block - outbpos; available_insamps = dz->ssampsread - ibufpos; while(copyblk >= available_outspace) { while(available_insamps <= available_outspace) { thisout = obuf+outbpos; thisin = ibuf+ibufpos; for(n=0;nsampbuf[0],dz))<0) return(exit_status); if(dz->vflag[IS_DRNK_OVERLAP]) do_pregain(pregain,dz); (*thisbuf)++; ibufpos = 0; outbpos += available_insamps; copyblk -= available_insamps; available_outspace -= available_insamps; available_insamps = dz->ssampsread; } if(available_outspace > 0) { thisout = obuf+outbpos; thisin = ibuf+ibufpos; for(n=0;nssampsread - ibufpos; } if(write_block > 0) { if((exit_status = write_samps(dz->sampbuf[1],write_block,dz))<0) return(exit_status); } display_virtual_time(dz->total_samps_written,dz); memset((char *)dz->sampbuf[1],0,write_block * sizeof(float)); write_block = dz->sampbuf[2] - dz->sampbuf[1]; /* change writeable block to outbuf only */ outbpos = 0; available_outspace = dz->buflen; } while(available_insamps < copyblk) { thisout = obuf+outbpos; thisin = ibuf+ibufpos; for(n=0;nsampbuf[0],dz))<0) return(exit_status); if(dz->vflag[IS_DRNK_OVERLAP]) do_pregain(pregain,dz); (*thisbuf)++; ibufpos = 0; outbpos += available_insamps; copyblk -= available_insamps; available_insamps = dz->ssampsread; } if(copyblk > 0) { thisout = obuf+outbpos; thisin = ibuf+ibufpos; for(n=0;n= dz->buflen) { /* if we're now beyond outbuf end: do bufwrite & copyback */ if((exit_status = do_intermediate_write(endwrite,&outbpos,dz))<0) return(exit_status); } *obufpos = outbpos; return FINISHED; } /***************************** GET_THISDUR *******************************/ int get_thisdur(int *thisdur,int *goalpcnt,int *pcnt,dataptr dz) { double randv; if(dz->mode==HAS_SOBER_MOMENTS && is_paus(goalpcnt,pcnt,dz)) return TRUE; randv = drand48() * dz->param[DRNK_CLOKRND]; if((*thisdur = round((double)dz->iparam[DRNK_CLOKTIK] * (1.0 + randv)))iparam[DRNK_SPLICELEN]) *thisdur = round((double)dz->iparam[DRNK_CLOKTIK] * (1.0 - randv)); *thisdur *= dz->infile->channels; return FALSE; } /***************************** GET_POS_AND_DUR_FOR_PAUSE *******************************/ int get_pos_and_dur_for_pause(int *here,int *thisdur,int *thisbuf,int *ibufpos,double pregain,dataptr dz) { int exit_status; int step; int chans = dz->infile->channels; int ambitus = dz->iparam[DRNK_AMBITUS] * chans; int locus = dz->iparam[DRNK_LOCUS] * chans; int splicelen = dz->iparam[DRNK_SPLICELEN] * chans; if(ambitus>0 && (step = get_step(chans,dz))!=0) *here = get_new_pos(*here,ambitus,locus,step); if((exit_status = get_pausdur(here,splicelen,chans,thisdur,dz))<0) return(exit_status); return adjust_bufs(*here,ibufpos,thisbuf,pregain,dz); } /***************************** GET_POS *******************************/ int get_pos(int *here,int thisdur,dataptr dz) { int step = 0; int chans = dz->infile->channels; int ambitus = dz->iparam[DRNK_AMBITUS] * chans; int locus = dz->iparam[DRNK_LOCUS] * chans; int splicelen = dz->iparam[DRNK_SPLICELEN] * chans; if(ambitus > 0 && (step = get_step(chans,dz))!=0) *here = get_new_pos(*here,ambitus,locus,step); else if(dz->iparam[DRNK_LAST_LOCUS] != dz->iparam[DRNK_LOCUS]) *here = get_new_locus_pos(*here,ambitus,locus,step); dz->iparam[DRNK_LAST_LOCUS] = dz->iparam[DRNK_LOCUS]; return bounce_off_file_end_if_necessary(here,thisdur,chans,splicelen,dz); } /*************************** PREGAIN **************************** * * Allows for effect of overlapping segments. */ void do_pregain(double pregain,dataptr dz) { int i; double j; float *iptr = dz->sampbuf[0]; for(i=0;issampsread;i++) { j = (*iptr) * pregain; *iptr++ = (float) /*round*/j; } } /******************************* IS_PAUS *******************************/ int is_paus(int *goalpcnt,int *pcnt,dataptr dz) { if(*goalpcnt < 0) { /* if 1st time */ setup_paus_params(dz); *goalpcnt = round(drand48() * (double)dz->iparam[DRNK_DRNKTIK_RANG]); *goalpcnt += dz->iparam[DRNK_MIN_DRNKTIK]; } else if((*pcnt)++ >= *goalpcnt) { /* if counted enough events to insert pause */ setup_paus_params(dz); *goalpcnt = round(drand48() * (double)dz->iparam[DRNK_DRNKTIK_RANG]); *goalpcnt += dz->iparam[DRNK_MIN_DRNKTIK]; *pcnt = 0; /* Reset event counter to zero */ return TRUE; /* Flag that pz has been returned */ } return FALSE; /* ELSE Flag no pz on this occasion */ } /************************* ADJUST_BUFS *********************/ int adjust_bufs(int here,int *ibufpos,int *thisbuf,double pregain,dataptr dz) { int exit_status; int nextbuf = here/dz->buflen; if(nextbuf != *thisbuf) { if((sndseekEx(dz->ifd[0],nextbuf * dz->buflen,0))<0) { sprintf(errstr,"seek error in adjust_bufs()\n"); return(SYSTEM_ERROR); } if((exit_status = read_samps(dz->sampbuf[0],dz))<0) return(exit_status); if(dz->vflag[IS_DRNK_OVERLAP]) do_pregain(pregain,dz); } *ibufpos = here % dz->buflen; if(*ibufpos >= dz->ssampsread) { sprintf(errstr,"Buffer accounting problem: adjust_bufs()\n"); return(PROGRAM_ERROR); } *thisbuf = nextbuf; return FINISHED; } /************************* DO_INTERMEDIATE_WRITE *********************/ int do_intermediate_write(int *endwrite,int *obufpos,dataptr dz) { int exit_status; int samps_to_move = *endwrite - dz->buflen; int samps_available = dz->sampbuf[3] - dz->sampbuf[1]; if((exit_status = write_samps(dz->sampbuf[1],dz->buflen,dz))<0) return(exit_status); display_virtual_time(dz->total_samps_written,dz); memmove((char *)dz->sampbuf[1],(char *)dz->sampbuf[2],(size_t)(samps_to_move* sizeof(float))); memset((char *)(dz->sampbuf[1] + samps_to_move),0,(size_t)((samps_available - samps_to_move)*sizeof(float))); *endwrite -= dz->buflen; *obufpos -= dz->buflen; return(FINISHED); } /************************* SETUP_PAUS_PARAMS *********************/ void setup_paus_params(dataptr dz) { int tempval; if(dz->iparam[DRNK_MIN_DRNKTIK] > dz->iparam[DRNK_MAX_DRNKTIK]) { tempval = dz->iparam[DRNK_MIN_DRNKTIK]; dz->iparam[DRNK_MIN_DRNKTIK] = dz->iparam[DRNK_MAX_DRNKTIK]; dz->iparam[DRNK_MAX_DRNKTIK] = tempval; } dz->iparam[DRNK_DRNKTIK_RANG] = (int)(dz->iparam[DRNK_MAX_DRNKTIK] - dz->iparam[DRNK_MIN_DRNKTIK]); if(dz->param[DRNK_MIN_PAUS] >= dz->insams[0]) dz->iparam[DRNK_MAXHOLD] = TRUE; else { dz->iparam[DRNK_MAXHOLD] = FALSE; if(dz->iparam[DRNK_MIN_PAUS] > dz->iparam[DRNK_MAX_PAUS]) { tempval = dz->iparam[DRNK_MIN_PAUS]; dz->iparam[DRNK_MIN_PAUS] = dz->iparam[DRNK_MAX_PAUS]; dz->iparam[DRNK_MAX_PAUS] = tempval; } dz->iparam[DRNK_PAUS_RANG] = (int)(dz->iparam[DRNK_MAX_PAUS] - dz->iparam[DRNK_MIN_PAUS]); } } /************************* GET_PREGAIN *********************/ double get_pregain(dataptr dz) { double val; val = 1.0 - dz->param[DRNK_MAX_OVLAP]; /* e.g. 3/4+ -> 1/4 || .76 -> .24 */ val = 1.0/val; /* i.e 1/4 -> 4 || .24 -> 4+ */ val += 1.0; /* i.e. 4 -> 5 || 4+ -> 5+ */ //TW UPDATE // return val; return 1.0/val; } /*************************** DO_START_SPLICE **************************/ int do_start_splice(int chans,float *obuf,int *obufpos,float *ibuf,int *ibufpos,int *thisbuf, double pregain,int *endwrite,int outbufspace,dataptr dz) { int exit_status; int n; int m; int outbpos = *obufpos; int inbpos = *ibufpos; for(n=0;niparam[DRNK_SPLICELEN];n++) { for(m=0;m= outbufspace) { *endwrite = outbpos; if((exit_status = do_intermediate_write(endwrite,&outbpos,dz))<0) return(exit_status); } obuf[outbpos++] += (float)/*round*/((double)ibuf[inbpos++] * dz->parray[DRNK_SPLICETAB][n]); } if(inbpos >= dz->ssampsread) { if((exit_status = read_samps(dz->sampbuf[0],dz))<0) return(exit_status); if(dz->vflag[IS_DRNK_OVERLAP]) do_pregain(pregain,dz); inbpos = 0; (*thisbuf)++; } } *obufpos = outbpos; *ibufpos = inbpos; return(FINISHED); } /*************************** DO_END_SPLICE **************************/ int do_end_splice(int chans,float *obuf,int *obufpos,float *ibuf,int *ibufpos,int *thisbuf,double pregain,dataptr dz) { int exit_status; int n; int m; int outbpos = *obufpos; int inbpos = *ibufpos; for(n=dz->iparam[DRNK_SPLICELEN]-1;n>=0;n--) { for(m=0;mparray[DRNK_SPLICETAB][n]); if(inbpos >= dz->ssampsread) { if((exit_status = read_samps(dz->sampbuf[0],dz))<0) return(exit_status); if(dz->vflag[IS_DRNK_OVERLAP]) do_pregain(pregain,dz); inbpos = 0; (*thisbuf)++; } } *obufpos = outbpos; *ibufpos = inbpos; return(FINISHED); } /*************************** GET_NEW_POS **************************/ int get_new_pos(int here,int ambitus,int locus,int step) { int current_stray = here - locus; /* distance frm start available seg (locus) to current pos*/ int new_stray = current_stray + step; /* new_stray = distance from locus */ int otherstray, newstep; if(new_stray > ambitus || new_stray < -ambitus ) { /* if new_stray greater than ambitus */ otherstray = current_stray - step; if(otherstray >= 0 && otherstray <= ambitus) here = locus + otherstray; /* try reversing step */ else if(otherstray <0 && otherstray >= -ambitus) here = locus + otherstray; else { newstep = abs(new_stray) % ambitus; /* otherwise take modulus */ if(step >= 0) here = locus + newstep; else here = locus - newstep; } } else here += step; if(here<0) /* Bounce off start of buffer if ness */ here = -here; return(here); } /*************************** GET_NEW_LOCUS_POS **************************/ int get_new_locus_pos(int here,int ambitus,int locus,int step) { int current_stray = here - locus; /* distance frm start available seg (locus) to current pos*/ int new_stray = current_stray + step; /* new_stray = distance from locus */ if(new_stray > ambitus || new_stray < -ambitus) /* if new_stray greater than ambitus */ here = locus + step; else here += step; if(here<0) /* Bounce off start of buffer if ness */ here = -here; return(here); } /*************************** GET_STEP **************************/ int get_step(int chans,dataptr dz) { int step; double dstep = (drand48() * 2.0) - 1.0; /* range +1 to -1 */ dstep *= dz->param[DRNK_GSTEP]; /* range +gstep to -gstep */ step = round(dstep); /* Current stepsize in mintime-grains */ step *= dz->iparam[DRNK_LGRAIN]; /* Current stepsize in samples */ step *= chans; return step; } /*************************** GET_PAUSDUR **************************/ int get_pausdur(int *here,int splicelen,int chans,int *thisdur,dataptr dz) { int this_pause; int max_pause = dz->insams[0] - *here - splicelen; if(EVEN(chans) && ODD(max_pause)) { sprintf(errstr,"Stereo anomaly at file end: get_pausdur()\n"); return(PROGRAM_ERROR); } if(max_pause < 0) { sprintf(errstr,"Negative pause duration: get_pausdur()\n"); return(PROGRAM_ERROR); } if(dz->iparam[DRNK_MAXHOLD]) *thisdur = max_pause; else { this_pause = round(drand48() * dz->iparam[DRNK_PAUS_RANG]); /* gen pause dur between */ this_pause += dz->iparam[DRNK_MIN_PAUS]; /* given limits */ this_pause *= chans; *thisdur = min(this_pause,max_pause); /* but not >endoffile */ } return(FINISHED); } /*************************** BOUNCE_OFF_FILE_END_IF_NECESSARY **************************/ //TW MY CURRENT CODE AGREES WITH THIS, so removed #ifdef int bounce_off_file_end_if_necessary(int *here,int thisdur,int chans,int splicelen,dataptr dz) { int diff, initial_diff, needed; initial_diff = abs(dz->insams[0] - *here); /* Ensure enough room to read final segment and splice */ if(EVEN(chans) && ODD(initial_diff)) { sprintf(errstr,"Stereo anomaly at file end: bounce_off_file_end_if_necessary()\n"); return(PROGRAM_ERROR); } if((needed = thisdur + splicelen) > dz->insams[0]) { sprintf(errstr,"Segment duration exceeds size of sound\n"); return(DATA_ERROR); } while((diff = dz->insams[0] - *here) < needed) { *here -= initial_diff; /* Bounce off end of buffer if ness */ if(*here < 0 || initial_diff == 0) { /* But, if it bounces off BOTH ends !! */ *here = (dz->insams[0] - needed)/dz->infile->channels; *here = (int)round(*here * drand48()) * dz->infile->channels; } } return(FINISHED); }