/* * 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 * */ /* RWD 22/02/2018 changed sndfile interleave code to eliminate glitch on ch2 only suffix number to outfile name for sloom */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include /*RWD*/ //TW UPDATE #include #include //#ifdef unix #define round(x) lround((x)) //#endif static int gentable(int tabsize,dataptr dz); static int gen_wave(int sampdur,double sr,dataptr dz); static int gen_silence(int sampdur,dataptr dz); static int gen_noise(int sampdur,double sr,dataptr dz); static int update_wave_params(double *ampstep,double *frqstep,double *lastamp,double *lastfrq,double inverse_sr, int *samptime, int *nextsamptime,int blokstep,dataptr dz); static double getval(double *tab,int i,double fracstep,double amp); static int advance_in_table(int *i,double convertor,double *step,double *fracstep, double *amp,double *frq,double dtabsize,double *ampstep,double *frqstep,int *samptime,int *nextsamptime, double *lastamp,double *lastfrq,double inverse_sr,int blokstep,dataptr dz); void set_band_limits(int clength,int *supertight, double *bwidth, int *minchan, int *centrchan, double *hfbwidth, int *lo_n, int *hi_n, double *offset, double hfchwidth, dataptr dz); int do_stereo_specsynth(dataptr dz); //TW UPDATE static int gen_clicktrack(dataptr dz); static int gen_chord(int sampdur,dataptr dz); /******************************* DO_SYNTH ******************************/ int do_synth(dataptr dz) { int exit_status; int sampdur = 0; double sr = 0.0; //TW UPDATES if(dz->process == CLICK) dz->infile->channels = 1; else { dz->infile->channels = dz->iparam[SYN_CHANS]; dz->infile->srate = dz->iparam[SYN_SRATE]; sr = (double)dz->infile->srate; sampdur = round(sr * dz->param[SYN_DUR]) * dz->iparam[SYN_CHANS]; dz->tempsize = sampdur; } if(dz->floatsam_output) dz->infile->stype = SAMP_FLOAT; else dz->infile->stype = SAMP_SHORT; switch(dz->process) { case(SYNTH_SIL): return gen_silence(sampdur,dz); case(SYNTH_NOISE): return gen_noise(sampdur,sr,dz); //TW UPDATES case(CLICK): return gen_clicktrack(dz); } if((dz->parray[SYNTH_TAB] = (double *)malloc((dz->iparam[SYN_TABSIZE]+1) * sizeof(double)))==NULL) { sprintf(errstr,"Insufficient memory for wave table.\n"); return(MEMORY_ERROR); } if(dz->process == MULTI_SYN) dz->mode = WAVE_SINE; if((exit_status = gentable(dz->iparam[SYN_TABSIZE],dz))<0) return(exit_status); if(dz->process == MULTI_SYN) return gen_chord(sampdur,dz); return gen_wave(sampdur,sr,dz); } /******************************* GENTABLE ******************************/ int gentable(int tabsize,dataptr dz) { int n, m, k0, k1; double minstep, step; double *tab = dz->parray[SYNTH_TAB]; switch(dz->mode) { case(WAVE_SINE): step = (2.0 * PI)/(double)tabsize; for(n=0;niparam[SYN_TABSIZE]; double convertor = dtabsize * inverse_sr; int m, i, k; int chans = dz->infile->channels; double timestep = 10.0 * MS_TO_SECS, ampstep, frqstep, lastamp, lastfrq, amp, frq; int blokstep = round(timestep * sr); int samptime = 0, nextsamptime = blokstep; double *tab = dz->parray[SYNTH_TAB]; double fracstep = 0.0, val; int do_start = 1; int synth_splicelen = SYNTH_SPLICELEN * chans; int total_samps = 0; int startj = 0, endj = SYNTH_SPLICELEN; int total_samps_left = sampdur; int endsplicestart = sampdur - synth_splicelen; int todo; step = 0.0; i = 0; if(sampdur < (synth_splicelen * 2) + chans) { fprintf(stdout,"ERROR: Specified output duration is less then available splicing length.\n"); return(DATA_ERROR); } if((exit_status = read_values_from_all_existing_brktables(0.0,dz))<0) return(exit_status); if((exit_status = update_wave_params(&step,&frqstep,&lastamp,&lastfrq,inverse_sr,&samptime,&nextsamptime,blokstep,dz))<0) return(exit_status); amp = lastamp; frq = lastfrq; while(total_samps_left > 0) { if(total_samps_left/dz->buflen <= 0) todo = total_samps_left; else todo = dz->buflen; m = 0; while(m < todo) { val = getval(tab,i,fracstep,amp); if(do_start) { val *= (startj++/(double)SYNTH_SPLICELEN); if(startj >= SYNTH_SPLICELEN) do_start = 0; } if(total_samps >= endsplicestart) val *= (endj--/(double)SYNTH_SPLICELEN); for(k=0;kbigbuf[m++] = (short)round(val); dz->bigbuf[m++] = (float)val; total_samps++; } if((exit_status = advance_in_table(&i,convertor,&step,&fracstep,&,&frq,dtabsize, &step,&frqstep,&samptime,&nextsamptime,&lastamp,&lastfrq,inverse_sr,blokstep,dz))<0) return(exit_status); } if(todo) { if((exit_status = write_samps(dz->bigbuf,todo,dz))<0) return(exit_status); } total_samps_left -= dz->buflen; } return(FINISHED); } /****************************** GEN_SILENCE *************************/ int gen_silence(int sampdur,dataptr dz) { int exit_status; int n, bufcnt = sampdur/dz->buflen; int remain = sampdur - (bufcnt * dz->buflen); for(n=0;nbuflen;n++) dz->bigbuf[n] = (float)0; for(n=0;nbigbuf,dz->buflen,dz))<0) return(exit_status); } if(remain) return write_samps(dz->bigbuf,remain,dz); return FINISHED; } /****************************** GEN_NOISE *************************/ int gen_noise(int sampdur,double sr,dataptr dz) { int exit_status; int n; int k, chans = dz->infile->channels; double amp, lastamp,lastfrq,ampstep,frqstep; double inverse_sr = 1.0/sr; double timestep = 10.0 * MS_TO_SECS; int blokstep = round(timestep * sr); int samptime = 0, nextsamptime = blokstep; int total_samps = 0; int synth_splicelen = SYNTH_SPLICELEN * chans, startj = 0, endj = SYNTH_SPLICELEN; int endsplicestart = sampdur - synth_splicelen; int do_start = 1; int total_samps_left = sampdur; int todo; double val; if(sampdur < (synth_splicelen * 2) + chans) { fprintf(stdout,"ERROR: Specified output duration is less then available splicing length.\n"); return(DATA_ERROR); } if((exit_status = read_values_from_all_existing_brktables(0.0,dz))<0) return(exit_status); if((exit_status = update_wave_params(&step,&frqstep,&lastamp,&lastfrq,inverse_sr,&samptime,&nextsamptime,blokstep,dz))<0) return(exit_status); amp = lastamp; while(total_samps_left > 0) { if(total_samps_left/dz->buflen <= 0) todo = total_samps_left; else todo = dz->buflen; for(n=0;n= SYNTH_SPLICELEN) do_start = 0; } if(total_samps >= endsplicestart) val *= endj--/(double)SYNTH_SPLICELEN; for(k=0;kbigbuf[n+k] = (float)val; amp += ampstep; if(++samptime >= nextsamptime) { if((exit_status = update_wave_params (&step,&frqstep,&lastamp,&lastfrq,inverse_sr,&samptime,&nextsamptime,blokstep,dz))<0) return(exit_status); amp = lastamp; } } if(todo) { if((exit_status = write_samps(dz->bigbuf,todo,dz))<0) return(exit_status); } total_samps_left -= dz->buflen; } return(FINISHED); } /****************************** GETVAL *************************/ double getval(double *tab,int i,double fracstep,double amp) { double diff, val = tab[i]; diff = tab[i+1] - val; val += diff * fracstep; val *= amp; return(val); } /****************************** UPDATE_WAVE_PARAMS *************************/ int update_wave_params(double *ampstep,double *frqstep,double *lastamp,double *lastfrq,double inverse_sr, int *samptime, int *nextsamptime,int blokstep,dataptr dz) { int exit_status; double thistime = (double)(*nextsamptime) * inverse_sr; double ratio; *lastfrq = dz->param[SYN_FRQ]; *lastamp = dz->param[SYN_AMP]; *ampstep = 0.0; *frqstep = 1.0; if((exit_status = read_values_from_all_existing_brktables(thistime,dz))<0) return(exit_status); if(dz->brksize[SYN_AMP]) *ampstep = (dz->param[SYN_AMP] - *lastamp)/(double)blokstep; if(dz->brksize[SYN_FRQ]) { ratio = dz->param[SYN_FRQ]/(*lastfrq); *frqstep = pow(10.0,log10(ratio)/(double)blokstep); } *samptime = *nextsamptime; *nextsamptime += blokstep; return(FINISHED); } /****************************** ADVANCE_IN_TABLE *************************/ static int advance_in_table(int *i,double convertor,double *step,double *fracstep, double *amp,double *frq,double dtabsize,double *ampstep,double *frqstep,int *samptime,int *nextsamptime, double *lastamp,double *lastfrq,double inverse_sr,int blokstep,dataptr dz) { int exit_status; *step += *frq * convertor; while(*step >= dtabsize) *step -= dtabsize; *i = (int)(*step); /* TRUNCATE */ *fracstep = *step - (double)(*i); *amp += *ampstep; *frq *= *frqstep; if(++(*samptime) >= *nextsamptime) { if((exit_status = update_wave_params (ampstep,frqstep,lastamp,lastfrq,inverse_sr,samptime,nextsamptime,blokstep,dz))<0) return(exit_status); *amp = *lastamp; *frq = *lastfrq; } return(FINISHED); } /****************************** DO_STEREO_SPECSYNTH *************************/ #define SAFETY (10) //TW CONVERTED int do_stereo_specsynth(dataptr dz) { int exit_status; double hfchwidth = dz->chwidth/2.0; float *bufend; double focusrange = 0.0, basefrq, frq, *frqq, bwidth = 0.0, hfbwidth, offset = 0.0, totalamp; double thisfocus, ampscaler, amp, wobble, dcf, hfchansprd; int minchan = 0, supertight, lo_n = 0, hi_n = 0, wcnt, jj, n, m, k; int remainder, samps_written; int clength = dz->wanted/2, centrchan = 0; int orig_process_type; char outfnam[256], outfilename[256]; unsigned int samps_so_far; int floats_out = dz->wlength * dz->wanted; int samps_read1, samps_read2, samps_read; int OK = 1; int orig_process, orig_proctype, orig_chans, orig_stype; int orig_srate; //TW UPDATE CORRECTION int overlap = (dz->infile->channels - 2)/dz->infile->Dfac; int snd_floats_out = floats_out/overlap; extern int sloom; dz->tempsize = (floats_out + snd_floats_out) * 2; if((frqq = (double *)malloc(clength * sizeof(double)))==NULL) { sprintf(errstr,"No memory for initial-frequency storage-array.\n"); return(MEMORY_ERROR); } bufend = dz->bigfbuf + dz->big_fsize; if(!dz->brksize[SS_FOCUS2] && !dz->brksize[SS_FOCUS]) focusrange = dz->param[SS_FOCUS2] - dz->param[SS_FOCUS]; /* SET BAND LIMITS */ if(!dz->brksize[SS_SPREAD] && !dz->brksize[SS_CENTRFRQ]) set_band_limits(clength,&supertight,&bwidth,&minchan,¢rchan, &hfbwidth,&lo_n,&hi_n,&offset,hfchwidth,dz); outfnam[0] = ENDOFSTR; strcat(outfnam,dz->wordstor[0]); //TW REVISION for new protocol: always pass file-extension on cmdline if(sloom) delete_filename_lastchar(outfnam); /* axe trailing zero on outfilename */ samps_so_far = 0; for(jj=1;jj<3;jj++) { strcpy(outfilename,outfnam); //TW REVISION for new protocol: always pass file-extension on cmdline insert_new_number_at_filename_end(outfilename,jj+2,0); orig_process_type = dz->process_type; dz->process_type = BIG_ANALFILE; dz->outfiletype = ANALFILE_OUT; if((exit_status = create_sized_outfile(outfilename,dz)) < 0) { sprintf(errstr,"Cannot open temporary analysis file '%s' to generate sound data:%s\n", outfilename,sferrstr()); return(SYSTEM_ERROR); } // dz->outfiletype = NO_OUTPUTFILE; /* TW */ Thought I was, for safety, resetting to its original val (changed above) but did it wrongly, but not necessary. dz->total_windows = 0; dz->time = (float)0.0; dz->flbufptr[0] = dz->bigfbuf; for(wcnt = 0; wcnt < dz->wlength; wcnt++) { memset((char *)dz->flbufptr[0],0,dz->wanted * sizeof(float)); if((exit_status = read_values_from_all_existing_brktables((double)dz->time,dz))<0) return(exit_status); if(dz->brksize[SS_FOCUS2] || dz->brksize[SS_FOCUS]) focusrange = dz->param[SS_FOCUS2] - dz->param[SS_FOCUS]; if(dz->brksize[SS_SPREAD] || dz->brksize[SS_CENTRFRQ]) set_band_limits(clength,&supertight,&bwidth,&minchan,¢rchan, &hfbwidth,&lo_n,&hi_n,&offset,hfchwidth,dz); hfchansprd = (hi_n - lo_n)/2.0; totalamp = 0.0; for(n=lo_n, m = minchan; ntotal_windows==0) { /* for 1st window, establish a channel frq */ frq = (drand48() * bwidth) + basefrq; frqq[n] = frq; } else if(dz->param[SS_TRAND] > 0.0) { /* if chan frq wobbles thro time, vary it */ wobble = ((drand48() * 2.0) - 1.0)/2.0; frq = frqq[n] + (wobble * bwidth * dz->param[SS_TRAND]); } else /* if not, retain frq from first window */ frq = frqq[n]; dcf = (double)abs(centrchan - m)/hfchansprd; /* fraction of chan-sprd we are away from centre */ thisfocus = (drand48() * focusrange) + dz->param[SS_FOCUS]; thisfocus = 1.0/thisfocus; dcf = pow(dcf,thisfocus); /* squeeze or unsqueeze cosin distrib */ amp = (cos(dcf * PI) + 1.0)/2.0; /* cosin distrib */ totalamp += amp; k = m * 2; if(dz->total_windows) dz->flbufptr[0][k] = (float)amp; dz->flbufptr[0][++k] = (float)frq; } if(dz->total_windows) { ampscaler = (double)SPECSYN_MAXAMP/totalamp; for(n=lo_n, k = minchan*2; nflbufptr[0][k] = (float)(dz->flbufptr[0][k] * ampscaler); } if((dz->flbufptr[0] += dz->wanted) >= bufend) { if((exit_status = write_samps_no_report(dz->bigfbuf,dz->buflen,&samps_written,dz)) < 0) return(exit_status); display_virtual_time(dz->total_samps_written + samps_so_far,dz); dz->flbufptr[0] = dz->bigfbuf; } dz->time = (float)(dz->time + dz->frametime); dz->total_windows++; } if((remainder = dz->flbufptr[0] - dz->bigfbuf) > 0) { if((exit_status = write_samps_no_report(dz->bigfbuf,remainder,&samps_written,dz)) < 0) return(exit_status); display_virtual_time(dz->total_samps_written + samps_so_far,dz); } dz->process_type = orig_process_type; /* SEE NOTES IN pvoc_addon.c in PVOC directory */ if((exit_status = pvoc_out(floats_out,&samps_so_far,outfilename,outfnam,jj,dz))<0) return(exit_status); } //TW NEW: merge the 2 output files reset_file_params_for_sndout(&orig_proctype,&orig_srate,&orig_chans,&orig_stype,dz); for(jj=0;jj<2;jj++) { strcpy(outfilename,outfnam); insert_new_number_at_filename_end(outfilename,jj+1,0); if((dz->ifd[jj] = sndopenEx(outfilename,0,CDP_OPEN_RDONLY)) < 0) { sprintf(errstr,"Cannot reopen mono file '%s' to convert to stereo :%s\n", outfilename,sferrstr()); return(SYSTEM_ERROR); } } dz->insams[0] *= 2; dz->process_type = EQUAL_SNDFILE; dz->infile->channels = dz->outfile->channels = STEREO; dz->infile->filetype = SNDFILE; /* forces formatted sndfile creation */ strcpy(outfilename,outfnam); if(dz->floatsam_output) dz->infile->stype = SAMP_FLOAT; else dz->infile->stype = SAMP_SHORT; dz->infile->srate = round(dz->param[SS_SRATE]); dz->outfiletype = SNDFILE_OUT; orig_process = dz->process; dz->process = EDIT_CUT; /* any process creating a standard sound outfile */ dz->infile->srate = (int)round(dz->param[SS_SRATE]); if(sloom) /* TW 24/2/18 */ insert_new_number_at_filename_end(outfilename,0,0); if((exit_status = create_sized_outfile(outfilename,dz)) < 0) { sprintf(errstr,"Cannot open temporary soundfile '%s' to generate sound data:%s\n", outfilename,sferrstr()); return(SYSTEM_ERROR); } if((exit_status = reset_peak_finder(dz))<0) return(exit_status); dz->insams[0] /= 2; OK = 1; while(OK) { memset((char *)dz->bigfbuf,0,dz->buflen * sizeof(float)); memset((char *)dz->flbufptr[2],0,dz->buflen * sizeof(float)); memset((char *)dz->flbufptr[3],0,dz->buflen * sizeof(float)); if((samps_read1 = fgetfbufEx(dz->flbufptr[2],dz->buflen,dz->ifd[0],0))<=0) { if(samps_read1 < 0) { sprintf(errstr,"Sample read failed: "); for(jj=0;jj<2;jj++) { char pfname[_MAX_PATH]; strcpy(pfname, snd_getfilename(dz->ifd[jj])); sndcloseEx(dz->ifd[jj]); if(remove(/*outfilename*/pfname)<0) { fprintf(stdout,"WARNING: Tempfile %s not removed: ",outfilename); fflush(stdout); } } strcat(errstr,"\n"); return(SYSTEM_ERROR); } else break; } if((samps_read2 = fgetfbufEx(dz->flbufptr[3],dz->buflen,dz->ifd[1],0))<=0) { if(samps_read2< 0) { sprintf(errstr,"Sample read failed: "); for(jj=0;jj<2;jj++) { char pfname[_MAX_PATH]; strcpy(pfname, snd_getfilename(dz->ifd[jj])); sndcloseEx(dz->ifd[jj]); if(remove(/*outfilename*/pfname)<0) { fprintf(stdout,"WARNING: Tempfile %s not removed: ",outfilename); fflush(stdout); } } strcat(errstr,"\n"); return(SYSTEM_ERROR); } else break; } if((samps_read = min(samps_read1,samps_read2)) <= 0) break; #ifdef NOTDEF for(n = 0,k=0; n < samps_read-1;n++,k+=2) { dz->bigfbuf[k] = dz->flbufptr[2][n]; dz->bigfbuf[k+1] = dz->flbufptr[3][n]; } dz->bigfbuf[k] = dz->flbufptr[2][n]; #else for(n = 0,k=0; n < samps_read;n++,k+=2) { dz->bigfbuf[k] = dz->flbufptr[2][n]; dz->bigfbuf[k+1] = dz->flbufptr[3][n]; } #endif /* last samp remains in situ */ if((exit_status = write_samps(dz->bigfbuf,samps_read * 2,dz))<0) { sprintf(errstr,"Sample write failed: "); for(jj=0;jj<2;jj++) { char pfname[_MAX_PATH]; strcpy(pfname, snd_getfilename(dz->ifd[jj])); sndcloseEx(dz->ifd[jj]); if(remove(/*outfilename*/pfname)<0) { fprintf(stdout,"WARNING: Tempfile %s not removed: ",outfilename); fflush(stdout); } } strcat(errstr,"\n"); return(SYSTEM_ERROR); } } for(jj=0;jj<2;jj++) { /*RWD Feb 2004 */ char pfname[_MAX_PATH]; strcpy(pfname, snd_getfilename(dz->ifd[jj])); sndcloseEx(dz->ifd[jj]); if(remove(/*outfilename*/pfname)<0) { fprintf(stdout,"WARNING: Tempfile %s not removed: ",outfilename); fflush(stdout); } } dz->process = orig_process; // In order to correctly write header, process_type should remain EQUAL_SNDFILE // dz->process_type = OTHER_PROCESS; return(FINISHED); } /**** With cosinusoidal energy distribution ------------------------------------- DCF(dist-from-centre-frq) = fabs(frq - centre-frq) (range 0 - 1) ------------------- half-interval-spread To focus energy towards centre, we squeeze values towards position 0 -------------------------------------------------------------------- DCF^focus if(focus > 1) squeezes if(focus < 1) braodens ampscaler = (cos(CDF*PI) + 1)/2.0; ****/ /****************************** SET_BAND_LIMITS *************************/ void set_band_limits(int clength,int *supertight, double *bwidth, int *minchan, int *centrchan, double *hfbwidth, int *lo_n, int *hi_n, double *offset, double hfchwidth, dataptr dz) { int chancnt; double hifrq, lofrq, frqsprd; int lochan, hichan, chanspreadmin; if(dz->vflag[SS_PICHSPRD]) { if(dz->param[SS_SPREAD] < 1.0) dz->param[SS_SPREAD] = 1.0/dz->param[SS_SPREAD]; hifrq = min(dz->param[SS_CENTRFRQ] * dz->param[SS_SPREAD],dz->nyquist); lofrq = max(dz->param[SS_CENTRFRQ] / dz->param[SS_SPREAD],SPEC_MINFRQ); } else { hifrq = min(dz->param[SS_CENTRFRQ] + dz->param[SS_SPREAD],dz->nyquist); lofrq = max(dz->param[SS_CENTRFRQ] - dz->param[SS_SPREAD],SPEC_MINFRQ); } frqsprd = hifrq - lofrq; /* ESTABLISH WHICH CHANS INVOLVED */ lochan = (int)floor((lofrq + hfchwidth)/dz->chwidth) - 1; hichan = (int)floor((hifrq + hfchwidth)/dz->chwidth) - 1; //TW UPDATES lochan = max(lochan,0); hichan = max(hichan,0); chancnt = hichan - lochan + 1; chanspreadmin = (CHANUP * 2) + 1; if (chancnt < chanspreadmin) { chancnt = chanspreadmin; *bwidth = frqsprd/chanspreadmin; *centrchan = (int)floor((dz->param[SS_CENTRFRQ] + hfchwidth)/dz->chwidth) - 1; if(*centrchan - CHANUP < 0) *minchan = 0; else if (*centrchan + CHANUP > clength) *minchan = clength - chanspreadmin; else *minchan = *centrchan - CHANUP; *centrchan = *minchan + CHANUP; *supertight = 1; } else { *bwidth = dz->chwidth; *minchan = lochan; *supertight = 0; } *hfbwidth = (*bwidth)/2.0; if(*supertight) { *lo_n = 0; *hi_n = chancnt; *offset = lofrq; } else { *lo_n = lochan; *hi_n = hichan; *centrchan = (lochan + hichan)/2; *offset = -(*hfbwidth); } } //TW UPDATE: New Function /****************************** GEN_CLICKTRACK *************************/ #define LINE_TIMES (0) int gen_clicktrack(dataptr dz) { double *clikdata = dz->parray[0], *clik = dz->parray[1]; double amp, tottime; int n, m, j = 0, bufsamptime, bufsampendtime, samptime, tcnt = 0; float *buf = dz->sampbuf[0]; int k, exit_status; int from_start = 1; int to_end = 1; double click_ofset = 0.0, starttime_offset = 0.0; if(dz->mode == CLICK_BY_LINE) { if(dz->iparam[CLIKOFSET] > 0) click_ofset = dz->parray[2][dz->iparam[CLIKOFSET]]; dz->param[CLIKSTART] = dz->parray[2][dz->iparam[CLIKSTART]] - click_ofset; if(dz->iparam[CLIKEND] + 1 == dz->iparam[CLICKTIME]) dz->iparam[CLIKEND]++; else to_end = 0; dz->param[CLIKEND] = dz->parray[2][dz->iparam[CLIKEND]] - click_ofset; } if(sloom) { tottime = dz->param[CLIKEND] - dz->param[CLIKSTART]; if((dz->tempsize = (int)round(tottime * CLICK_SRATE)) < 0) { fprintf(stdout,"WARNING: File is too long to give accurate progress display on Progress Bar.\n"); fflush(stdout); dz->tempsize = INT_MAX; } } if(!flteq(dz->param[CLIKSTART],0.0)) from_start = 0; if(dz->iparam[CLIKOFSET] > 0) { click_ofset = dz->parray[2][dz->iparam[CLIKOFSET]]; if(!from_start) starttime_offset = dz->param[CLIKSTART] + click_ofset; dz->param[CLIKEND] += click_ofset; fprintf(stdout,"INFO: MUSIC STARTS %lf secs AFTER CLICKS\n",click_ofset); fflush(stdout); } else starttime_offset = dz->param[CLIKSTART]; for(n=dz->itemcnt-2;n >=0;n-=2) { /* throw away data beyond endtime of generating clicks */ if((dz->parray[0][n] < dz->param[CLIKEND]) || flteq(dz->parray[0][n],dz->param[CLIKEND])) { dz->itemcnt = n+2; break; } } if(!to_end) dz->itemcnt -= 2; if(!from_start) { /* throw away data before starttime of generating clicks */ while(dz->parray[0][0] < starttime_offset) { dz->parray[0]+=2; if((dz->itemcnt-=2) <= 0) { sprintf(errstr,"No click data found between the specified times.\n"); return(DATA_ERROR); } } for(n=0;n < dz->itemcnt;n+=2) /* and adjust data time values so generation starts at outfile starttime 0.0 */ dz->parray[0][n] -= starttime_offset; } if(dz->vflag[LINE_TIMES]) { tcnt = 0; /* skip over times-of-lines prior to start of click-generation */ while(dz->parray[2][tcnt] < starttime_offset) { if(++tcnt >= dz->iparam[CLICKTIME]) { sprintf(errstr,"Anomaly in data about timing of data lines.\n"); return(PROGRAM_ERROR); } } } clikdata = dz->parray[0]; memset((char *)buf,0,dz->buflen * sizeof(float)); for(n=0,m=1;nitemcnt;n+=2,m+=2) { samptime = (int)round(clikdata[n] * dz->infile->srate); if(dz->vflag[LINE_TIMES] && (tcnt < dz->iparam[CLICKTIME])) { if(flteq(dz->parray[2][tcnt],(clikdata[n] + starttime_offset))) { fprintf(stdout,"INFO: LINE %d at %lf\n",tcnt+1,(dz->parray[2][tcnt] - click_ofset)); fflush(stdout); tcnt++; } else if(dz->parray[2][tcnt] < (clikdata[n] + starttime_offset)) tcnt++; /* skips lines which start with unaccented beat */ } bufsamptime = samptime - dz->total_samps_written; while(bufsamptime >= dz->buflen) { if((exit_status = write_samps(dz->bigbuf,dz->buflen,dz))<0) return(exit_status); memset((char *)buf,0,dz->buflen * sizeof(float)); bufsamptime = samptime - dz->total_samps_written; } bufsampendtime = bufsamptime + CLICKLEN + 1; amp = clikdata[m]; k = 0; if(bufsampendtime <= dz->buflen) { for(j = bufsamptime; j < bufsampendtime; j++) buf[j] = (float)((double)clik[k++] * amp); } else { for(j = bufsamptime; j < dz->buflen; j++) buf[j] = (float)((double)clik[k++] * amp); if((exit_status = write_samps(dz->bigbuf,dz->buflen,dz))<0) return(exit_status); memset((char *)buf,0,dz->buflen * sizeof(float)); j = 0; while(k <= CLICKLEN) buf[j++] = (float)((double)clik[k++] * amp); } } if(j > 0) { if((exit_status = write_samps(dz->bigbuf,j,dz))<0) return(exit_status); } return(FINISHED); } /****************************** GEN_CHORD *************************/ #define JITTER_RANGE (1.0) #define JITTERSTEP (8) int gen_chord(int sampdur,dataptr dz) { int exit_status; double dtabsize = (double)dz->iparam[SYN_TABSIZE]; int m, n, k, kk; int chans = dz->infile->channels; double amp = dz->param[SYN_AMP]; double *tab = dz->parray[SYNTH_TAB]; double val; int do_start = 1, jittercnt = 0; int synth_splicelen = SYNTH_SPLICELEN * chans; int total_samps = 0; int startj = 0, endj = SYNTH_SPLICELEN, this_chordend, this_chordstart, thischord_notecnt; int total_samps_left = sampdur; int endsplicestart = sampdur - synth_splicelen; int todo = 0, total_samps_done; double *step = dz->parray[1]; double *pos = dz->parray[2]; double *fracstep = dz->parray[3]; int *samppos = dz->lparray[0]; double *jitter=NULL, *lastjitter=NULL, *thisjitstep=NULL, *thisjitter=NULL; if ((jitter = (double *)malloc(dz->itemcnt * sizeof(double)))==NULL) { fprintf(stdout,"WARNING: Insufficient memory to add jitter.\n"); fflush(stdout); } else if ((thisjitter = (double *)malloc(dz->itemcnt * sizeof(double)))==NULL) { fprintf(stdout,"WARNING: Insufficient memory (2) to add jitter.\n"); fflush(stdout); } else if ((lastjitter = (double *)malloc(dz->itemcnt * sizeof(double)))==NULL) { fprintf(stdout,"WARNING: Insufficient memory (3) to add jitter.\n"); fflush(stdout); } else if ((thisjitstep = (double *)malloc(dz->itemcnt * sizeof(double)))==NULL) { fprintf(stdout,"WARNING: Insufficient memory (4) to add jitter.\n"); fflush(stdout); } else { for(n=0;nitemcnt;n++) { jitter[n] = step[n] * (pow(SEMITONE_INTERVAL,JITTER_RANGE) - 1.0); /* Jitter within 0.5 of a semitone */ lastjitter[n] = 0.0; thisjitter[n] = ((drand48() * 2.0) - 1.0) * jitter[n]; /* +- within jitter range */ thisjitstep[n] = thisjitter[n]/(double)JITTERSTEP; } } if(sampdur < (synth_splicelen * 2) + chans) { fprintf(stdout,"ERROR: Specified output duration is less then available splicing length.\n"); return(DATA_ERROR); } if(dz->ringsize > 1) { total_samps_left = (int)round((double)(sampdur/chans)/(double)dz->ringsize) * chans; total_samps_done = 0; m = 0; this_chordend = -1; for(kk=0; kk < dz->ringsize; kk++) { do_start = 1; startj = 0; endj = SYNTH_SPLICELEN; if(kk == dz->ringsize - 1) total_samps_left = sampdur - total_samps_done; endsplicestart = total_samps_left - synth_splicelen; this_chordend++; this_chordstart = this_chordend; while(step[this_chordend] > 0) { if(++this_chordend >= dz->itemcnt) break; } thischord_notecnt = this_chordend - this_chordstart; todo = min(m + total_samps_left,dz->buflen); total_samps = 0; while(total_samps_left > 0) { while(m < todo) { val = 0.0; for(n=this_chordstart;n < this_chordend;n++) val += getval(tab,samppos[n],fracstep[n],amp); val /= (double)thischord_notecnt; if(do_start) { val *= (startj++/(double)SYNTH_SPLICELEN); if(startj >= SYNTH_SPLICELEN) do_start = 0; } if(total_samps >= endsplicestart) val *= (endj--/(double)SYNTH_SPLICELEN); for(k=0;kbigbuf[m++] = (float)val; total_samps++; total_samps_done++; } if(jitter != NULL) { if(++jittercnt >= JITTERSTEP) { for(n=this_chordstart;n= dtabsize) pos[n] -= dtabsize; samppos[n] = (int)pos[n]; fracstep[n] = pos[n] - (double)samppos[n]; } } total_samps_left -= todo; if(m >= dz->buflen) { if((exit_status = write_samps(dz->bigbuf,dz->buflen,dz))<0) return(exit_status); todo = min(total_samps_left,dz->buflen); m = 0; } } } if(todo > 0) { if((exit_status = write_samps(dz->bigbuf,todo,dz))<0) return(exit_status); } } else { while(total_samps_left > 0) { if(total_samps_left/dz->buflen <= 0) todo = total_samps_left; else todo = dz->buflen; m = 0; while(m < todo) { val = 0.0; for(n=0;n < dz->itemcnt;n++) val += getval(tab,samppos[n],fracstep[n],amp); val /= (double)dz->itemcnt; if(do_start) { val *= (startj++/(double)SYNTH_SPLICELEN); if(startj >= SYNTH_SPLICELEN) do_start = 0; } if(total_samps >= endsplicestart) val *= (endj--/(double)SYNTH_SPLICELEN); for(k=0;kbigbuf[m++] = (float)val; total_samps++; } if(jitter != NULL) { if(++jittercnt >= JITTERSTEP) { for(n=0;nitemcnt;n++) { lastjitter[n] = thisjitter[n]; thisjitter[n] = ((drand48() * 2.0) - 1.0) * jitter[n]; /* +- within jitter range */ thisjitstep[n] = (thisjitter[n] - lastjitter[n])/(double)JITTERSTEP; } jittercnt = 0; } } for(n=0;nitemcnt;n++) { pos[n] += step[n]; if(jitter != NULL) pos[n] += thisjitstep[n]; while(pos[n] >= dtabsize) pos[n] -= dtabsize; samppos[n] = (int)pos[n]; fracstep[n] = pos[n] - (double)samppos[n]; } } if((exit_status = write_samps(dz->bigbuf,todo,dz))<0) return(exit_status); total_samps_left -= dz->buflen; } } return(FINISHED); }