/* * 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 #include #include #include #include #include #include #ifdef unix #include #endif #if defined unix || defined __GNUC__ #define round(x) lround((x)) #endif #ifndef HUGE #define HUGE 3.40282347e+38F #endif // Use existing "long" items in struct "dz" to remember various process constants #define envcount itemcnt // Number of timed-envelope entries #define envsrcs ringsize // number of the array at which envelope data begins #define envbuf rampbrksize // number of the array where interpolated envelope is constructed #define outlevs temp_sampsize // number of the array where current levels on each multichan out-channel are stored #define fltcnt is_transpos // Constant related to the order of the filter #define fltmul is_flat // Filter multiplier #define fltractv could_be_pitch // Flags whether filtering will be required #define fulldur is_sharp // Duration of event #define SIGNAL_TO_LEFT (0) // Parameters for stereo-hole-in-middle-compensation #define SIGNAL_TO_RIGHT (1) #define ROOT2 (1.4142136) #define FILTER_GAIN (-96.0) // Filter gain for lo-pass filter #define FLT_LPHP_ARRAYS_PER_FILTER (4) #define FLT_DEN1 (0) #define FLT_DEN2 (1) #define FLT_CN (2) #define FLT_S1_BASE (3) #define FLT_S2_BASE (4) #define FLT_E1_BASE (5) #define FLT_E2_BASE (6) char errstr[2400]; int anal_infiles = 1; int sloom = 0; int sloombatch = 0; const char* cdp_version = "7.1.0"; //CDP LIB REPLACEMENTS static int check_fracture_param_validity_and_consistency(dataptr dz); static int setup_fracture_application(dataptr dz); static int parse_sloom_data(int argc,char *argv[],char ***cmdline,int *cmdlinecnt,dataptr dz); static int parse_infile_and_check_type(char **cmdline,dataptr dz); static int setup_fracture_param_ranges_and_defaults(dataptr dz); static int handle_the_outfile(int *cmdlinecnt,char ***cmdline,dataptr dz); static int open_the_outfile(dataptr dz); static int setup_and_init_input_param_activity(dataptr dz,int tipc); static int setup_input_param_defaultval_stores(int tipc,aplptr ap); static int establish_application(dataptr dz); static int initialise_vflags(dataptr dz); static int setup_parameter_storage_and_constants(int storage_cnt,dataptr dz); static int initialise_is_int_and_no_brk_constants(int storage_cnt,dataptr dz); static int mark_parameter_types(dataptr dz,aplptr ap); static int assign_file_data_storage(int infilecnt,dataptr dz); static int get_tk_cmdline_word(int *cmdlinecnt,char ***cmdline,char *q); static int get_the_process_no(char *prog_identifier_from_cmdline,dataptr dz); static int get_the_mode_from_cmdline(char *str,dataptr dz); static int setup_and_init_input_brktable_constants(dataptr dz,int brkcnt); static int fracture(int ibuflen,int envbuflen,int overflow,dataptr dz); static int handle_the_special_data(char *,dataptr dz); static int read_the_special_data(dataptr dz); static int fragment_param_preprocess (int *maxpulse,double *maxtrans,int *minfragmax,dataptr dz); static int create_fracture_sndbufs(int maxpulse,double maxtrans,int minfragmax,int *ibuflen,int *envbuflen,int *overflow,int *mbuflen,dataptr dz); static int read_the_envelope(double now, dataptr dz); static int getstakwritestt(double stakcntr,int ldur,double incr); static double getstakcentre(double *tempenv,dataptr dz); static void pancalc(double position,double *leftgain,double *rightgain); // mode > 0 static int panspread(int *sectcnt,double *centre,double *spread,int *cntrswitch,int *outside,double *fmix,int samps_to_process,dataptr dz); static int spread_pan(double *thiscentre,int *cntrswitch,int *outside,double *spread,double *fmix,dataptr dz); static int filter_process(int *samps_to_process,int *endzeros,dataptr dz); static int do_lphp_filter_stereo(dataptr dz); static int lphp_filt_stereo(double *e1,double *e2,double *s1,double *s2,double *den1,double *den2,double *cn,dataptr dz,int chan); static int setup_lphp_filter(dataptr dz); static int establish_order_of_filter(double passfrq,double stopfrq,dataptr dz); static int allocate_internal_params_lphp(dataptr dz); static void calculate_filter_poles_lphp(double signd,int filter_order,double passfrq,dataptr dz); static void initialise_filter_coeffs_lphp(dataptr dz); /**************************************** MAIN *********************************************/ int main(int argc,char *argv[]) { int exit_status; dataptr dz = NULL; char **cmdline; int cmdlinecnt; int maxpulse = 0, ibuflen = 0, envbuflen = 0, minfragmax = 0, overflow = 0, mbuflen = 0; double maxtrans = 1.0; // aplptr ap; int is_launched = FALSE; if(argc==2 && (strcmp(argv[1],"--version") == 0)) { fprintf(stdout,"%s\n",cdp_version); fflush(stdout); return 0; } /* CHECK FOR SOUNDLOOM */ if((sloom = sound_loom_in_use(&argc,&argv)) > 1) { sloom = 0; sloombatch = 1; } if(sflinit("cdp")){ sfperror("cdp: initialisation\n"); return(FAILED); } /* SET UP THE PRINCIPLE DATASTRUCTURE */ if((exit_status = establish_datastructure(&dz))<0) { // CDP LIB print_messages_and_close_sndfiles(exit_status,is_launched,dz); return(FAILED); } if(!sloom) { if(argc == 1) { usage1(); return(FAILED); } else if(argc == 2) { usage2(argv[1]); return(FAILED); } } if(!sloom) { if((exit_status = make_initial_cmdline_check(&argc,&argv))<0) { // CDP LIB print_messages_and_close_sndfiles(exit_status,is_launched,dz); return(FAILED); } cmdline = argv; cmdlinecnt = argc; if((get_the_process_no(argv[0],dz))<0) return(FAILED); cmdline++; cmdlinecnt--; dz->maxmode = 2; if((exit_status = get_the_mode_from_cmdline(cmdline[0],dz))<0) { print_messages_and_close_sndfiles(exit_status,is_launched,dz); return(exit_status); } cmdline++; cmdlinecnt--; // setup_particular_application = if((exit_status = setup_fracture_application(dz))<0) { print_messages_and_close_sndfiles(exit_status,is_launched,dz); return(FAILED); } if((exit_status = count_and_allocate_for_infiles(cmdlinecnt,cmdline,dz))<0) { // CDP LIB print_messages_and_close_sndfiles(exit_status,is_launched,dz); return(FAILED); } } else { //parse_TK_data() = if((exit_status = parse_sloom_data(argc,argv,&cmdline,&cmdlinecnt,dz))<0) { exit_status = print_messages_and_close_sndfiles(exit_status,is_launched,dz); return(exit_status); } } // ap = dz->application; // parse_infile_and_hone_type() = if((exit_status = parse_infile_and_check_type(cmdline,dz))<0) { exit_status = print_messages_and_close_sndfiles(exit_status,is_launched,dz); return(FAILED); } // setup_param_ranges_and_defaults() = if((exit_status = setup_fracture_param_ranges_and_defaults(dz))<0) { exit_status = print_messages_and_close_sndfiles(exit_status,is_launched,dz); return(FAILED); } // open_first_infile CDP LIB if((exit_status = open_first_infile(cmdline[0],dz))<0) { print_messages_and_close_sndfiles(exit_status,is_launched,dz); return(FAILED); } cmdlinecnt--; cmdline++; // handle_extra_infiles() : redundant // handle_outfile() = if((exit_status = handle_the_outfile(&cmdlinecnt,&cmdline,dz))<0) { print_messages_and_close_sndfiles(exit_status,is_launched,dz); return(FAILED); } // handle_formants() redundant // handle_formant_quiksearch() redundant if((exit_status = handle_the_special_data(cmdline[0],dz))<0) { print_messages_and_close_sndfiles(exit_status,is_launched,dz); return(FAILED); } cmdlinecnt--; cmdline++; if((exit_status = read_parameters_and_flags(&cmdline,&cmdlinecnt,dz))<0) { // CDP LIB print_messages_and_close_sndfiles(exit_status,is_launched,dz); return(FAILED); } // check_param_validity_and_consistency.... if((exit_status = check_fracture_param_validity_and_consistency(dz))<0) { print_messages_and_close_sndfiles(exit_status,is_launched,dz); return(FAILED); } if((exit_status = fragment_param_preprocess(&maxpulse,&maxtrans,&minfragmax,dz))<0) { print_messages_and_close_sndfiles(exit_status,is_launched,dz); return(FAILED); } is_launched = TRUE; if((exit_status = create_fracture_sndbufs(maxpulse,maxtrans,minfragmax,&ibuflen,&envbuflen,&overflow,&mbuflen,dz))<0) { print_messages_and_close_sndfiles(exit_status,is_launched,dz); return(FAILED); } if((exit_status = open_the_outfile(dz))<0) { print_messages_and_close_sndfiles(exit_status,is_launched,dz); return(FAILED); } if((exit_status = fracture(ibuflen,envbuflen,overflow,dz))<0) { print_messages_and_close_sndfiles(exit_status,is_launched,dz); return(FAILED); } if((exit_status = complete_output(dz))<0) { // CDP LIB print_messages_and_close_sndfiles(exit_status,is_launched,dz); return(FAILED); } exit_status = print_messages_and_close_sndfiles(FINISHED,is_launched,dz); // CDP LIB free(dz); return(SUCCEEDED); } /********************************************** REPLACED CDP LIB FUNCTIONS **********************************************/ /****************************** SET_PARAM_DATA *********************************/ int set_param_data(aplptr ap, int special_data,int maxparamcnt,int paramcnt,char *paramlist) { ap->special_data = (char)special_data; ap->param_cnt = (char)paramcnt; ap->max_param_cnt = (char)maxparamcnt; if(ap->max_param_cnt>0) { if((ap->param_list = (char *)malloc((size_t)(ap->max_param_cnt+1)))==NULL) { sprintf(errstr,"INSUFFICIENT MEMORY: for param_list\n"); return(MEMORY_ERROR); } strcpy(ap->param_list,paramlist); } return(FINISHED); } /****************************** SET_VFLGS *********************************/ int set_vflgs (aplptr ap,char *optflags,int optcnt,char *optlist,char *varflags,int vflagcnt, int vparamcnt,char *varlist) { ap->option_cnt = (char) optcnt; /*RWD added cast */ if(optcnt) { if((ap->option_list = (char *)malloc((size_t)(optcnt+1)))==NULL) { sprintf(errstr,"INSUFFICIENT MEMORY: for option_list\n"); return(MEMORY_ERROR); } strcpy(ap->option_list,optlist); if((ap->option_flags = (char *)malloc((size_t)(optcnt+1)))==NULL) { sprintf(errstr,"INSUFFICIENT MEMORY: for option_flags\n"); return(MEMORY_ERROR); } strcpy(ap->option_flags,optflags); } ap->vflag_cnt = (char) vflagcnt; ap->variant_param_cnt = (char) vparamcnt; if(vflagcnt) { if((ap->variant_list = (char *)malloc((size_t)(vflagcnt+1)))==NULL) { sprintf(errstr,"INSUFFICIENT MEMORY: for variant_list\n"); return(MEMORY_ERROR); } strcpy(ap->variant_list,varlist); if((ap->variant_flags = (char *)malloc((size_t)(vflagcnt+1)))==NULL) { sprintf(errstr,"INSUFFICIENT MEMORY: for variant_flags\n"); return(MEMORY_ERROR); } strcpy(ap->variant_flags,varflags); } return(FINISHED); } /***************************** APPLICATION_INIT **************************/ int application_init(dataptr dz) { int exit_status; int storage_cnt; int tipc, brkcnt; aplptr ap = dz->application; if(ap->vflag_cnt>0) initialise_vflags(dz); tipc = ap->max_param_cnt + ap->option_cnt + ap->variant_param_cnt; ap->total_input_param_cnt = (char)tipc; if(tipc>0) { if((exit_status = setup_input_param_range_stores(tipc,ap))<0) return(exit_status); if((exit_status = setup_input_param_defaultval_stores(tipc,ap))<0) return(exit_status); if((exit_status = setup_and_init_input_param_activity(dz,tipc))<0) return(exit_status); } brkcnt = tipc; //THERE ARE NO INPUTFILE brktables USED IN THIS PROCESS if(brkcnt>0) { if((exit_status = setup_and_init_input_brktable_constants(dz,brkcnt))<0) return(exit_status); } if((storage_cnt = tipc + ap->internal_param_cnt)>0) { if((exit_status = setup_parameter_storage_and_constants(storage_cnt,dz))<0) return(exit_status); if((exit_status = initialise_is_int_and_no_brk_constants(storage_cnt,dz))<0) return(exit_status); } if((exit_status = mark_parameter_types(dz,ap))<0) return(exit_status); // establish_infile_constants() replaced by dz->infilecnt = 1; //establish_bufptrs_and_extra_buffers(): return(FINISHED); } /********************** SETUP_PARAMETER_STORAGE_AND_CONSTANTS ********************/ /* RWD malloc changed to calloc; helps debug version run as release! */ int setup_parameter_storage_and_constants(int storage_cnt,dataptr dz) { if((dz->param = (double *)calloc(storage_cnt, sizeof(double)))==NULL) { sprintf(errstr,"setup_parameter_storage_and_constants(): 1\n"); return(MEMORY_ERROR); } if((dz->iparam = (int *)calloc(storage_cnt, sizeof(int) ))==NULL) { sprintf(errstr,"setup_parameter_storage_and_constants(): 2\n"); return(MEMORY_ERROR); } if((dz->is_int = (char *)calloc(storage_cnt, sizeof(char)))==NULL) { sprintf(errstr,"setup_parameter_storage_and_constants(): 3\n"); return(MEMORY_ERROR); } if((dz->no_brk = (char *)calloc(storage_cnt, sizeof(char)))==NULL) { sprintf(errstr,"setup_parameter_storage_and_constants(): 5\n"); return(MEMORY_ERROR); } return(FINISHED); } /************** INITIALISE_IS_INT_AND_NO_BRK_CONSTANTS *****************/ int initialise_is_int_and_no_brk_constants(int storage_cnt,dataptr dz) { int n; for(n=0;nis_int[n] = (char)0; dz->no_brk[n] = (char)0; } return(FINISHED); } /***************************** MARK_PARAMETER_TYPES **************************/ int mark_parameter_types(dataptr dz,aplptr ap) { int n, m; /* PARAMS */ for(n=0;nmax_param_cnt;n++) { switch(ap->param_list[n]) { case('0'): break; /* dz->is_active[n] = 0 is default */ case('i'): dz->is_active[n] = (char)1; dz->is_int[n] = (char)1;dz->no_brk[n] = (char)1; break; case('I'): dz->is_active[n] = (char)1; dz->is_int[n] = (char)1; break; case('d'): dz->is_active[n] = (char)1; dz->no_brk[n] = (char)1; break; case('D'): dz->is_active[n] = (char)1; /* normal case: double val or brkpnt file */ break; default: sprintf(errstr,"Programming error: invalid parameter type in mark_parameter_types()\n"); return(PROGRAM_ERROR); } } /* OPTIONS */ for(n=0,m=ap->max_param_cnt;noption_cnt;n++,m++) { switch(ap->option_list[n]) { case('i'): dz->is_active[m] = (char)1; dz->is_int[m] = (char)1; dz->no_brk[m] = (char)1; break; case('I'): dz->is_active[m] = (char)1; dz->is_int[m] = (char)1; break; case('d'): dz->is_active[m] = (char)1; dz->no_brk[m] = (char)1; break; case('D'): dz->is_active[m] = (char)1; /* normal case: double val or brkpnt file */ break; default: sprintf(errstr,"Programming error: invalid option type in mark_parameter_types()\n"); return(PROGRAM_ERROR); } } /* VARIANTS */ for(n=0,m=ap->max_param_cnt + ap->option_cnt;n < ap->variant_param_cnt; n++, m++) { switch(ap->variant_list[n]) { case('0'): break; case('i'): dz->is_active[m] = (char)1; dz->is_int[m] = (char)1; dz->no_brk[m] = (char)1; break; case('I'): dz->is_active[m] = (char)1; dz->is_int[m] = (char)1; break; case('d'): dz->is_active[m] = (char)1; dz->no_brk[m] = (char)1; break; case('D'): dz->is_active[m] = (char)1; /* normal case: double val or brkpnt file */ break; default: sprintf(errstr,"Programming error: invalid variant type in mark_parameter_types()\n"); return(PROGRAM_ERROR); } } /* INTERNAL */ for(n=0, m=ap->max_param_cnt + ap->option_cnt + ap->variant_param_cnt; ninternal_param_cnt; n++,m++) { switch(ap->internal_param_list[n]) { case('0'): break; /* dummy variables: variables not used: but important for internal paream numbering!! */ case('i'): dz->is_int[m] = (char)1; dz->no_brk[m] = (char)1; break; case('d'): dz->no_brk[m] = (char)1; break; default: sprintf(errstr,"Programming error: invalid internal param type in mark_parameter_types()\n"); return(PROGRAM_ERROR); } } return(FINISHED); } /************************ HANDLE_THE_OUTFILE *********************/ int handle_the_outfile(int *cmdlinecnt,char ***cmdline,dataptr dz) { char *filename = (*cmdline)[0], *p; if(filename[0]=='-' && filename[1]=='f') { dz->floatsam_output = 1; dz->true_outfile_stype = SAMP_FLOAT; filename+= 2; } if(!sloom) { if(file_has_invalid_startchar(filename) || value_is_numeric(filename)) { sprintf(errstr,"Outfile name %s has invalid start character(s) or looks too much like a number.\n",filename); return(DATA_ERROR); } } p = filename; // Drop file extension while(*p != ENDOFSTR) { if(*p == '.') { *p = ENDOFSTR; break; } p++; } strcpy(dz->outfilename,filename); (*cmdline)++; (*cmdlinecnt)--; return(FINISHED); } /************************ OPEN_THE_OUTFILE *********************/ int open_the_outfile(dataptr dz) { int exit_status; dz->infile->channels = dz->iparam[FRAC_CHANS]; if((exit_status = create_sized_outfile(dz->outfilename,dz))<0) return(exit_status); dz->infile->channels = 1; return(FINISHED); } /***************************** ESTABLISH_APPLICATION **************************/ int establish_application(dataptr dz) { aplptr ap; if((dz->application = (aplptr)malloc(sizeof (struct applic)))==NULL) { sprintf(errstr,"establish_application()\n"); return(MEMORY_ERROR); } ap = dz->application; memset((char *)ap,0,sizeof(struct applic)); return(FINISHED); } /************************* INITIALISE_VFLAGS *************************/ int initialise_vflags(dataptr dz) { int n; if((dz->vflag = (char *)malloc(dz->application->vflag_cnt * sizeof(char)))==NULL) { sprintf(errstr,"INSUFFICIENT MEMORY: vflag store,\n"); return(MEMORY_ERROR); } for(n=0;napplication->vflag_cnt;n++) dz->vflag[n] = FALSE; return FINISHED; } /************************* SETUP_INPUT_PARAM_DEFAULTVALS *************************/ int setup_input_param_defaultval_stores(int tipc,aplptr ap) { int n; if((ap->default_val = (double *)malloc(tipc * sizeof(double)))==NULL) { sprintf(errstr,"INSUFFICIENT MEMORY for application default values store\n"); return(MEMORY_ERROR); } for(n=0;ndefault_val[n] = 0.0; return(FINISHED); } /***************************** SETUP_AND_INIT_INPUT_PARAM_ACTIVITY **************************/ int setup_and_init_input_param_activity(dataptr dz,int tipc) { int n; if((dz->is_active = (char *)malloc((size_t)tipc))==NULL) { sprintf(errstr,"setup_and_init_input_param_activity()\n"); return(MEMORY_ERROR); } for(n=0;nis_active[n] = (char)0; return(FINISHED); } /************************* SETUP_FRACTURE_APPLICATION *******************/ int setup_fracture_application(dataptr dz) { int exit_status; aplptr ap; if((exit_status = establish_application(dz))<0) // GLOBAL return(FAILED); ap = dz->application; // SEE parstruct FOR EXPLANATION of next 2 functions if(dz->mode == 0) { if((exit_status = set_param_data(ap,ENVSERIES,9,5,"iiDDD0000"))<0) return(FAILED); if((exit_status = set_vflgs(ap,"rpdvestSmM",10,"DDDDDDDiDD","yl",2,0,"00"))<0) return(FAILED); } else { if((exit_status = set_param_data(ap,ENVSERIES,9,9,"iiDDDiDdd"))<0) return(FAILED); if((exit_status = set_vflgs(ap,"rpdvesthmiazclfjkwg",19,"DDDDDDDiDDddddddddd","y",1,0,"0"))<0) return(FAILED); } // set_legal_infile_structure --> dz->has_otherfile = FALSE; // assign_process_logic --> dz->input_data_type = SNDFILES_ONLY; dz->process_type = UNEQUAL_SNDFILE; dz->outfiletype = SNDFILE_OUT; return application_init(dz); //GLOBAL } /************************* PARSE_INFILE_AND_CHECK_TYPE *******************/ int parse_infile_and_check_type(char **cmdline,dataptr dz) { int exit_status; infileptr infile_info; if(!sloom) { if((infile_info = (infileptr)malloc(sizeof(struct filedata)))==NULL) { sprintf(errstr,"INSUFFICIENT MEMORY for infile structure to test file data."); return(MEMORY_ERROR); } else if((exit_status = cdparse(cmdline[0],infile_info))<0) { sprintf(errstr,"Failed to parse input file %s\n",cmdline[0]); return(PROGRAM_ERROR); } else if(infile_info->filetype != SNDFILE) { sprintf(errstr,"File %s is not of correct type\n",cmdline[0]); return(DATA_ERROR); } else if(infile_info->channels != 1) { sprintf(errstr,"File %s is not of correct type (must be mono)\n",cmdline[0]); return(DATA_ERROR); } else if((exit_status = copy_parse_info_to_main_structure(infile_info,dz))<0) { sprintf(errstr,"Failed to copy file parsing information\n"); return(PROGRAM_ERROR); } free(infile_info); } return(FINISHED); } /************************* SETUP_FRACTURE_PARAM_RANGES_AND_DEFAULTS *******************/ int setup_fracture_param_ranges_and_defaults(dataptr dz) { int exit_status; aplptr ap = dz->application; // set_param_ranges() ap->total_input_param_cnt = (char)(ap->max_param_cnt + ap->option_cnt + ap->variant_param_cnt); // NB total_input_param_cnt is > 0 !!! if((exit_status = setup_input_param_range_stores(ap->total_input_param_cnt,ap))<0) return(FAILED); // get_param_ranges() ap->hi[FRAC_CHANS] = 16; if(dz->mode == 0) { ap->lo[FRAC_CHANS] = 2; ap->default_val[FRAC_CHANS] = 2; } else { ap->lo[FRAC_CHANS] = 4; ap->default_val[FRAC_CHANS] = 8; } ap->lo[FRAC_STRMS] = 4; ap->hi[FRAC_STRMS] = 512; ap->default_val[FRAC_STRMS] = 16; ap->lo[FRAC_PULSE] = .05; ap->hi[FRAC_PULSE] = 8; ap->default_val[FRAC_PULSE] = 1; ap->lo[FRAC_DEPTH] = 0; ap->hi[FRAC_DEPTH] = 8; ap->default_val[FRAC_DEPTH] = 1; ap->lo[FRAC_STACK] = 0; ap->hi[FRAC_STACK] = 12; ap->default_val[FRAC_STACK] = 0; ap->lo[FRAC_INRND] = 0; ap->hi[FRAC_INRND] = 1; ap->default_val[FRAC_INRND] = 0; ap->lo[FRAC_OUTRND] = 0; ap->hi[FRAC_OUTRND] = 1; ap->default_val[FRAC_OUTRND] = 0; ap->lo[FRAC_SCAT] = 0; ap->hi[FRAC_SCAT] = 1; ap->default_val[FRAC_SCAT] = 0; ap->lo[FRAC_LEVRND] = 0; ap->hi[FRAC_LEVRND] = 1; ap->default_val[FRAC_LEVRND] = 0; ap->lo[FRAC_ENVRND] = 0; ap->hi[FRAC_ENVRND] = 32767; ap->default_val[FRAC_ENVRND] = 0; ap->lo[FRAC_STKRND] = 0; ap->hi[FRAC_STKRND] = 1; ap->default_val[FRAC_STKRND] = 0; ap->lo[FRAC_PCHRND] = 0; ap->hi[FRAC_PCHRND] = 1200; ap->default_val[FRAC_PCHRND] = 0; ap->lo[FRAC_SEED] = 0; ap->hi[FRAC_SEED] = 32767; ap->default_val[FRAC_SEED] = 0; ap->lo[FRAC_MIN] = 0; ap->hi[FRAC_MIN] = 1; ap->default_val[FRAC_MIN] = 0; ap->lo[FRAC_MAX] = 0; ap->hi[FRAC_MAX] = 16; ap->default_val[FRAC_MAX] = 0; if(dz->mode > 0) { ap->lo[FRAC_CENTRE] = 0; ap->hi[FRAC_CENTRE] = 16; ap->default_val[FRAC_CENTRE] = 1; ap->lo[FRAC_FRONT] = -4; // -2= -infinity : further -2 allows for max-mdepth (* 2) as rear of moving-front dragged behind front ap->hi[FRAC_FRONT] = 2; // 2 = +infinity ap->default_val[FRAC_FRONT] = 0; ap->lo[FRAC_MDEPTH] = 0; ap->hi[FRAC_MDEPTH] = 1; ap->default_val[FRAC_MDEPTH] = 0.5; ap->lo[FRAC_ROLLOFF] = 0.0; ap->hi[FRAC_ROLLOFF] = 1.0; ap->default_val[FRAC_ROLLOFF] = 0.0; ap->lo[FRAC_ATTEN] = 1.0; ap->hi[FRAC_ATTEN] = 10.0; ap->default_val[FRAC_ATTEN] = 3.0; ap->lo[FRAC_ZPOINT] = 0.0; ap->hi[FRAC_ZPOINT] = 1.0; ap->default_val[FRAC_ZPOINT] = 0.66; ap->lo[FRAC_CONTRACT] = 0.0; ap->hi[FRAC_CONTRACT] = 1.0; ap->default_val[FRAC_CONTRACT] = 0.66; ap->lo[FRAC_FPOINT] = 0.0; ap->hi[FRAC_FPOINT] = 1.0; ap->default_val[FRAC_FPOINT] = 0.66; ap->lo[FRAC_FFACTOR] = 0.0; ap->hi[FRAC_FFACTOR] = 1.0; ap->default_val[FRAC_FFACTOR] = 0.66; ap->lo[FRAC_FFREQ] = 10.0; ap->hi[FRAC_FFREQ] = (dz->nyquist/2.0) * 0.8; ap->default_val[FRAC_FFREQ] = 500.0; ap->lo[FRAC_UP] = 0.0; ap->hi[FRAC_UP] = 1.0; ap->default_val[FRAC_UP] = 0.0; ap->lo[FRAC_DN] = 0.0; ap->hi[FRAC_DN] = 1.0; ap->default_val[FRAC_DN] = 0.0; ap->lo[FRAC_GAIN] = 0.0; ap->hi[FRAC_GAIN] = 1.0; ap->default_val[FRAC_GAIN] = 1.0; } dz->maxmode = 2; if(!sloom) put_default_vals_in_all_params(dz); return(FINISHED); } /********************************* PARSE_SLOOM_DATA *********************************/ int parse_sloom_data(int argc,char *argv[],char ***cmdline,int *cmdlinecnt,dataptr dz) { int exit_status; int cnt = 1, infilecnt; int filesize, insams, inbrksize; double dummy; int true_cnt = 0; // aplptr ap; while(cnt<=PRE_CMDLINE_DATACNT) { if(cnt > argc) { sprintf(errstr,"Insufficient data sent from TK\n"); return(DATA_ERROR); } switch(cnt) { case(1): if(sscanf(argv[cnt],"%d",&dz->process)!=1) { sprintf(errstr,"Cannot read process no. sent from TK\n"); return(DATA_ERROR); } break; case(2): if(sscanf(argv[cnt],"%d",&dz->mode)!=1) { sprintf(errstr,"Cannot read mode no. sent from TK\n"); return(DATA_ERROR); } if(dz->mode > 0) dz->mode--; //setup_particular_application() = if((exit_status = setup_fracture_application(dz))<0) return(exit_status); // ap = dz->application; break; case(3): if(sscanf(argv[cnt],"%d",&infilecnt)!=1) { sprintf(errstr,"Cannot read infilecnt sent from TK\n"); return(DATA_ERROR); } if(infilecnt < 1) { true_cnt = cnt + 1; cnt = PRE_CMDLINE_DATACNT; /* force exit from loop after assign_file_data_storage */ } if((exit_status = assign_file_data_storage(infilecnt,dz))<0) return(exit_status); break; case(INPUT_FILETYPE+4): if(sscanf(argv[cnt],"%d",&dz->infile->filetype)!=1) { sprintf(errstr,"Cannot read filetype sent from TK (%s)\n",argv[cnt]); return(DATA_ERROR); } break; case(INPUT_FILESIZE+4): if(sscanf(argv[cnt],"%d",&filesize)!=1) { sprintf(errstr,"Cannot read infilesize sent from TK\n"); return(DATA_ERROR); } dz->insams[0] = filesize; break; case(INPUT_INSAMS+4): if(sscanf(argv[cnt],"%d",&insams)!=1) { sprintf(errstr,"Cannot read insams sent from TK\n"); return(DATA_ERROR); } dz->insams[0] = insams; break; case(INPUT_SRATE+4): if(sscanf(argv[cnt],"%d",&dz->infile->srate)!=1) { sprintf(errstr,"Cannot read srate sent from TK\n"); return(DATA_ERROR); } break; case(INPUT_CHANNELS+4): if(sscanf(argv[cnt],"%d",&dz->infile->channels)!=1) { sprintf(errstr,"Cannot read channels sent from TK\n"); return(DATA_ERROR); } break; case(INPUT_STYPE+4): if(sscanf(argv[cnt],"%d",&dz->infile->stype)!=1) { sprintf(errstr,"Cannot read stype sent from TK\n"); return(DATA_ERROR); } break; case(INPUT_ORIGSTYPE+4): if(sscanf(argv[cnt],"%d",&dz->infile->origstype)!=1) { sprintf(errstr,"Cannot read origstype sent from TK\n"); return(DATA_ERROR); } break; case(INPUT_ORIGRATE+4): if(sscanf(argv[cnt],"%d",&dz->infile->origrate)!=1) { sprintf(errstr,"Cannot read origrate sent from TK\n"); return(DATA_ERROR); } break; case(INPUT_MLEN+4): if(sscanf(argv[cnt],"%d",&dz->infile->Mlen)!=1) { sprintf(errstr,"Cannot read Mlen sent from TK\n"); return(DATA_ERROR); } break; case(INPUT_DFAC+4): if(sscanf(argv[cnt],"%d",&dz->infile->Dfac)!=1) { sprintf(errstr,"Cannot read Dfac sent from TK\n"); return(DATA_ERROR); } break; case(INPUT_ORIGCHANS+4): if(sscanf(argv[cnt],"%d",&dz->infile->origchans)!=1) { sprintf(errstr,"Cannot read origchans sent from TK\n"); return(DATA_ERROR); } break; case(INPUT_SPECENVCNT+4): if(sscanf(argv[cnt],"%d",&dz->infile->specenvcnt)!=1) { sprintf(errstr,"Cannot read specenvcnt sent from TK\n"); return(DATA_ERROR); } dz->specenvcnt = dz->infile->specenvcnt; break; case(INPUT_WANTED+4): if(sscanf(argv[cnt],"%d",&dz->wanted)!=1) { sprintf(errstr,"Cannot read wanted sent from TK\n"); return(DATA_ERROR); } break; case(INPUT_WLENGTH+4): if(sscanf(argv[cnt],"%d",&dz->wlength)!=1) { sprintf(errstr,"Cannot read wlength sent from TK\n"); return(DATA_ERROR); } break; case(INPUT_OUT_CHANS+4): if(sscanf(argv[cnt],"%d",&dz->out_chans)!=1) { sprintf(errstr,"Cannot read out_chans sent from TK\n"); return(DATA_ERROR); } break; /* RWD these chanegs to samps - tk will have to deal with that! */ case(INPUT_DESCRIPTOR_BYTES+4): if(sscanf(argv[cnt],"%d",&dz->descriptor_samps)!=1) { sprintf(errstr,"Cannot read descriptor_samps sent from TK\n"); return(DATA_ERROR); } break; case(INPUT_IS_TRANSPOS+4): if(sscanf(argv[cnt],"%d",&dz->is_transpos)!=1) { sprintf(errstr,"Cannot read is_transpos sent from TK\n"); return(DATA_ERROR); } break; case(INPUT_COULD_BE_TRANSPOS+4): if(sscanf(argv[cnt],"%d",&dz->could_be_transpos)!=1) { sprintf(errstr,"Cannot read could_be_transpos sent from TK\n"); return(DATA_ERROR); } break; case(INPUT_COULD_BE_PITCH+4): if(sscanf(argv[cnt],"%d",&dz->could_be_pitch)!=1) { sprintf(errstr,"Cannot read could_be_pitch sent from TK\n"); return(DATA_ERROR); } break; case(INPUT_DIFFERENT_SRATES+4): if(sscanf(argv[cnt],"%d",&dz->different_srates)!=1) { sprintf(errstr,"Cannot read different_srates sent from TK\n"); return(DATA_ERROR); } break; case(INPUT_DUPLICATE_SNDS+4): if(sscanf(argv[cnt],"%d",&dz->duplicate_snds)!=1) { sprintf(errstr,"Cannot read duplicate_snds sent from TK\n"); return(DATA_ERROR); } break; case(INPUT_BRKSIZE+4): if(sscanf(argv[cnt],"%d",&inbrksize)!=1) { sprintf(errstr,"Cannot read brksize sent from TK\n"); return(DATA_ERROR); } if(inbrksize > 0) { switch(dz->input_data_type) { case(WORDLIST_ONLY): break; case(PITCH_AND_PITCH): case(PITCH_AND_TRANSPOS): case(TRANSPOS_AND_TRANSPOS): dz->tempsize = inbrksize; break; case(BRKFILES_ONLY): case(UNRANGED_BRKFILE_ONLY): case(DB_BRKFILES_ONLY): case(ALL_FILES): case(ANY_NUMBER_OF_ANY_FILES): if(dz->extrabrkno < 0) { sprintf(errstr,"Storage location number for brktable not established by CDP.\n"); return(DATA_ERROR); } if(dz->brksize == NULL) { sprintf(errstr,"CDP has not established storage space for input brktable.\n"); return(PROGRAM_ERROR); } dz->brksize[dz->extrabrkno] = inbrksize; break; default: sprintf(errstr,"TK sent brktablesize > 0 for input_data_type [%d] not using brktables.\n", dz->input_data_type); return(PROGRAM_ERROR); } break; } break; case(INPUT_NUMSIZE+4): if(sscanf(argv[cnt],"%d",&dz->numsize)!=1) { sprintf(errstr,"Cannot read numsize sent from TK\n"); return(DATA_ERROR); } break; case(INPUT_LINECNT+4): if(sscanf(argv[cnt],"%d",&dz->linecnt)!=1) { sprintf(errstr,"Cannot read linecnt sent from TK\n"); return(DATA_ERROR); } break; case(INPUT_ALL_WORDS+4): if(sscanf(argv[cnt],"%d",&dz->all_words)!=1) { sprintf(errstr,"Cannot read all_words sent from TK\n"); return(DATA_ERROR); } break; case(INPUT_ARATE+4): if(sscanf(argv[cnt],"%f",&dz->infile->arate)!=1) { sprintf(errstr,"Cannot read arate sent from TK\n"); return(DATA_ERROR); } break; case(INPUT_FRAMETIME+4): if(sscanf(argv[cnt],"%lf",&dummy)!=1) { sprintf(errstr,"Cannot read frametime sent from TK\n"); return(DATA_ERROR); } dz->frametime = (float)dummy; break; case(INPUT_WINDOW_SIZE+4): if(sscanf(argv[cnt],"%f",&dz->infile->window_size)!=1) { sprintf(errstr,"Cannot read window_size sent from TK\n"); return(DATA_ERROR); } break; case(INPUT_NYQUIST+4): if(sscanf(argv[cnt],"%lf",&dz->nyquist)!=1) { sprintf(errstr,"Cannot read nyquist sent from TK\n"); return(DATA_ERROR); } break; case(INPUT_DURATION+4): if(sscanf(argv[cnt],"%lf",&dz->duration)!=1) { sprintf(errstr,"Cannot read duration sent from TK\n"); return(DATA_ERROR); } break; case(INPUT_MINBRK+4): if(sscanf(argv[cnt],"%lf",&dz->minbrk)!=1) { sprintf(errstr,"Cannot read minbrk sent from TK\n"); return(DATA_ERROR); } break; case(INPUT_MAXBRK+4): if(sscanf(argv[cnt],"%lf",&dz->maxbrk)!=1) { sprintf(errstr,"Cannot read maxbrk sent from TK\n"); return(DATA_ERROR); } break; case(INPUT_MINNUM+4): if(sscanf(argv[cnt],"%lf",&dz->minnum)!=1) { sprintf(errstr,"Cannot read minnum sent from TK\n"); return(DATA_ERROR); } break; case(INPUT_MAXNUM+4): if(sscanf(argv[cnt],"%lf",&dz->maxnum)!=1) { sprintf(errstr,"Cannot read maxnum sent from TK\n"); return(DATA_ERROR); } break; default: sprintf(errstr,"case switch item missing: parse_sloom_data()\n"); return(PROGRAM_ERROR); } cnt++; } if(cnt!=PRE_CMDLINE_DATACNT+1) { sprintf(errstr,"Insufficient pre-cmdline params sent from TK\n"); return(DATA_ERROR); } if(true_cnt) cnt = true_cnt; *cmdlinecnt = 0; while(cnt < argc) { if((exit_status = get_tk_cmdline_word(cmdlinecnt,cmdline,argv[cnt]))<0) return(exit_status); cnt++; } return(FINISHED); } /********************************* GET_TK_CMDLINE_WORD *********************************/ int get_tk_cmdline_word(int *cmdlinecnt,char ***cmdline,char *q) { if(*cmdlinecnt==0) { if((*cmdline = (char **)malloc(sizeof(char *)))==NULL) { sprintf(errstr,"INSUFFICIENT MEMORY for TK cmdline array.\n"); return(MEMORY_ERROR); } } else { if((*cmdline = (char **)realloc(*cmdline,((*cmdlinecnt)+1) * sizeof(char *)))==NULL) { sprintf(errstr,"INSUFFICIENT MEMORY for TK cmdline array.\n"); return(MEMORY_ERROR); } } if(((*cmdline)[*cmdlinecnt] = (char *)malloc((strlen(q) + 1) * sizeof(char)))==NULL) { sprintf(errstr,"INSUFFICIENT MEMORY for TK cmdline item %d.\n",(*cmdlinecnt)+1); return(MEMORY_ERROR); } strcpy((*cmdline)[*cmdlinecnt],q); (*cmdlinecnt)++; return(FINISHED); } /****************************** ASSIGN_FILE_DATA_STORAGE *********************************/ int assign_file_data_storage(int infilecnt,dataptr dz) { int exit_status; int no_sndfile_system_files = FALSE; dz->infilecnt = infilecnt; if((exit_status = allocate_filespace(dz))<0) return(exit_status); if(no_sndfile_system_files) dz->infilecnt = 0; return(FINISHED); } /************************* redundant functions: to ensure libs compile OK *******************/ int assign_process_logic(dataptr dz) { return(FINISHED); } void set_legal_infile_structure(dataptr dz) {} int set_legal_internalparam_structure(int process,int mode,aplptr ap) { return(FINISHED); } int setup_internal_arrays_and_array_pointers(dataptr dz) { return(FINISHED); } int establish_bufptrs_and_extra_buffers(dataptr dz) { return(FINISHED); } int read_special_data(char *str,dataptr dz) { return(FINISHED); } int inner_loop (int *peakscore,int *descnt,int *in_start_portion,int *least,int *pitchcnt,int windows_in_buf,dataptr dz) { return(FINISHED); } int get_process_no(char *prog_identifier_from_cmdline,dataptr dz) { return(FINISHED); } /******************************** USAGE1 ********************************/ int usage1(void) { usage2("fracture"); return(USAGE_ONLY); } /**************************** CHECK_FRACTURE_PARAM_VALIDITY_AND_CONSISTENCY *****************************/ int check_fracture_param_validity_and_consistency(dataptr dz) { int exit_status; double maxval, minval, xs; int n,m; if(dz->brksize[FRAC_STACK]) { for(n=0,m=1;n < dz->brksize[FRAC_STACK];n++,m+=2) { if(dz->brk[FRAC_STACK][m] <= 0.0) { sprintf(errstr,"Stacking value cannot be zero inside a breakpoint file,\n"); return(DATA_ERROR); } } } if(dz->iparam[FRAC_SEED] > 0) srand((int)dz->iparam[FRAC_SEED]); if(dz->brksize[FRAC_DEPTH]) { if((exit_status = get_maxvalue_in_brktable(&maxval,FRAC_DEPTH,dz))<0) return PROGRAM_ERROR; } else maxval = dz->param[FRAC_DEPTH]; if(maxval <= 1.0) { if(dz->brksize[FRAC_STACK] || (dz->param[FRAC_STACK] != 0)) { fprintf(stdout,"WARNING: Stack parameter set, but Depth never exceeds 1, so no stacking.\n"); fflush(stdout); dz->brksize[FRAC_STACK] = 0; dz->param[FRAC_STACK] = 0.0; } if(dz->brksize[FRAC_STKRND] || (dz->param[FRAC_STKRND] != 0)) { fprintf(stdout,"WARNING: Stack randomisation parameter set, but Depth never exceeds 1, so no stacking.\n"); fflush(stdout); dz->brksize[FRAC_STKRND] = 0; dz->param[FRAC_STKRND] = 0.0; } } else { // If stack value will be operational, if set to zero, reset NOW to 12 if(!dz->brksize[FRAC_STACK] && dz->param[FRAC_STACK] == 0.0) dz->param[FRAC_STACK] = 12.0; } if(dz->mode > 0) { if(dz->iparam[FRAC_CHANS] % 4 != 0) { sprintf(errstr,"Number of output channels must be a multiple of 4.\n"); return(DATA_ERROR); } xs = dz->param[FRAC_MDEPTH] * 2; if(dz->brksize[FRAC_FRONT]) { maxval = dz->brk[FRAC_FRONT][1]; minval = maxval; for(n=1,m=3;nbrksize[FRAC_FRONT];n++,m+=2) { if(dz->brk[FRAC_FRONT][m] > minval) { sprintf(errstr,"Front value must move from high values to low values,\n"); return(DATA_ERROR); } minval = dz->brk[FRAC_FRONT][m]; } dz->fulldur = dz->brk[FRAC_FRONT][(dz->brksize[FRAC_FRONT] -1) * 2]; } else { dz->fulldur = dz->duration; maxval = dz->param[FRAC_FRONT]; minval = dz->param[FRAC_FRONT]; } dz->fltractv = 0; if(maxval > 1.0 || minval < -(1 + xs)) dz->fltractv = 1; if(dz->param[FRAC_UP] + dz->param[FRAC_DN] >= 1.0) { sprintf(errstr,"Fade up and Fade down times must add up to LESS THEN 1.\n"); return(DATA_ERROR); } dz->param[FRAC_UP] *= dz->fulldur; dz->param[FRAC_DN] *= dz->fulldur; } return FINISHED; } /********************************************************************************************/ int get_the_process_no(char *prog_identifier_from_cmdline,dataptr dz) { if(!strcmp(prog_identifier_from_cmdline,"fracture")) dz->process = FRACTURE; else { sprintf(errstr,"Unknown program identification string '%s'\n",prog_identifier_from_cmdline); return(USAGE_ONLY); } return(FINISHED); } /******************************** SETUP_AND_INIT_INPUT_BRKTABLE_CONSTANTS ********************************/ int setup_and_init_input_brktable_constants(dataptr dz,int brkcnt) { int n; if((dz->brk = (double **)malloc(brkcnt * sizeof(double *)))==NULL) { sprintf(errstr,"setup_and_init_input_brktable_constants(): 1\n"); return(MEMORY_ERROR); } if((dz->brkptr = (double **)malloc(brkcnt * sizeof(double *)))==NULL) { sprintf(errstr,"setup_and_init_input_brktable_constants(): 6\n"); return(MEMORY_ERROR); } if((dz->brksize = (int *)malloc(brkcnt * sizeof(int)))==NULL) { sprintf(errstr,"setup_and_init_input_brktable_constants(): 2\n"); return(MEMORY_ERROR); } if((dz->firstval = (double *)malloc(brkcnt * sizeof(double)))==NULL) { sprintf(errstr,"setup_and_init_input_brktable_constants(): 3\n"); return(MEMORY_ERROR); } if((dz->lastind = (double *)malloc(brkcnt * sizeof(double)))==NULL) { sprintf(errstr,"setup_and_init_input_brktable_constants(): 4\n"); return(MEMORY_ERROR); } if((dz->lastval = (double *)malloc(brkcnt * sizeof(double)))==NULL) { sprintf(errstr,"setup_and_init_input_brktable_constants(): 5\n"); return(MEMORY_ERROR); } if((dz->brkinit = (int *)malloc(brkcnt * sizeof(int)))==NULL) { sprintf(errstr,"setup_and_init_input_brktable_constants(): 7\n"); return(MEMORY_ERROR); } for(n=0;nbrk[n] = NULL; dz->brkptr[n] = NULL; dz->brkinit[n] = 0; dz->brksize[n] = 0; } return(FINISHED); } /******************************** USAGE2 ********************************/ int usage2(char *str) { if(!strcmp(str,"fracture")) { fprintf(stderr, "USAGE:fracture fracture 1\n" "infil outfil etab chns strms pulse edpth stkint [-hseed] [-mmin] [-imax] [-rrrnd]\n" "[-pprnd] [-ddisp] [-vlrnd] [-eernd] [-srnd] [-ttrnd] [-y] [-l]\n" "\n" "OR\n" "\n" "USAGE:fracture fracture 2\n" "infil outfil etab chns strms pulse edpth stkint cntre frnt depth rolloff [-hseed]\n" "[-mmin] [-imax] [-rrrnd] [-pprnd] [-ddisp] [-vlrnd] [-eernd] [-srnd] [-ttrnd]\n" "[-aatten] [-zzpoint] [-ccontract] [] [-llopnt] [-ffmix] [-jffrq] [-kup] [-wdn] [-y]\n" "\n" "DISPERSE MONO SIGNAL INTO FRAGMENTS SPREAD OVER N-CHANNEL SPACE.\n" "\n" "Mode 1: Output is N-channel dispersal in N-channel space.\n" "Mode 2: Output is stereo dispersal (posibly moving) in surround space.\n" "\n" "PRESS ANY KEY TO CONTINUE\n"); while(!kbhit()) ; if(kbhit()) { fprintf(stderr, "ETAB Textfile: Each line is a TIME followed by 7 PAIRS of envelope-data.\n" " envelope-data represented in form \"etime lev\"\n" " where \"etime\" is relative time WITHIN envelope (values between 0 & 1)\n" " and \"lev\" is level at etime (values 0-1). In each envelope-data set\n" " \"lev\" must start and end at zero and rise to a max value of 1.0\n" "CHNS Number of channels in output file (2-16). (Mode 2, multiples of 4 only).\n" "STRMS No. of spatial positions (streams) for resulting fragments ( >=4 ).\n" "PULSE Average gap btwn 1 set-of-frags (each in different strm) & next set.\n" " Disp = 0: all frags in sync at each (possibly randomised) pulse.\n" " Disp > 0: frags time-scattered around pulse centre. (see below).\n" "EDPTH Envelope depth. 1: env cuts down to zero, 0.75: cuts 3/4 way to zero,\n" "(+STACK) 0.1: cuts only 1/10 way to zero, 0: env has no effect on source.\n" " Once depth exceeds 1, fragments begin to stack (but NOT before)\n" " (i.e. transposed copies added to fragment, synced at envelope peak).\n" " Depth 2 -> Stack 1: 1st transposed element added at full level.\n" " Depth 1.5 -> Stack 06.5: 1st transpd element added at 1/2 (0.5) level.\n" " Depth 2.5 -> Stack 1.5: 1st added at full level, 2nd at 1/2 level etc\n" "STKINT Interval of (upward) transposition in stack, in semitones (0-12).\n" " Default(0) is read as octave(12). NO ZEROS in stack brkpoint files.\n" "SEED If NOT zero, repeating process with same seed gives identical output.\n" "MIN/MAX Minimum/maximum duration of fragments. If zero, no minimum/maximum.\n" "RRND Randomisation of read-time in src. Range 0-1.\n" "PRND Randomisation of pulse-time in output. Range 0-1.\n" " In both cases, Max(1) scatters in range +- half-duration of pulse.\n" "DISP Dispersal (scatter) of output timings between different streams.\n" " If pulse(+prnd) gives time \"P\", then for disp 0: all frags are at \"P\"\n" " for disp 1: frags scattered within max range (+- half-dur of pulse).\n" "LRND Randomisation of levels (volume) of fragments. Range 0 - 1.\n" " 0: All frags full level. 1: Frags at random levels between 0 & full.\n" "ERND Randomisation of envelope used. A time range (trange).\n" " Event at \"now\" reads etable at randtime btwn \"now\" & now-minus-trange.\n" "SRND Randomisation of stack. Range 0 - 1 (NB stack value (S) = DEPTH-1)\n" " 0: Stack value is S. 1: Stack val selected at random between 0 & S.\n" "TRND Random tranpose of fragments. Range 0-1200 cents (1 octave upwards).\n" " Event pitch randomised between pitch+trnd and pitch-trnd.\n" "-z Permit stacking of very short events. Default = forbid, prevent clipping.\n" "-l For more than 2 output chans, lspkrs assumed to encircle listeners,\n" " with a single lspkr at centre front.\n" " Setting -l flag assumes linear array, with leftmost+rightmost lspkrs.\n" "\n" "NB: STKINT, MAX, RRND, LRND, SRND and TRND are INACTIVE if depth < 1.\n" "All these params can timevary EXCEPT \"chns\", \"strms\" & \"seed\".\n" "\n" "PRESS KEY \"2\" TO SEE EXTRA OPTIONS AVAILABLE IN MODE 2\n" "OR ANY OTHER KEY TO FINISH.\n"); } if(getch()=='2') { fprintf(stderr, "MODE 2 ONLY: Additional parameters.\n" "\n" "CNTRE Channel from which stereo-image spreads out.\n" "FRNT Output leading edge: 1 = in cntr lspkr: -1= in lspkr opposite cntr.\n" " 0 = on bisector of entire sound-surround space.\n" " 2 = infinitely far away in direction of centre,\n" " -(2+(depth*2)) = infinitely far away in direction opposite to centre.\n" " If front moves, forward movement only (no reversals of direction)\n" " and if doesn't go to infinity, event itself fades to 0 from midtime.\n" "DEPTH maximum fraction of all output chans turned on, behind front.\n" "ROLLOFF level fall as signal is spread over several chans. Range 0-1.\n" " 0 = no fall in level, 1 = level divided by number of chans in use.\n" "ATTEN Level Attenuation factor for distance, or sound fade-out.\n" " (Range >= 1 : 1 = linear).\n" "ZPOINT Point where image subtends zero angle(mono): 0 circle edge, 1 infinity\n" "CONTRACT Contraction factor narrowing distant image width (>=1 : 1= linear).\n" "LOPNT Distance where lopas-filtering is total ( 0 circle edge, 1 infinity.\n" "FMIX Factor for mixing lopas-filtrd signal into orig, with distance (>=1).\n" "FFREQ Lo-pass filter cut-off frequency.\n" "UP If NOT zero, proportion of overall dur over which event fades from 0.\n" " This is independent of any fadeup-with-approach-to-circle.\n" "DN If NOT zero, proportion of overall dur over which event fades to 0.\n" " This is independent of any fadeout-with-distance-from-circle.\n" "GAIN Overall gain (0-1). If \"contract\" is very much faster than \"atten\",\n" " rare possibility of overload, as signal is forced to mono.\n" "-z Permit stacking of very short events. Default = forbid, prevent clipping.\n" "\n" "in MODE 2, of the additional parameters, only \"frnt\" can vary in time.\n"); } } else fprintf(stdout,"Unknown option '%s'\n",str); return(USAGE_ONLY); } int usage3(char *str1,char *str2) { fprintf(stderr,"Insufficient parameters on command line.\n"); return(USAGE_ONLY); } /******************************** FRACTURE *******************************/ int fracture(int ibuflen,int envbuflen,int overflow,dataptr dz) { int exit_status, chans, tim, lev, stim, etim, toget, thistack, filter_state = 0, dostack; double srate = (double)dz->infile->srate, maxsamp = 0.0, normaliser; int n, m, total_samps_written = 0, end_read_buf_at = -1, start_read_buf_at = 0; int strmcnt = dz->iparam[FRAC_STRMS]; /* * LONG ARRAYS: S = number of streams iptr (start of read WITHIN current input buffer, for each stream) * | temp storage of event starttimes * |---------------|---------------| | | * | segendsamp | inreadsamp | | | NB segendsamp is in MONO samps * address 0 S 2S| | need to change to (segendsamp * chans) * | | | 2S+1 + lmost(rmost) % dz->buflen * array | maxevents | maxevents | | | for write!! * length | | strmcnt * | | | strmcnt */ int **evend = dz->lparray, **iread = dz->lparray + strmcnt; // Event endtime & input-read position, for each \fragment in each stream in each event-group int *iptr = dz->lparray[2*strmcnt]; // Pointers into input buffer, for each stream in current event-group int *evstt = dz->lparray[(2*strmcnt)+1]; // Envelope starttime in each stream in current event-group /* * DOUBLE ARRAYS: S = number of streams | llev * | | | rlev * |---------------|---------------|---------------|---------------|---------------| | pos * | depth | level | transpos | envreadtime | stacking | | | tempenv * | | | | | 5S| | | envdata * | | | | | | 5S+1| | stakcentre * address 0 S 2S 3S 4S | | 5S+2| | grptimes * | | | | | | | | 5S+3| | | * | | | | | | | | | 5S+4| | * array | maxevents | maxevents | maxevents | maxevents | maxevents | | | | | 5S+5| * length | | | | | S S S | | | 5S+6 * | | | | | | | | 14| | | | * | | | | | | | | | dz->envcount * 15 * | | | | | | | | | | S | | * | | | | | | | | | | | maxevents */ double **depth = dz->parray; // Envelope (end) depth for each event in each stream double **evlev = dz->parray + strmcnt; // Level for each event in each stream double **evpch = dz->parray + (2 * strmcnt); // Transposition for each event in each stream double **eread = dz->parray + (3 * strmcnt); // Position to read envelope table for each event in each stream double **stakk = dz->parray + (4 * strmcnt); // Stacking value for each event in each stream double *llev = dz->parray[5 * strmcnt], *rlev = dz->parray[(5 * strmcnt)+1]; // Left and Right level for each stream, to create correct positioning double *tempenv = dz->parray[dz->envbuf]; // Temporary envelope store double *stkcntr = dz->parray[(5 * strmcnt)+5]; // Central peak of current envelope for each stream double *gptime = dz->parray[(5 * strmcnt)+6]; // group-Timing of events (for reading brktables) /* * INTEGER ARRAYS: S = number of streams * * lmost * | rmost * | | | * address 0 1 | * | | | * array S S | * length | | | */ int *lmost = dz->iparray[0], *rmost = dz->iparray[1]; // Left & right lspkr for each stream /* * SOUND BUFFERS * | input | enveloping| stacking | output | overflow | * */ float *ibuf = dz->sampbuf[0]; float *ebuf = dz->sampbuf[1]; float *stkbuf= dz->sampbuf[2]; float *obuf = dz->sampbuf[3]; float *ovflw = dz->sampbuf[4]; int write_end = 0; double gp_stependtime = 0.0, last_gp_stependtime = 0.0, time, endtime, readtime; double init_depth, startdepth, enddepth, depthchange, thisdepth; double gp_stepdur, last_gp_stepdur = 0.0, randscat, maxeoffset, stack, this_stack, level, lbas, tdiff, ldiff, eval, frac; double transpos, incr, dsampcnt, loval, hival, diff, val, levrand, outincr, dipos, centre = 0.0; int losamp, hisamp, sectcnt = 0, cntrswitch = 0, outside = 0; int evcnt = 0, total_evcnt, minevstt, minread = 0, maxread = 0, ldur, sampcnt, stakwrite_at, opos, lpos, rpos, samps_to_write, iposlo, iposhi; int samps_to_read, samps_read, this_write_end, evlen, endevent, endeventend, fracmax = 0, endzeros = 0, samps_to_process; int display_limit = 2 * dz->infile->srate, this_display_limit = display_limit; double maxscatrange, lastev, offset, scatter_ambit_stt, scatter_ambit_end, available_dur, spread = 0.0, fmix = 0.0, prand; if(dz->mode == 0) chans = dz->iparam[FRAC_CHANS]; else chans = STEREO; // Process initially creates stereo image which is then dispersed over multichannel space fprintf(stdout,"INFO: Level Check at %lf secs\n",(double)(total_samps_written/chans)/srate); fflush(stdout); while(gp_stependtime < dz->duration) { time = gp_stependtime; // Set start-time to end of last GROUP step gptime[evcnt] = time; if((exit_status = read_values_from_all_existing_brktables(time,dz))<0) return exit_status; if(dz->param[FRAC_MAX] > 0.0 && dz->param[FRAC_MIN] >= dz->param[FRAC_MAX]) { sprintf(errstr,"Max (%lf) and min (%lf) fragment-lengths incompatible at %lf secs\n", dz->param[FRAC_MIN],dz->param[FRAC_MAX],time); return DATA_ERROR; } dz->iparam[FRAC_MAX] = (int)ceil(dz->param[FRAC_MAX] * srate); init_depth = dz->param[FRAC_DEPTH]; // Initial depth retained here for first event // SET THE STREAMS-GROUP END-POSITION, POSSIBLY RANDOMISED gp_stepdur = dz->param[FRAC_PULSE]; // Get duration of this step if(dz->param[FRAC_OUTRND] > 0.0) { // If ness, random scatter this randscat = (drand48() * 2.0) - 1.0; // Range -1 to +1 randscat *= gp_stepdur/2.0; // Range (1/2*stepdur) to (3/2*stepdur) gp_stepdur += randscat; // Modify grp-stepdur } gp_stependtime = time + gp_stepdur; // This will be start of next event // GET THE EVENT START AND END WRITE POSITIONS FOR EACH STREAM (POSSIBLT SCATTERED) for(n=0;nparam[FRAC_SCAT] > 0.0) { // Around the (already rand-offset) end-timing of the group if(dz->param[FRAC_MIN] > 0.0) { scatter_ambit_stt = gp_stependtime - maxscatrange; scatter_ambit_end = gp_stependtime + maxscatrange; if(evcnt == 0) lastev = 0.0; else lastev = (evend[n][evcnt-1])/srate; // End time of previous event available_dur = scatter_ambit_end - lastev; if(available_dur <= dz->param[FRAC_MIN]) { // If insufficient space for min-dur fragment if(evcnt == 0) evend[n][evcnt] = 0; else evend[n][evcnt] = evend[n][evcnt-1]; // Reduce event length to zero i.e. eliminate the event continue; } else { endtime = lastev + dz->param[FRAC_MIN]; // Move base of rand-vary to min-duration point if(endtime >= scatter_ambit_stt) { // If the min length falls inside ambit of current gp-position available_dur -= dz->param[FRAC_MIN]; // Length to scatter-amongst is what remains } else { // If NOT endtime = scatter_ambit_stt; // force base into ambit of current gp-position available_dur = maxscatrange * 2.0; // Length to scatter-amongst is whole ambit around gp-position } // Do randomisation within the remaining range randscat = drand48(); // Range 0 to 1 randscat *= available_dur * dz->param[FRAC_SCAT]; } } else { randscat = (drand48() * 2) - 1.0; // Range -1 to 1 if(evcnt > 0) { lastev = (evend[n][evcnt-1])/srate; // End time of previous event offset = gp_stependtime - lastev; // Time between end of last event and current event_group centre if(offset <= 0) { // Previous event end is beyond current gpevent-end evend[n][evcnt] = evend[n][evcnt-1]; // Reduce event length to zero i.e. eliminate the event continue; } else if(offset < maxscatrange && randscat < 0.0) // If scattering DOWN, and offset smaller than maxrange randscat *= offset * dz->param[FRAC_SCAT]; // Scatter within offset else // In all other cases, scatter within true maxrange randscat *= maxscatrange * dz->param[FRAC_SCAT]; } else randscat *= maxscatrange * dz->param[FRAC_SCAT]; } endtime += randscat; // Use the actual group step-position as basis to calc rand-offsets } evend[n][evcnt] = (int)round(endtime * srate); } // DECIDE IF A WRITE-OUTBUF IS REQUIRED, AND IF SO, DO IT minevstt = evstt[0]; // Find minimum event start for(n=1;n= dz->buflen) { // If next write will start at or after buffer end if(total_samps_written/chans > this_display_limit) { fprintf(stdout,"INFO: Level Check at %lf secs\n",(double)(total_samps_written/chans)/srate); fflush(stdout); this_display_limit += display_limit; } for(n=0;n < dz->buflen;n++) // "Write", copy overflow back, zero overflow maxsamp = max(maxsamp,fabs(obuf[n])); total_samps_written += dz->buflen; write_end -= dz->buflen; for(n = 0;n < write_end;n++) // Copy back overflow into obuf (overflow may be longer than obuf) obuf[n] = ovflw[n]; // and zero remainder of overflow memset((char *)(obuf+write_end),0,(dz->buflen + overflow - write_end) * sizeof(float)); } // FIND END DEPTH OF EACH STREAM for(n=0;nbrksize[FRAC_DEPTH]) { if((exit_status = read_value_from_brktable(endtime,FRAC_DEPTH,dz))<0) return(exit_status); // And read depth at end of event } depth[n][evcnt] = dz->param[FRAC_DEPTH]; } // FIND READ SAMPLE OF EACH STREAM, (RANDOMISED IF REQUIRED) AND MAX AND MINIMUM READ if(evcnt == 0) { // At very start, all segments are read at 0 for(n=0;niparam[FRAC_MAX]; } else { for(n=0;nparam[FRAC_INRND] > 0) { randscat = (drand48() * 2) - 1.0; // Around the timing START of the group randscat *= (last_gp_stepdur/2.0) * dz->param[FRAC_INRND]; readtime += randscat;// Using the actual group step-duration as basis to calc rand offsets } iread[n][evcnt] = (int)round(readtime * srate); fracmax = dz->iparam[FRAC_MAX]; } evlen = evend[n][evcnt] - evend[n][evcnt-1]; if(fracmax > 0) evlen = min(evlen,fracmax); if(n==0) { minread = iread[n][evcnt]; maxread = iread[n][evcnt] + evlen; } else { minread = min(iread[n][evcnt],minread); maxread = max(iread[n][evcnt] + evlen,maxread); } } } // SEARCH TO APPROPRIATE PLACE IN INPUT, AND SET IPTRS if(maxread - minread > ibuflen) { sprintf(errstr,"INPUT BUFFERSIZE MISCALCULATION\n"); return(PROGRAM_ERROR); } if(maxread > end_read_buf_at) { sndseekEx(dz->ifd[0],minread,0); start_read_buf_at = minread; samps_to_read = maxread - minread; memset((char *)ibuf,0,ibuflen * sizeof(float)); if((samps_read = fgetfbufEx(ibuf,ibuflen,dz->ifd[0],0))<0) { sprintf(errstr,"Sound read error: %s\n",sferrstr()); return(SYSTEM_ERROR); } if(samps_read < samps_to_read) { fprintf(stdout,"INFO: Ran out of input samples: Terminating.\n"); fflush(stdout); break; } end_read_buf_at = start_read_buf_at + samps_read; } for(n=0;nparam[FRAC_ENVRND] > 0.0) { // If the envelope reading is scattered over a time-range maxeoffset = min(dz->param[FRAC_ENVRND],eread[n][evcnt]); randscat = drand48() * maxeoffset; // Check timerange does not exceed "now" eread[n][evcnt] -= randscat; // Then generate randomisation of read position } } } for(n=0;nbrksize[FRAC_DEPTH]) { if((exit_status = read_value_from_brktable(endtime,FRAC_DEPTH,dz))<0) return(exit_status); // And read depth at end of event } depth[n][evcnt] = dz->param[FRAC_DEPTH]; } // READ ENVELOPE-TEMPLATE, MODIFY DEPTHS AND TIMINGS (AND CHECK FOR STACKING) for(n=0;n= 1.0 && enddepth >= 1.0) { // If depth values beyond 1, this represents stacking. stack = startdepth - 1.0; // Derive stacking value from depth at start of event. startdepth = 1.0; // and reset depth values to depth-maxima (1.0) enddepth = 1.0; // NB Both depths must be 1, so envelope edges tied to zero, so stack causes no glitches } else { // If depths is not everywhere at max, interp depth data onto env depthchange = enddepth - startdepth; for(tim=0,lev=1;tim<14;tim+=2,lev+=2) { thisdepth = depthchange * tempenv[tim]; // Times are between 0 and 1, so time also represents FRACTION of time thisdepth += startdepth; if(thisdepth > 1.0) thisdepth = 1.0; level = 1.0 - thisdepth; // Max Depth = min env level depth 1 -> 0 level| depth 1/3 -> level2/3| depth 0 -> level 1 level += (tempenv[lev] * thisdepth);// Env fills remaining space i.e whole space | upper 1/3 of space: | None of space, env has no effect tempenv[lev] = level; } } // COPY APPROPRIATE INPUT SAMPLES TO ENVELOPE BUFFER, AND DO ENVELOPING if(evcnt == 0) ldur = evend[n][0]; else ldur = evend[n][evcnt] - evend[n][evcnt-1]; if(fracmax > 0) ldur = min(ldur,fracmax); if(ldur > envbuflen) { sprintf(errstr,"ENVELOPE BUFFERSIZE MISCALCULATION: required sample duration = %d available envelope buffer length = %d\n",ldur,envbuflen); return(PROGRAM_ERROR); } memset((char *)ebuf,0,envbuflen * sizeof(float)); memcpy((char *)ebuf,(char *)(ibuf + iptr[n]),ldur * sizeof(float)); stim = 0; etim = 2; lbas = tempenv[stim+1]; // Start of envelope segment tdiff = tempenv[etim] - tempenv[stim]; // Timestep in envelope segment ldiff = tempenv[etim+1] - tempenv[stim+1]; // Level step in envelope segment for(sampcnt=0;sampcnt tempenv[etim]) { // Locate which envelope seg we're in stim = etim; // advancing to next where ness etim += 2; if(etim >= 14) { // Gets default value at table end toget = 0; break; } else { lbas = tempenv[stim+1]; // and resetting segment constants tdiff = tempenv[etim] - tempenv[stim]; ldiff = tempenv[etim+1] - tempenv[stim+1]; } } if(toget) { // Interp in envelope table eval = (frac - tempenv[stim])/tdiff; eval *= ldiff; eval += lbas; } } // Use envelope val to scale input ebuf[sampcnt] = (float)(ebuf[sampcnt] * eval); } // IF STACKING - IF STACKING RANDOMISED SET A STACK VALUE - STORE STACKING VALUE if(stack > 0) { dostack = 1; if(ldur < 8192) { // Prevent stacking of very short events if(!dz->vflag[0]) { // Unless allowed dostack = 0; stack = 0; } } if (dostack) { if(dz->param[FRAC_STKRND] > 0) { this_stack = stack; stack *= drand48() * dz->param[FRAC_STKRND]; stack = this_stack - stack; } } } stakk[n][evcnt] = stack; // Store stack values for next pass if(stack > 0) { memset((char *)stkbuf,0,envbuflen * sizeof(float)); thistack = (int)floor(stack); // e.g. 2.0 e.g. 2.3 while(thistack > 0) { // --> 2 --> 2 if(flteq((double)thistack,stack)) level = 1.0; // level 1 // trans remains 2 else { level = stack - (double)thistack; // level 0.3 thistack++; // trans 3 } transpos = dz->param[FRAC_STACK] * thistack; // Derives stacking interval from multiple of stack parameter incr = pow(2.0,(transpos/SEMITONES_PER_OCTAVE)); // semitones to frq ratio stakwrite_at = getstakwritestt(stkcntr[n],ldur,incr); // Find where to start writing this particular transposition into stakbuf dsampcnt = 0.0; while(dsampcnt < ldur) { // Read the enveloped orig, with an incr that transposes it losamp = (int)floor(dsampcnt); // Interpolating as ness hisamp = losamp+1; frac = dsampcnt - (double)losamp; loval = ebuf[losamp]; hival = ebuf[hisamp]; diff = hival - loval; diff *= frac; val = loval + diff; // Add the interpd val into stakbuffer stkbuf[stakwrite_at] = (float)(stkbuf[stakwrite_at] + val); // (There may be more than 1 stack component to add) stakwrite_at++; // Incr normally in stacking buffer dsampcnt += incr; // Incr transpositionwise in read-from buff } thistack--; // -->1 --> 1 stack = (double)thistack; // Will now generate full level for lower stack components } // Once all staks generated, add stacks to original envelope buffer for(m=0;m= 1.0 && enddepth >= 1.0) { // Level or pitch-shifting can only happem if(dz->param[FRAC_LEVRND] > 0) { // if edges of event are tied to zero-level levrand = drand48() * dz->param[FRAC_LEVRND]; levrand = 1.0 - levrand; evlev[n][evcnt] = levrand; for(m=0;mparam[FRAC_PCHRND] > 0) { prand = drand48() * dz->param[FRAC_PCHRND]; outincr = pow(2.0,(prand/SEMITONES_PER_OCTAVE)); // Convert from semitones to frq-ratio } else outincr = 1.0; evpch[n][evcnt] = outincr; // Store } else { evlev[n][evcnt] = 1.0; evpch[n][evcnt] = 1.0; outincr = 1.0; } // SAFETY CHECK FOR OUTPUT BUFFER OVERFLOW opos = evstt[n] * chans; // Change write position to frame of output opos -= total_samps_written; // Change write position to frame of output-buffer samps_to_write = (int)ceil((double)ldur/outincr) * chans; if(samps_to_write + opos >= dz->buflen + overflow) { sprintf(errstr,"OVERFLOW BUFFER ITSELF OVERFLOWED WHEN PITCH INCR WAS %lf.\n",outincr); return(PROGRAM_ERROR); } // WRITE OUTPUT lpos = opos + lmost[n]; // Change write position to correct left and right channels rpos = opos + rmost[n]; dipos = 0.0; while(dipos < ldur) { // This should wraparound OK, as buffer is preset with zeros iposlo = (int)floor(dipos); // So wraparound sample will be zero iposhi = iposlo+1; frac = dipos - (double)iposlo; loval = ebuf[iposlo]; hival = ebuf[iposhi]; diff = hival - loval; diff *= frac; val = loval + diff; // Add the interpd enveloped-val into output buffer obuf[lpos] = (float)(obuf[lpos] + (val * llev[n])); obuf[rpos] = (float)(obuf[rpos] + (val * rlev[n])); dipos += outincr; // Interpolate in input (enveloped) sound lpos += chans; // Jump by a whole channel-group in output buffer rpos += chans; } this_write_end = (lpos/chans) * chans; // Round up to end of last-group written, to find end of write in buffer write_end = max(this_write_end,write_end); // Find write_end from all stream writes (and previous writes) } // ONCE ALL STREAMS ADDED TO OUTPUT evcnt++; // Count event last_gp_stependtime = gp_stependtime; // Remember startsamp and sampduration of previous group-segment last_gp_stepdur = gp_stepdur; // Need for generating input-read time } total_evcnt = evcnt; if(write_end > 0) { fprintf(stdout,"INFO: Level Check at %lf secs\n",(double)(total_samps_written/chans)/srate); fflush(stdout); for(n=0;n < write_end;n++) // "Write", copy overflow back, zero overflow maxsamp = max(maxsamp,fabs(obuf[n])); total_samps_written += write_end; } normaliser = 1.0; if(maxsamp > 0.95) { normaliser = 0.95/maxsamp; fprintf(stdout,"INFO: Normalising by %lf secs\n",(double)normaliser); fflush(stdout); } for(n=0;n= 0) { if(evend[n][m] < endeventend) // If previous event begins earlier, we've found end event break; else { // Else end of two events coincides, thus zero-length event. endevent = m; // Skip back over it,to find real last-active-event m--; } } depth[n][endevent] = 1; // Force this last event to fade to zero at stream's end } fprintf(stdout,"INFO: Second pass: generating output.\n"); fflush(stdout); if(sloom) { if(dz->mode == 0) dz->insams[0] = total_samps_written; // This forces sloom progress bar to proceed correctly, without mod to libraries else dz->insams[0] = (total_samps_written/STEREO) * dz->iparam[FRAC_CHANS]; } sndseekEx(dz->ifd[0],0,0); reset_filedata_counters(dz); memset((char *)obuf,0,(dz->buflen + overflow) * sizeof(float)); // reset output and overflow buffers memset((char *)ibuf,0,ibuflen * sizeof(float)); // reset input buffer total_samps_written = 0; end_read_buf_at = -1; start_read_buf_at = 0; write_end = 0; evcnt = 0; while(evcnt < total_evcnt) { time = gptime[evcnt]; // Set start-time to end of last GROUP step if((exit_status = read_values_from_all_existing_brktables(time,dz))<0) return exit_status; dz->iparam[FRAC_MAX] = (int)ceil(dz->param[FRAC_MAX] * srate); init_depth = dz->param[FRAC_DEPTH]; // GET THE EVENT START POSITIONS FOR EACH STREAM for(n=0;n= dz->buflen) { // If next write will start at or after buffer end for(n=0;n < dz->buflen;n++) // Normalise, write output, copy overflow back, zero overflow obuf[n] = (float)(obuf[n] * normaliser); if(dz->mode == 0) { if((exit_status = write_samps(obuf,dz->buflen,dz))<0) return(exit_status); total_samps_written += dz->buflen; write_end -= dz->buflen; for(n = 0;n < write_end;n++) // Copy back overflow into obuf (overflow may be longer than obuf) obuf[n] = ovflw[n]; // and zero remainder of overflow memset((char *)(obuf+write_end),0,(dz->buflen + overflow - write_end) * sizeof(float)); } else { samps_to_process = dz->buflen; if(dz->fltractv) { if((exit_status = filter_process(&samps_to_process,&endzeros,dz))<0) return(exit_status); } if((exit_status = panspread(§cnt,¢re,&spread,&cntrswitch,&outside,&fmix,samps_to_process,dz))<0) return(exit_status); if(exit_status == CONTINUE) { total_samps_written += dz->buflen; write_end -= dz->buflen; for(n = 0;n < write_end;n++) // Copy back overflow into obuf (overflow may be longer than obuf) obuf[n] = ovflw[n]; // and zero remainder of overflow memset((char *)(obuf+write_end),0,(dz->buflen + overflow - write_end) * sizeof(float)); } else { write_end = 0; break; } } } // FIND READ SAMPLE OF EACH STREAM, AND MAX AND MINIMUM READ if(evcnt == 0) { // At very start, all segments are read at 0 minread = 0; maxread = 0; for(n=0;niparam[FRAC_MAX]; } else { for(n=0;niparam[FRAC_MAX]; evlen = evend[n][evcnt] - evend[n][evcnt-1]; if(fracmax > 0) evlen = min(evlen,fracmax); if(n==0) { minread = iread[n][evcnt]; maxread = iread[n][evcnt] + evlen; } else { minread = min(iread[n][evcnt],minread); maxread = max(iread[n][evcnt] + evlen,maxread); } } } // SEARCH TO APPROPRIATE PLACE IN INPUT (IF NECESSARY), AND SET IPTRS if(maxread > end_read_buf_at) { sndseekEx(dz->ifd[0],minread,0); start_read_buf_at = minread; samps_to_read = maxread - minread; if((samps_read = fgetfbufEx(ibuf,ibuflen,dz->ifd[0],0))<0) { sprintf(errstr,"Sound read error: %s\n",sferrstr()); return(SYSTEM_ERROR); } if(samps_read < samps_to_read) { fprintf(stdout,"WARNING: Sound Read anomaly - short buffer read, probably at end of file: Terminating.\n"); fflush(stdout); // This shouled not happen as it's trapped on the first pass break; } end_read_buf_at = start_read_buf_at + samps_read; } for(n=0;n= 1.0 && enddepth >= 1.0) { startdepth = 1.0; enddepth = 1.0; } else { depthchange = enddepth - startdepth; for(tim=0,lev=1;tim<14;tim+=2,lev+=2) { thisdepth = depthchange * tempenv[tim]; // Times are between 0 and 1, so time also represents FRACTION of time thisdepth += startdepth; if(thisdepth > 1.0) thisdepth = 1.0; level = 1.0 - thisdepth; // Max Depth = min env level depth 1 -> 0 level| depth 1/3 -> level2/3| depth 0 -> level 1 level += (tempenv[lev] * thisdepth);// Env fills remaining space i.e whole space | upper 1/3 of space: | None of space, env has no effect tempenv[lev] = level; } } // COPY APPROPRIATE INPUT SAMPLES TO ENVELOPE BUFFER, AND DO ENVELOPING if(evcnt == 0) ldur = evend[n][0]; else ldur = evend[n][evcnt] - evend[n][evcnt-1]; if(fracmax > 0) ldur = min(ldur,fracmax); memset((char *)ebuf,0,envbuflen * sizeof(float)); memcpy((char *)ebuf,(char *)(ibuf + iptr[n]),ldur * sizeof(float)); stim = 0; etim = 2; lbas = tempenv[stim+1]; // Start of envelope segment tdiff = tempenv[etim] - tempenv[stim]; // Timestep in envelope segment ldiff = tempenv[etim+1] - tempenv[stim+1]; // Level step in envelope segment for(sampcnt=0;sampcnt tempenv[etim]) { // Locate which envelope seg we're in stim = etim; // advancing to next where ness etim += 2; if(etim >= 14) { toget = 0; break; } else { lbas = tempenv[stim+1]; // and resetting segment constants tdiff = tempenv[etim] - tempenv[stim]; ldiff = tempenv[etim+1] - tempenv[stim+1]; } } if(toget) { // Interp in envelope table eval = (frac - tempenv[stim])/tdiff; eval *= ldiff; eval += lbas; } } // Use envelope val to scale input ebuf[sampcnt] = (float)(ebuf[sampcnt] * eval); } // IF STACKING - DO STACKING stack = stakk[n][evcnt]; if(stack > 0) { memset((char *)stkbuf,0,envbuflen * sizeof(float)); thistack = (int)floor(stack); // e.g. 2.0 e.g. 2.3 while(thistack > 0) { // --> 2 --> 2 if(flteq((double)thistack,stack)) level = 1.0; // level 1 // trans remains 2 else { level = stack - (double)thistack; // level 0.3 transpos = dz->param[FRAC_STACK] * (1 + thistack); // trans 3 } transpos = dz->param[FRAC_STACK] * thistack; // Derives stacking interval from multiple of stack parameter incr = pow(2.0,(transpos/SEMITONES_PER_OCTAVE)); // semitones to frq ratio stakwrite_at = getstakwritestt(stkcntr[n],ldur,incr); // Find where to start writing this particular transposition into stakbuf dsampcnt = 0.0; while(dsampcnt < ldur) { // Read the enveloped orig, with an incr that transposes it losamp = (int)floor(dsampcnt); // Interpolating as ness hisamp = losamp+1; frac = dsampcnt - (double)losamp; loval = ebuf[losamp]; hival = ebuf[hisamp]; diff = hival - loval; diff *= frac; val = loval + diff; // Add the interpd val into stakbuffer stkbuf[stakwrite_at] = (float)(stkbuf[stakwrite_at] + val); // (There may be more than 1 stack component to add) stakwrite_at++; // Incr normally in stacking buffer dsampcnt += incr; // Incr transpositionwise in read-from buff } thistack--; // -->1 --> 1 stack = (double)thistack; // Will now generate full level for lower stack components } // Once all staks generated, add stacks to original envelope buffer for(m=0;m 0) { for(n=0;n < write_end;n++) // Normalise remainder of output (ALL OF IT) obuf[n] = (float)(obuf[n] * normaliser); if(dz->mode == 0) { // In mode 0, write all of remaining output if((exit_status = write_samps(obuf,write_end,dz))<0) return(exit_status); } else { // In mode > 0, process output in chunks of buflen samps (or less) while(write_end > dz->buflen) { samps_to_process = dz->buflen; if(dz->fltractv) { if((exit_status = filter_process(&samps_to_process,&endzeros,dz))<0) return(exit_status); } if((exit_status = panspread(§cnt,¢re,&spread,&cntrswitch,&outside,&fmix,dz->buflen,dz))<0) return(exit_status); if(exit_status == CONTINUE) { write_end -= dz->buflen; for(n = 0;n < write_end;n++) // Copy back overflow into obuf (overflow may be longer than obuf) obuf[n] = ovflw[n]; // and zero remainder of overflow memset((char *)(obuf+write_end),0,(dz->buflen + overflow - write_end) * sizeof(float)); } else { write_end = 0; break; } } if(dz->fltractv) { // In the fitered case, filter will continue to output, even if no input samps_to_process = write_end; do { if((exit_status = filter_process(&samps_to_process,&endzeros,dz))<0) return(exit_status); // Filter returns number of samples that are not (trailing) zeros filter_state = exit_status; // & filter_state = CONTINUE if not at end of its data, or FINISHED if reached end if(samps_to_process) { // Only spatialise data if filter outputs some data ... if((exit_status = panspread(§cnt,¢re,&spread,&cntrswitch,&outside,&fmix,samps_to_process,dz))<0) return(exit_status); } // Quit this loop once filter runs to stream of zeros (filter_state = FINISHED) samps_to_process = 0; // After first buffer, no samples are being sent to filter } while(filter_state == CONTINUE); } else if(write_end > 0) { if((exit_status = panspread(§cnt,¢re,&spread,&cntrswitch,&outside,&fmix,write_end,dz))<0) return(exit_status); } } } return FINISHED; } /****************************** GET_MODE *********************************/ int get_the_mode_from_cmdline(char *str,dataptr dz) { char temp[200], *p; if(sscanf(str,"%s",temp)!=1) { sprintf(errstr,"Cannot read mode of program.\n"); return(USAGE_ONLY); } p = temp + strlen(temp) - 1; while(p >= temp) { if(!isdigit(*p)) { fprintf(stderr,"Invalid mode of program entered.\n"); return(USAGE_ONLY); } p--; } if(sscanf(str,"%d",&dz->mode)!=1) { fprintf(stderr,"Cannot read mode of program.\n"); return(USAGE_ONLY); } if(dz->mode <= 0 || dz->mode > dz->maxmode) { fprintf(stderr,"Program mode value [%d] is out of range [1 - %d].\n",dz->mode,dz->maxmode); return(USAGE_ONLY); } dz->mode--; /* CHANGE TO INTERNAL REPRESENTATION OF MODE NO */ return(FINISHED); } /**************************** HANDLE_THE_SPECIAL_DATA ****************************/ int handle_the_special_data(char *str,dataptr dz) { int exit_status; double dummy = 0.0, lasttime = 0.0, lastetime = 0.0, maxlevel = 0.0; FILE *fp; int cnt, linecnt; char temp[800], *p; if((fp = fopen(str,"r"))==NULL) { sprintf(errstr,"Cannot open file %s to read times.\n",str); return(DATA_ERROR); } linecnt = 0; while(fgets(temp,200,fp)!=NULL) { p = temp; while(isspace(*p)) p++; if(*p == ';' || *p == ENDOFSTR) // Allow comments in file continue; cnt = 0; while(get_float_from_within_string(&p,&dummy)) { switch(cnt) { case(0): if(linecnt == 0) { if(dummy != 0) { sprintf(errstr,"First time (first entry in first line) in envelopes data (%lf) must be zero.\n",dummy); return(DATA_ERROR); } else lasttime = dummy; } else { if(dummy <= lasttime) { sprintf(errstr,"Times (first entry) do not advance at line %d in transpositions data.\n",linecnt+1); return(DATA_ERROR); } } break; case(1): if(dummy != 0) { sprintf(errstr,"First envelope time (2nd entry) (%lf) in envelope data line (%d) must be zero.\n",dummy,linecnt+1); return(DATA_ERROR); } lastetime = dummy; break; case(2): if(dummy != 0) { sprintf(errstr,"First level (3rd entry) (%lf) in envelope data line (%d) must be zero.\n",dummy,linecnt+1); return(DATA_ERROR); } maxlevel = dummy; break; case(13): if(!flteq(dummy,1.0)) { sprintf(errstr,"Last envelope time (14th entry) (%lf) in envelope data line (%d) must be ONE.\n",dummy,linecnt+1); return(DATA_ERROR); } break; case(14): if(dummy != 0) { sprintf(errstr,"Last level (15th entry) (%lf) in envelope data line (%d) must be zero.\n",dummy,linecnt+1); return(DATA_ERROR); } break; default: if(dummy < 0.0 || dummy > 1.0) { sprintf(errstr,"Values and envelope-times in envelope data must lie between 0 and 1 (see line %d).\n",linecnt+1); return(DATA_ERROR); } if(ODD(cnt)) { // ODD entries, envelope-time if(dummy <= lastetime) { sprintf(errstr,"Envelope times do not increase at entry %d in line %d.\n",cnt+1,linecnt+1); return(DATA_ERROR); } lastetime = dummy; } else maxlevel = max(dummy,maxlevel); break; } cnt++; } if(cnt != 15) { sprintf(errstr,"Invalid number of entries (%d) on line %d: should be 15 (1 time plus 7-etime-level pairs\n",cnt,linecnt+1); return(DATA_ERROR); } if(!flteq(maxlevel,1.0)) { sprintf(errstr,"Envelope data in line %d does not rise to maximum of 1.0.\n",linecnt+1); return(DATA_ERROR); } linecnt++; } if(linecnt == 0) { sprintf(errstr,"No data found in envelope data file.\n"); return(DATA_ERROR); } dz->envcount = linecnt; // Number of different envelopes .... dz->all_words = 0; if((exit_status = store_filename(str,dz))<0) return(exit_status); fclose(fp); return FINISHED; } /**************************** READ_THE_SPECIAL_DATA ****************************/ int read_the_special_data(dataptr dz) { double *envdata, dummy; FILE *fp; int cnt; char temp[800], *p; envdata = dz->parray[dz->envsrcs]; if((fp = fopen(dz->wordstor[0],"r"))==NULL) { sprintf(errstr,"Cannot open file %s to envelope data times.\n",dz->wordstor[0]); return(DATA_ERROR); } cnt = 0; while(fgets(temp,200,fp)!=NULL) { p = temp; while(isspace(*p)) p++; if(*p == ';' || *p == ENDOFSTR) // Allow comments in file continue; while(get_float_from_within_string(&p,&dummy)) { envdata[cnt] = dummy; cnt++; } } return FINISHED; } /**************************** FRAGMENT_PARAM_PREPROCESS ****************************/ int fragment_param_preprocess (int *maxpulse,double *maxtrans,int *minfragmax,dataptr dz) { int exit_status, chans, strmcnt; int n, m, eventcnt; double d_minpulse, d_maxpulse, d_minfragmax, srate, leftgain, rightgain, val; int *lmost, *rmost; double *llev, *rlev, *pos; if(dz->mode == 0) chans = dz->iparam[FRAC_CHANS]; else chans = STEREO; strmcnt = dz->iparam[FRAC_STRMS]; srate = (double)dz->infile->srate; if(dz->brksize[FRAC_PCHRND]) { for(n=0,m=1;n < dz->brksize[FRAC_PCHRND];n++,m+=2) { val = dz->brk[FRAC_PCHRND][m]; val /= 100.0; // Convert from cents to semitones dz->brk[FRAC_PCHRND][m] = val; } if((exit_status = get_maxvalue_in_brktable(&val,FRAC_PCHRND,dz))<0) return PROGRAM_ERROR; *maxtrans = pow(2.0,(val/SEMITONES_PER_OCTAVE)); } else { dz->param[FRAC_PCHRND] /= 100.0; val = dz->param[FRAC_PCHRND]; *maxtrans = pow(2.0,(val/SEMITONES_PER_OCTAVE)); // Retain max transposition for calculation of buffer sizes } if(dz->brksize[FRAC_MIN]) { if((exit_status = get_maxvalue_in_brktable(&d_minfragmax,FRAC_MIN,dz))<0) return PROGRAM_ERROR; } else d_minfragmax = dz->param[FRAC_MIN]; *minfragmax = (int)ceil(d_minfragmax * srate); if(dz->brksize[FRAC_PULSE]) { if((exit_status = get_minvalue_in_brktable(&d_minpulse,FRAC_PULSE,dz))<0) return PROGRAM_ERROR; if((exit_status = get_maxvalue_in_brktable(&d_maxpulse,FRAC_PULSE,dz))<0) return PROGRAM_ERROR; } else { d_minpulse = dz->param[FRAC_PULSE]; d_maxpulse = dz->param[FRAC_PULSE]; } d_maxpulse *= 2.0; // Allow for maximum randomisation extension of pulse-duration = 1/2 pulse dur, but at BOTH ends *maxpulse = (int)ceil(d_maxpulse * srate); d_minpulse /= 2.0; // Allow for maximum randomisation reduction of pulse-duration eventcnt = (int)ceil(dz->duration/d_minpulse) + 16; // SAFETY /* * DOUBLE ARRAYS: S = number of streams | llev * | | | rlev * |---------------|---------------|---------------|---------------|---------------| | pos * | depth | level | transpos | envreadtime | stacking | | | tempenv * | | | | | 5S| | | envdata * | | | | | | 5S+1| | stakcentre * address 0 S 2S 3S 4S | | 5S+2| | grptimes * | | | | | | | | 5S+3| | chan-levels(mode>0 only) * | | | | | | | | | 5S+4| | | * array | maxevents | maxevents | maxevents | maxevents | maxevents | | | | | 5S+5| | * length | | | | | S S S | | | 5S+6| then 11 filter arrays * | | | | | | | | 14| | | | | * | | | | | | | | | dz->envcount * 15 * | | | | | | | | | | S | | | * | | | | | | | | | | | maxevents * | | | | | | | outchans */ if((dz->parray = (double **)malloc(((strmcnt * 5) + 19) * sizeof(double *)))==NULL) { sprintf(errstr,"INSUFFICIENT MEMORY for double arrays.\n"); return(MEMORY_ERROR); } for(n=0,m=1;nparray[n] = (double *)malloc(eventcnt * sizeof(double)))==NULL) { sprintf(errstr,"INSUFFICIENT MEMORY for stream %d depth array.\n",m); return(MEMORY_ERROR); } } for(m=1;nparray[n] = (double *)malloc(eventcnt * sizeof(double)))==NULL) { sprintf(errstr,"INSUFFICIENT MEMORY for stream %d level array.\n",m); return(MEMORY_ERROR); } } for(m=1;nparray[n] = (double *)malloc(eventcnt * sizeof(double)))==NULL) { sprintf(errstr,"INSUFFICIENT MEMORY for stream %d transposition array.\n",m); return(MEMORY_ERROR); } } for(m=1;nparray[n] = (double *)malloc(eventcnt * sizeof(double)))==NULL) { // NB these could have been randomised sprintf(errstr,"INSUFFICIENT MEMORY for stream %d envelope readtime array.\n",m); return(MEMORY_ERROR); } } for(m=1;nparray[n] = (double *)malloc(eventcnt * sizeof(double)))==NULL) { // NB these could have been randomised sprintf(errstr,"INSUFFICIENT MEMORY for stream %d envelope readtime array.\n",m); return(MEMORY_ERROR); } } if((dz->parray[n++] = (double *)malloc(strmcnt * sizeof(double)))==NULL) { // Stream level at leftmost channel sprintf(errstr,"INSUFFICIENT MEMORY for left-levels array.\n"); return(MEMORY_ERROR); } if((dz->parray[n++] = (double *)malloc(strmcnt * sizeof(double)))==NULL) { // Stream level at rightmost channel sprintf(errstr,"INSUFFICIENT MEMORY for right-levels array.\n"); return(MEMORY_ERROR); } if((dz->parray[n++] = (double *)malloc(strmcnt * sizeof(double)))==NULL) { // Positioning of output streams sprintf(errstr,"INSUFFICIENT MEMORY for storing input envelope data.\n"); return(MEMORY_ERROR); } dz->envbuf = n; // Store array number of temporary envelope if((dz->parray[n++] = (double *)malloc(14 * sizeof(double)))==NULL) { // Stores temporary envelope calculated for specific event sprintf(errstr,"INSUFFICIENT MEMORY for current envelope array.\n"); return(MEMORY_ERROR); } dz->envsrcs = n; // Store array number of input envelope data if((dz->parray[n++] = (double *)malloc((dz->envcount * 15) * sizeof(double)))==NULL) { // Original envelope data in blocks of time+14 = 15 sprintf(errstr,"INSUFFICIENT MEMORY for storing input envelope data.\n"); return(MEMORY_ERROR); } if((dz->parray[n++] = (double *)malloc(strmcnt * sizeof(double)))==NULL) { // Centre of envelope (for stacking) sprintf(errstr,"INSUFFICIENT MEMORY for storing input envelope data.\n"); return(MEMORY_ERROR); } if((dz->parray[n++] = (double *)malloc(eventcnt * sizeof(double)))==NULL) { // Group-time of events sprintf(errstr,"INSUFFICIENT MEMORY for storing input envelope data.\n"); return(MEMORY_ERROR); } if(dz->mode > 0) { // Channel levels in calculation of multichannel output dz->outlevs = n; if((dz->parray[n] = (double *)malloc(dz->iparam[FRAC_CHANS] * sizeof(double)))==NULL) { sprintf(errstr,"INSUFFICIENT MEMORY to store out-levels for multichannel output.\n"); return(MEMORY_ERROR); } } /* * INTEGER ARRAYS: S = number of streams * * lmost * | rmost * | | | * address 0 1 | * | | | * array S S | * length | | | */ if((dz->iparray = (int **)malloc(2 * sizeof(int *)))==NULL) { sprintf(errstr,"INSUFFICIENT MEMORY for integer arrays.\n"); return(MEMORY_ERROR); } if((dz->iparray[0] = (int *)malloc(strmcnt * sizeof(int)))==NULL) { // leftmost channel for each stream sprintf(errstr,"INSUFFICIENT MEMORY for stream leftmost channels.\n"); return(MEMORY_ERROR); } if((dz->iparray[1] = (int *)malloc(strmcnt * sizeof(int)))==NULL) { // rightmost channel for each stream sprintf(errstr,"INSUFFICIENT MEMORY for stream rightmost channels.\n"); return(MEMORY_ERROR); } /* * LONG ARRAYS: S = number of streams iptr (start of read WITHIN current input buffer, for each stream) * | temp storage of event starttimes * |---------------|---------------| | | * | segendsamp | inreadsamp | | | NB segendsamp is in MONO samps * address 0 S 2S| | need to change to (segendsamp * chans) * | | | 2S+1 + lmost(rmost) % dz->buflen * array | maxevents | maxevents | | | for write!! * length | | strmcnt * | | | strmcnt */ if((dz->lparray = (int **)malloc(((strmcnt*2)+2) * sizeof(int *)))==NULL) { sprintf(errstr,"INSUFFICIENT MEMORY for ints arrays.\n"); return(MEMORY_ERROR); } for(n=0,m=1;nlparray[n] = (int *)malloc(eventcnt * sizeof(int)))==NULL) { sprintf(errstr,"INSUFFICIENT MEMORY for stream %d eventend sampletimes.\n",m); return(MEMORY_ERROR); } } for(m=1;nlparray[n] = (int *)malloc(eventcnt * sizeof(int)))==NULL) { sprintf(errstr,"INSUFFICIENT MEMORY for stream %d eventread sampletimes.\n",m); return(MEMORY_ERROR); } } // Pointers within CURRENT buffer, to start of segments to read, for each stream if((dz->lparray[n++] = (int *)malloc(strmcnt * sizeof(int)))==NULL) { sprintf(errstr,"INSUFFICIENT MEMORY for stream src Pointers in input buffers.\n"); return(MEMORY_ERROR); } // Temporary storage of event start-times for each stream if((dz->lparray[n] = (int *)malloc(strmcnt * sizeof(int)))==NULL) { sprintf(errstr,"INSUFFICIENT MEMORY for stream src Pointers in input buffers.\n"); return(MEMORY_ERROR); } if((exit_status = read_the_special_data(dz))<0) // Read the envelope data input return exit_status; // Assign output streams to correct positions among output channels lmost = dz->iparray[0]; rmost = dz->iparray[1]; llev = dz->parray[strmcnt * 5]; rlev = dz->parray[(strmcnt * 5) + 1]; pos = dz->parray[(strmcnt * 5) + 2]; if(strmcnt == chans) { for(n = 0;nmode == 0 && dz->vflag[1]) || chans == 2) { for(n = 0;nmode > 0) { // SET UP FILTER if((exit_status = setup_lphp_filter(dz))<0) // Set up the distance filter return exit_status; } return FINISHED; } /**************************** CREATE_FRACTURE_SNDBUFS ****************************/ int create_fracture_sndbufs(int maxpulse,double maxtrans,int minfragmax,int *ibuflen,int *envbuflen,int *overflow, int *mbuflen, dataptr dz) { int framesize = dz->infile->channels * F_SECSIZE; int chans; unsigned int bigbufsize; int seccnt, obuflen, fbuflen = 0; double d_obuflen; if(dz->mode == 0) chans = dz->iparam[FRAC_CHANS]; else chans = STEREO; if((dz->sampbuf = (float **)malloc(sizeof(float *) * 8))==NULL) { sprintf(errstr,"INSUFFICIENT MEMORY establishing sample buffers.\n"); return(MEMORY_ERROR); } if((dz->sbufptr = (float **)malloc(sizeof(float *) * 8))==NULL) { sprintf(errstr,"INSUFFICIENT MEMORY establishing sample buffer pointers.\n"); return(MEMORY_ERROR); } *ibuflen = maxpulse; // Already allows for maximum random expansion of maximum read-segment length *ibuflen *= 3; // Allow for maximum offset of reads in different streams *ibuflen += minfragmax; // Allows for minimum fragment-size being larger than maxpulse *ibuflen += 64; // SAFETY seccnt = *ibuflen/framesize; if(seccnt * framesize != *ibuflen) { seccnt++; *ibuflen = seccnt * framesize; } *envbuflen = maxpulse * 2; // Frag start and ends can be randomly displaced away from one another ... allow a maximum safety margin!! *envbuflen += minfragmax; // If a minimum fragment-size specified, allows for length of minsize + any rand-extension *envbuflen += 16; // SAFETY seccnt = (*envbuflen)/framesize; if(seccnt * framesize != *envbuflen) { seccnt++; *envbuflen = seccnt * framesize; } d_obuflen = (double)maxpulse; if(maxtrans > 1.0) // Allow for maximum transposition (downwards) of data (redundant: transpos always upwards) d_obuflen *= maxtrans; obuflen = (int)ceil(d_obuflen) + 16; // SAFETY obuflen *= chans; seccnt = obuflen/framesize; if(seccnt * framesize != obuflen) { seccnt++; obuflen = seccnt * framesize; } if(dz->mode > 0) { *mbuflen = (obuflen/STEREO) * dz->iparam[FRAC_CHANS]; fbuflen = obuflen; } *overflow = obuflen * 2; // Allow for 2 whole maximal segments overwrite of end of output buffer *overflow += minfragmax; // Allow for min-length segments which are bigger than maxpulse dz->buflen = obuflen; bigbufsize = *ibuflen + (*envbuflen * 2) + obuflen + *overflow + fbuflen + *mbuflen; if((dz->bigbuf = (float *)malloc(bigbufsize * sizeof(float))) == NULL) { sprintf(errstr,"INSUFFICIENT MEMORY to create sound buffers.\n"); return(MEMORY_ERROR); } /* * SOUND BUFFERS * * MODE 1 | input | enveloping| stacking | output | overflow | * * MODE 2 | input | enveloping| stacking | stereo | stereo | filter | multichan | * output overflow buffer output */ dz->sampbuf[0] = dz->bigbuf; dz->sbufptr[0] = dz->sampbuf[0]; dz->sampbuf[1] = dz->sampbuf[0] + *ibuflen; dz->sbufptr[1] = dz->sampbuf[1]; dz->sampbuf[2] = dz->sampbuf[1] + *envbuflen; dz->sbufptr[2] = dz->sampbuf[2]; dz->sampbuf[3] = dz->sampbuf[2] + *envbuflen; dz->sbufptr[3] = dz->sampbuf[3]; dz->sampbuf[4] = dz->sampbuf[3] + obuflen; dz->sbufptr[4] = dz->sampbuf[4]; dz->sampbuf[5] = dz->sampbuf[4] + *overflow; dz->sbufptr[5] = dz->sampbuf[5]; dz->sampbuf[6] = dz->sampbuf[5] + fbuflen; dz->sbufptr[6] = dz->sampbuf[6]; dz->sampbuf[7] = dz->sampbuf[6] + *mbuflen; dz->sbufptr[7] = dz->sampbuf[7]; return FINISHED; } /**************************** READ_THE_ENVELOPE ****************************/ int read_the_envelope(double now, dataptr dz) { double *envarray = dz->parray[dz->envsrcs], *tempenv = dz->parray[dz->envbuf]; int n, m, k, thisenv, lastenv, lastj, thisj, endj; double time_of_envelope, lasttime, thistime, timediff, timefrac, val; for(n = 0,m= 0;m < dz->envcount; n+=15,m++) { // Step through the time values, at every 15th entry time_of_envelope = envarray[n]; if(time_of_envelope >= now) { // Once time-of-envelope is beyond "now" time thisenv = m; // Mark the two envelopes bracketing "now" lastenv = m-1; if(lastenv < 0) { // If there is no previous envelope, we must be at zero time for(k=0;k<14;k++) // so copy envelope at zero time to output (temporary envelope) tempenv[k] = envarray[k+1]; return FINISHED; } else { // Otherwise, get the array-indexes of the times of the bracketing envelopes lastj = lastenv * 15; thisj = thisenv * 15; endj = thisj; // And remember the index of the END of the last-envelope data lasttime = envarray[lastj]; // get those bracketing times thistime = envarray[thisj]; // and calculate the fraction of time we are at, between the bracketing times timediff = thistime - lasttime; timefrac = (now - lasttime)/timediff; lastj++; // Step from time-of-envelope to envelope data itself thisj++; k = 0; // Initialise counter for output temporary-envelope while(lastj < endj) { // For every (time and level) entry in the bracketing envelopes val = envarray[thisj] - envarray[lastj]; val *= timefrac; // Interpolate using timefrac val += envarray[lastj]; tempenv[k++] = val; lastj++; thisj++; } return FINISHED; } } } // If we've gone through all data without reaching input "time", use final envelope lastenv = m-1; lastj = lastenv * 15; lastj++; for(k=0;k<14;k++) tempenv[k] = envarray[lastj++]; return FINISHED; } /**************************** GETSTAKCENTRE **************************** * * Find time of (first) peak in envelope */ double getstakcentre(double *tempenv,dataptr dz) { int tim, lev; double maxlev = -1.0; double maxtim = 0.0; for(tim=0,lev=1;tim < 14;tim+=2,lev+=2) { if(tempenv[lev] > maxlev) { maxlev = tempenv[lev]; maxtim = tempenv[tim]; } } return maxtim; } /**************************** GETSTAKWRITESTT **************************** * * Find sample in stak-buffer where transposed-data, centred on peak, should start to be written */ int getstakwritestt(double stakcntr,int ldur,double incr) { double stakcentre = (double)ldur * stakcntr; double shrinkto = stakcentre/incr; return (int)round(stakcentre - shrinkto); } /************************************ PANCALC *******************************/ void pancalc(double position,double *leftgain,double *rightgain) { int dirflag; double temp; double relpos; double reldist, invsquare; if(position < 0.0) dirflag = SIGNAL_TO_LEFT; /* signal on left */ else dirflag = SIGNAL_TO_RIGHT; if(position < 0) relpos = -position; else relpos = position; if(relpos <= 1.0){ /* between the speakers */ temp = 1.0 + (relpos * relpos); reldist = ROOT2 / sqrt(temp); temp = (position + 1.0) / 2.0; *rightgain = temp * reldist; *leftgain = (1.0 - temp ) * reldist; } else { /* outside the speakers */ temp = (relpos * relpos) + 1.0; reldist = sqrt(temp) / ROOT2; /* relative distance to source */ invsquare = 1.0 / (reldist * reldist); if(dirflag == SIGNAL_TO_LEFT){ *leftgain = invsquare; *rightgain = 0.0; } else { /* SIGNAL_TO_RIGHT */ *rightgain = invsquare; *leftgain = 0; } } } /*************************** PANSPREAD **************************** * * This function takes the output of mode 0 (but forced to stereo) * and uses it as the stereo input to the multichannel spatialiseation process (of "mchanpan" - MODE 3- stereo input branch) * * Data is fed in in chunks of dz->buflen (or possibly less for the last chunk) * and written to multichannel output from here. * * There is no reason to run this part of the function during the level-testing pass * as, once the stereo level has been normalised, there is no (per channel) level increase at this stage. * * Signal gain has several componenets * Stereo positioning gain (relative level on Left/Right loudspeakers) is already included in the input stereo signal * Position gain perpendicular to stereo-plain OR attenuation with distance beyond the circle * Natural attenuation of the image "atten" where it fades before reaching infinity. * Externally imposed gain-reduction "gain" to avoid an overload. */ int panspread(int *sectcnt,double *centre,double *spread,int *cntrswitch,int *outside,double *fmix,int samps_to_process,dataptr dz) { int exit_status, pan_exit_status = CONTINUE, outchans = dz->iparam[FRAC_CHANS], m, k; int ibufpos, obufpos = 0; double *levels; int inchans = STEREO; float *ibuf = dz->sampbuf[3]; // Input buffer is the former "obuf", now used as intermediate stereo-storage float *fbuf = dz->sampbuf[5]; // buffer for filtering float *obuf = dz->sampbuf[6]; // and the output buffer is the multichan-outbuf "mbuf" double time = 0.0, srate = (double)dz->infile->srate, gain = dz->param[FRAC_GAIN]; int obuflen = (dz->buflen/STEREO) * outchans; double stereo_pos, atten, timeratio; double relpos, temp, holecompensate; double left_leftchan_level, left_ritechan_level; double valcentre, valoffcen; double fadeoutat = dz->fulldur - dz->param[FRAC_DN]; int halfstage = outchans/2; int c_left, c_rite, cen_tr; double left_contrib_to_c_left, rite_contrib_to_c_left, left_contrib_to_c_rite, rite_contrib_to_c_rite, val; levels = dz->parray[dz->outlevs]; // Array created earlier. memset((char *)obuf,0,obuflen * sizeof(float)); if(dz->param[FRAC_DN] <= 0.0) fadeoutat = dz->fulldur * 200.0; // i.e. an unreachable time for(ibufpos = 0, obufpos = 0;ibufpos < samps_to_process;ibufpos+=inchans,obufpos += outchans) { if((*sectcnt) % 256 == 0) { time = (double)(*sectcnt)/srate; if((exit_status = read_values_from_all_existing_brktables(time,dz))<0) return(exit_status); if(spread_pan(centre,cntrswitch,outside,spread,fmix,dz) == FINISHED) { pan_exit_status = FINISHED; break; } } if(time < dz->param[FRAC_UP]) { // Factor in any natural decay of event (i.e NOT distance realted) timeratio = time/dz->param[FRAC_UP]; atten = pow(timeratio,dz->param[FRAC_ATTEN]); } else if(time > fadeoutat) { timeratio = (time - fadeoutat)/dz->param[FRAC_DN]; timeratio = 1.0 - timeratio; atten = pow(timeratio,dz->param[FRAC_ATTEN]); } else atten = 1.0; atten *= gain; // Factor in any externally imposed gain-limiting. if(*outside) { stereo_pos = 1.0 - *spread; // Spread is to left of centre, incresing leftward, but stereo-position measured rightward relpos = fabs(0.5 - stereo_pos) * 2.0; // position relative_to_stereo_centre : Range 0-1 goes to 1-0-1 temp = 1.0 + (relpos * relpos); // calculate stereo-hole-in-middle compensation holecompensate = ROOT2 / sqrt(temp); left_leftchan_level = *spread * levels[0] * holecompensate; // contrib of left chan to left edge of shrunk image left_ritechan_level = (1-(*spread)) * levels[0] * holecompensate; // contrib of right chan to left edge of shrunk image // ADD IN ANY FILTERED SOUND, TO STEREO IMAGE if(*fmix > 0) { ibuf[ibufpos] = (float)(((1-(*fmix)) * ibuf[ibufpos]) + (*fmix * fbuf[ibufpos])); ibuf[ibufpos+1] = (float)(((1-(*fmix)) * ibuf[ibufpos+1]) + (*fmix * fbuf[ibufpos+1])); } if(*cntrswitch == 0) { valcentre = ibuf[ibufpos+1]; // The RHS of stereo will remain where it is valoffcen = ibuf[ibufpos]; // The LHS will drift towards the right, till they become mono, at right (=final image centre) } else { valcentre = ibuf[ibufpos]; // LHS & RHS of original stereo signal switched, because centre moved to opposite pole: see elsewhere valoffcen = ibuf[ibufpos+1]; } valcentre = valcentre + (left_ritechan_level * valoffcen); // Stereo-right + an increasing portion of stereo-left valoffcen = left_leftchan_level * valoffcen; // a decreasing portion of stereo left cen_tr = (int)floor(*centre); c_left = cen_tr - 1; if(c_left < 0) c_left += outchans; obuf[obufpos + cen_tr] = (float)(valcentre * atten * levels[0]); // Attenuation is any dying away of signal proper (nothing to do with distance) obuf[obufpos + c_left] = (float)(valoffcen * atten * levels[0]); // levels[0] is the level associated with distance from circle } else { c_left = (int)floor(*centre); c_rite = c_left + 1; if(c_rite >= outchans) c_rite -= outchans; for(k=1;k= outchans) m -= outchans; if(*cntrswitch) obuf[obufpos + m] = (float)(ibuf[ibufpos] * levels[m] * atten); else obuf[obufpos + m] = (float)(ibuf[ibufpos+1] * levels[m] * atten); } // Central pair get a mix of left and right signals stereo_pos = *centre - (double)c_left; left_contrib_to_c_left = (1.0 + (2.0 * stereo_pos))/2.0; left_contrib_to_c_left = min(1.0,left_contrib_to_c_left); rite_contrib_to_c_left = (1.0 - (2.0 * stereo_pos))/2.0; rite_contrib_to_c_left = max(0.0,rite_contrib_to_c_left); if(*cntrswitch) val = (ibuf[ibufpos+1] * left_contrib_to_c_left) + (ibuf[ibufpos] * rite_contrib_to_c_left); else val = (ibuf[ibufpos] * left_contrib_to_c_left) + (ibuf[ibufpos+1] * rite_contrib_to_c_left); val *= levels[c_left]; obuf[obufpos + c_left] = (float)(val * atten); left_contrib_to_c_rite = ((2.0 * stereo_pos) - 1.0)/2.0; left_contrib_to_c_rite = max(0.0,left_contrib_to_c_rite); rite_contrib_to_c_rite = (3.0 - (2.0 * stereo_pos))/2.0; rite_contrib_to_c_rite = min(1.0,rite_contrib_to_c_rite); if(*cntrswitch) val = (ibuf[ibufpos+1] * left_contrib_to_c_rite) + (ibuf[ibufpos] * rite_contrib_to_c_rite); else val = (ibuf[ibufpos] * left_contrib_to_c_rite) + (ibuf[ibufpos+1] * rite_contrib_to_c_rite); val *= levels[c_rite]; obuf[obufpos + c_rite] = (float)(val * atten); left_contrib_to_c_rite = ((2.0 * stereo_pos) - 1.0)/2.0; } (*sectcnt)++; } if(obufpos > 0) { if((exit_status = write_samps(obuf,obufpos,dz))<0) return(exit_status); } return pan_exit_status; } /* WITH CENTRE BETWEEN CHANNELS ... * left_contrib_to_c_left = * rite_contrib_to_c_left = * left_contrib_to_c_rite = * rite_contrib_to_c_rite = * MAX of 1.0 AND * MIN of 0.0 AND * MAX of 0.0 AND * MAX of 1.0 AND * (1.0 + (2.0 * stereo_pos)/2.0; * (1.0 - (2.0 * stereo_pos)/2.0; * ((2.0 * stereo_pos) - 1.0)/2.0; * (3.0 - (2.0 * stereo_pos)/2.0; * * * * * POSITION OF CENTRE * POSITION OF CENTRE * POSITION OF CENTRE * POSITION OF CENTRE * c-left c_rite * c-left c_rite * c-left c_rite * c-left c_rite * 1.0 | . . . .________| * 1.0 |. . . . . . . . | * 1.0 | . . . . . . . .| * 1.0 |________ . . . | * | / | * | | * | | * | \ | * | / | * | | * | | * | \ | * | / | * | | * | | * | \ | * 0.5 |/ . . . . . . . | * 0.5 |. . . . . . . . | * 0.5 |. . . . . . . . | * 0.5 |. . . . . . . .\| * | | * |\ | * | /| * | | * | | * | \ | * | / | * | | * | | * | \ | * | / | * | | * 0.0 | . . . . . . . | * 0.0 | . . \_________| * 0.0 |_________/ . . | * 0.0 | . . . . . . . .| * */ /*************************** SPREAD_PAN ****************************/ int spread_pan(double *thiscentre,int *cntrswitch,int *outside,double *spread,double *fmix,dataptr dz) { int outchans = dz->iparam[FRAC_CHANS]; double centre = (double)dz->iparam[FRAC_CENTRE]; double halfspread = 0.0, front = dz->param[FRAC_FRONT], ffront; double depth; double rolloff = dz->param[FRAC_ROLLOFF]; double *levels = dz->parray[dz->outlevs]; double spredej_left, spredej_right; int spredej_left_leftchan, spredej_left_rightchan, spredej_right_leftchan, spredej_right_rightchan, k, j, ochan; double range, maxlevel, hole, stereopos_left, stereopos_right, relpos, temp, holecompensate; double holej_right, holej_left, zleft, zright, floor_zleft, floor_zright; double left_leftchan_level, right_rightchan_level; double kk, jj, holing, mingap; double contraction_distance, filter_distance; *cntrswitch = 0; *outside = 0; depth = (dz->param[FRAC_MDEPTH] * outchans)/2.0; // Find (max) no of outchans to turn on depth = min(depth,(double)outchans/2.0); // depth (no of ON lspks) to each side of centre is 1/2 of this if((centre = centre - 1.0) < 0.0) // Change from 1-to-N to 0-to-(N-1) frame, for calculations centre += (double)outchans; if(fabs(front) <= 1.0) { // If WITHIN the circle of lspkrs centre -= 0.5; // force the active centre to be BETWEEN 2 channels if(centre < 0.0) centre += outchans; if(front >= 0) // Front moves from a spread of 1 lspkr-width (at 1) *spread = (1-front) * (outchans/2 - 1) + 1; // to a spread of 1/2-of-lspkrs (outchans/2) at midline else { front = -front; // After midline, hole in lspkrs has same relation to (abs value of) front. *spread = (1-front) * (outchans/2 - 1) + 1; // so calculate symmetrically *spread = outchans - *spread; // then subtract hole from total lspkrs } } else { // Leading-edge of front is outside circle of lspkrs *outside = 1; if(front < -1) { // If passed OUT of ring, place front at its TRAILING edge, for calculations front += (dz->param[FRAC_MDEPTH] * 2); if(front <= -2) // Once trailing edge of data reaches infinity, curtail output return FINISHED; else if(front >= -1) { // If trailing edge of front has (unlike true front) NOT left circle of lspkrs centre -= 0.5; // force the active centre to be BETWEEN 2 channels if(centre < 0.0) centre += outchans; *outside = 0; // Do normal inside-circle calculations BUT centre -= (double)(outchans/2); // Invert frame of reference if(centre < 0.0) // centre -> leaving-centre opposite original centre centre += (double)outchans; front = -front; // Front inverted symmetrically about centre-line (0) *cntrswitch = 1; // and left and right inverted in calling loop if(front >= 0) // Then calculate spread in normal way, but from this leaving-centre *spread = (1-front) * (outchans/2 - 1) + 1; else { front = -front; *spread = (1-front) * (outchans/2 - 1) + 1; *spread = outchans - *spread; } // As depth MUST now be covering all chans from trailing edge (new "front") to leaving-centre depth = (*spread)/2.0; // set depth to real halfspread, } } if(*outside) { // Once front OUTSIDE circle, shrink to MONO into the original-specified central channel ffront = fabs(front); // Calculations for outside ring are symmetrical (Range 1 to 2) ffront -= 1.0; // Change range to 0-1 : ringedge-to-infinity (Range 0 to 1) maxlevel = pow((1.0 - ffront),dz->param[FRAC_ATTEN]); // As front increases, loudness decreases // (and only 1channel active, so no scaling required for no. of chans contraction_distance = min(1.0,ffront/dz->param[FRAC_ZPOINT]); // Fraction of distance towards zero-angle point, max 1.0 *spread = pow((1.0 - contraction_distance),dz->param[FRAC_CONTRACT]);// As contraction_distance increases, width decreases halfspread = (*spread)/2.0; filter_distance = min(1.0,ffront/dz->param[FRAC_FPOINT]); // Fraction of distance towards total-filering point, max 1.0 *fmix = pow(filter_distance,dz->param[FRAC_FFACTOR]); // As filter_distance increases, proportion filtered sig in mix increases centre = (double)dz->iparam[FRAC_CENTRE]; // Revert to original channel-centred centre if((centre = centre - 1.0) < 0.0) // Change from 1-to-N to 0-to-(N-1) frame, for calculations centre += outchans; if(front < 0.0) { // If LEAVING circle, *cntrswitch = 1; // Invert left and right in calling loop centre += outchans/2; // Invert centre, to opposite-to-centre channel if(centre > outchans) centre -= outchans; } for(ochan = 0;ochan < outchans;ochan++) levels[ochan] = 0.0; levels[0] = maxlevel; // Central channel to which we'll shrink gets current maxlevel, but we canstore it in levels[0] *thiscentre = centre; return(CONTINUE); // we're returning an "outside" flag, a moved centre, a shrunk "halfspread" and a filtering-mix value } } halfspread = (*spread)/2.0; if(depth <= 0.0) depth = FLTERR; if((halfspread = (*spread)/2.0) == 0.0) halfspread = FLTERR; for(ochan = 0;ochan < outchans;ochan++) levels[ochan] = 0.0; /* Establish maxlevel (determined by rolloff) */ if(*spread < 1.0) range = 0.0; else range = 1.0 - (1.0/(*spread)); maxlevel = 1.0 - (rolloff * range); // Set all channels fully within the spread to maxlevel spredej_left = centre - halfspread; // spredej_left and right could be determined while(spredej_left < 0) // by a "position-of-front" parameter spredej_left += (double)outchans; // working backwards towards centre, using halfspread spredej_right = centre + halfspread; while(spredej_right >= outchans) // Once this is done .. easier to deal with spredej_right -= (double)outchans; // distant (filtered) signalwith no (or limited) width spredej_left_leftchan = (int)floor(spredej_left); // at trailing, or leading centre if((spredej_left_rightchan = spredej_left_leftchan + 1) >= outchans) spredej_left_rightchan = 0; // Centre is behind front if front moving away from entre spredej_right_leftchan = (int)floor(spredej_right); // and <= hlafway to f/b midoint. // Having crossed that, centre moves to OPPOSITE position. hole = *spread - (depth * 2.0); // Once available lspk-spread is < specified spread, // there.s no hole in the middle. if(*spread >= outchans) { // Once available loudspeaker spread < 2 for(k = 0;k 1.0) { k = spredej_left_leftchan; if(spredej_left_leftchan == spredej_left) levels[k] = maxlevel; if(++k >= outchans) k -= outchans; while(k != spredej_right_leftchan) { levels[k] = maxlevel; if(++k >= outchans) k -= outchans; } levels[spredej_right_leftchan] = maxlevel; } else { // In fact, this is what is happening here !!!! /* Deal with case where spread extends to both sides of a channel, even if less than 1.0 */ zleft = centre - halfspread; zright = centre + halfspread; if(zleft < 0.0) { zleft += outchans; zright += outchans; } if(zleft >= 0.0) floor_zleft = floor(zleft); else floor_zleft = -ceil(fabs(zleft)); if(zright >= 0.0) floor_zright = floor(zright); else floor_zright = -ceil(fabs(zright)); if(floor_zleft < floor_zright) levels[spredej_right_leftchan] = maxlevel; } /* Do fractional channels on leading edges of spread */ stereopos_left = spredej_left - (double)spredej_left_leftchan; relpos = fabs(0.5 - stereopos_left) * 2.0; // position relative_to_stereo_centre : Range 0 - 1 temp = 1.0 + (relpos * relpos); // calculate stereo-hole-in-middle compensation holecompensate = ROOT2 / sqrt(temp); left_leftchan_level = (1 - stereopos_left) * maxlevel * holecompensate; if(spredej_left_leftchan != spredej_right_leftchan) levels[spredej_left_leftchan] = left_leftchan_level; stereopos_right = spredej_right - (double)spredej_right_leftchan; relpos = fabs(0.5 - stereopos_right) * 2.0; // position relative_to_stereo_centre : Range 0 - 1 temp = 1.0 + (relpos * relpos); // calculate stereo-hole-in-middle compensation holecompensate = ROOT2 / sqrt(temp); right_rightchan_level = stereopos_right * maxlevel * holecompensate; if(spredej_right > spredej_right_leftchan) { if((spredej_right_rightchan = spredej_right_leftchan + 1) >= outchans) spredej_right_rightchan -= outchans; if(spredej_right_rightchan != spredej_left_rightchan) { if(spredej_right_rightchan == spredej_left_leftchan) { levels[spredej_right_rightchan] += right_rightchan_level; } else { levels[spredej_right_rightchan] = right_rightchan_level; } } } /* IF hole in the middle of the spread, because depth too small, find edges of hole */ halfspread = (*spread)/2.0; if(hole > 0.0) { holej_right = centre + halfspread - depth; holej_left = centre - halfspread + depth; k = (int)ceil(holej_left); j = (int)floor(holej_right); // Look at all chans in hole while(k <= j) { kk = k - holej_left; jj = holej_right - k; mingap = min(jj,kk); holing = min(mingap,1.0); holing = 1.0 - holing; ochan = k; while(ochan < 0) ochan += outchans; while(ochan >= outchans) ochan -= outchans; levels[ochan] *= holing; k++; } } *thiscentre = centre; return CONTINUE; } /* * INNER HOLE * range = Starts at 1.0 , where no hole. Ends at appropriate stereo-position-level (this_level), once hole extends as far as an existing chan; * mingap = minimum distance from holeedge to nearest channel * mingap += hole; we then add this to size of hole, to see size of area including hole and distance to nearest chan. Always <= 1.0; * holeratio = hole/mingap; with a tiny hole, this is always c. zero, as hole enlarges, gets bigger, till, when hole touches a channel, it gets to be 1.0 * this_level = 1.0 - (range * holeratio); When holeratio = 1, level becomes 1.0 - range = this_level i.e. expected stereo level * = 1.0 - (1.0 - this_level) = this_level i.e. expected stereo level */ /* * POSITIONS OF MOVING FRONT * 2 = "+infinitely" distant: 1 = in plane of front-centre lspkr : 0 = in plane of midline: * -1 = in plane of read lspkr: -2 = "-infinitely" distant * * Depth-param now expressed as fraction of lspkr-space. 1 = chans, 1/2 = chans/2 etc ..... (so original spread param = depth *chans) * * 2 Let "spread" at 1 be 1/chans (i.e. 1/2 lspkr width on either side of central lspkr) * "spread" at centre (front = 0) is always ochans/2 * 1 For "front" in range 1 - 0 therefore. * x x spread = ((1 - front) * (chans/2 - 1)) + 1 and calculations can proceed as normal * For front in range 0 to -1,by symmetry * x 0 x spread = chans - (((1 + front) * (chans/2 - 1)) + 1) * * x x As the front has a depth, and therefore a trailing edge which does not reach -1 at same time as true front, * -1 calculations relating to fade-out and filtering between -1 and -2, have to be based on trailing edge vals. * So trailing edge only reaches -2 when front is at -2+depth. * User needs to build this in to the "fonr" breakpoint file data. * -2 * With the new value of depth, trailing edge is at front + (depth * 2) * This is "+" as front always move +ve to -ve * and uses factor "2" because, when depth 1 = all lspkrs in use, but distance front to back (1 to -1) = 2. * So if 1/2 loudpseakers are activated, trailing edge is half-way back round space and: * and "HALFway" for front means distance of "1" (Thus depth[1/2] * 2 = 1) */ //FILTER // set stopfrq [expr $sd(filt) + (double($sd(filt))/4.0)] // set cmd [file join $evv(CDPROGRAM_DIR) filter] // set cmd [list $cmd lohi 1 $sd_infnam cdptest0$evv(SNDFILE_EXT) -96 $sd(filt) $stopfrq] /****************************** FILTER_PROCESS *************************/ int filter_process(int *samps_to_process,int *endzeros,dataptr dz) { int exit_status; float *fbuf = dz->sampbuf[5], *obuf = dz->sampbuf[3]; int n; memset((char *)fbuf,0,dz->buflen * sizeof(float)); if(*samps_to_process) memcpy((char *)fbuf,(char *)obuf,*samps_to_process * sizeof(float)); dz->ssampsread = dz->buflen; // To force filter to continue to operate, when input exhausted if((exit_status = do_lphp_filter_stereo(dz)) <0) return(exit_status); if( *samps_to_process == 0) { n = dz->buflen - 1; while(n >= 0) { // Force exit when 256 consecutive grp-samples are zero if(fbuf[n] == 0.0) (*endzeros)++; else break; n--; } n++; if(*endzeros >= 256 * STEREO) { *samps_to_process = n; return FINISHED; } } return(CONTINUE); } /***************************** FILTER *************************************/ int do_lphp_filter_stereo(dataptr dz) { int exit_status, i; int index, fbase = dz->outlevs + 1; double *e1,*e2,*s1,*s2; double *den1 = dz->parray[fbase + FLT_DEN1]; double *den2 = dz->parray[fbase + FLT_DEN2]; double *cn = dz->parray[fbase + FLT_CN]; for(i=0; i < STEREO; i++) { index = i * FLT_LPHP_ARRAYS_PER_FILTER; e1 = dz->parray[fbase + FLT_E1_BASE + index]; e2 = dz->parray[fbase + FLT_E2_BASE + index]; s1 = dz->parray[fbase + FLT_S1_BASE + index]; s2 = dz->parray[fbase + FLT_S2_BASE + index]; if((exit_status = lphp_filt_stereo(e1,e2,s1,s2,den1,den2,cn,dz,i))<0) return exit_status; } return(FINISHED); } /***************************** LPHP_FILT_CHAN *************************************/ int lphp_filt_stereo(double *e1,double *e2,double *s1,double *s2, double *den1,double *den2,double *cn,dataptr dz,int chan) { int i; int k; float *buf = dz->sampbuf[5]; double ip, op = 0.0, b1; for (i = chan ; i < dz->ssampsread; i+= STEREO) { ip = (double) buf[i]; for (k = 0 ; k < dz->fltcnt; k++) { b1 = dz->fltmul * cn[k]; op = (cn[k] * ip) + (den1[k] * s1[k]) + (den2[k] * s2[k]) + (b1 * e1[k]) + (cn[k] * e2[k]); s2[k] = s1[k]; s1[k] = op; e2[k] = e1[k]; e1[k] = ip; } if(op >= HUGE || op <= -HUGE) { sprintf(errstr,"Filter numeric overflow at %lf secs: try a different (higher) cutoff frequency.\n", (double)((dz->total_samps_written/dz->infile->channels) + (i/STEREO))/(double)dz->infile->srate); return GOAL_FAILED; } op *= dz->scalefact; if (fabs(op) > 1.0) { dz->scalefact *= .9999; if (op > 0.0) op = 1.0; else op = -1.0; } buf[i] = (float)op; } return FINISHED; } /********************************* SETUP_LPHP_FILTER *****************************/ int setup_lphp_filter(dataptr dz) { int exit_status; int filter_order; double signd = 1.0, passfrq, stopfrq; dz->scalefact = 1.0; // Start with no prescaling: turn down if filter blows up passfrq = dz->param[FRAC_FFREQ]; stopfrq = dz->param[FRAC_FFREQ] * 1.25; signd = -1.0; dz->fltmul = 2.0; filter_order = establish_order_of_filter(passfrq,stopfrq,dz); if((exit_status = allocate_internal_params_lphp(dz))<0) return(exit_status); calculate_filter_poles_lphp(signd,filter_order,passfrq,dz); initialise_filter_coeffs_lphp(dz); return(FINISHED); } /********************************* ESTABLISH_ORDER_OF_FILTER *****************************/ int establish_order_of_filter(double passfrq,double stopfrq,dataptr dz) { int filter_order; double tc, tp, tt, pii, xx, yy, fltgain = FILTER_GAIN; double sr = (double)dz->infile->srate; pii = 4.0 * atan(1.0); passfrq = pii * passfrq/sr; tp = tan(passfrq); stopfrq = pii * stopfrq/sr; tc = tan(stopfrq); tt = tc / tp ; tt = (tt * tt); fltgain = fabs(fltgain); fltgain = fltgain * log(10.0)/10.0 ; fltgain = exp(fltgain) - 1.0 ; xx = log(fltgain)/log(tt) ; yy = floor(xx); if ((xx - yy) == 0.0 ) yy = yy - 1.0 ; filter_order = ((int)yy) + 1; if (filter_order <= 1) filter_order = 2; dz->fltcnt = filter_order/2 ; filter_order = 2 * dz->fltcnt; dz->fltcnt = min(dz->fltcnt,200); filter_order = 2 * dz->fltcnt; return(filter_order); } /********************************* ALLOCATE_INTERNAL_PARAMS_LPHP *****************************/ int allocate_internal_params_lphp(dataptr dz) { int fbase = dz->outlevs + 1; int i; if((dz->parray[fbase + FLT_DEN1] = (double *)calloc(dz->fltcnt * sizeof(double),sizeof(char)))==NULL || (dz->parray[fbase + FLT_DEN2] = (double *)calloc(dz->fltcnt * sizeof(double),sizeof(char)))==NULL || (dz->parray[fbase + FLT_CN] = (double *)calloc(dz->fltcnt * sizeof(double),sizeof(char)))==NULL || (dz->parray[fbase + FLT_S1_BASE] = (double *)calloc(dz->fltcnt * sizeof(double),sizeof(char)))==NULL || (dz->parray[fbase + FLT_E1_BASE] = (double *)calloc(dz->fltcnt * sizeof(double),sizeof(char)))==NULL || (dz->parray[fbase + FLT_S2_BASE] = (double *)calloc(dz->fltcnt * sizeof(double),sizeof(char)))==NULL || (dz->parray[fbase + FLT_E2_BASE] = (double *)calloc(dz->fltcnt * sizeof(double),sizeof(char)))==NULL) { sprintf(errstr,"INSUFFICIENT MEMORY for arrays of filter parameters.\n"); return(MEMORY_ERROR); } for(i = 1; i < STEREO;i++) { int index = i*FLT_LPHP_ARRAYS_PER_FILTER; if((dz->parray[fbase + FLT_S1_BASE + index] = (double *)calloc(dz->fltcnt * sizeof(double),sizeof(char)))==NULL || (dz->parray[fbase + FLT_E1_BASE + index] = (double *)calloc(dz->fltcnt * sizeof(double),sizeof(char)))==NULL || (dz->parray[fbase + FLT_S2_BASE + index] = (double *)calloc(dz->fltcnt * sizeof(double),sizeof(char)))==NULL || (dz->parray[fbase + FLT_E2_BASE + index] = (double *)calloc(dz->fltcnt * sizeof(double),sizeof(char)))==NULL) { sprintf(errstr,"INSUFFICIENT MEMORY for arrays of filter parameters.\n"); return(MEMORY_ERROR); } } return(FINISHED); } /********************************* CALCULATE_FILTER_POLES_LPHP *****************************/ void calculate_filter_poles_lphp(double signd,int filter_order,double passfrq,dataptr dz) { double ss, xx, aa, tppwr, x1, x2, cc; double pii = 4.0 * atan(1.0); double tp = tan(passfrq); int k; int fbase = dz->outlevs + 1; ss = pii / (double)(2 * filter_order); for (k = 0; k < dz->fltcnt; k++ ) { xx = (double) ((2.0 * (k+1)) - 1.0); aa = -sin(xx * ss); tppwr = pow(tp,2.0); cc = 1.0 - (2.0 * aa * tp) + tppwr; x1 = 2.0 * (tppwr - 1.0)/cc ; x2 = (1.0 + (2.0 * aa * tp) + tppwr)/cc ; dz->parray[fbase + FLT_DEN1][k] = signd * x1; dz->parray[fbase + FLT_DEN2][k] = -x2 ; dz->parray[fbase + FLT_CN][k] = pow(tp,2.0)/cc ; } } /********************************* INITIALISE_FILTER_COEFFS_LPHP *****************************/ void initialise_filter_coeffs_lphp(dataptr dz) { int k; int i,index; int fbase = dz->outlevs + 1; for (k = 0 ; k < dz->iparam[FLT_CNT]; k++) { dz->parray[fbase + FLT_S1_BASE][k] = 0.0; dz->parray[fbase + FLT_S2_BASE][k] = 0.0; dz->parray[fbase + FLT_E1_BASE][k] = 0.0; dz->parray[fbase + FLT_E2_BASE][k] = 0.0; } for(i=1;i < STEREO; i++){ index = i * FLT_LPHP_ARRAYS_PER_FILTER; for (k = 0 ; k < dz->iparam[FLT_CNT]; k++) { dz->parray[fbase + FLT_S1_BASE + index][k] = 0.0; dz->parray[fbase + FLT_S2_BASE + index][k] = 0.0; dz->parray[fbase + FLT_E1_BASE + index][k] = 0.0; dz->parray[fbase + FLT_E2_BASE + index][k] = 0.0; } } } //// // HEREH When do we start the filtering ?? // How do we use the finishing strategy for the filter tail ?? // How do we test whether filter works (output filter !!!!) /**************************** ESTABLISH_ECHOS *************************** void establish_echos(int *maxdelay,dataptr dz) { int n; double *delay = dz->parray[dz->echobas]; // size 20 double *gainl = dz->parray[dz->echobas + 1]; // size 20 double *gainr = dz->parray[dz->echobas + 2]; // size 20 double tdelay[] = {0.131832, 0.215038, 0.322274, 0.414122, 0.504488, 0.637713, 0.730468, 0.808751, 0.910460, 1.027041, 1.132028, 1.244272, 1.336923, 1.427700, 1.528503, 1.618661, 1.715413, 1.814730, 1.914843, 2.000258}; double gain[] = {0.500000,0.354813,0.354813,0.251189,0.125893,0.125893,0.063096,0.063096,0.031623,0.031623,0.012589,0.012589,0.005012,0.005012,0.002512,0.002512,0.002512,0.002512,0.002512,0.002512}; double pan[] = {.9,.5,-.5,0.1,.7,-.7,.3,-.3,.15,-.15,.85,-.85,.4,-.4,.6,-.6,.225,-.225,.775,-.775}; for(n=0;n < dz->iparam[FRAC_ECHOCNT]; n++) delay[n] = (int)round(tdelay[n] * dz->infile->srate * dz->param[STAD_SIZE]) * STEREO; *maxdelay = delay[dz->iparam[FRAC_ECHOCNT - 1]]; if(dz->param[FRAC_EROLL]<1.0) { for(n=0;niparam[FRAC_ECHOCNT];n++) gain[n] = pow(gain[n],dz->param[FRAC_EROLL]); } for(n=0;niparam[FRAC_ECHOCNT];n++) { if(pan[n] < 0.0) { // LEFTWARDS gainl[n] = gain[n] * dz->param[FRAC_EPREGN]; gainr[n] = gain[n] * dz->param[FRAC_EPREGN] * (1.0+pan[n]); } else { // RIGHTWARDS gainl[n] = gain[n] * dz->param[FRAC_EPREGN] * (1.0-pan[n]); gainr[n] = gain[n] * dz->param[FRAC_EPREGN]; } } } */