/* * 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 #include // modes #define DO_UNKNOT 0 #define DO_KNOT 1 #define KNOTCNT 2 #define KNOT_REGULAR .1 // Difference in duration between events for the pulse to be deemed regular #ifdef unix #define round(x) lround((x)) #endif char errstr[2400]; #define celltime scalefact int anal_infiles = 1; int sloom = 0; int sloombatch = 0; const char* cdp_version = "7.0.0"; //CDP LIB REPLACEMENTS static int unknot_param_preprocess(int *patterncnt,dataptr dz); static int setup_unknot_application(dataptr dz); static int setup_unknot_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 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 open_all_infiles(char **cmdline, int *patterncnt, dataptr dz); static int open_special_infile(char *str, dataptr dz); static int unknot(int *patterncnt,int *knotdatacnt,double **spatpos,double **spatstep,double **comboarray,int *combopatterncnt,double **outdata,dataptr dz); static int pulse_regular(double a,double b,double minstep); static int pulse_more(double thisstep,double maxstep,double minerror); static int unknot_output(int *patterncnt,int knotdatacnt,double *spatpos,double *spatstep,double *comboarray,int combopatterncnt,double *outdata,dataptr dz); static void sortcomoboarray(int combopatterncnt,double *comboarray); static int setup_respatialisation_params(double *spatpos,double *spatstep,double *comboarray, int combopatterncnt,int respacecnt,dataptr dz); static int GenerateKnotCombo (double *comboarray,int combono,int *patterncnt,dataptr dz); static int IsAnIntegerInRange(char *str,int imin, int imax); static int IsAFilename(char *str); /**************************************** MAIN *********************************************/ int main(int argc,char *argv[]) { int exit_status, paramcnt = 0, test, OK, OK2, OK3; dataptr dz = NULL; char **cmdline, *p; int *patterncnt; int cmdlinecnt; int knotdatacnt = 0; double *spatpos, *spatstep, *outdata = 0, *comboarray, dummy; int combopatterncnt, n; // 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(argc == 1) { usage1(); return(FAILED); } else if(argc == 2) { usage2(argv[1]); return(FAILED); } 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 = 3; 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_unknot_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); } // ap = dz->application; // setup_param_ranges_and_defaults() = if((exit_status = setup_unknot_param_ranges_and_defaults(dz))<0) { exit_status = print_messages_and_close_sndfiles(exit_status,is_launched,dz); return(FAILED); } switch(dz->mode) { case(KNOTCNT): paramcnt = 0; break; default: paramcnt = 10; break; } n = argc - 1; while(argv[n][0] == '-') { // Count backwards over any flags paramcnt++; // And add these items to number of params on cmdline n--; } if((dz->infilecnt = cmdlinecnt - paramcnt) <= 0) { fprintf(stderr,"Too few parameters on cmdline.\n"); return(FAILED); } test = 0; OK = 1; OK2 = 1; OK3 = 1; while(test < 8) { if(dz->mode == KNOTCNT) { if(!IsAFilename(argv[n])) OK3 = 0; } else { switch(test) { case(0): case(1): p = argv[n]; if(!get_float_from_within_string(&p,&dummy)) OK = 0; if(dummy < 0.0 || dummy > 8.0) OK = 0; break; case(2): if(!IsAnIntegerInRange(argv[n],0,5)) OK2 = 0; break; case(4): if(!IsAnIntegerInRange(argv[n],1,256)) OK2 = 0; break; case(3): case(5): case(6): case(7): if(!IsAnIntegerInRange(argv[n],0,256)) OK2 = 0; break; } } if(!OK) { fprintf(stderr,"Invalid or out of range channel-range position (%s).\n\n",argv[n]); usage2("unknot"); return(FAILED); } if(!OK2) { fprintf(stderr,"Invalid or out of range integer param (%s) (or too few integer params).\n\n",argv[n]); usage2("unknot"); return(FAILED); } if(!OK3) { fprintf(stderr,"Invalid param (%s) (expecting file): possibly too many or too few params.\n\n",argv[n]); usage2("unknot"); return(FAILED); } test++; n--; if(n < 3) break; } dz->ifd = NULL; // Prevents spurious attempts to close output soundfiles if((patterncnt = (int *)malloc(dz->infilecnt * sizeof(int)))==NULL) { fprintf(stderr,"setting up input file data counters.\n"); return(FAILED); } if((exit_status = open_all_infiles(cmdline,patterncnt,dz))<0) { print_messages_and_close_sndfiles(exit_status,is_launched,dz); return(FAILED); } cmdline += dz->infilecnt; cmdlinecnt -= dz->infilecnt; // handle_outfile() = if(dz->mode != KNOTCNT) { 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 // handle_special_data() redundant if(dz->mode != KNOTCNT) { if((exit_status = open_special_infile(cmdline[0],dz))<0) { print_messages_and_close_sndfiles(exit_status,is_launched,dz); return(FAILED); } cmdline++; cmdlinecnt--; } 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 = unknot_param_preprocess(patterncnt,dz))<0) { print_messages_and_close_sndfiles(exit_status,is_launched,dz); return(FAILED); } is_launched = TRUE; //spec_process_file = if(dz->mode != KNOTCNT) { if((exit_status = open_the_outfile(dz))<0) { print_messages_and_close_sndfiles(exit_status,is_launched,dz); return(FAILED); } } if((exit_status = unknot(patterncnt,&knotdatacnt,&spatpos,&spatstep,&comboarray,&combopatterncnt,&outdata,dz))<0) { print_messages_and_close_sndfiles(exit_status,is_launched,dz); return(FAILED); } if(dz->mode != KNOTCNT) { if((exit_status = unknot_output(patterncnt,knotdatacnt,spatpos,spatstep,comboarray,combopatterncnt,outdata,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; dz->extrabrkno = brkcnt; brkcnt++; /* Required by CDP library logic for textfile input */ // BUT 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; // Flags 1 or more infiles //establish_bufptrs_and_extra_buffers(): return(FINISHED); } /********************** SETUP_PARAMETER_STORAGE_AND_CONSTANTS ********************/ /* RWD mallo changed to calloc; helps debug verison 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]; 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); } strcpy(dz->outfilename,filename); (*cmdline)++; (*cmdlinecnt)--; return(FINISHED); } /************************ OPEN_THE_OUTFILE *********************/ int open_the_outfile(dataptr dz) { int exit_status; if((exit_status = create_sized_outfile(dz->outfilename,dz))<0) return(exit_status); 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_UNKNOT_APPLICATION *******************/ int setup_unknot_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 switch(dz->mode) { case(DO_UNKNOT): case(DO_KNOT): exit_status = set_param_data(ap,0,8,8,"iiiiiidd"); break; case(KNOTCNT): exit_status = set_param_data(ap,0,8,0,"00000000"); break; } if(exit_status < 0) return(FAILED); if(dz->mode == KNOTCNT) exit_status = set_vflgs(ap,"",0,"","mct",3,2,"di0"); else exit_status = set_vflgs(ap,"",0,"","mcte",4,2,"di00"); if(exit_status < 0) return(FAILED); // set_legal_infile_structure --> dz->has_otherfile = FALSE; // assign_process_logic --> dz->input_data_type = ALL_FILES; dz->process_type = TO_TEXTFILE; dz->outfiletype = TEXTFILE_OUT; return application_init(dz); //GLOBAL } /************************* SETUP_UNKNOT_PARAM_RANGES_AND_DEFAULTS *******************/ int setup_unknot_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() if(dz->mode != KNOTCNT) { ap->lo[KNOT_PATREP] = 0; ap->hi[KNOT_PATREP] = 256; ap->default_val[KNOT_PATREP] = 2; ap->lo[KNOT_COMBOREP] = 0; ap->hi[KNOT_COMBOREP] = 256; ap->default_val[KNOT_COMBOREP] = 2; ap->lo[KNOT_ALLREP] = 0; ap->hi[KNOT_ALLREP] = 256; ap->default_val[KNOT_ALLREP] = 2; ap->lo[KNOT_UNKNOTREP] = 1; ap->hi[KNOT_UNKNOTREP] = 256; ap->default_val[KNOT_UNKNOTREP] = 2; ap->lo[KNOT_GOALREP] = 0; ap->hi[KNOT_GOALREP] = 256; ap->default_val[KNOT_GOALREP] = 2; ap->lo[KNOT_SPACETYP] = 0; ap->hi[KNOT_SPACETYP] = 5; ap->default_val[KNOT_SPACETYP] = 0; ap->lo[KNOT_CHANA] = 0; ap->hi[KNOT_CHANA] = 8; ap->default_val[KNOT_CHANA] = 1; ap->lo[KNOT_CHANB] = 0; ap->hi[KNOT_CHANB] = 8; ap->default_val[KNOT_CHANB] = 1; } ap->lo[KNOT_MIN] = FLTERR; ap->hi[KNOT_MIN] = 0.1; ap->default_val[KNOT_MIN] = KNOT_REGULAR; ap->lo[KNOT_CLIP] = 1; ap->hi[KNOT_CLIP] = 16; ap->default_val[KNOT_CLIP] = 1; dz->maxmode = 3; put_default_vals_in_all_params(dz); 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); } /**************************** UNKNOT_PARAM_PREPROCESS *****************************/ int unknot_param_preprocess(int *patterncnt,dataptr dz) { int n; int endtimeloc, warned = 0; double endtime = 0.0; for(n=0;ninfilecnt;n++) { endtimeloc = (patterncnt[n] - 1) * 4; if(n==0) endtime = dz->parray[n][endtimeloc]; else if(!flteq(endtime,dz->parray[n][endtimeloc])) { if(!warned) { fprintf(stdout,"WARNING: PATTERNS DO NOT ALL END IN SYNC.\n"); fflush(stdout); warned = 1; } endtime = max(endtime,dz->parray[n][endtimeloc]); } } dz->celltime = endtime; if(dz->mode == KNOTCNT) { dz->iparam[KNOT_PATREP] = 0; dz->iparam[KNOT_COMBOREP] = 0; dz->iparam[KNOT_ALLREP] = 0; dz->iparam[KNOT_UNKNOTREP] = 0; dz->iparam[KNOT_GOALREP] = 0; dz->iparam[KNOT_SPACETYP] = 0; dz->iparam[KNOT_CHANA] = 0; dz->iparam[KNOT_CHANB] = 0; } else { if(dz->param[KNOT_CHANA] < 1.0) dz->param[KNOT_CHANA] += 8.0; // Change range from 0 to 8, to 1 to < 9.0 dz->param[KNOT_CHANA] -= 1.0; // Change range to 0 to < 8.0 (allows modulo-8 arithmetic) if(dz->param[KNOT_CHANB] < 1.0) dz->param[KNOT_CHANB] += 8.0; dz->param[KNOT_CHANB] -= 1.0; } return FINISHED; } /********************************************************************************************/ int get_the_process_no(char *prog_identifier_from_cmdline,dataptr dz) { if(!strcmp(prog_identifier_from_cmdline,"unknot")) dz->process = UNKNOT; 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); } /****************************** 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); } /******************************** USAGE1 ********************************/ int usage1(void) { usage2("unknot"); return(USAGE_ONLY); } /******************************** USAGE2 ********************************/ int usage2(char *str) { if(!strcmp(str,"unknot")) { fprintf(stdout, "USAGE: unknot unknot 1-2 inf1 inf2 [inf3 ...] " " outfile combos r_pats r_combos r_all r_unknots r_goal spacetyp cha chb ....\n" "OR: unknot unknot 3 inf1 inf2 [inf3 ...] ....\n " "[-mmin] [-cclip] [-e] [-t]\n" "\n" "Takes set of textfiles, representing rhythmic patterns, creating combined pattern,\n" "repeating this, gradually unknotting it to regular timepulse & spatial distribution.\n" "MODES:\n" "1) Unknots (Events gradually moved, in turn, to be time & space equidistant).\n" "2) Knots (Runs process in reverse).\n" "3) Counts unknotting steps (No output).\n" "There are 5 (possible) stages to the unknotting process....\n" "(1) Repeat (each) original pattern (optional).\n" "(2) Repeat (each) specified combination of patterns (optional).\n" "(3) Repeat the combination of all patterns (optional).\n" "(4) Unknot the combined pattern.\n" "(5) Repeat the unknotted pattern (optional).\n" "Input patterns have lines each with 4 entries \"time MIDI level pos\"\n" "time : must start at zero and not decrease.\n" "MIDI : vals between 0 & 127, where convention is 0 indicates a silent file.\n" "level: lies between >0 and 1.\n" "pos : position in an 8-channel space, range 0 to 8 (fractional values OK).\n" "PARAMETERS:\n" "COMBOS Textfile List of pattern combos to use. (or zero, if no combos used)\n" " Each line lists 2 or more patterns to combine.\n" "Number of repetitions of......\n" "R_PATS each original pattern (Unknot, placed at start : Knot, placed at end).\n" "R_COMBOS each pattern combination.(Unknot, placed next : Knot, placed penultimate).\n" "R_ALL combined initial pattern.\n" "R_UNKNOTS each unknotting/knotting step.\n" "R_GOAL goal pattern.\n" "SPACETYP Type of spatial distribution for unknotted pattern.\n" " 0 No spatial redistribution. 3 Rotate anticlock between channels.\n" " 1 Alternating between channels. 4 Rotate clock-anticlock between channels.\n" " 2 Rotate clockwise between chans. 5 Rotate anticlock-clock between channels.\n" "(Redistributions to mono, tutti etc, can be made by a mix to mono, & crossfading).\n" "CHA First channel for spacetyp redistribution.\n" "CHB Second channel for spacetyp redistribution.\n" "MIN Event-Duration-differences read as \"zero\" (pulse \"regular\" = unknotted).\n" "CLIP Number of events to reposition at each (un)knotting step (default 1).\n" "-e Spatial redistribution starts at (un)knotting end.\n" " (default: ....starts at (un)knotting start.)\n" "-t Output data with titles and spacing to identify patterns being output.\n"); } else fprintf(stdout,"Unknown option '%s'\n",str); return(USAGE_ONLY); } /******************************** USAGE3 ********************************/ int usage3(char *str1,char *str2) { fprintf(stderr,"Insufficient parameters on command line.\n"); return(USAGE_ONLY); } /******************************** OPEN_ALL_INFILES ********************************/ int open_all_infiles(char **cmdline, int *patterncnt, dataptr dz) { int n, linecnt, cnt, idummy; double lasttime, dummy; FILE *fp; char temp[400], *p; if((dz->parray = (double **)malloc(dz->infilecnt * sizeof(double *)))==NULL) { sprintf(errstr,"INSUFFICIENT MEMORY pattern storage integer arrays.\n"); return(MEMORY_ERROR); } for(n = 0; n < dz->infilecnt;n++) { if((fp = fopen(cmdline[n],"r"))==NULL) { sprintf(errstr,"Cannot open file %s to read pattern data. (Check usage)\n",cmdline[n]); return(DATA_ERROR); } patterncnt[n] = 0; linecnt = 1; lasttime = -1.0; while(fgets(temp,400,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 == 1 && dummy != 0.0) { sprintf(errstr,"FILE %s does not begin at time zero\n",cmdline[n]); return(DATA_ERROR); } if(dummy < lasttime) { sprintf(errstr,"FILE %s does not advance between times %lf and %lf\n",cmdline[n],lasttime,dummy); return(DATA_ERROR); } lasttime = dummy; break; case(1): idummy = (int)round(dummy); if(idummy != dummy) { sprintf(errstr,"FILE %s has non-integer MIDI value (%lf) at time %lf\n",cmdline[n],dummy,lasttime); return(DATA_ERROR); } if(idummy < 0 || idummy > 127) { sprintf(errstr,"FILE %s has out of range MIDI value (%d) at time %lf\n",cmdline[n],idummy,lasttime); return(DATA_ERROR); } break; case(2): if(dummy <= 0 || dummy > 1.0) { sprintf(errstr,"FILE %s has out of range LEVEL value (%lf) at time %lf\n",cmdline[n],dummy,lasttime); return(DATA_ERROR); } break; case(3): if(dummy < 0 || dummy > 8.0) { sprintf(errstr,"FILE %s has out of range POSITION value (%lf) at time %lf\n",cmdline[n],dummy,lasttime); return(DATA_ERROR); } break; default: sprintf(errstr,"FILE %s has too many values on line %d\n",cmdline[n],linecnt); return(DATA_ERROR); break; } cnt++; patterncnt[n]++; } if(cnt != 4) { sprintf(errstr,"FILE %s has too few values on line %d (should be 4)\n",cmdline[n],linecnt); return(DATA_ERROR); break; } linecnt++; } fseek(fp,0,0); if((dz->parray[n] = (double *)malloc(patterncnt[n] * sizeof(double)))==NULL) { sprintf(errstr,"INSUFFICIENT MEMORY for pattern %d data.\n",n+1); return(MEMORY_ERROR); } cnt = 0; while(fgets(temp,400,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)) dz->parray[n][cnt++] = dummy; } patterncnt[n] /= 4; // 4 entries per line in pattern fclose(fp); } return FINISHED; } /******************************** OPEN_SPECIAL_INFILE ********************************/ int open_special_infile(char *str, dataptr dz) { int linecnt, cnt, kcnt, idummy; double dummy; FILE *fp; char temp[400], *p; int *gpcnts, *gpcheck; if (!strcmp(str,"0")) { dz->itemcnt = 0; return FINISHED; } if((gpcheck = (int *)malloc(dz->infilecnt * sizeof(int)))==NULL) { sprintf(errstr,"INSUFFICIENT MEMORY for pattern checking.\n"); return(MEMORY_ERROR); } if((fp = fopen(str,"r"))==NULL) { sprintf(errstr,"Cannot open file %s to read pattern data.\n",str); return(DATA_ERROR); } linecnt = 0; while(fgets(temp,400,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)) { if (cnt >= dz->infilecnt) { sprintf(errstr,"TOO MANY ITEMS (%d) IN GROUPING ON LINE %d IN FILE %s\n",cnt+1,linecnt+1,str); return(DATA_ERROR); } idummy = (int)round(dummy); if(idummy < 1 || idummy > dz->infilecnt) { sprintf(errstr,"PATTERN MEMBER \"%d\" OUT OF RANGE (1 - %d) IN FILE %s\n",idummy,dz->infilecnt,str); return(DATA_ERROR); } gpcheck[cnt] = idummy; kcnt = cnt-1; while(kcnt >= 0) { if(gpcheck[cnt] == gpcheck[kcnt]) { sprintf(errstr,"ITEM \"%d\" DUPLICATED IN LINE %d IN FILE %s\n",gpcheck[cnt],linecnt+1,str); return(DATA_ERROR); } kcnt--; } cnt++; } if(cnt < 2) { sprintf(errstr,"LINE %d IN FILE %s HAS ONLT ONE ENTRY (MUST BE AT LEAST 2)\n",linecnt+1,str); return(DATA_ERROR); } linecnt++; } if(linecnt <= 0) { sprintf(errstr,"NO DATA FOUND IN FILE %s.\n",str); return(DATA_ERROR); } dz->itemcnt = linecnt; if((dz->iparray = (int **)malloc((dz->itemcnt+1) * sizeof(int *)))==NULL) { sprintf(errstr,"INSUFFICIENT MEMORY for pattern groupings.\n"); return(MEMORY_ERROR); } if((dz->iparray[dz->itemcnt] = (int *)malloc(dz->itemcnt * sizeof(int)))==NULL) { sprintf(errstr,"INSUFFICIENT MEMORY for pattern grouping %d\n",linecnt+1); return(MEMORY_ERROR); } gpcnts = dz->iparray[dz->itemcnt]; fseek(fp,0,0); linecnt = 0; while(fgets(temp,400,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)) cnt++; gpcnts[linecnt] = cnt; if((dz->iparray[linecnt] = (int *)malloc(cnt * sizeof(int)))==NULL) { sprintf(errstr,"INSUFFICIENT MEMORY for pattern grouping %d\n",linecnt+1); return(MEMORY_ERROR); } linecnt++; } fseek(fp,0,0); linecnt = 0; while(fgets(temp,400,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)) { dz->iparray[linecnt][cnt] = (int)round(dummy); cnt++; } linecnt++; } fclose(fp); return FINISHED; } /******************************** UNKNOT ********************************** * * dz->parray[0] to dz->parray[dz->infilecnt-1] contain all input patterns (in sets of 4 values) * patterncnt[n] contains no of LINES in pattern n (4 items per"line") so arraysizes are patterncnt[n]*4 * Data in arrays interleaved as as "time MIDI level position" * itemcnt = number of combos (for initial play of combos) * dz->iparray[dz->itemcnt] contains the sizes of each combo * dz->iparray[0] to dz->iparray[itemcnt-1] contains the actual combo * * celltime is duration of cell to be unknotted. */ int unknot(int *patterncnt,int *knotdatacnt,double **spat_pos,double **spat_step,double **combo_array,int *combo_patterncnt,double **out_data,dataptr dz) { double *timediff, *comboarray, *outdata = NULL, *spatpos, *spatstep, *outpos; int comboarraysize, outdiffcnt, outtestcnt, unknotting_eventcnt, outpatterncnt, outdatacnt = 0; int n, m, r, k, tn, tm, tnow, tnext,/* tlast,*/ passno, smooth, combopatterncnt, lastnonzerodiff; int unknotcnt = 0, maxcnt, adjacent, zerocnt = 0, prezerocnt, postzerocnt, adjacentzeros, maxloc, respacecnt = 0; double tim_n, mid_n, lev_n, pos_n, tim_m, mid_m, lev_m, pos_m; double bastime, maxdiff, span, halfspan, sum; int spacetyp = dz->iparam[KNOT_SPACETYP]; int writesteps = 0; combopatterncnt = 0; for(n=0;n < dz->infilecnt;n++) combopatterncnt += patterncnt[n] - 1; // Count total number of events in combined pattern *combo_patterncnt = combopatterncnt; comboarraysize = combopatterncnt * 4; if((*combo_array = (double *)malloc(comboarraysize * sizeof(double)))==NULL) { sprintf(errstr,"Insufficient memory for output pattern.\n"); // Array to store combined pattern return(MEMORY_ERROR); } comboarray = *combo_array; if((timediff = (double *)malloc(combopatterncnt * sizeof(double)))==NULL) { // Array to store timesteps in combined pattern sprintf(errstr,"Insufficient memory for output pattern.\n"); return(MEMORY_ERROR); } if((*spat_step = (double *)malloc(combopatterncnt * sizeof(double)))==NULL) { // Array to store spatial steps, for moving pattern element sprintf(errstr,"Insufficient memory for output pattern.\n"); return(MEMORY_ERROR); } spatstep = *spat_step; if((*spat_pos = (double *)malloc(combopatterncnt * sizeof(double)))==NULL) { // Array to spatial positions, as pattern elements are moved sprintf(errstr,"Insufficient memory for output pattern.\n"); return(MEMORY_ERROR); } spatpos = *spat_pos; if((outpos = (double *)malloc(combopatterncnt * sizeof(double)))==NULL) { // Array to spatial positions, as pattern elements are moved sprintf(errstr,"Insufficient memory for output pattern.\n"); return(MEMORY_ERROR); } k = 0; for(n=0;n < dz->infilecnt;n++) { // Copy all patterns into combination array for(m=0;m < (patterncnt[n] - 1) * 4; m++) // But dropping endmarkers comboarray[k++] = dz->parray[n][m]; } sortcomoboarray(combopatterncnt,comboarray); outdiffcnt = combopatterncnt - 1; tnow = 0; for(n= 0, tnext=4;n < outdiffcnt;n++,tnext+=4) { // Caculate and store timesteps in combined pattern timediff[n] = comboarray[tnext] - comboarray[tnow]; tnow = tnext; } lastnonzerodiff = outdiffcnt-1; for(n = outdiffcnt-1;n >= 0;n--) { if(flteq(timediff[n],0.0)) { // Count zero steps (simultaneous events) in comobo-pattern zerocnt++; if(n == lastnonzerodiff) lastnonzerodiff--; } } if(outdiffcnt == zerocnt) { sprintf(errstr,"ALL EVENTS ARE SYNCHRONOUS: CANNOT PROCEED\n"); return DATA_ERROR; } if(outdiffcnt - 1 == zerocnt) { sprintf(errstr,"ALL EVENTS BUT ONE ARE SYNCHRONOUS: CANNOT PROCEED\n"); return DATA_ERROR; } outtestcnt = outdiffcnt - zerocnt; // How many time-steps to test, when checking result of unknotting step for(passno = 0;passno<2;passno++) { // First pass assesses number of unknot steps and hence size of array writesteps = 0; if(passno > 0) { tnow = 0; for(n= 0, tnext=4;n < outdiffcnt;n++,tnext+=4) { // Reset original timediff vals timediff[n] = comboarray[tnext] - comboarray[tnow]; tnow = tnext; } } smooth = 0; // Second pass does the unknotting outdatacnt = 0; // Count the size of the output array bastime = 0.0; // Start-time of each pattern, as unknotting takes place unknotcnt = 0; // Count the number of unknotting steps while(!smooth) { maxdiff = -1; // Preset maximum step between events maxcnt = 0; // Count number of steps having the maximum value adjacent = 0; // Count the number of steps equal-and-adjacent to the current maximum step zerocnt = 0; // Count any run of zero-steps (event-sumultaneities) prezerocnt = 0; // Remember number of zero-steps immediately prior to maximum step postzerocnt = 0; // Remember number of zero steps immediately after a maximum step adjacentzeros = 0; // Remember number of zero steps immediately prior to any maximum step equal-and-adjacent to the current maximum step maxloc = 0; // Initialise location of found maximum step for(n = 0;n < outdiffcnt;n++) { if(flteq(timediff[n],0.0)) { // Skip, but count, zero steps zerocnt++; // Count zeros if(maxloc + postzerocnt == n-1) // If previous value was the maximum, or a zero-following-a-maximum postzerocnt++; // count zeros AFTER a maximum } else if(pulse_more(timediff[n],maxdiff,dz->param[KNOT_MIN])) { // If this is a maximum maxdiff = timediff[n]; // remember size maxloc = n; // and location maxcnt = 1; // And start count of number of maxima with this value adjacent = 0; // Number of adjacent maxima with this value (yet) adjacentzeros = 0; // There are not yet adjacent maxima, so no zeros pre-adjacent maxima prezerocnt = zerocnt; // Remember Number of preceding zerosteps zerocnt = 0; // Reset zerocounter postzerocnt = 0; // No zeros AFTER the current maximum (yet) } else if(pulse_regular(timediff[n],maxdiff,dz->param[KNOT_MIN])) { // If this is "equal" to the current maximum if(n == maxloc+postzerocnt+1) { // If minimum adjacent to current min or separated from it solely by zeros adjacent += postzerocnt+1; // count the adjacent maxima and zeros adjacentzeros = prezerocnt; // and if zeros adjacent to first of adjacent-maxima, remember this postzerocnt = 0; // Reset zeros AFTER current min to 0 } else { // If new maximum is not next to previous one adjacent = 0; // no adjacent maxima here (yet), adjacentzeros = 0; // therefore no zeros adjacent to adjacent-maxima prezerocnt = zerocnt; // Remember Number of preceding zerosteps } maxloc = n; // Remember the time-latest of the adjacent maxima maxcnt++; // Count the maxima with this value zerocnt = 0; // Reset zerocounter postzerocnt = 0; // No zeros AFTER the current maximum (yet) } else { zerocnt = 0; // postzerocnt is NOT reset, as this is remembering } // any set of zeros after last maximum found. // prezerocnt is NOT reset, as this is remembering // any set of zeros prior to last maximum found. } if(maxcnt == outtestcnt) { // If all steps are equivalent if(unknotcnt == 0) { sprintf(errstr,"INITIAL PATTERN IS ALREADY UNKNOTTED\n"); return DATA_ERROR; } smooth = 1; // process is complete. } if(!smooth) { if(maxloc == prezerocnt) { // isolated maximum at start, (or after ALL-zero steps) if(maxloc+postzerocnt+1 >= outdiffcnt) { sprintf(errstr,"ERROR IN SEGMENT ACCOUNTING 1\n"); return(PROGRAM_ERROR); } // Span time-interval and one ABOVE (ignoring intervening zero-steps) span = timediff[maxloc] + timediff[maxloc+postzerocnt+1]; halfspan = span/2.0; // Find average timediff[maxloc] = halfspan; // Equalise the time-differences timediff[maxloc+postzerocnt+1] = halfspan; } else if(maxloc == lastnonzerodiff) { // maximum at top edge if(adjacent) { // if adjacent to others maxloc -= adjacent; // Find earliest maxdiff segment prezerocnt = adjacentzeros; // Find any zeros immediately prior to this } // Span time-intervals and one BELOW (ignoring any intervening zero-steps) if(maxloc-prezerocnt-1 < 0) { sprintf(errstr,"ERROR IN SEGMENT ACCOUNTING 2\n"); return(PROGRAM_ERROR); } span = timediff[maxloc] + timediff[maxloc-prezerocnt-1]; halfspan = span/2.0; // Find average timediff[maxloc-prezerocnt-1] = halfspan; // Equalise the time-differences timediff[maxloc] = halfspan; // maximum not at edge } else { if(maxloc+postzerocnt+1 < outdiffcnt) { // Span max seg and one ABOVE span = timediff[maxloc] + timediff[maxloc+postzerocnt+1]; halfspan = span/2.0; timediff[maxloc] = halfspan; timediff[maxloc+postzerocnt+1] = halfspan; } else { // Else, maximum entirely followed by zeros, span max seg and one BELOW if(adjacent) { // if adjacent to others maxloc -= adjacent; // Find earliest maxdiff segment prezerocnt = adjacentzeros; // Find any zeros immediately prior to this } if(maxloc-prezerocnt-1 < 0) { sprintf(errstr,"ERROR IN SEGMENT ACCOUNTING 3\n"); return(PROGRAM_ERROR); } span = timediff[maxloc] + timediff[maxloc-prezerocnt-1]; halfspan = span/2.0; timediff[maxloc-prezerocnt-1] = halfspan; timediff[maxloc] = halfspan; } } } if(unknotcnt % dz->iparam[KNOT_CLIP] == 0) { // Write out every Nth copy of unknotting, depending on value of KNOT_CLIP writesteps++; switch(passno) { case(0): outdatacnt += combopatterncnt; break; case(1): if(respacecnt) { for(n = 0; n < combopatterncnt;n++) { outpos[n] = spatpos[n] + 1.0; // Reconvert current spatial-position of each event to (0)1-8 range for output channel if(outpos[n] > 8.0) outpos[n] -= 8.0; } for(r=0;riparam[KNOT_UNKNOTREP];r++) { // Copy to output UNKNOTREP copies of part-unknotted stream sum = 0.0; outdata[outdatacnt++] = bastime; outdata[outdatacnt++] = comboarray[1]; outdata[outdatacnt++] = comboarray[2]; outdata[outdatacnt++] = outpos[0]; // Put in new position data m = 4; for(n = 0; n < outdiffcnt; n++) { sum += timediff[n]; // Increment time through the new pattern outdata[outdatacnt++] = sum + bastime; // Offet time by start-time of this pattern m++; // Copy the MIDI-level data to output outdata[outdatacnt++] = comboarray[m++]; outdata[outdatacnt++] = comboarray[m++]; m++; outdata[outdatacnt++] = outpos[n+1]; // Put in new position data } bastime += dz->celltime; // Increment to next pattern start time } for(n = 0; n < combopatterncnt;n++) { spatpos[n] += spatstep[n]; // Advance position towards goal position for each pattern element if(spatpos[n] >= 8.0) // spatpos uses 0 - <8 range for modulo8 arithmetic spatpos[n] -= 8.0; else if(spatpos[n] < 0.0) spatpos[n] += 8.0; } } else { for(r=0;riparam[KNOT_UNKNOTREP];r++) { // Copy to output UNKNOTREP copies of part-unknotted stream sum = 0.0; outdata[outdatacnt++] = bastime; outdata[outdatacnt++] = comboarray[1]; outdata[outdatacnt++] = comboarray[2]; outdata[outdatacnt++] = comboarray[3]; m = 4; for(n = 0; n < outdiffcnt; n++) { sum += timediff[n]; // Increment time through the new pattern outdata[outdatacnt++] = sum + bastime; // Offet time by start-time of this pattern m++; // Copy the MIDI-level-position data to output outdata[outdatacnt++] = comboarray[m++]; outdata[outdatacnt++] = comboarray[m++]; outdata[outdatacnt++] = comboarray[m++]; } bastime += dz->celltime; // Increment to next pattern start time } } break; } } unknotcnt++; } if(passno == 0) { if(writesteps <= 1) fprintf(stdout,"INFO: %d STEP ONLY: NO UNKNOTTING\n",writesteps); else fprintf(stdout,"INFO: %d STEPS IN UNKNOTTING\n",writesteps); fflush(stdout); if(dz->mode == KNOTCNT) return FINISHED; else if(writesteps <= 1) { fprintf(stdout,"WARNING: NO UNKNOTTING - MIN or CLIP TOO LARGE?? - HENCE NO RESPATIALISING.\n"); fflush(stdout); } outdatacnt *= 4; // Every counted patterns needs 4 slots outdatacnt *= dz->iparam[KNOT_UNKNOTREP]; // Each pattern is output KNOT_UNKNOTREP times if((*out_data = (double *)malloc(outdatacnt * sizeof(double)))==NULL) { sprintf(errstr,"Insufficient memory to store output data.\n"); return(MEMORY_ERROR); } outdata = *out_data; if(spacetyp > 0 && !dz->vflag[3] && writesteps > 1) { // Respatialise DURING unknotting respacecnt = writesteps; setup_respatialisation_params(spatpos,spatstep,comboarray,combopatterncnt,respacecnt,dz); } } } if(dz->mode == DO_KNOT) { unknotting_eventcnt = outdatacnt/4; m = unknotting_eventcnt - 1; n = 0; outpatterncnt = writesteps * dz->iparam[KNOT_UNKNOTREP]; // Number of patterns in unknotting output m = outpatterncnt - 1; while(m > n) { // INVERT ARRAY in groups of patterns tm = m * combopatterncnt * 4; // Indeces of time at start of each pattern tn = n * combopatterncnt * 4; for(k = 0; k < combopatterncnt;k++) { // Progressing through one entire pattern tim_m = outdata[tm]; mid_m = outdata[tm+1]; lev_m = outdata[tm+2]; pos_m = outdata[tm+3]; tim_n = outdata[tn]; mid_n = outdata[tn+1]; lev_n = outdata[tn+2]; pos_n = outdata[tn+3]; outdata[tm] = tim_n; // Exchange data of the two patterns outdata[tm+1] = mid_n; outdata[tm+2] = lev_n; outdata[tm+3] = pos_n; outdata[tn] = tim_m; outdata[tn+1] = mid_m; outdata[tn+2] = lev_m; outdata[tn+3] = pos_m; tm += 4; tn += 4; } m--; n++; } bastime = 0.0; // tlast = 0; outpatterncnt = writesteps * dz->iparam[KNOT_UNKNOTREP]; // Number of patterns in unknotting output for(n = 0,r = 0; n < outpatterncnt;n++,r+=combopatterncnt) { // For every pattern, (each pattern starts at r) sum = 0.0; // Single pattern timesum tnow = r * 4; // Index in outpattern of start of this pattern for(m=0,k=r;mcelltime; } } *knotdatacnt = outdatacnt; return(FINISHED); } /********************************************* UNKNOT_OUTPUT *********************************/ int unknot_output(int *patterncnt,int knotdatacnt,double *spatpos,double *spatstep,double *comboarray,int combopatterncnt,double *outdata,dataptr dz) { int respace = 0, n, pcnt, r, ccnt, spacetyp = dz->iparam[KNOT_SPACETYP]; double *thispattern, *combo, bastime,/*endtime,*/ thispos, starttime; int combosize = 0, tim, mid, lev, pos, outpatterncnt, unknotting_eventcnt, sttim, stmid, stlev, stpos; char temp[400]; for(n=0;ninfilecnt;n++) { for(pcnt=0;pcnt < patterncnt[n]; pcnt++) combosize++; } combosize *= 4; if((combo = (double *)malloc(combosize * sizeof(double)))==NULL) { sprintf(errstr,"Insufficient memory to store intermediate combined-patterns.\n"); return(MEMORY_ERROR); } bastime = 0.0; if(dz->mode == DO_UNKNOT) { if(dz->iparam[KNOT_PATREP]) { if(dz->vflag[2]) { sprintf(temp,";ORIGINAL PATTERN REPEATS\n"); fputs(temp,dz->fp); } for(n=0;ninfilecnt;n++) { for(r = 0; r < dz->iparam[KNOT_PATREP];r++) { thispattern = dz->parray[n]; tim = 0; mid = 1; lev = 2; pos = 3; for(pcnt=0;pcnt < patterncnt[n] - 1; pcnt++) { // Don't output the endmarker events sprintf(temp,"%lf\t%d\t%lf\t%lf\n",thispattern[tim] + bastime,(int)round(thispattern[mid]),thispattern[lev],thispattern[pos]); if(fputs(temp,dz->fp) < 0) { sprintf(errstr,"FAILED TO WRITE TO INDIVIDUAL PATTERNS OUTPUT FILE \n"); return SYSTEM_ERROR; } tim += 4; mid += 4; lev += 4; pos += 4; } if(dz->vflag[2]) { sprintf(temp,"\n"); fputs(temp,dz->fp); } bastime += dz->celltime; } } } if(dz->iparam[KNOT_COMBOREP]) { if(dz->vflag[2]) { sprintf(temp,";REPEATS OF COMBINATIONS OF ORIGINAL PATTERNS\n"); fputs(temp,dz->fp); } for(ccnt = 0; ccnt < dz->itemcnt; ccnt++) { // For each pattern combination combopatterncnt = GenerateKnotCombo(combo,ccnt,patterncnt,dz); for(r=0;riparam[KNOT_COMBOREP];r++) { tim = 0; mid = 1; lev = 2; pos = 3; for(pcnt=0;pcnt < combopatterncnt; pcnt++) { sprintf(temp,"%lf\t%d\t%lf\t%lf\n",combo[tim] + bastime,(int)round(combo[mid]),combo[lev],combo[pos]); if(fputs(temp,dz->fp) < 0) { sprintf(errstr,"FAILED TO WRITE PATTERN COMBINATIONS TO OUTPUT FILE \n"); return SYSTEM_ERROR; } tim += 4; mid += 4; lev += 4; pos += 4; } if(dz->vflag[2]) { sprintf(temp,"\n"); fputs(temp,dz->fp); } bastime += dz->celltime; } } } } if(dz->iparam[KNOT_ALLREP]) { // For combination of all patterns if(dz->vflag[2]) { sprintf(temp,";REPEATS OF COMBINED-PATTERN\n"); fputs(temp,dz->fp); } combopatterncnt = GenerateKnotCombo(combo,-1,patterncnt,dz); for(r=0;riparam[KNOT_ALLREP];r++) { tim = 0; mid = 1; lev = 2; pos = 3; for(pcnt=0;pcnt < combopatterncnt; pcnt++) { if(dz->mode == DO_KNOT) // Get unknotted spatialisation thispos = outdata[pos]; else thispos = combo[pos]; sprintf(temp,"%lf\t%d\t%lf\t%lf\n",combo[tim] + bastime,(int)round(combo[mid]),combo[lev],thispos); if(fputs(temp,dz->fp) < 0) { sprintf(errstr,"FAILED TO WRITE TOTAL-PATTERN REPETITIONS TO OUTPUT FILE \n"); return SYSTEM_ERROR; } tim += 4; mid += 4; lev += 4; pos += 4; } if(dz->vflag[2]) { sprintf(temp,"\n"); fputs(temp,dz->fp); } bastime += dz->celltime; } if(dz->mode == DO_KNOT) { // Get unknotted spatialisation for(n= 0;n < combopatterncnt; n++) { pos = (n * 4) + 3; thispos = outdata[pos]; } } } // OUTPUT THE UNKNOTTING unknotting_eventcnt = knotdatacnt/4; outpatterncnt = unknotting_eventcnt/combopatterncnt; tim = 0; mid = 1; lev = 2; pos = 3; // endtime = bastime; if(dz->vflag[2]) { sprintf(temp,";UNKNOTTING\n"); fputs(temp,dz->fp); } for(n = 0; n < unknotting_eventcnt;n++) { sprintf(temp,"%lf\t%d\t%lf\t%lf\n",outdata[tim] + bastime,(int)round(outdata[mid]),outdata[lev],outdata[pos]); if(fputs(temp,dz->fp) < 0) { sprintf(errstr,"FAILED TO WRITE UNKNOTTING DATA TO OUTPUT FILE \n"); return SYSTEM_ERROR; } if(dz->vflag[2]) { if(n % combopatterncnt == combopatterncnt-1) { sprintf(temp,"\n"); fputs(temp,dz->fp); } } tim += 4; mid += 4; // Note that tim advances to end of unknotting array "outdata" lev += 4; pos += 4; } bastime += (dz->celltime * outpatterncnt); // Next event is outpatterncnt cells later // IF repatialise AFTER unknotting CALCULATE RESPATIALISATION PARAMS if(spacetyp > 0 && dz->vflag[3] && dz->iparam[KNOT_GOALREP] > 1) { respace = 1; setup_respatialisation_params(spatpos,spatstep,comboarray,combopatterncnt,dz->iparam[KNOT_GOALREP],dz); } // OUTPUT THE GOAL PATTERN if(dz->iparam[KNOT_GOALREP]) { if(dz->vflag[2]) { sprintf(temp,";GOAL PATTERN REPEATS\n"); fputs(temp,dz->fp); } combopatterncnt = 0; for(n=0;n < dz->infilecnt;n++) combopatterncnt += patterncnt[n] - 1; // Count total number of events in combined pattern sttim = tim - (combopatterncnt * 4); // Set counters to start of goal pattern (in unknotting array) stmid = mid - (combopatterncnt * 4); stlev = lev - (combopatterncnt * 4); stpos = pos - (combopatterncnt * 4); starttime = outdata[sttim]; tim = sttim; mid = stmid; lev = stlev; pos = stpos; for(r=0;riparam[KNOT_GOALREP];r++) { for(n = 0; n < combopatterncnt;n++) { if(respace) { thispos = spatpos[n] + 1.0; // Reconvert to (0)1-8 range for output channel if(thispos > 8.0) thispos -= 8.0; sprintf(temp,"%lf\t%d\t%lf\t%lf\n",(outdata[tim] - starttime) + bastime,(int)round(outdata[mid]),outdata[lev],thispos); if(fputs(temp,dz->fp) < 0) { sprintf(errstr,"FAILED TO WRITE GOAL EVENT REPETITIONS TO OUTPUT FILE\n"); return SYSTEM_ERROR; } spatpos[n] += spatstep[n]; // Advance position towards goal position for each pattern element if(spatpos[n] >= 8.0) // spatpos uses 0 - <8 range for modulo8 arithmetic spatpos[n] -= 8.0; else if(spatpos[n] < 0.0) spatpos[n] += 8.0; } else { sprintf(temp,"%lf\t%d\t%lf\t%lf\n",(outdata[tim] - starttime) + bastime,(int)round(outdata[mid]),outdata[lev],outdata[pos]); if(fputs(temp,dz->fp) < 0) { sprintf(errstr,"FAILED TO WRITE GOAL EVENT REPETITIONS TO OUTPUT FILE\n"); return SYSTEM_ERROR; } } tim += 4; mid += 4; lev += 4; pos += 4; } tim = sttim; // back to start of last pattern of unknotting's "outdata" mid = stmid; lev = stlev; pos = stpos; if(dz->vflag[2]) { sprintf(temp,"\n"); fputs(temp,dz->fp); } bastime += dz->celltime; } } if(dz->mode == DO_KNOT) { if(dz->iparam[KNOT_COMBOREP]) { if(dz->vflag[2]) { sprintf(temp,";REPEATS OF COMBINATIONS OF ORIGINAL PATTERNS\n"); fputs(temp,dz->fp); } for(ccnt = 0; ccnt < dz->itemcnt; ccnt++) { // For each pattern combination combopatterncnt = GenerateKnotCombo(combo,ccnt,patterncnt,dz); for(r=0;riparam[KNOT_COMBOREP];r++) { tim = 0; mid = 1; lev = 2; pos = 3; for(pcnt=0;pcnt < combopatterncnt; pcnt++) { sprintf(temp,"%lf\t%d\t%lf\t%lf\n",combo[tim] + bastime,(int)round(combo[mid]),combo[lev],combo[pos]); if(fputs(temp,dz->fp) < 0) { sprintf(errstr,"FAILED TO WRITE PATTERN COMBINATIONS TO OUTPUT FILE \n"); return SYSTEM_ERROR; } tim += 4; mid += 4; lev += 4; pos += 4; } if(dz->vflag[2]) { sprintf(temp,"bastime = %lf\n",bastime); fputs(temp,dz->fp); } bastime += dz->celltime; } } } if(dz->iparam[KNOT_PATREP]) { if(dz->vflag[2]) { sprintf(temp,";ORIGINAL PATTERN REPEATS\n"); fputs(temp,dz->fp); } for(n=0;ninfilecnt;n++) { for(r = 0; r < dz->iparam[KNOT_PATREP];r++) { thispattern = dz->parray[n]; tim = 0; mid = 1; lev = 2; pos = 3; for(pcnt=0;pcnt < patterncnt[n] - 1; pcnt++) { // Don't output the endmarker events sprintf(temp,"%lf\t%d\t%lf\t%lf\n",thispattern[tim] + bastime,(int)round(thispattern[mid]),thispattern[lev],thispattern[pos]); if(fputs(temp,dz->fp) < 0) { sprintf(errstr,"FAILED TO WRITE TO INDIVIDUAL PATTERNS OUTPUT FILE \n"); return SYSTEM_ERROR; } tim += 4; mid += 4; lev += 4; pos += 4; } if(dz->vflag[2]) { sprintf(temp,"\n"); fputs(temp,dz->fp); } bastime += dz->celltime; } } } } return FINISHED; } /**************************************** PULSE_REGULAR ****************************************/ int pulse_regular(double a,double b,double minstep) { if(fabs(a-b) < minstep) return 1; return 0; } /**************************************** PULSE_MORE ****************************************/ int pulse_more(double thisstep,double maxstep,double minerror) { if(thisstep > maxstep + minerror) return 1; return 0; } /**************************************** GENERATEKNOTCOMBO ****************************************/ // dz->iparray[dz->itemcnt] contains the sizes of each combo // dz->iparray[0] to dz->iparray[itemcnt-1] contains the actual combo int GenerateKnotCombo (double *comboarray,int combono,int *patterncnt,dataptr dz) { int arraysize = 0; int *thiscombo, *combocnts, thiscombocnt, k = 0, n, m, thispattern; if(combono >= 0) { thiscombo = dz->iparray[combono]; // Array with list of patterns in this combination combocnts = dz->iparray[dz->itemcnt]; // Array counting number of members in EACH combination thiscombocnt = combocnts[combono]; // Count of members in THIS combination for(n = 0;n < thiscombocnt;n++) { // For every pattern in this combination thispattern = thiscombo[n]; // Get this pattern thispattern--; // Change to 0 to n-1 counting for(m=0;m < (patterncnt[thispattern] - 1) * 4; m++) { comboarray[k++] = dz->parray[thispattern][m]; arraysize++; } } } else { for(n=0;n < dz->infilecnt;n++) { // Copy all patterns into combination array for(m=0;m < (patterncnt[n] - 1) * 4; m++) { comboarray[k++] = dz->parray[n][m]; arraysize++; } } } thiscombocnt = arraysize/4; sortcomoboarray(thiscombocnt,comboarray); return thiscombocnt; } /**************************************** SORTCOMOBOARRAY ****************************************/ void sortcomoboarray(int combopatterncnt,double *comboarray) { int n, m, tn, tm; double tim_m, mid_m,lev_m, pos_m, tim_n, mid_n, lev_n, pos_n; for(n=0;n < combopatterncnt - 1;n++) { // Sort combined pattern into time-order tn = n * 4; tim_n = comboarray[tn]; for(m=n+1;m < combopatterncnt;m++) { tm = m * 4; tim_m = comboarray[tm]; if(tim_m < tim_n) { mid_n = comboarray[tn+1]; lev_n = comboarray[tn+2]; pos_n = comboarray[tn+3]; mid_m = comboarray[tm+1]; lev_m = comboarray[tm+2]; pos_m = comboarray[tm+3]; comboarray[tn] = tim_m; comboarray[tn+1] = mid_m; comboarray[tn+2] = lev_m; comboarray[tn+3] = pos_m; comboarray[tm] = tim_n; comboarray[tm+1] = mid_n; comboarray[tm+2] = lev_n; comboarray[tm+3] = pos_n; tim_n = tim_m; } } } } /**************************************** SETUP_RESPATIALISATION_PARAMS ****************************************/ int setup_respatialisation_params(double *spatpos,double *spatstep,double *comboarray, int combopatterncnt,int respacecnt,dataptr dz) { int n, m, spactyp; int steps, pos; double final_spatial_spread = 0, final_space_step, startpos, distance, goal; spactyp = dz->iparam[KNOT_SPACETYP]; if(spactyp == 1) { for(n=0,m=1;nparam[KNOT_CHANA]; // Alternating spatpos[m] = dz->param[KNOT_CHANB]; } } else { switch(spactyp) { // Assign final spatial spread for each event case(2): case(4): if(dz->param[KNOT_CHANB] > dz->param[KNOT_CHANA]) final_spatial_spread = dz->param[KNOT_CHANB] - dz->param[KNOT_CHANA]; else if (dz->param[KNOT_CHANB] == dz->param[KNOT_CHANA]) final_spatial_spread = 8; else // dz->param[KNOT_CHANB] < dz->param[KNOT_CHANA]) final_spatial_spread = dz->param[KNOT_CHANB] - dz->param[KNOT_CHANA] + 8; break; case(3): case(5): if(dz->param[KNOT_CHANA] > dz->param[KNOT_CHANB]) final_spatial_spread = dz->param[KNOT_CHANA] - dz->param[KNOT_CHANB]; else if (dz->param[KNOT_CHANA] == dz->param[KNOT_CHANB]) final_spatial_spread = 8; else // dz->param[KNOT_CHANA] < dz->param[KNOT_CHANB]) final_spatial_spread = dz->param[KNOT_CHANA] - dz->param[KNOT_CHANB] + 8; break; } switch(spactyp) { // Assign actual goal-spatial-positions for each event case(2): final_space_step = (double)final_spatial_spread/(double)(combopatterncnt-1); spatpos[0] = dz->param[KNOT_CHANA]; for(n=1;nparam[KNOT_CHANA] + (n * final_space_step); if(spatpos[n] >= 8.0) spatpos[n] -= 8.0; } spatpos[combopatterncnt-1] = dz->param[KNOT_CHANB]; break; case(3): final_space_step = (double)final_spatial_spread/(double)(combopatterncnt-1); spatpos[0] = dz->param[KNOT_CHANA]; for(n=1;nparam[KNOT_CHANA] - (n * final_space_step); if(spatpos[n] < 0.0) spatpos[n] += 8.0; } spatpos[combopatterncnt-1] = dz->param[KNOT_CHANB]; break; case(4): steps = combopatterncnt/2; if(steps * 2 != combopatterncnt) steps++; final_space_step = (double)final_spatial_spread/(double)steps; spatpos[0] = dz->param[KNOT_CHANA]; for(n=1;nparam[KNOT_CHANA] + (n * final_space_step); if(spatpos[n] >= 8.0) spatpos[n] -= 8.0; } spatpos[n++] = dz->param[KNOT_CHANB]; for(m = 1;nparam[KNOT_CHANB] - (m * final_space_step); if(spatpos[n] < 0.0) spatpos[n] += 8.0; } break; case(5): steps = combopatterncnt/2; if(steps * 2 != combopatterncnt) steps++; final_space_step = (double)final_spatial_spread/(double)steps; spatpos[0] = dz->param[KNOT_CHANA]; for(n=1;nparam[KNOT_CHANA] - (n * final_space_step); if(spatpos[n] < 0.0) spatpos[n] += 8.0; } spatpos[n++] = dz->param[KNOT_CHANB]; for(m = 1;nparam[KNOT_CHANB] + (m * final_space_step); if(spatpos[n] >= 8.0) spatpos[n] -= 8.0; } break; } } // Calculate stepsize necessary to move events to final positions by shortest route pos = 3; for(n=0;n= 8.0) // e.g. 8 10 1 7 goal -= 8.0; // e.g. 0 2 1 7 if(flteq(goal,spatpos[n])) // YES NO NO YES spatstep[n] = distance/(respacecnt-1); // clock clock else // anticlok anticlok spatstep[n] = -distance/(respacecnt-1); spatpos[n] = comboarray[pos] - 1; // Assign the initial spatial positions of each event (in 0 to chas-1 frame) pos += 4; } return FINISHED; } int IsAnIntegerInRange(char *str,int imin, int imax) { char *q, *p = str; int i; q = p + strlen(str); q--; while(q != p) { if(!isdigit(*q)) return 0; q--; } i = atoi(str); if(i < imin || i > imax) return 0; return 1; } int IsAFilename(char *str) { char *q, *p = str; int ispoint = 0, alpha = 0, wasbackslash = 0; if(isdigit(*p) || (*p == '.') || (*p == '-')) return 0; q = p + strlen(str); q--; while(q != p) { if(!isalnum(*q) && (*q != '-') && (*q != '_') && (*q != '.') && (*q != '\\')) return 0; // Must be aphanumeric with valid spearators if(isalpha(*q)) alpha++; if(*q == '\\') { // RWD removed extra brackets if(wasbackslash) return 0; // No double backslashes wasbackslash = 1; } else wasbackslash = 0; if(*q == '.') { if(ispoint) return 0; // No more than one file-extension-marker "." ispoint++; } q--; } if(!alpha) // Must have alphabetic chars return 0; return 1; }