/* * 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 #define MARGIN (16) #define IS_CLICK (1.0/(3.0 * MS_TO_SECS)) /* from zero to full amplitude in 3ms */ /* anything faster is a 'click'!! */ #define MINSPAN (16) /* spanning points for creating exponential env */ #define ATTEN (3.33333333) /* Attenuation for creating exponential env */ #define ATTENATOR (1.7) /* Attenuation for creating exponential env */ #define STEEP_ATTEN (2.0) /* For ATTACK */ static int realloc_envcreate_tables(int tabsize,dataptr dz); static int envnorm(float *env,float *envend); static int envceiling(float *env,float *envend); static int envduck(float *env,float *envend,dataptr dz); static int envrevers(float *env,float *envend); static int envexagg(float *env,float *envend,dataptr dz); static int envatten(float *env,float *envend,dataptr dz); static int envlift(float *env,float *envend,dataptr dz); static int envtstretch(float **env,float **envend,dataptr dz); static int envflatn(float *env,float *envend,dataptr dz); static int envgate(float *env,float *envend,dataptr dz); static int envinvert(float *env,float *envend,dataptr dz); static int envexpand(float *env,float *envend,dataptr dz); static int envlimit(float *env,float *envend,dataptr dz); static int envkorrug(float *env,float *envend,dataptr dz); static int envpeakcnt(float *env,float *envend,dataptr dz); static int envtrig(float **env,float **envend,dataptr dz); static int envshortn(float **env,float **envend,double timestretch); static int envlenthn(float **env,float **envend,double timestretch); static float envintpl(double here,double winbase,double base,double next); static void brkdeglitch(double *,double **); static int gen_trigger_envelope(double **brk, double **brkend,dataptr dz); static int gen_reapplied_trigger_envelope(double **brk, double **brkend,dataptr dz); static int gatefilt(float *p,float *envend,double gate,int smoothing); static int do_simple_gating(float *env,float *envend,dataptr dz); static int do_smoothed_gating(float *env,float *envend,int smoothing,dataptr dz); static void do_env_invert(float *p,double upratio,double dnratio,dataptr dz); static void do_expanding(float *p,float *envend,int *gating,double squeeze,int smoothing,dataptr dz); static void digout_trough(float *env,float *envend,float *shadowenv,int del,float *q); static int ispeak(float *env,float *envend,float *q,int width); static int istrough(float *env,float *envend,float *q,int width); static int enlarge_brktable(double **brk,double **brkend, double **q,int *arraysize); static void convert_to_on_triggers(double now,double timestep,double rise,int *triggered,double **q); static int round_off_brktable(double *q,double **brk,double **brkend,double envlen); static int locate_and_size_triggers(float *env,float *envend,double **brk,double **brkend,dataptr dz); static int convert_other_brktable_to_envtable(double *brk,double *brkend,float **env,float **envend,dataptr dz); static float read_a_val_from_brktable(double *brk,double *brkend,double thistime); /*************************** ENVELOPE_WARP ************************/ int envelope_warp(float **env,float **envend,dataptr dz) { int exit_status; if(flteq((double)dz->outfile->window_size,0.0)) { sprintf(errstr,"dz->outfile->wsize not set: envelope_warp()\n"); return(PROGRAM_ERROR); } if(dz->process!=ENV_WARPING && dz->process!=ENV_REPLOTTING && dz->process!=ENV_RESHAPING) { sprintf(errstr,"this function not valid with this process: envelope_warp()\n"); return(PROGRAM_ERROR); } switch(dz->mode) { case(ENV_NORMALISE): exit_status = envnorm(*env,*envend); break; case(ENV_REVERSE): exit_status = envrevers(*env,*envend); break; case(ENV_EXAGGERATING): exit_status = envexagg(*env,*envend,dz); break; case(ENV_ATTENUATING): exit_status = envatten(*env,*envend,dz); break; case(ENV_LIFTING): exit_status = envlift(*env,*envend,dz); break; case(ENV_TSTRETCHING): exit_status = envtstretch(env,envend,dz); break; case(ENV_FLATTENING): exit_status = envflatn(*env,*envend,dz); break; case(ENV_GATING): exit_status = envgate(*env,*envend,dz); break; case(ENV_INVERTING): exit_status = envinvert(*env,*envend,dz); break; case(ENV_EXPANDING): exit_status = envexpand(*env,*envend,dz); break; case(ENV_LIMITING): exit_status = envlimit(*env,*envend,dz); break; case(ENV_CORRUGATING): exit_status = envkorrug(*env,*envend,dz); break; case(ENV_TRIGGERING): exit_status = envtrig(env,envend,dz); break; case(ENV_CEILING): exit_status = envceiling(*env,*envend); break; case(ENV_DUCKED): exit_status = envduck(*env,*envend,dz); break; case(ENV_PEAKCNT): exit_status = envpeakcnt(*env,*envend,dz); break; default: sprintf(errstr,"Unknown case in envelope_warp()\n"); return(PROGRAM_ERROR); } return(exit_status); } /*************************** ENVNORM ************************/ int envnorm(float *env,float *envend) { float *p = env; double convertor, maxval = 0.0; while(p < envend) { maxval = max(*p,maxval); p++; } if(flteq(maxval,0.0)) { sprintf(errstr,"Envelope level is effectively zero: cannot normalise.\n"); return(DATA_ERROR); } p = env; convertor = 1.0/maxval; while(p < envend) { *p = (float)((*p) * convertor); *p = (float)min(*p,1.0); /* SAFETY */ p++; } return(FINISHED); } /*************************** ENVCEILING ************************/ int envceiling(float *env,float *envend) { float *p = env; double maxval = 0.0; while(p < envend) { maxval = max(*p,maxval); p++; } p = env; while(p < envend) { *p = (float)maxval; p++; } return(FINISHED); } /*************************** ENVDUCK ************************/ int envduck(float *env,float *envend,dataptr dz) { int exit_status; float *p = env; double thistime = 0.0; double timestep = dz->outfile->window_size * MS_TO_SECS; switch(dz->process) { case(ENV_WARPING): while(p < envend) { if((exit_status = read_values_from_all_existing_brktables(thistime,dz))<0) return(exit_status); if(*p > dz->param[ENV_THRESHOLD]) *p = (float)dz->param[ENV_GATE]; thistime += timestep; p++; } break; case(ENV_RESHAPING): case(ENV_REPLOTTING): while(p < envend) { if((exit_status = read_values_from_all_existing_brktables(thistime,dz))<0) return(exit_status); if(*p > dz->param[ENV_THRESHOLD]) *p = (float)dz->param[ENV_GATE]; else *p = 1.0f; thistime += timestep; p++; } break; default: sprintf(errstr,"Unknown case in envduck()\n"); return(PROGRAM_ERROR); } return(FINISHED); } /*************************** ENVREVERS ************************/ int envrevers(float *env,float *envend) { float *p = env, *q = envend - 1; float temp; while(q > p) { temp = *p; *p = *q; *q = temp; p++; q--; } return(FINISHED); } /*************************** ENVEXAGG ************************/ int envexagg(float *env,float *envend,dataptr dz) { int exit_status; float *p = env; double thistime = 0.0; double timestep = dz->outfile->window_size * MS_TO_SECS; if(dz->brk[ENV_EXAG]) { while(pparam[ENV_EXAG]); p++; thistime += timestep; } } else { while(pparam[ENV_EXAG]); p++; } } return(FINISHED); } /*************************** ENVATTEN *************************/ int envatten(float *env,float *envend,dataptr dz) { int exit_status; float *p = env; double thistime = 0.0; double timestep = dz->outfile->window_size * MS_TO_SECS; if(dz->brk[ENV_ATTEN]) { while(pparam[ENV_ATTEN]); p++; thistime += timestep; } } else { while(pparam[ENV_ATTEN]); p++; } } return(FINISHED); } /*************************** ENVLIFT ************************/ int envlift(float *env,float *envend,dataptr dz) { int exit_status; float *p = env; int saturated = 0; double thistime = 0.0; double timestep = dz->outfile->window_size * MS_TO_SECS; if(dz->brk[ENV_ATTEN]) { while(pparam[ENV_LIFT]))> 1.0) { *p = 1.0f; saturated++; } p++; thistime += timestep; } } else { while(pparam[ENV_LIFT]))> 1.0) { *p = 1.0f; saturated++; } p++; } } if(saturated) { fprintf(stdout,"WARNING: Envelope was clipped, but will not distort sounds.\n"); fflush(stdout); } return(FINISHED); } /**************************** ENVTSTRETCH **************************/ int envtstretch(float **env,float **envend,dataptr dz) { int exit_status; double timestretch = dz->param[ENV_TSTRETCH]; if(dz->brksize[ENV_TSTRETCH]) { sprintf(errstr,"Invalid use of brktable: envtstretch()\n"); return(PROGRAM_ERROR); } if(timestretch>1.0) { if((exit_status = envlenthn(env,envend,timestretch))<0) return(exit_status); } if(timestretch<1.0) { if((exit_status = envshortn(env,envend,timestretch))<0) return(exit_status); } return(FINISHED); } /**************************** ENVSHORTN **************************/ int envshortn(float **env,float **envend,double timestretch) { int oldenvlen, newenvlen; int n, m = 0; float *nuenv, *p; double here, skip, base, winbase, next; skip = 1.0/timestretch; oldenvlen = *envend - *env; newenvlen = (int)(((double)oldenvlen * timestretch) + 1.0); /* rescale & round up */ newenvlen += MARGIN; if((nuenv = (float *)malloc(newenvlen*sizeof(float)))==NULL) { sprintf(errstr,"INSUFFICIENT MEMORY to create new envelope array.\n"); return(MEMORY_ERROR); } p = nuenv; *p++ = **env; for(;;) { if(++m > newenvlen) { sprintf(errstr,"New envelope array bound exceeded in envshortn()\n"); return(PROGRAM_ERROR); } here = skip * (double)(m); if(here>=(double)(oldenvlen-1)) { *p = *(p-1); newenvlen = p - nuenv; free(*env); if((*env = (float *)realloc(nuenv,newenvlen*sizeof(float)))==NULL) { sprintf(errstr,"envshortn(): 2\n"); return(MEMORY_ERROR); } *envend = *env + newenvlen; break; } winbase = floor(here); n = round(winbase); base = (double)*((*env) + n); if(n > oldenvlen-1) next = base; else next = (double)*((*env) + n + 1); *p++ = envintpl(here,winbase,base,next); } return(FINISHED); } /**************************** ENVLENTHN ***************************/ int envlenthn(float **env,float **envend,double timestretch) { int oldenvlen, newenvlen; int n = 0, m = 0; double here = 0.0, skip; float *nuenv, *p; double base, winbase, next; skip = 1.0/timestretch; oldenvlen = *envend - *env; newenvlen = (int)(((double)oldenvlen * timestretch) + 1.0); newenvlen += MARGIN; if((nuenv = (float *)malloc(newenvlen * sizeof(float)))==NULL) { sprintf(errstr,"INSUFFICIENT MEMORY to create new envelope array.\n"); return(MEMORY_ERROR); } p = nuenv; next = (double)**env; for(;;) { base = next; winbase = (double)n; if(++n > oldenvlen-1) { if(!m) { sprintf(errstr,"Anomaly in envlenthn()\n"); return(PROGRAM_ERROR); } newenvlen = p - nuenv; free(*env); if((*env = (float *)realloc(nuenv,newenvlen*sizeof(float)))==NULL) { sprintf(errstr,"INSUFFICIENT MEMORY to reallocate new envelope array.\n"); return(MEMORY_ERROR); } *envend = *env + newenvlen; break; } next = (double)*((*env) + n); while(here <= (double)n) { *p++ = envintpl(here,winbase,base,next); here = skip * (double)(++m); if(m >= newenvlen) { sprintf(errstr,"envlenthn(): New array bounds exceeded\n"); return(PROGRAM_ERROR); } } } return(FINISHED); } /*************************** ENVINTPL ****************************/ float envintpl(double here,double winbase,double base,double next) { double tratio = here - winbase; double valdif = next - base; double val = base + (tratio * valdif); return((float)val); } /*************************** ENVFLATN *************************/ int envflatn(float *env, float *envend, dataptr dz) { int exit_status; float *p, *q, *z, *nuenv; int envlen = envend - env, ppos, qpos; int backovflow, fowdovflow, thisback, n; double thistime = 0.0; double d, sum; double timestep = dz->outfile->window_size * MS_TO_SECS; int maxflatn; if(dz->brksize[ENV_FLATN]) { if((exit_status = get_maxvalue_in_brktable(&d,ENV_FLATN,dz))<0) return(exit_status); maxflatn = round(d); } else maxflatn = dz->iparam[ENV_FLATN]; if(maxflatn >= envlen) { sprintf(errstr,"Flattening param too large for infile.\n"); return(DATA_ERROR); } if((nuenv=(float *)malloc((envlen + maxflatn)*sizeof(float)))==NULL) { sprintf(errstr,"INSUFFICIENT MEMORY to create new envelope array.\n"); return(MEMORY_ERROR); } backovflow = maxflatn/2; fowdovflow = maxflatn - backovflow - 1; p = env; q = nuenv; for(n=0;nbrksize[ENV_FLATN]) { while(p < envend) { if((exit_status = read_value_from_brktable(thistime,ENV_EXAG,dz))<0) return(exit_status); thisback = dz->iparam[ENV_FLATN]/2; ppos = p - env; qpos = ppos + backovflow - thisback; z = nuenv + qpos; sum = 0.0; for(n=0;niparam[ENV_FLATN];n++) sum += *z++; sum /= (double)dz->iparam[ENV_FLATN]; *p++ = (float)sum; thistime += timestep; } } else { while(p < envend) { z = q++; sum = 0.0; for(n=0;niparam[ENV_FLATN];n++) sum += *z++; sum /= (double)dz->iparam[ENV_FLATN]; *p++ = (float)sum; } } free(nuenv); return(FINISHED); } /********************************* ENVGATE ****************************/ int envgate(float *env,float *envend,dataptr dz) { int exit_status; int smoothing = dz->iparam[ENV_SMOOTH]; if(smoothing==0) exit_status = do_simple_gating(env,envend,dz); else exit_status = do_smoothed_gating(env,envend,smoothing,dz); return(exit_status); } /********************************* DO_SIMPLE_GATING ****************************/ int do_simple_gating(float *env,float *envend,dataptr dz) { int exit_status; double thistime = 0.0; float *p = env; double timestep = dz->outfile->window_size * MS_TO_SECS; if(dz->brksize[ENV_GATE]) { while(pparam[ENV_GATE]) *p = 0.0f; p++; thistime += timestep; } } else { while(pparam[ENV_GATE]) *p = 0.0f; p++; } } return(FINISHED); } /********************************* DO_SMOOTHED_GATING ****************************/ int do_smoothed_gating(float *env,float *envend,int smoothing,dataptr dz) { int exit_status; double thistime = 0.0; int gating = TRUE; float *p = env; double timestep = dz->outfile->window_size * MS_TO_SECS; if(dz->brksize[ENV_GATE]) { while(p= dz->param[ENV_GATE]) /* 1 */ && (!gating || (gating && !gatefilt(p,envend,dz->param[ENV_GATE],smoothing)))) { gating = FALSE; } else { *p = 0.0f; /* 2 */ gating = TRUE; } p++; thistime += timestep; } } else { while(p= dz->param[ENV_GATE]) /* 1 */ && (!gating || (gating && !gatefilt(p,envend,dz->param[ENV_GATE],smoothing)))) { gating = FALSE; } else { *p = 0.0f; /* 2 */ gating = TRUE; } p++; } } return(FINISHED); } /****************************** GATEFILT *************************/ int gatefilt(float *p,float *envend,double gate,int smoothing) { int this_smoothfactor, windows_remain; int n; double average = 0.0; float *q; if((windows_remain = envend - p) >= smoothing) this_smoothfactor = smoothing; else this_smoothfactor = windows_remain; q = p; for(n=0;noutfile->window_size * MS_TO_SECS; if(dz->brksize[ENV_GATE]) { if(dz->brksize[ENV_MIRROR]) thistype = G_AND_M_BRK; else { thistype = G_BRK; hirange = 1.0 - dz->param[ENV_MIRROR]; } } else { if(dz->brksize[ENV_MIRROR]) thistype = M_BRK; else { thistype = NO_BRK; hirange = 1.0 - dz->param[ENV_MIRROR]; lorange = dz->param[ENV_MIRROR] - dz->param[ENV_GATE]; upratio = hirange/lorange; dnratio = lorange/hirange; } } p = env; if(thistype == NO_BRK) { while(pparam[ENV_MIRROR] - dz->param[ENV_GATE]; break; case(M_BRK): if((exit_status = read_value_from_brktable(thistime,ENV_MIRROR,dz))<0) return(exit_status); hirange = 1.0 - dz->param[ENV_MIRROR]; lorange = dz->param[ENV_MIRROR] - dz->param[ENV_GATE]; break; case(G_AND_M_BRK): if((exit_status = read_value_from_brktable(thistime,ENV_GATE,dz))<0) return(exit_status); if((exit_status = read_value_from_brktable(thistime,ENV_MIRROR,dz))<0) return(exit_status); hirange = 1.0 - dz->param[ENV_MIRROR]; lorange = dz->param[ENV_MIRROR] - dz->param[ENV_GATE]; break; } upratio = hirange/lorange; dnratio = lorange/hirange; do_env_invert(p,upratio,dnratio,dz); thistime += timestep; p++; } } return(FINISHED); } /*************************** DO_ENV_INVERT *************************/ void do_env_invert(float *p,double upratio,double dnratio,dataptr dz) { if(*pparam[ENV_GATE]) { *p = 0.0f; } else { if(*p<=dz->param[ENV_THRESHOLD]) *p = (float)(((dz->param[ENV_THRESHOLD] - *p) * upratio) + dz->param[ENV_THRESHOLD]); else *p = (float)(dz->param[ENV_THRESHOLD] - ((*p - dz->param[ENV_THRESHOLD]) * dnratio)); } } /**************************** ENVFEXPAND ******************************/ int envexpand(float *env,float *envend,dataptr dz) { #define NO_BRK (0) #define G_BRK (1) #define T_BRK (2) #define G_AND_T_BRK (3) int exit_status; float *p; double toprange = 0.0, newrange = 0.0, squeeze = 0.0; double thistime = 0.0; int gating = TRUE; int smoothing = dz->iparam[ENV_SMOOTH]; int thistype; double timestep = dz->outfile->window_size * MS_TO_SECS; if(dz->brksize[ENV_GATE]) { if(dz->brksize[ENV_THRESHOLD]) thistype = G_AND_T_BRK; else { thistype = G_BRK; newrange = 1.0 - dz->param[ENV_THRESHOLD]; } } else { toprange = 1.0 - dz->param[ENV_GATE]; if(dz->brksize[ENV_THRESHOLD]) thistype = T_BRK; else { thistype = NO_BRK; newrange = 1.0 - dz->param[ENV_THRESHOLD]; squeeze = newrange/toprange; } } p = env; if(thistype == NO_BRK) { while(pparam[ENV_GATE]; /* fall thro */ case(T_BRK): if((exit_status = read_value_from_brktable(thistime,ENV_THRESHOLD,dz))<0) return(exit_status); newrange = 1.0 - dz->param[ENV_THRESHOLD]; break; case(G_BRK): if((exit_status = read_value_from_brktable(thistime,ENV_GATE,dz))<0) return(exit_status); toprange = 1.0 - dz->param[ENV_GATE]; break; } squeeze = newrange/toprange; do_expanding(p,envend,&gating,squeeze,smoothing,dz); thistime += timestep; p++; } } return(FINISHED); } /**************************** DO_EXPANDING ****************************/ void do_expanding(float *p,float *envend,int *gating,double squeeze,int smoothing,dataptr dz) { if(smoothing) { if((*p > dz->param[ENV_GATE]) && (*gating==FALSE || ((*gating==TRUE) && !gatefilt(p,envend,dz->param[ENV_GATE],smoothing)))) { *p = (float)(1.0 - ((1.0 - *p) * squeeze)); *gating = FALSE; } else { *p = 0.0f; *gating = TRUE; } } else { if(*p > dz->param[ENV_GATE]) *p = (float)(1.0 - ((1.0 - *p) * squeeze)); else *p = 0.0f; } } /**************************** ENVLIMIT ******************************/ int envlimit(float *env,float *envend,dataptr dz) { #define NO_BRK (0) #define TH_BRK (1) #define L_BRK (2) #define T_AND_L_BRK (3) int exit_status; float *p; double x, toprange = 0.0, newrange, squeeze = 0.0; double thistime = 0.0; int thistype; double timestep = dz->outfile->window_size * MS_TO_SECS; if(dz->brksize[ENV_THRESHOLD]) { if(dz->brksize[ENV_LIMIT]) thistype = T_AND_L_BRK; else thistype = TH_BRK; } else { toprange = 1.0 - dz->param[ENV_THRESHOLD]; if(dz->brksize[ENV_LIMIT]) thistype = L_BRK; else { thistype = NO_BRK; newrange = dz->param[ENV_LIMIT] - dz->param[ENV_THRESHOLD]; squeeze = newrange/toprange; } } p = env; if(thistype == NO_BRK) { while(p dz->param[ENV_THRESHOLD]) { x = (*p - dz->param[ENV_THRESHOLD]) * squeeze; *p = (float)(dz->param[ENV_THRESHOLD] + x); } p++; } } else { while(pparam[ENV_LIMIT] - dz->param[ENV_THRESHOLD]; squeeze = newrange/toprange; break; case(T_AND_L_BRK): if((exit_status = read_value_from_brktable(thistime,ENV_LIMIT,dz))<0) return(exit_status); /* fall thro */ case(TH_BRK): if((exit_status = read_value_from_brktable(thistime,ENV_THRESHOLD,dz))<0) return(exit_status); toprange = 1.0 - dz->param[ENV_THRESHOLD]; newrange = dz->param[ENV_LIMIT] - dz->param[ENV_THRESHOLD]; squeeze = newrange/toprange; break; } if(*p > dz->param[ENV_THRESHOLD]) { x = (*p - dz->param[ENV_THRESHOLD]) * squeeze; *p = (float)(dz->param[ENV_THRESHOLD] + x); } thistime += timestep; p++; } } return(FINISHED); } /*************************** ENVKORRUG *************************/ int envkorrug(float *env,float *envend,dataptr dz) { int exit_status; int upwards; double thistime = 0.0; float *p, *q; double timestep = dz->outfile->window_size * MS_TO_SECS; float *shadowenv; size_t bytelen = (envend - env) * sizeof(float); if((shadowenv = (float *)malloc(bytelen))==NULL) { sprintf(errstr,"INSUFFICIENT MEMORY to create shadow envelope array.\n"); return(MEMORY_ERROR); } memset((char *)shadowenv,0,(size_t)bytelen); p = env+1; q = env; if (*p > *q) upwards = TRUE; else upwards = FALSE; while(p < envend) { if((exit_status = read_values_from_all_existing_brktables(thistime,dz))<0) return(exit_status); if(upwards) { if(*p <= *q) { if(ispeak(env,envend,q,(int)dz->iparam[ENV_PKSRCHWIDTH])) *(shadowenv + (q - env)) = 1.0f; upwards = FALSE; } } else { if(*p > *q) upwards = TRUE; } thistime += timestep; p++; q++; } thistime = 0.0; p = env+1; q = env; while(p < envend) { if((exit_status = read_values_from_all_existing_brktables(thistime,dz))<0) return(exit_status); if(upwards) { if(*p <= *q) { upwards = FALSE; } } else { if(*p > *q) { if(istrough(env,envend,q,(int)dz->iparam[ENV_PKSRCHWIDTH])) digout_trough(env,envend,shadowenv,(int)dz->iparam[ENV_TROFDEL],q); upwards = TRUE; } } thistime += timestep; p++; q++; } if(dz->process==ENV_WARPING) { p = env; while(p < envend) { if(*p>0.0) *p = 1.0f; /* NB: NB: Therefore don't use REPLACE with corrugation, when WARPING !! */ p++; } } free(shadowenv); return(FINISHED); } /*************************** ISTROUGH **********************************/ int istrough(float *env,float *envend,float *q,int width) { int up, down; float *upq, *downq, *r; if(width<2) return(1); down = up = width/2; if(EVEN(width)) down = up - 1; /* set search p[arams above and below q */ downq = q - down; upq = q + up; upq = min(envend-1,upq); /* allow for ends of envelope table */ downq = max(env,downq); for(r = downq; r<=upq; r++) { if(*q > *r) return(FALSE); } return(TRUE); /* if r is minimum of all in trough, return 1 */ } /*************************** ISPEAK **********************************/ int ispeak(float *env,float *envend,float *q,int width) { int up, down; float *upq, *downq, *r; if(width<2) return(TRUE); down = up = width/2; if(EVEN(width)) down = up - 1; /* set search params above and below q */ downq = q - down; upq = q + up; upq = min(envend-1,upq); /* allow for ends of envelope table */ downq = max(env,downq); for(r = downq; r<=upq; r++) { if(*q < *r) return(FALSE); } return(TRUE); /* if r is maximum of all in peak, return 1 */ } /***************************** DIGOUT_TROUGH *********************************/ void digout_trough(float *env,float *envend,float *shadowenv,int del,float *q) { float *r, *upq, *downq; int down, up, herepos, lopos, hipos, thispos; if(del<2) { *q = 0.0f; /* set single-sector trough to 0.0 */ return; } down = up = del/2; if(EVEN(del)) down = up - 1; /* set trof_delete limits above and below q */ downq = q - down; upq = q + up; upq = min(envend-1,upq); /* allow for ends of envelope table */ downq = max(env,downq); herepos = q-env; lopos = downq - env; /* find relative positions in env-table */ hipos = upq - env; /* search downwards for peaks set in shadow table */ for(r = shadowenv + herepos; r>= shadowenv + lopos; r--) { if(*r>FLTERR) { thispos = (r+1) - shadowenv; downq = env + thispos;/* & adjust downward delete-limit accordingly */ break; /* to avoid deleting peaks */ } } /* search upwards for peaks set in shadow table */ for(r = shadowenv + herepos; r<=shadowenv + hipos; r++) { if(*r>FLTERR) { thispos = (r-1) - shadowenv; upq = env + thispos; /* and adjust upward delete-limit accordingly */ break; /* to avoid deleting peaks */ } } for(r = downq; r<=upq; r++) /* delete the defined trough */ *r = 0.0f; } /**************************** ENVTRIG *********************************/ int envtrig(float **env,float **envend,dataptr dz) /* NOTE THIS USES POINTERS TO env AND envend */ { int exit_status; double *brk, *brkend; if((exit_status = locate_and_size_triggers(*env,*envend,&brk,&brkend,dz))<0) return(exit_status); switch(dz->process) { case(ENV_REPLOTTING): case(ENV_RESHAPING): exit_status = gen_trigger_envelope(&brk,&brkend,dz); break; case(ENV_WARPING): exit_status = gen_reapplied_trigger_envelope(&brk,&brkend,dz); break; } if(exit_status < 0) return(exit_status); return convert_other_brktable_to_envtable(brk,brkend,env,envend,dz); } /**************************** LOCATE_AND_SIZE_TRIGGERS *******************************/ int locate_and_size_triggers(float *env,float *envend,double **brk,double **brkend,dataptr dz) { int exit_status; float *p = env, *end; double *q, rise, mean, now; double timestep = dz->outfile->window_size * MS_TO_SECS; double envdur; int n, scan, arraysize = BIGARRAY; int triggered = FALSE, k; double maxrise, thistime = 0.0; int look_ahead = 4; if((*brk = (double *)malloc(arraysize * sizeof(double)))==NULL) { sprintf(errstr,"INSUFFICIENT MEMORY to create trigger brktable.\n"); return(MEMORY_ERROR); } q = *brk; *brkend = *brk + arraysize; if((scan = (int)(dz->param[ENV_TRIGDUR]/timestep))<=0) { sprintf(errstr,"scansize too small for envelope windows.\n"); return(GOAL_FAILED); } end = envend - scan - 1; *q++ = 0.0; *q++ = 0.0; /*Store an initial brkpnt value of zero */ n = scan; while(pdz->param[ENV_GATE] /* deduce mean rate of rise[fall] and compare with triggering rate */ && fabs(rise)>=dz->param[ENV_TRIGRISE]) {/* if triggering criteria met */ if(q+look_ahead >= *brkend) { if((exit_status = enlarge_brktable(brk,brkend,&q,&arraysize))<0) return(exit_status); } now = n * timestep; convert_to_on_triggers(now,timestep,rise,&triggered,&q); p += scan; n += scan; thistime += timestep * scan; } else { triggered = FALSE; p++; n++; thistime += timestep; } } envdur = (envend - env) * timestep; /* if end of new brktable not at orig end of envel.. extend */ if((exit_status = round_off_brktable(q,brk,brkend,envdur))<0) return(exit_status); return(FINISHED); } /******************************* GEN_TRIGGER_ENVELOPE ******************************/ int gen_trigger_envelope(double **brk, double **brkend,dataptr dz) { int exit_status; int n, brklen; double next_trigtime, this_trigtime, nuhere, last_outval = 0.0, trigval; double *q, *nubrkptr, *nubrk, *nubrkend; double *trigptr, *trigbrk, *trigbrkend; int arraysize = BIGARRAY; trigptr = trigbrk = *brk; trigbrkend = *brkend; if((nubrk = (double *)malloc(arraysize * sizeof(double)))==NULL) { sprintf(errstr,"INSUFFICIENT MEMORY to create new envelope array.\n"); return(MEMORY_ERROR); } nubrkend = nubrk + arraysize; nubrkptr = nubrk; while(trigptr < trigbrkend) { this_trigtime = *trigptr++; trigval = *trigptr++; if(trigptr < trigbrkend) next_trigtime = *trigptr; else next_trigtime = DBL_MAX; if(flteq(trigval,0.0)) { /* if the trigger table value is 0.0 put Zero in new table */ *nubrkptr++ = this_trigtime; *nubrkptr++ = 0.0; } else { /* else */ if(trigval < last_outval) /* If the new trigger value is less than current value held, */ trigval = last_outval; /* set trig val to held value, (else, keep the new value). */ q = dz->rampbrk; /* start copying values from ramp table into new brkpnt table, */ n = 0; /* until ramptable ends, OR we reach next brkpnt in trigger table */ while(n < dz->rampbrksize && (nuhere = this_trigtime + *q++)=(nubrkend-2)) { if((exit_status = enlarge_brktable(&nubrk,&nubrkend,&nubrkptr,&arraysize))<0) return(exit_status); } } brkdeglitch(nubrk,&nubrkptr); /* get rid of too fast amp rises or falls */ brklen = nubrkptr - nubrk; free((char *)(*brk)); if((*brk=(double *)realloc((char *)nubrk,brklen * sizeof(double)))==NULL) { sprintf(errstr,"INSUFFICIENT MEMORY to reallocate new envelope array.\n"); return(MEMORY_ERROR); } if((brklen/2) * 2 != brklen) { sprintf(errstr,"Anomalous breaktable size in gen_trigger_envelope()\n"); return(PROGRAM_ERROR); } *brkend = *brk + brklen; return(FINISHED); } /**************************** BRKDEGLITCH **************************** * Check a breakpoint table for sudden glitches, and smooth them. * * (1) If the brktable has very sudden rise or fall, current time-point is moved forward a little. * (2) If, as a result last time-points moved beyond original endtime, readjust to orig duration. */ void brkdeglitch(double *brk,double **brkend) { double *p = brk, *here, *next; double rise, risetime, slope, newtime; double thistime, thisval, timeshift, timeratio; double lasttime = *p++; double lastval = *p++; double endtime = *((*brkend)-2); double timediff, valdiff, valstep; double click = IS_CLICK; // int cnt = 0; while(p < *brkend) { thistime = *p++; thisval = *p++; rise =fabs(thisval-lastval); if((slope = rise/(thistime-lasttime))>click) { /* If the brktable has very sudden rise or fall */ risetime = rise/click; here = p-2; next = p; newtime = lasttime + risetime; /* current time-point is moved forward a little */ timeshift = newtime - thistime; while(next < *brkend) { *here += timeshift; if(*here >= *next) { here += 2; next += 2; } else break; } if(next >= *brkend) *here += timeshift; thistime = newtime; } lasttime = thistime; lastval = thisval; } p = *brkend - 2; if(flteq((double)*p,endtime)) { *p = endtime; *brkend = p + 2; } else { while(*p > endtime + FLTERR) /* if, as as a result of deglitches, endtime of table is moved forward */ p -= 2; /* Find the last point prior to the true endtime */ if(flteq((double)*p,endtime)) { /* and establish the correct time .. */ *p = endtime; *brkend = p + 2; } else { /* ... or the correct value, for that true endtime */ lasttime = *p; lastval = *(p+1); thistime = *(p+2); thisval = *(p+3); timediff = thistime - lasttime; valdiff = thisval - lastval; timeratio= (endtime - lasttime)/timediff; valstep = valdiff * timeratio; thisval = lastval + valstep; p += 2; *p++ = endtime; *p++ = thisval; *brkend = p; } } return; } /********************************* ENVREPLACE ************************* * * NEEDED FOR all WARP, except KORRUGATION and TRIGGER */ int envreplace(float *env,float **envend,float *origenv,float *origend) { float *p, *q; double gate = MIN_FRACTION_OF_LEVEL; /* minimum non-zero value of envelope */ double maxval = 0.0; p = origenv; q = env; if((origend - origenv) < (*envend - env)) { while(poutfile->window_size * MS_TO_SECS; // double inc = timestep; double duration = *(brkend-2); if(timestep <= 0.0) { sprintf(errstr,"No window_size set: convert_other_brktable_to_envtable()\n"); return(PROGRAM_ERROR); } if(timestep < ENV_MIN_WSIZE * MS_TO_SECS) { sprintf(errstr,"Invalid window_size: convert_other_brktable_to_envtable()\n"); return(PROGRAM_ERROR); } if(duration < timestep) { sprintf(errstr,"Brktable duration less than window_size: Cannot proceed.\n"); return(DATA_ERROR); } envlen = (int)((duration/timestep) + 1.0); /* round up */ envlen += MARGIN; /* allow for errors in float-calculation */ if(brk==NULL) { sprintf(errstr,"No existing brkpnt table. convert_brktable_to_envtable()\n"); return(PROGRAM_ERROR); } if(*env != NULL) free(*env); if((*env = (float *)malloc(envlen * sizeof(float)))==NULL) { sprintf(errstr,"INSUFFICIENT MEMORY to create new envelope array.\n"); return(MEMORY_ERROR); } q = *env; n = 0; while(n(duration+FLTERR)) break; *q = read_a_val_from_brktable(brk,brkend,here); q++; n++; } envlen = n; if((*env = (float *)realloc(*env,envlen * sizeof(float)))==NULL) { sprintf(errstr,"INSUFFICIENT MEMORY to reallocate new envelope array.\n"); return(MEMORY_ERROR); } *envend = *env + envlen; return(FINISHED); } /**************************** READ_A_VAL_FROM_BRKTABLE *****************************/ float read_a_val_from_brktable(double *brk,double *brkend,double thistime) { float thisval; double *p = brk, val; double hival, loval, hiind, loind; double firstval = *(brk+1); double lastval = *(brkend-1); double lasttime = *(brkend-2); if(thistime <= 0.0) thisval = (float)firstval; else if(thistime >= lasttime) thisval = (float)lastval; else { while(*(p) 1) { if(flteq(nexttime,starttime)) { /* Junk any redundant initial zero */ memmove((char *)startadr,(char *)nextadr,(brksize-1)*2*sizeof(double)); brksize--; } } endadr = *brk + (brksize * 2); if(*(endadr - 2) != envdur) { /* IF lasttime != length of envelope */ if(flteq(*(endadr - 2),envdur)) /* If approx equal, reset to equal */ *(endadr - 2) = envdur; else { /* Else generate an endtime time-val pair */ brksize++; if((*brk=(double *)realloc(*brk,(brksize*2)*sizeof(double)))==NULL) { sprintf(errstr,"INSUFFICIENT MEMORY to reallocate brktable.\n"); return(MEMORY_ERROR); } endadr = *brk + (brksize * 2); *(endadr-2) = envdur; /* true end time gets */ *(endadr-1) = 0.0; /* 0 endvalue */ } } if((*brk=(double *)realloc(*brk,(brksize*2)*sizeof(double)))==NULL) { sprintf(errstr,"INSUFFICIENT MEMORY to reallocate brktable.\n"); return(MEMORY_ERROR); } *brkend = *brk + (brksize * 2); return(FINISHED); } /**************************** CONVERT_TO_ON_TRIGGERS *****************************/ void convert_to_on_triggers(double now,double timestep,double rise,int *triggered,double **q) { double *p = *q; if(*triggered==FALSE) { /* If not already RISING-triggered */ if(!flteq(*(p-2),now-timestep)) { /* If previous time-value was not too close to this one */ *p++ = now - timestep; /* Write pre-time and 0.0 for start of rise */ *p++ = 0.0; } *p++ = now; /* Write time and rise-value for end of rise */ *p++ = rise; *triggered = TRUE; /* Flag trigrise */ } else { /* If already RISING-triggered */ *(p-4) = now - timestep; /* readjust start-time of existing rise, from current time */ *(p-2) = now; /* readjust end-time of existing rise, from current time */ *(p-1) += rise; /* readjust total rise value */ } *q = p; } /******************************* GEN_REAPPLIED_TRIGGER_ENVELOPE ******************************/ int gen_reapplied_trigger_envelope(double **brk, double **brkend,dataptr dz) { int exit_status; int n, brklen; // double next_trigtime, this_trigtime, nuhere, last_outval = 0.0, trigval; double next_trigtime, this_trigtime, nuhere, trigval; double *q, *nubrkptr, *nubrk, *nubrkend; double *trigptr, *trigbrk, *trigbrkend; int arraysize = BIGARRAY; trigptr = trigbrk = *brk; trigbrkend = *brkend; if((nubrk = (double *)malloc(arraysize * sizeof(double)))==NULL) { sprintf(errstr,"INSUFFICIENT MEMORY to create new envelope table.\n"); return(MEMORY_ERROR); } nubrkend = nubrk + arraysize; nubrkptr = nubrk; while(trigptr < trigbrkend) { this_trigtime = *trigptr++; trigval = *trigptr++; if(trigptr < trigbrkend) next_trigtime = *trigptr; else next_trigtime = DBL_MAX; if(flteq(trigval,0.0)) { /* if the trigger table value is 0.0 put Zero in new table */ *nubrkptr++ = this_trigtime; *nubrkptr++ = 0.0; } else { /* else */ q = dz->rampbrk; /* start copying values from ramp table into new brkpnt table, */ n = 0; /* until ramptable ends, OR we reach next brkpnt in trigger table */ while(n < dz->rampbrksize && (nuhere = this_trigtime + *q++)=(nubrkend-2)) { if((exit_status = enlarge_brktable(&nubrk,&nubrkend,&nubrkptr,&arraysize))<0) return(exit_status); } } brkdeglitch(nubrk,&nubrkptr); /* get rid of too fast amp rises or falls */ brklen = nubrkptr - nubrk; free((char *)(*brk)); if((*brk=(double *)realloc((char *)nubrk,brklen * sizeof(double)))==NULL) { sprintf(errstr,"INSUFFICIENT MEMORY to reallocate new envelope table.\n"); return(MEMORY_ERROR); } if((brklen/2) * 2 != brklen) { sprintf(errstr,"Anomalous breaktable size in gen_reapplied_trigger_envelope()\n"); return(PROGRAM_ERROR); } *brkend = *brk + brklen; return(FINISHED); } /***************************** REALLOC_ENVCREATE_TABLES ****************************/ int realloc_envcreate_tables(int tabsize,dataptr dz) { if((dz->parray[ENV_CREATE_TIME] = (double *)realloc(dz->parray[ENV_CREATE_TIME],tabsize * sizeof(double)))==NULL || (dz->parray[ENV_CREATE_LEVL] = (double *)realloc(dz->parray[ENV_CREATE_LEVL],tabsize * sizeof(double)))==NULL) { sprintf(errstr,"INSUFFICIENT MEMORY to reallocate level array.\n"); return(MEMORY_ERROR); } return(FINISHED); } /***************************** CREATE_ENVELOPE **************************** * * (1) time_quantum has a minimum value, as this function can create a * brktable for conversion to an envfile. * 1a) Except in the case of ENV_ATTACK, which has very acute risetime!! */ int create_envelope(int *cnt,dataptr dz) { int exit_status; int falling = FALSE; int n,m, k, base, newcnt; double time_quantum, timestep, levelstep, attenator = 0.0; double thisduration, ratio; // double atten = 1.0/ATTEN; if((dz->parray[ENV_CREATE_TIME] = (double *)malloc(sizeof(double)))==NULL) { sprintf(errstr,"INSUFFICIENT MEMORY to create times array.\n"); return(MEMORY_ERROR); } if((dz->parray[ENV_CREATE_LEVL] = (double *)malloc(sizeof(double)))==NULL) { sprintf(errstr,"INSUFFICIENT MEMORY to create levels array.\n"); return(MEMORY_ERROR); } dz->parray[ENV_CREATE_TIME][0] = dz->parray[ENV_CREATE_INTIME][0]; dz->parray[ENV_CREATE_LEVL][0] = dz->parray[ENV_CREATE_INLEVEL][0]; *cnt = 1; for(n=1;nitemcnt;n++) { thisduration = dz->parray[ENV_CREATE_INTIME][n] - dz->parray[ENV_CREATE_INTIME][n-1]; //TW UPDATE if(dz->process == ENV_ATTACK || dz->process == ENV_DOVETAILING || dz->process == ENV_CURTAILING) time_quantum = max(thisduration/(double)MINSPAN,2.0/dz->infile->srate); /* 1a */ else time_quantum = max(thisduration/(double)MINSPAN,ENV_MIN_WSIZE * MS_TO_SECS); /* 1 */ if((levelstep = dz->parray[ENV_CREATE_INLEVEL][n] - dz->parray[ENV_CREATE_INLEVEL][n-1]) <= 0.0) falling = TRUE; else falling = FALSE; switch(dz->iparray[ENV_SLOPETYPE][n]) { case(ENVTYPE_LIN): (*cnt)++; if((exit_status = realloc_envcreate_tables(*cnt,dz))<0) return(exit_status); dz->parray[ENV_CREATE_TIME][*cnt - 1] = dz->parray[ENV_CREATE_INTIME][n]; dz->parray[ENV_CREATE_LEVL][*cnt - 1] = dz->parray[ENV_CREATE_INLEVEL][n]; break; case(ENVTYPE_STEEP): case(ENVTYPE_EXP): case(ENVTYPE_DBL): switch(dz->iparray[ENV_SLOPETYPE][n]) { case(ENVTYPE_STEEP): attenator = STEEP_ATTEN; break; case(ENVTYPE_EXP): attenator = ATTENATOR; break; case(ENVTYPE_DBL): attenator = ATTENATOR * 2; break; } base = *cnt; newcnt = (int)(thisduration/time_quantum); /* TRUNCATE */ /* RWD 4:2002 NB: div/zero bug here when newcnt resolves to zero */ /* should this be flagged as a user error? */ if(newcnt==0) newcnt = 1; timestep = thisduration/(double)newcnt; *cnt += newcnt; if((exit_status = realloc_envcreate_tables(*cnt,dz))<0) return(exit_status); for(m = 1,k = base;k < *cnt;k++,m++) { dz->parray[ENV_CREATE_TIME][k] = dz->parray[ENV_CREATE_INTIME][n-1] + (m * timestep); if(falling) { ratio = 1.0 - ((m * timestep)/thisduration); ratio = max(ratio,0.0); ratio = pow(ratio,attenator); dz->parray[ENV_CREATE_LEVL][k] = fabs(levelstep) * ratio; dz->parray[ENV_CREATE_LEVL][k] += dz->parray[ENV_CREATE_INLEVEL][n]; } else { ratio = (m * timestep)/thisduration; ratio = pow(ratio,attenator); ratio = min(ratio,1.0); dz->parray[ENV_CREATE_LEVL][k] = fabs(levelstep) * ratio; dz->parray[ENV_CREATE_LEVL][k] += dz->parray[ENV_CREATE_INLEVEL][n-1]; } } dz->parray[ENV_CREATE_TIME][*cnt-1] = dz->parray[ENV_CREATE_INTIME][n]; break; default: sprintf(errstr,"Unknown case in create_envelope()\n"); return(PROGRAM_ERROR); } } return(FINISHED); } /******************************** ENVELOPE_TREMOL **********************************/ int envelope_tremol(dataptr dz) { int exit_status; int m; int n, k, st_sampsread, st_samps_processed; double thistime, losin, hisin, frac, val; double fsinpos = 0.0; int sinpos; int chans = dz->infile->channels; double inverse_srate = 1.0/(double)dz->infile->srate; double tabsize_over_srate = (double)ENV_TREM_TABSIZE/(double)dz->infile->srate; float *buf = dz->sampbuf[0]; double *sintab = dz->parray[ENV_SINETAB]; while(dz->samps_left > 0) { st_samps_processed = dz->total_samps_read/chans; if((exit_status = read_samps(buf,dz))<0) return(exit_status); st_sampsread = dz->ssampsread/chans; for(n=0; n < st_sampsread; n++) { k = n * chans; thistime = (double)st_samps_processed * inverse_srate; if((exit_status = read_values_from_all_existing_brktables(thistime,dz))<0) return(exit_status); if(dz->brksize[ENV_TREM_FRQ] && dz->mode==ENV_TREM_LOG) dz->param[ENV_TREM_FRQ] = pow(10,dz->param[ENV_TREM_FRQ]); sinpos = (int)fsinpos; /* TRUNCATE */ frac = fsinpos - (double)sinpos; losin = sintab[sinpos]; hisin = sintab[sinpos+1]; val = losin + ((hisin - losin) * frac); /* interpd (normalised) sintable value */ val *= dz->param[ENV_TREM_DEPTH]; /* adjusted for tremolo depth */ val += (1.0 - dz->param[ENV_TREM_DEPTH]); /* subtract from max: tremol superimposed on existing level */ val *= dz->param[ENV_TREM_AMP]; /* multiply by overall signal gain (<= 1.0) */ fsinpos += (dz->param[ENV_TREM_FRQ] * tabsize_over_srate); /* advance sintable float-pointer */ fsinpos = fmod(fsinpos,(double)ENV_TREM_TABSIZE); /* wrap at table-size */ for(m=0;mssampsread > 0) { if((exit_status = write_samps(buf,dz->ssampsread,dz))<0) return(exit_status); } } return(FINISHED); } /*************************** ENVPEAKCNT *************************/ int envpeakcnt(float *env,float *envend,dataptr dz) { int exit_status; int upwards, peakkcnt = 0; double thistime = 0.0; float *p, *q; double timestep = dz->outfile->window_size * MS_TO_SECS; float *shadowenv; size_t bytelen = (envend - env) * sizeof(float); if((shadowenv = (float *)malloc(bytelen))==NULL) { sprintf(errstr,"INSUFFICIENT MEMORY to create shadow envelope array.\n"); return(MEMORY_ERROR); } memset((char *)shadowenv,0,(size_t)bytelen); p = env+1; q = env; if (*p > *q) upwards = TRUE; else upwards = FALSE; while(p < envend) { if((exit_status = read_values_from_all_existing_brktables(thistime,dz))<0) return(exit_status); if(upwards) { if(*p <= *q) { if(ispeak(env,envend,q,(int)dz->iparam[ENV_PKSRCHWIDTH])) peakkcnt++; upwards = FALSE; } } else { if(*p > *q) upwards = TRUE; } thistime += timestep; p++; q++; } fprintf(stdout,"INFO: Number of peaks = %d\n",peakkcnt); fflush(stdout); return(FINISHED); }