/* * Copyright (c) 1983-2013 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 * */ /* floatsam version */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include //#ifdef unix #define round(x) lround((x)) //#endif static int do_wrap(int samps_to_wrap,dataptr dz); static int read_rest_of_file(int initial_bufsize,dataptr dz); static int pluck(dataptr dz); static int envsyn_env(int *phase,int cyclestart,int *cycle_end,double one_less_trof,dataptr dz); static int envsyn_troffed(int cyclestart,int *cyclend,double one_less_trof,int *phase,dataptr dz); static int envsyn_userdef(int cyclestart,int *cyclend,int *phase,dataptr dz); static int envsyn_rising( int cyclestart,int *cyclend,double one_less_trof,int *phase,dataptr dz); static int envsyn_falling(int cyclestart,int *cyclend,double one_less_trof,int *phase,dataptr dz); static double do_firsthalf_trof(int k,int cyclehlf,double one_less_trof,dataptr dz); static double do_lasthalf_trof(int k,int cyclehlf,double one_less_trof,dataptr dz); static double do_rising(int k,int cyclelen,double one_less_trof,dataptr dz); static double do_falling(int k,int cyclelen,double one_less_trof,dataptr dz); static int read_from_user_envelope(double *env_val,double table_index,int init,dataptr dz); /****************************** ENVELOPE_PLUCK *************************/ int envelope_pluck(dataptr dz) { int exit_status; int initial_bufsize; int first_read_offset = dz->sampbuf[PLK_INITBUF] - dz->bigbuf; dz->buflen -= first_read_offset; /* size of buffer from where first read takes place */ if((exit_status = read_samps(dz->sampbuf[PLK_INITBUF],dz))<0) return(exit_status); initial_bufsize = dz->buflen; if((exit_status = pluck(dz))<0) return(exit_status); dz->buflen = dz->iparam[ENV_PLK_OBUFLEN]; /* size of buffer for subsequent reads */ return read_rest_of_file(initial_bufsize,dz); } /**************************** PLUCK ****************************** * * (1) goalbufend is the last sample of the cycle in the input file buffer from which we will * derive the pluck attack. We read it backwards, from this LAST sample. * (2) The outplukptr points to the position in the output buffer where we * are WRITING pluck-form wavecycles. We write these BKWDS * from here to start of dz->sampbuf[PLK_OUTBUF]. * (3) Set goalbufptr to start(i.e. end!!) of goalbuf. * (4) Inverse_index is a BACKWARDS count of the samples in the pluck. * (5) For each wavecycle of Pluck attack.. * (6) For each sample in wavecycle.... * (7) Noiselevel is directly proportional to distance (bkwds) into pluck. * (8) Then reduced via exponential curve. * (9) Becoming this fraction of the maximum amplitude. * (10) Noise input itself is a random value in range +- this noiselevel value. * (11) Reinitialise goalbufptr for eack wavecycle. * (13a)By the time we reach the start of the pluck, signal will cause# * spurious foldover when added to orig signal: but this will simply make * it more like noise!! * (12) Calculate sample length of initial risetime. * (13) Finally, envelope start of pluck!! */ int pluck(dataptr dz) { int n, m, inverse_index; float *goalbufend, *goalbufptr, *outplukptr; double noise_level; /*int*/double thisnoise; int startup; int pluklen = dz->iparam[ENV_PLK_CYCLEN] * dz->iparam[ENV_PLK_WAVELEN]; if((goalbufend = dz->sampbuf[PLK_PLUKEND] + dz->iparam[ENV_PLK_WAVELEN] - 1) >=dz->sampbuf[PLK_BUFEND]) { sprintf(errstr,"End of goal pluck_cycle falls outside buffer: Insufficient memory to proceed.\n"); return(GOAL_FAILED); /* 1 */ } if((outplukptr = dz->sampbuf[PLK_PLUKEND] - 1) < dz->bigbuf) { /* 2 */ sprintf(errstr,"Buffer accounting problem.\n"); return(PROGRAM_ERROR); } goalbufptr = goalbufend; /* 3 */ inverse_index = 0; /* 4 */ for(n=0;niparam[ENV_PLK_CYCLEN];n++) { /* 5 */ for(m=0;miparam[ENV_PLK_WAVELEN];m++) { /* 6 */ noise_level = (double)inverse_index/(double)pluklen; /* 7 */ noise_level = pow(noise_level,dz->param[ENV_PLK_DECAY]); /* 8 */ noise_level = noise_level * (double)F_MAXSAMP; /* 9 */ thisnoise = /*round*/ (((drand48() * 2.0) - 1.0) * noise_level); /* 10 */ *outplukptr = (float)((*goalbufptr) + thisnoise); outplukptr--; goalbufptr--; inverse_index++; } goalbufptr = goalbufend; /* 11 */ } startup = round(ENV_PLK_ONSET_TIME * MS_TO_SECS * (double)dz->infile->srate); /* 12 */ startup = min(startup,dz->iparam[ENV_PLK_CYCLEN] * dz->iparam[ENV_PLK_WAVELEN]); for(n=0;niparam[ENV_PLK-STSAMP]) * PLUS the added initial segment (dz->iparam[ENV_PLK_OWRAPLEN]). * ELSE * (3) Write a standard buffer_full, from start of obuf_preflow (where pluck has been constructed). * (4) This leaves, [ENV_PLK_OWRAPLEN] samples in end of dz->sampbuf[PLK_OUTBUF], * SO samps_to_wrap = [ENV_PLK_OWRAPLEN]; * (6) Do the wrap-around. * (8) Whilst ever there is something in wrap-around part of buffer... * (10) Try to read more samples (may get full-buff, part-buf * or zero if file already exhausted). * (11) Total samps to write is the wrapped samps plus those just read. * (12) If this leaves no samps to wrap (i.e. buffer is NOT full, therefore FILE must be exhausted), * write all these samps to out and quit. * (13) ELSE, write a bufferfull and do another wrap-around. */ int read_rest_of_file(int initial_bufsize,dataptr dz) { int exit_status; int samps_to_write, samps_to_wrap; int pluklen = dz->iparam[ENV_PLK_CYCLEN] * dz->iparam[ENV_PLK_WAVELEN]; if(dz->ssampsread < (int)(initial_bufsize)) { /* 1 */ if((samps_to_write = dz->ssampsread - dz->iparam[ENV_PLK_ENDSAMP] + pluklen)>0) { /* 2 */ if((exit_status = write_samps(dz->sampbuf[PLK_OUTBUF],samps_to_write,dz))<0) return(exit_status); } } else { if((exit_status = write_samps(dz->sampbuf[PLK_OUTBUF],dz->buflen,dz))<0) /* 3 */ return(exit_status); samps_to_wrap = dz->iparam[ENV_PLK_OWRAPLEN]; /* 4 */ if((exit_status = do_wrap(samps_to_wrap,dz))<0) /* 6 */ return(exit_status); while(samps_to_wrap > 0) { /* 8 */ if((exit_status = read_samps(dz->sampbuf[PLK_INBUF],dz))<0) /* 10 */ return(exit_status); samps_to_write = samps_to_wrap + dz->ssampsread; /* 11 */ if((samps_to_wrap = samps_to_write - dz->buflen) <= 0) { /* 12 */ if(samps_to_write > 0) { if((exit_status = write_samps(dz->sampbuf[PLK_OUTBUF],samps_to_write,dz))<0) return(exit_status); } } else { if((exit_status = write_samps(dz->sampbuf[PLK_OUTBUF],dz->buflen,dz))<0) /* 13 */ return(exit_status); if((exit_status = do_wrap(samps_to_wrap,dz))<0) return(exit_status); } } } return(FINISHED); } /*********************** DO_WRAP ************************/ int do_wrap(int samps_to_wrap,dataptr dz) { memmove((char *)dz->sampbuf[PLK_OUTBUF],(char *)dz->sampbuf[PLK_OBUFWRAP],(samps_to_wrap)*sizeof(float)); return(FINISHED); } /************************** ENVSYN **************************/ int envsyn(dataptr dz) { int exit_status; int current_pos = 0, cyclelen, cycle_end, done = 0; int phase, initial_phase; double thistime = 0.0, one_less_trof; int samps_needed; dz->param[ENVSYN_WSIZE] *= MS_TO_SECS; samps_needed = (int)floor((dz->param[ENVSYN_DUR]/ dz->param[ENVSYN_WSIZE]) + 1); dz->tempsize = samps_needed * sizeof(float); if((exit_status = read_values_from_all_existing_brktables(thistime,dz)) < 0) return(exit_status); one_less_trof = 1.0 - dz->param[ENVSYN_TROF]; cyclelen = (int)round(dz->param[ENVSYN_CYCLEN]/dz->param[ENVSYN_WSIZE]); cycle_end = cyclelen; phase = (int)round((double)cyclelen * dz->param[ENVSYN_STARTPHASE]); initial_phase = phase; for (;;) { if(cyclelen < 2) { sprintf(errstr,"ENVELOPE DURATION TOO SHORT FOR WINDOWSIZE at time %lf\n", (dz->total_samps_written + current_pos) * dz->param[ENV_WSIZE]); return(DATA_ERROR); } if((exit_status = envsyn_env(&phase,current_pos,&cycle_end,one_less_trof,dz))< 0) return(exit_status); if((done += cyclelen) >= samps_needed + initial_phase) break; thistime += dz->param[ENVSYN_CYCLEN]; if((exit_status = read_values_from_all_existing_brktables(thistime,dz)) < 0) return(exit_status); one_less_trof = 1.0 - dz->param[ENVSYN_TROF]; cyclelen = (int)round(dz->param[ENVSYN_CYCLEN]/dz->param[ENVSYN_WSIZE]); current_pos = cycle_end; cycle_end = current_pos + cyclelen; } if(cycle_end > 0) { if((exit_status = write_samps(dz->flbufptr[0],cycle_end,dz))<0) return(exit_status); } return(FINISHED); } /************************** ENVSYN_ENV **************************/ int envsyn_env(int *phase,int cyclestart,int *cycle_end,double one_less_trof,dataptr dz) { switch(dz->mode) { case(ENVSYN_TROFFED): return envsyn_troffed(cyclestart,cycle_end,one_less_trof,phase,dz); case(ENVSYN_USERDEF): return envsyn_userdef(cyclestart,cycle_end,phase,dz); case(ENVSYN_RISING): return envsyn_rising(cyclestart,cycle_end,one_less_trof,phase,dz); case(ENVSYN_FALLING): return envsyn_falling(cyclestart,cycle_end,one_less_trof,phase,dz); default: sprintf(errstr,"Unknown case: envsyn_env()\n"); return(PROGRAM_ERROR); } return(CONTINUE); } /************************** ENVSYN_TROFFED *******************************/ int envsyn_troffed(int cyclestart,int *cyclend,double one_less_trof,int *phase,dataptr dz) { int exit_status; register int k = 0, j = cyclestart; int cyclelen = *cyclend - cyclestart; int cyclehlf = cyclelen/2; int cyclemid = cyclestart + cyclehlf; float *b = dz->flbufptr[0]; if(*phase > 0) { if(*phase >= cyclehlf) { cyclemid = -1; k = (*phase - cyclehlf); } else { cyclemid -= *phase; k = *phase; } (*cyclend) -= *phase; *phase = 0; } while(j= dz->buflen) { if((exit_status = write_samps(b,dz->buflen,dz))<0) return(exit_status); j = 0; *cyclend -= dz->buflen; } } if(cyclemid >= 0) k = 0; cyclehlf = cyclelen - cyclehlf; while(j < *cyclend) { b[j] = (float)do_lasthalf_trof(k,cyclehlf,one_less_trof,dz); k++; j++; if(j >= dz->buflen) { if((exit_status = write_samps(b,dz->buflen,dz))<0) return(exit_status); j = 0; *cyclend -= dz->buflen; } } return(FINISHED); } /*************************** ENVSYN_USERDEF ***************************/ int envsyn_userdef(int cyclestart,int *cyclend,int *phase,dataptr dz) { int exit_status; register int k = 0, j = cyclestart; int cyclelen = *cyclend - cyclestart; double index; double z; int init = 1; float *b = dz->flbufptr[0]; if(*phase > 0) { k = *phase; (*cyclend) -= *phase; *phase = 0; } while(j<*cyclend) { index = (double)k/(double)cyclelen; if((exit_status = read_from_user_envelope(&z,index,init,dz))<0) return(exit_status); b[j] = (float)z; k++; j++; if(j >= dz->buflen) { if((exit_status = write_samps(b,dz->buflen,dz))<0) return(exit_status); j = 0; *cyclend -= dz->buflen; } init = 0; } return(FINISHED); } /*************************** ENVSYN_RISING ***********************/ int envsyn_rising(int cyclestart,int *cyclend,double one_less_trof,int *phase,dataptr dz) { int exit_status; register int k = 0, j = cyclestart; int cyclelen = *cyclend - cyclestart; float *b = dz->flbufptr[0]; if(*phase > 0) { k = *phase; (*cyclend) -= *phase; *phase = 0; } while(j<*cyclend) { b[j] = (float)do_rising(k,cyclelen - 1,one_less_trof,dz); k++; j++; if(j >= dz->buflen) { if((exit_status = write_samps(b,dz->buflen,dz))<0) return(exit_status); j = 0; *cyclend -= dz->buflen; } } return(FINISHED); } /********************** ENVSYN_FALLING *************************/ int envsyn_falling(int cyclestart,int *cyclend,double one_less_trof,int *phase,dataptr dz) { int exit_status; register int k = 0, j = cyclestart; int cyclelen = *cyclend - cyclestart; float *b = dz->flbufptr[0]; if(*phase > 0) { k = *phase; (*cyclend) -= *phase; *phase = 0; } while(j<*cyclend) { b[j] = (float)do_falling(k,cyclelen - 1,one_less_trof,dz); k++; j++; if(j >= dz->buflen) { if((exit_status = write_samps(b,dz->buflen,dz))<0) return(exit_status); j = 0; *cyclend -= dz->buflen; } } return(FINISHED); } /******************* DO_FIRSTHALF_TROF **************************/ double do_firsthalf_trof(int k,int cyclehlf,double one_less_trof,dataptr dz) { double z = 1.0 - ((double)k/(double)cyclehlf); z = (pow(z,dz->param[ENVSYN_EXPON]) * one_less_trof) + dz->param[ENVSYN_TROF]; return (z); } /******************* DO_LASTHALF_TROF **************************/ double do_lasthalf_trof(int k,int cyclehlf,double one_less_trof,dataptr dz) { double z = (double)k/(double)cyclehlf; z = (pow(z,dz->param[ENVSYN_EXPON]) * one_less_trof) + dz->param[ENVSYN_TROF]; return(z); } /************************ DO_RISING_TROFFED *******************************/ double do_rising(int k,int cyclelen,double one_less_trof,dataptr dz) { double z = (double)k/(double)cyclelen; z = pow(z,dz->param[ENVSYN_EXPON]); z *= one_less_trof; z += dz->param[ENVSYN_TROF]; return(z); } /************************ DO_FALLING_TROFFED *******************************/ double do_falling(int k,int cyclelen,double one_less_trof,dataptr dz) { double z; z = 1.0 - ((double)k/(double)cyclelen); z = (pow(z,dz->param[ENVSYN_EXPON]) * one_less_trof) + dz->param[ENVSYN_TROF]; return z; } /************************ READ_FROM_USER_ENVELOPE *******************************/ int read_from_user_envelope(double *env_val,double table_index,int init,dataptr dz) { double *p; double hi_env, lo_env, hi_index, lo_index; double env; if(init) dz->ptr[ENVSYN_ENV] = dz->parray[ENVSYN_ENV]; p = dz->ptr[ENVSYN_ENV]; while(table_index > *p) { if((p += 2) >= dz->ptr[ENVSYN_ENVEND]) { sprintf(errstr,"Problem reading user envelope data: read_from_user_envelope()\n"); return(PROGRAM_ERROR); } } if(p != dz->parray[ENVSYN_ENV]) { hi_env = *(p+1); hi_index = *p; lo_env = *(p-1); lo_index = *(p-2); env = (double)((table_index - lo_index)/(hi_index - lo_index)); env *= (double)(hi_env - lo_env); env += (double)lo_env; } else env = *(p+1); dz->ptr[ENVSYN_ENV] = p; *env_val = env; return(FINISHED); }