/* * 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 * */ /* floatsam version */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include //#ifdef unix #define round(x) lround((x)) //#endif #ifndef HUGE #define HUGE 3.40282347e+38F #endif #define SQUASH (2.0) /* non-linearity factor */ #define MAXPOSCNT (512) /* max no. of spatial positions between lspkrs */ static int initialise_texture_structure(dataptr dz); static int set_up_and_fill_insample_buffers(insamptr **insound,dataptr dz); static int setup_texflag(texptr tex,dataptr dz); static int adjust_some_input_params(dataptr dz); static int preset_some_internal_texture_params(dataptr dz); static int install_unused_texture_flags(int *total_flags,int unused_flags,dataptr dz); static int install_the_internal_flags(int total_flags,int internal_flags,dataptr dz); static int get_the_notedata(texptr tex,dataptr dz); static int extend_timeset(dataptr dz); static int generate_timeset(dataptr dz); static int do_prespace(motifptr tset,dataptr dz); static int get_sample_pitches(FILE *fp,dataptr dz); static int get_motifs(FILE *fp,int *motifcnt,dataptr dz); static int motifchek(motifptr thismotif); static void convert_cmdline_instrnos_to_internal_representation(dataptr dz); static int check_max_transpos_compatible_with_splicelen(dataptr dz); static int set_amptype_params(dataptr dz); static int set_decor_pitchposition_params(dataptr dz); static void copy_note(noteptr thisnote,noteptr orignote); static int add_motif_to_end_of_motiflist(motifptr *new,dataptr dz); static int scatter_and_quantise_tset_times(double *lasttime,noteptr *thisnote,dataptr dz); static int pre_space(noteptr thisnote,dataptr dz); static int getpos(double thistime,double *position,dataptr dz); static int spread_and_set_cpos(double *position,double given_position,double spread,dataptr dz); static int chekrang(double *val,dataptr dz); static int read_a_note_from_notedata_file (noteptr thisnote,int noteno,int motifno,double *lasttime,dataptr dz); static int generate_tset_times(double *thistime,noteptr *thisnote,dataptr dz); static int un_link_note(noteptr thisnote); static int new_motif(motifptr *thismotif); static int unlink_last_motif(motifptr thismotif); static void subtract_one_from_brkvals(int paramno,dataptr dz); static int bigscatter(noteptr *thisnote,double thistime,double timestep,double scatter,double *lasttime,dataptr dz); static int get_data_item(char *q,char **p,double *val); static int init_note(noteptr *thisnote); static void put_znote(noteptr thisnote); static int assign_timeset_hfset_motifsets(dataptr dz); static int massage_params(dataptr dz); static int init_motifs(dataptr dz); static int generate_outpositions(dataptr dz); /************************* TEXTURE_PREPROCESS **************************** * * (1) Establish the bitflag which characterises the texture process. * (2) For consistency across all texture processes, all unused flags are mallocd. * This ensures that the numbering of the INTERNAL flags is consistent across all applics. * (3) Convert some input parameters to form used internally, and check some against insnd lengths. */ int texture_preprocess(dataptr dz) { int exit_status; int total_flags, unused_flags, n; unsigned int texflag; initialise_random_sequence(IS_TEX_RSEED,TEXTURE_SEED,dz); if((exit_status = initialise_texture_structure(dz))<0) return(exit_status); if((exit_status = set_up_and_fill_insample_buffers(&(dz->tex->insnd),dz))<0) return(exit_status); if((exit_status = initperm(&(dz->tex->perm),dz))<0) return(exit_status); if((exit_status = setup_texflag(dz->tex,dz))<0) /* 1 */ return(exit_status); texflag = dz->tex->txflag; if((exit_status = adjust_some_input_params(dz))<0) return(exit_status); if((exit_status = preset_some_internal_texture_params(dz))<0) return(exit_status); /* 2 */ unused_flags = TOTAL_POSSIBLE_USER_FLAGS - dz->application->vflag_cnt; if((exit_status = install_unused_texture_flags(&total_flags,unused_flags,dz))<0) return(exit_status); if((exit_status = install_the_internal_flags(total_flags,INTERNAL_FLAGS_CNT,dz))<0) return(exit_status); if((exit_status = get_the_notedata(dz->tex,dz))<0) return(exit_status); if((exit_status = assign_timeset_hfset_motifsets(dz))<0) return(exit_status); if((exit_status = massage_params(dz))<0) /* 3 */ return(exit_status); if(texflag & ORN_DEC_OR_TIMED) { if((exit_status = extend_timeset(dz))<0) /* 7 */ return(exit_status); } else { if((exit_status = generate_timeset(dz))<0) /* 8 */ return(exit_status); } if((exit_status = do_prespace(dz->tex->timeset,dz))<0) return(exit_status); if(dz->process == SIMPLE_TEX && dz->vflag[CYCLIC_TEXFLAG]) { if(dz->infilecnt < 2) dz->vflag[CYCLIC_TEXFLAG] = 0; else if (dz->vflag[PERM_TEXFLAG]) { if((dz->peakno = (int *)malloc(dz->infilecnt * sizeof(int))) == NULL) { sprintf(errstr,"Insufficient memory for clyclic permutations of input files.\n"); return(MEMORY_ERROR); } if((dz->lastpeakno = (int *)malloc(dz->infilecnt * sizeof(int))) == NULL) { sprintf(errstr,"Insufficient memory for cyclic permutations of input files.\n"); return(MEMORY_ERROR); } for(n=0;ninfilecnt;n++) { dz->peakno[n] = n; dz->lastpeakno[n] = n; } } } if(dz->vflag[4]) { if((exit_status = generate_outpositions(dz))<0) /* 8 */ return(exit_status); } return(FINISHED); } /*********************** INITIALISE_TEXTURE_STRUCTURE ******************************/ int initialise_texture_structure(dataptr dz) { int n; if((dz->tex = (texptr)malloc(sizeof(struct textural)))==NULL) { sprintf(errstr,"INSUFFICIENT MEMORY for texture structure.\n"); return(MEMORY_ERROR); } dz->tex->txflag = 0; dz->tex->motifhead = (motifptr)0; dz->tex->insnd = (insamptr *)0; dz->tex->timeset = (motifptr)0; dz->tex->hfldmotif = (motifptr)0; dz->tex->phrase = (motifptr *)0; dz->tex->perm = (int **)0; dz->tex->dectypstor = 0; dz->tex->dectypcnt = 0; dz->tex->amptypstor = 0; dz->tex->amptypcnt = 0; dz->tex->phrasecnt = 0; dz->tex->ampdirectd = FALSE; if((dz->tex->insnd = (insamptr *)malloc(dz->infilecnt * sizeof(insamptr)))==NULL) { sprintf(errstr,"INSUFFICIENT MEMORY for texture insound structure.\n"); return(MEMORY_ERROR); } for(n=0;ninfilecnt;n++) { dz->tex->insnd[n] = (insamptr)0; if((dz->tex->insnd[n]= (insamptr)malloc(sizeof(struct insample)))==NULL) { sprintf(errstr,"INSUFFICIENT MEMORY for texture insound[%d] structure.\n",n+1); return(MEMORY_ERROR); } } return(FINISHED); } /************************** SET_UP_AND_FILL_INSAMPLE_BUFFERS **************************** * * 1) Set buffer pointer to zero, until it has been malloced. * This make freeing of tex structure possible. */ int set_up_and_fill_insample_buffers(insamptr **insound,dataptr dz) { int n; int samps_read; int thisbufsize /*, seccnt*/; int wrap_around_samps = 1; for(n=0;ninfilecnt;n++) { ((*insound)[n])->buffer = /*(float *)0*/NULL; /* 1 */ thisbufsize = dz->insams[n]; thisbufsize += wrap_around_samps; if((((*insound)[n])->buffer = (float *)malloc(thisbufsize * sizeof(float)))==NULL) { sprintf(errstr,"INSUFFICIENT MEMORY for texture insound buffer pointer %d.\n",n+1); return(MEMORY_ERROR); } memset((char *)((*insound)[n])->buffer,0,thisbufsize * sizeof(float)); if((samps_read = fgetfbufEx(((*insound)[n])->buffer,thisbufsize,dz->ifd[n],0)) < 0) { sprintf(errstr,"Can't read sndfile %d to buffer: set_up_and_fill_insample_buffers()\n",n+1); return(SYSTEM_ERROR); } if(samps_read != dz->insams[n]) { sprintf(errstr,"Error reading sndfile %d to buf: set_up_and_fill_insample_buffers()\n",n+1); return(PROGRAM_ERROR); } } return(FINISHED); } /***************************** SETUP_TEXFLAG ****************************/ int setup_texflag(texptr tex,dataptr dz) { tex->txflag = 0; switch(dz->process) { case(SIMPLE_TEX): break; case(GROUPS): tex->txflag |= IS_GROUPS; break; case(DECORATED): tex->txflag |= IS_DECOR; break; case(PREDECOR): tex->txflag |= IS_DECOR; tex->txflag |= ISPRE_DECORORN; break; case(POSTDECOR): tex->txflag |= IS_DECOR; tex->txflag |= ISPOST_DECORORN; break; case(ORNATE): tex->txflag |= IS_ORNATE; break; case(PREORNATE): tex->txflag |= IS_ORNATE; tex->txflag |= ISPRE_DECORORN; break; case(POSTORNATE): tex->txflag |= IS_ORNATE; tex->txflag |= ISPOST_DECORORN; break; case(MOTIFS): tex->txflag |= IS_MOTIFS; break; case(MOTIFSIN): tex->txflag |= IS_MOTIFS; tex->txflag |= MOTIF_IN_HF; break; case(TIMED): tex->txflag |= ISTIMED; break; case(TGROUPS): tex->txflag |= IS_GROUPS; tex->txflag |= ISTIMED; break; case(TMOTIFS): tex->txflag |= IS_MOTIFS; tex->txflag |= ISTIMED; break; case(TMOTIFSIN): tex->txflag |= IS_MOTIFS; tex->txflag |= MOTIF_IN_HF; tex->txflag |= ISTIMED; break; default: sprintf(errstr,"Unknown process in setup_texflag()\n"); return(PROGRAM_ERROR); } switch(dz->mode) { case(TEX_NEUTRAL): break; case(TEX_HFIELD): tex->txflag |= ISHARM; break; case(TEX_HFIELDS): tex->txflag |= ISHARM; tex->txflag |= ISMANY_HFLDS; break; case(TEX_HSET): tex->txflag |= ISHARM; tex->txflag |= IS_HS; break; case(TEX_HSETS): tex->txflag |= ISHARM; tex->txflag |= IS_HS; tex->txflag |= ISMANY_HFLDS; break; default: sprintf(errstr,"Unknown mode in setup_texflag()\n"); return(PROGRAM_ERROR); } return(FINISHED); } /************************** ADJUST_SOME_INPUT_PARAMS **************************** * * (1) dz->vflag[WHICH_CHORDNOTE] internally carries all 3 vals (first,highest,every). * * (2) Gprange, in cases with Hfields, is an integer count of HF-field notes to use. */ int adjust_some_input_params(dataptr dz) { int texflag = dz->tex->txflag; if((texflag & IS_ORN_OR_DEC) && dz->vflag[FORCE_EVERY]==TRUE) dz->vflag[WHICH_CHORDNOTE] = DECOR_EVERY; /* 1 */ if((texflag & IS_DEC_OR_GRP) && (texflag & ISHARM)) { /* 2 */ dz->is_int[TEX_GPRANGLO] = TRUE; dz->is_int[TEX_GPRANGHI] = TRUE; dz->iparam[TEX_GPRANGLO] = round(dz->param[TEX_GPRANGLO]); dz->iparam[TEX_GPRANGHI] = round(dz->param[TEX_GPRANGHI]); } return(FINISHED); } /***************************** PRESET_SOME_INTERNAL_TEXTURE_PARAMS ****************************/ int preset_some_internal_texture_params(dataptr dz) { int cnt = 0; dz->iparam[SPINIT] = 0; cnt++; /* ALL CLUMPS */ dz->iparam[SPCNT] = 0; cnt++; dz->iparam[DIRECTION] = 0; cnt++; dz->param[CPOS] = 0.5; cnt++; /* for safety only */ /* SPATIALISATION */ dz->param[TPOSITION] = 0.5; cnt++; /* for safety only */ dz->param[THISSPRANGE]= 1.0; cnt++; /* full range */ /*dz->iparam[TEX_MAXOUT]= 0.0; cnt++; *//* min value */ dz->param[TEX_MAXOUT] = 0.0; cnt++; /*RWD*/ if(cnt != dz->application->internal_param_cnt) { sprintf(errstr,"preset_some_internal_texture_params() has false count\n"); return(PROGRAM_ERROR); } dz->itemcnt = 0; return(FINISHED); } /***************************** INSTALL_UNUSED_TEXTURE_FLAGS ****************************/ int install_unused_texture_flags(int *total_flags,int unused_flags,dataptr dz) { int n; *total_flags = dz->application->vflag_cnt + unused_flags; if(unused_flags > 0) { if((dz->vflag = (char *)realloc(dz->vflag,(*total_flags) * sizeof(char)))==NULL) { sprintf(errstr,"INSUFFICIENT MEMORY for internal flags.\n"); return(MEMORY_ERROR); } for(n=0;nvflag[2] = FALSE; break; case(3): dz->vflag[3] = FALSE; break; case(2): dz->vflag[4] = FALSE; break; case(1): dz->vflag[5] = FALSE; break; case(0): dz->vflag[6] = FALSE; break; } } } return(FINISHED); } /***************************** INSTALL_THE_INTERNAL_FLAGS ****************************/ int install_the_internal_flags(int total_flags,int internal_flags,dataptr dz) { /* THESE FLAGS ARE NOT AVAILABLE TO USER : but they are used in the code */ total_flags += internal_flags; if((dz->vflag = (char *)realloc(dz->vflag,total_flags * sizeof(char)))==NULL) { sprintf(errstr,"INSUFFICIENT MEMORY to reallocate internal flags.\n"); return(MEMORY_ERROR); } dz->iparam[DECCENTRE] = FALSE; return(FINISHED); } /***************************** GET_THE_NOTEDATA ****************************/ int get_the_notedata(texptr tex,dataptr dz) { int exit_status; unsigned int texflag = tex->txflag; int motifcnt, expected_motifcnt = 0; if(dz->fp==NULL) { sprintf(errstr,"notedata fileptr not initialised: get_the_notedata()\n"); return(PROGRAM_ERROR); } if((exit_status = get_sample_pitches(dz->fp,dz))<0) { sprintf(errstr,"Insufficient pitch values in notedata file.\n"); return(DATA_ERROR); } if((exit_status = get_motifs(dz->fp,&motifcnt,dz))<0) return(exit_status); if(texflag & ORN_DEC_OR_TIMED) expected_motifcnt++; /* Line to work on */ if(texflag & ISHARM) expected_motifcnt++; /* HF data */ if(texflag & IS_ORN_OR_MTF) expected_motifcnt++; /* Ornmnts or mtfs */ if(texflag & IS_ORN_OR_MTF) { if(motifcnt < expected_motifcnt) { sprintf(errstr,"Insufficient motifs in notedata file.\n"); return(DATA_ERROR); } } else { if(motifcnt!=expected_motifcnt) { sprintf(errstr,"Incorrect number [%d] of motifs in notedata file (expected %d).\n", motifcnt,expected_motifcnt); return(DATA_ERROR); } } return(FINISHED); } /**************************** EXTEND_TIMESET *******************************/ int extend_timeset(dataptr dz) { int exit_status; int origcnt = 0, n; noteptr startnote = dz->tex->motifhead->firstnote; noteptr orignote, thisnote = startnote; double *timediff; if(startnote==(noteptr)0) { sprintf(errstr,"Problem in note timings: extend_timeset()\n"); return(PROGRAM_ERROR); } while(thisnote!=(noteptr)0) { if(thisnote->ntime > dz->param[TEXTURE_DUR]) { delete_notes_here_and_beyond(thisnote); return(FINISHED); } thisnote = thisnote->next; origcnt++; } if((timediff = (double *)malloc(origcnt * sizeof(double)))==NULL) { sprintf(errstr,"INSUFFICIENT MEMORY for timegaps array.\n"); return(MEMORY_ERROR); } n = 1; thisnote = startnote; while(thisnote->next !=(noteptr)0) { thisnote = thisnote->next; timediff[n++] = thisnote->ntime - thisnote->last->ntime; } if(dz->brksize[TEXTURE_SKIP]) { if((exit_status = read_value_from_brktable(thisnote->ntime,TEXTURE_SKIP,dz))<0) { free(timediff); return(exit_status); } } timediff[0] = dz->param[TEXTURE_SKIP]; n = 0; orignote = startnote; for(;;) { if(thisnote->ntime > dz->param[TEXTURE_DUR] && timediff[n] > 0.0) break; if((exit_status = make_new_note(&thisnote))<0) { free(timediff); return(exit_status); } copy_note(thisnote,orignote); thisnote->ntime = (float)(thisnote->last->ntime + timediff[n]); if(++n>=origcnt) { if(dz->brksize[TEXTURE_SKIP]) { if((exit_status = read_value_from_brktable(thisnote->ntime,TEXTURE_SKIP,dz))<0) { free(timediff); return(exit_status); } timediff[0] = dz->param[TEXTURE_SKIP]; } n = 0; orignote = startnote; } else orignote = orignote->next; } dz->brksize[TEXTURE_SKIP] = 0; /* prevent future reads */ free(timediff); return(FINISHED); } /********************************************************************* * * (1) Generating the tset (set of timed values on or around which the * texture is to be generated). */ /************************** GENERATE_TIMESET ****************************** * * (A) Zero all other parameters besides time. */ int generate_timeset(dataptr dz) { int exit_status; double lasttime, thistime = 0.0; noteptr thisnote; motifptr tset; if((exit_status = add_motif_to_end_of_motiflist(&(dz->tex->timeset),dz))<0) return(exit_status); tset = dz->tex->timeset; if((thisnote = tset->firstnote)==(noteptr)0) { sprintf(errstr,"Failure to find 1st note in motif: generate_timeset()\n"); return(PROGRAM_ERROR); } put_znote(thisnote); /* A */ thisnote->ntime = (float)thistime; if(dz->brksize[TEXTURE_PACK]) { if((exit_status = read_value_from_brktable(thistime,TEXTURE_PACK,dz))<0) return(exit_status); } thistime += dz->param[TEXTURE_PACK]; while(thistimeparam[TEXTURE_DUR]) { if((exit_status = generate_tset_times(&thistime,&thisnote,dz))<0) return(exit_status); put_znote(thisnote); /* A */ } thisnote = tset->firstnote; lasttime = thisnote->ntime; thisnote = thisnote->next; while(thisnote!=(noteptr)0) { if((exit_status = scatter_and_quantise_tset_times(&lasttime,&thisnote,dz))<0) return(exit_status); } dz->brksize[TEXTURE_PACK] = 0; /* set these brktables to appear empty, so no read attempts later */ dz->brksize[TEXTURE_SCAT] = 0; dz->brksize[TEXTURE_TGRID] = 0; return(FINISHED); } /***************************** DO_PRESPACE ****************************** * * Spatialise the time set, prior to output phase&/or ornamentation. */ int do_prespace(motifptr tset,dataptr dz) { int exit_status; noteptr thisnote = tset->firstnote; while(thisnote!=(noteptr)0) { if((exit_status = pre_space(thisnote,dz))<0) return(exit_status); thisnote = thisnote->next; } return(FINISHED); } /**************************** GET_SAMPLE_PITCHES *****************************/ int get_sample_pitches(FILE *fp,dataptr dz) { int exit_status; /* TW MARCH 2010: 2000--> 20000 */ char temp[20000], *q; int pitchcnt = 0; double *p; int got_all_pitches = FALSE; /* TW MARCH 2010: 2000 --> 20000 */ while(!got_all_pitches && (fgets(temp,20000,fp)!=NULL)) { q = temp; if(*q == ';') // Allow comments in file continue; p = &(((dz->tex->insnd)[pitchcnt])->pitch); while((exit_status = get_float_from_within_string(&q,p))==TRUE) { if(++pitchcnt >= dz->infilecnt) { got_all_pitches = TRUE; break; } p = &(((dz->tex->insnd)[pitchcnt])->pitch); } if(exit_status==FALSE) return(DATA_ERROR); } if(!got_all_pitches) return(DATA_ERROR); return(FINISHED); } /**************************** GET_MOTIFS ***************************** * * Read data from an ascii file to notelist. */ int get_motifs(FILE *fp,int *motifcnt,dataptr dz) { int exit_status; motifptr thismotif; noteptr thisnote; char *p, temp[200]; double lasttime=0.0; int datalen, noteno, motifno = 0; if((exit_status = init_motifs(dz))<0) /* 8 */ return(exit_status); thismotif = dz->tex->motifhead; while(fgets(temp,200,fp)!=NULL) { p = temp; while(isspace(*p)) p++; if(*p==ENDOFSTR) continue; if(*p!=TEXTURE_SEPARATOR) { //TW UPDATE sprintf(errstr,"'%c' missing before datacount in notedata file: motif %d (or more notes listed than indicated by %cN)\n" "check datalen is correct\n",TEXTURE_SEPARATOR,motifno+1,TEXTURE_SEPARATOR); return(DATA_ERROR); } p++; if(!isdigit(*p) || sscanf(p,"%d",&datalen)!=1) { sprintf(errstr,"No datalength given: motif %d\n",motifno+1); return(DATA_ERROR); } if(datalen <= 0) { sprintf(errstr,"Invalid data length %d in notedata: motif %d\n",datalen,motifno+1); return(DATA_ERROR); } motifno++; thisnote = thismotif->firstnote; for(noteno=1;noteno<=datalen;noteno++) { if((exit_status = read_a_note_from_notedata_file(thisnote,noteno,motifno,&lasttime,dz))<0) return(exit_status); if(exit_status==CONTINUE) { noteno--; continue; } if((exit_status = make_new_note(&thisnote))<0) return(exit_status); } if((exit_status = un_link_note(thisnote))<0) return(exit_status); if((exit_status = new_motif(&thismotif))<0) return(exit_status); } *motifcnt = motifno; if(motifno > 0) return unlink_last_motif(thismotif); return(FINISHED); } /************************** MOTIFCHEK ******************************** * * Check we've not run out of motifs. */ int motifchek(motifptr thismotif) { if(thismotif == (motifptr)0) { sprintf(errstr,"motifchek(): Insufficient motifs: even though correctly counted.\n"); return(PROGRAM_ERROR); } return(FINISHED); } /***************************** CONVERT_CMDLINE_INSTRNOS_TO_INTERNAL_REPRESENTATION ****************************/ void convert_cmdline_instrnos_to_internal_representation(dataptr dz) { if(dz->brksize[TEXTURE_INSLO]) subtract_one_from_brkvals(TEXTURE_INSLO,dz); else dz->iparam[TEXTURE_INSLO]--; if(dz->brksize[TEXTURE_INSHI]) subtract_one_from_brkvals(TEXTURE_INSHI,dz); else dz->iparam[TEXTURE_INSHI]--; } /***************************** CHECK_MAX_TRANSPOS_COMPATIBLE_WITH_SPLICELEN ****************************/ int check_max_transpos_compatible_with_splicelen(dataptr dz) { int n, exit_status; double max_maxpitch, max_minpitch, max_transpospitch, maxupshift, upratio, minlen; double min_sndlength = (TEXTURE_SPLICELEN + TEXTURE_SAFETY) * MS_TO_SECS * (double)dz->infile->srate; dz->frametime = TEXTURE_SPLICELEN; if(dz->brksize[TEXTURE_MAXPICH]) { if((exit_status = get_maxvalue_in_brktable(&max_maxpitch,TEXTURE_MAXPICH,dz))<0) return(exit_status); } else max_maxpitch = dz->param[TEXTURE_MAXPICH]; if(dz->brksize[TEXTURE_MINPICH]) { if((exit_status = get_maxvalue_in_brktable(&max_minpitch,TEXTURE_MINPICH,dz))<0) return(exit_status); } else max_minpitch = dz->param[TEXTURE_MINPICH]; max_transpospitch = max(max_minpitch,max_maxpitch); dz->zeroset = 0; /* use as flag re splicelen change */ for(n=0;ninfilecnt;n++) { maxupshift = max_transpospitch - ((dz->tex->insnd)[n])->pitch; upratio = pow(2.0,(maxupshift/SEMITONES_PER_OCTAVE)); minlen = (double)dz->insams[n]/upratio; if(minlen < min_sndlength) { dz->frametime = 2.0; min_sndlength = (dz->frametime + TEXTURE_SAFETY) * MS_TO_SECS * (double)dz->infile->srate; if(minlen < min_sndlength) { dz->frametime = 1.0; min_sndlength = (dz->frametime + TEXTURE_SAFETY) * MS_TO_SECS * (double)dz->infile->srate; if(minlen < min_sndlength) { sprintf(errstr,"sndfile %d [%.3lf secs] too short for max upward transposition [ratio %.2lf].\n", n+1,(double)dz->insams[n]/(double)dz->infile->srate,upratio); return(DATA_ERROR); } } } } return(FINISHED); } /************************* SET_AMPTYPE_PARAMS *******************************/ int set_amptype_params(dataptr dz) { int mask = 1, n; dz->tex->amptypcnt = 0; dz->tex->amptypstor = 0; switch(dz->iparam[TEX_AMPCONT]) { case(IS_MIXED): dz->tex->amptypstor |= 1; dz->tex->amptypstor |= 2; break; case(IS_CRESC): dz->tex->amptypstor |= 2; break; case(IS_FLAT): dz->tex->amptypstor |= 1; break; case(IS_DECRESC): dz->tex->amptypstor |= 4; break; case(IS_FLAT_AND_CRESC): dz->tex->amptypstor |= 1; dz->tex->amptypstor |= 2; break; case(IS_CRESC_AND_DECRESC): dz->tex->amptypstor |= 2; dz->tex->amptypstor |= 4; break; case(IS_FLAT_AND_DECRESC): dz->tex->amptypstor |= 1; dz->tex->amptypstor |= 4; break; case(IS_DIRECTIONAL): dz->tex->ampdirectd = TRUE; dz->tex->amptypcnt = 1; break; case(IS_DIREC_OR_FLAT): dz->tex->ampdirectd = TRUE; dz->tex->amptypcnt = 2; break; default: sprintf(errstr,"Unknown case in set_amptype_params()\n"); return(PROGRAM_ERROR); } if(dz->tex->amptypstor > 0) { for(n=0;n<3;n++) { if(mask & dz->tex->amptypstor) dz->tex->amptypcnt++; mask <<= 1; } } return(FINISHED); } /************************* SET_DECOR_PITCHPOSITION_PARAMS ******************************/ int set_decor_pitchposition_params(dataptr dz) { int n, mask = 1; dz->tex->dectypstor = 0; dz->tex->dectypcnt = 0; switch(dz->iparam[TEX_DECPCENTRE]) { case(DEC_CENTRED): dz->tex->dectypstor |= 1; break; case(DEC_ABOVE): dz->tex->dectypstor |= 2; break; case(DEC_BELOW): dz->tex->dectypstor |= 4; break; case(DEC_C_A): dz->tex->dectypstor |= 1; dz->tex->dectypstor |= 2; break; case(DEC_C_B): dz->tex->dectypstor |= 1; dz->tex->dectypstor |= 4; break; case(DEC_A_B): dz->tex->dectypstor |= 2; dz->tex->dectypstor |= 4; break; case(DEC_C_A_B): dz->tex->dectypstor |= 1; dz->tex->dectypstor |= 2; dz->tex->dectypstor |= 4; break; default: sprintf(errstr,"Unknown case in set_decor_pitchposition_params()\n"); return(PROGRAM_ERROR); } if(dz->tex->dectypstor > 0) { for(n=0;n<3;n++) { if(mask & dz->tex->dectypstor) dz->tex->dectypcnt++; mask <<= 1; } } return(FINISHED); } /********************** DELETE_NOTES_HERE_AND_BEYOND ******************************* void delete_notes_here_and_beyond(noteptr startnote) { noteptr here = startnote; if(here==(noteptr)0) return; while(here->next!=(noteptr)0) here=here->next; while(here!=startnote) { here=here->last; free(here->next); } if(startnote->last!=(noteptr)0) startnote->last->next = (noteptr)0; free(startnote); } ****/ /********************** MAKE_NEW_NOTE **************************** * * Create new link in note list. */ int make_new_note(noteptr *thisnote) { if(((*thisnote)->next = (noteptr)malloc(sizeof(struct nnote)))==NULL) { sprintf(errstr,"INSUFFICIENT MEMORY for a further note store.\n"); return(MEMORY_ERROR); } (*thisnote)->next->last = *thisnote; *thisnote = (*thisnote)->next; (*thisnote)->next = (noteptr)0; return(FINISHED); } /**************************** COPY_NOTE *******************************/ void copy_note(noteptr thisnote,noteptr orignote) { thisnote->ntime = orignote->ntime; thisnote->amp = orignote->amp; thisnote->pitch = orignote->pitch; thisnote->dur = orignote->dur; thisnote->instr = orignote->instr; thisnote->spacepos = orignote->spacepos; thisnote->motioncentre = orignote->motioncentre; } /************************** ADD_MOTIF_TO_END_OF_MOTIFLIST ****************************** * * Create new motif at end of list. */ int add_motif_to_end_of_motiflist(motifptr *new,dataptr dz) { int exit_status; motifptr here = dz->tex->motifhead; while(here->next!=(motifptr)0) here = here->next; if((exit_status = new_motif(&here))<0) return(exit_status); *new = here; return(FINISHED); } /************************* SCATTER_AND_QUANTISE_TSET_TIMES ******************************/ int scatter_and_quantise_tset_times(double *lasttime,noteptr *thisnote,dataptr dz) { int exit_status; double thistime = (*thisnote)->ntime; /* 1 */ double timestep = thistime - *lasttime; /* 2 */ *lasttime = thistime; /* 2a */ if(dz->brksize[TEXTURE_SCAT]) { if((exit_status = read_value_from_brktable(thistime,TEXTURE_SCAT,dz))<0) return(exit_status); } if(dz->param[TEXTURE_SCAT]>1.0) { /* 3a */ //TW UPDATE (original code error) if((exit_status = bigscatter(thisnote,thistime,timestep,dz->param[TEXTURE_SCAT],lasttime,dz))<0) return(exit_status); } else { if(!flteq(dz->param[TEXTURE_SCAT],0.0)) /* 4 */ thistime -= (float)(drand48() * dz->param[TEXTURE_SCAT] * timestep); if(dz->param[TEXTURE_TGRID]>0.0) thistime = quantise(thistime,dz->param[TEXTURE_TGRID]); /* 6 */ (*thisnote)->ntime = (float)thistime; } *thisnote = (*thisnote)->next; return(FINISHED); /* 8a */ } /************************** PRE_SPACE ******************************** * * Store spatial data in the tsetnote spacepos and motioncentre. */ int pre_space(noteptr thisnote,dataptr dz) { int exit_status; double position; if((exit_status = getpos((double)thisnote->ntime,&position,dz))<0) return(exit_status); thisnote->spacepos = (float)position; thisnote->motioncentre = (float)dz->param[CPOS]; return(FINISHED); } /************************** GETPOS **************************** * * Calculate spatial position of event from it's time. */ int getpos(double thistime,double *position,dataptr dz) { int exit_status; if(dz->brksize[TEXTURE_POS] && (exit_status = read_value_from_brktable(thistime,TEXTURE_POS,dz))<0) return(exit_status); if(dz->brksize[TEXTURE_SPRD] && (exit_status = read_value_from_brktable(thistime,TEXTURE_SPRD,dz))<0) return(exit_status); if(dz->param[TEXTURE_SPRD] > 0.0) { if((exit_status = spread_and_set_cpos(position,dz->param[TEXTURE_POS],dz->param[TEXTURE_SPRD],dz))<0) return(exit_status); } else { /* NOV 1997--> */ dz->param[CPOS] = dz->param[TEXTURE_POS]; /* <--NOV 1997 */ *position = dz->param[TEXTURE_POS]; } return(FINISHED); } /***************************** SPREAD_AND_SET_CPOS *****************************/ int spread_and_set_cpos(double *position,double given_position,double spread,dataptr dz) { int exit_status; //static int firsttime = 1; int posno, spswitch; int poscnt,hposcnt; double hspread,spacing; double lchan; /* leftmost channel of position value */ double stereo_given_position; /* position within stereo gap between 2 lspkrs (0-1) */ /* total stereospace has MAXPOSCNT positions: calc no. & spacing of positions available at given spread */ given_position -= 1.0; /* input parma run from 1 to N, calc params run from 0 to (N-1) */ if(given_position < 0.0) given_position += (double)dz->iparam[TEXTURE_OUTCHANS]; dz->param[CPOS] = given_position; poscnt = round(spread * (double)MAXPOSCNT); hposcnt = poscnt/2; hspread = spread/(double)2.0; if(hposcnt != 0) spacing = hspread/(double)hposcnt; else { /* bandwidth effectively zero: return given position */ dz->param[CPOS] = given_position; *position = given_position; return(FINISHED); } /* randomly select leftwards/rightwards of the given position */ if((exit_status = doperm(2,PM_SPACE,&spswitch,dz))<0) return(exit_status); if(!spswitch) spswitch = -1; /* randomly chose a pos (to left or right) around centre pos */ posno = round(drand48() * hposcnt); posno *= spswitch; /* If (position+spread) leaks to right of stereo-space : squeeze position */ lchan = (double)(int)round(given_position); stereo_given_position = given_position - lchan; dz->param[CPOS] = stereo_given_position; *position = dz->param[CPOS] + ((double)posno * spacing); *position += lchan; if(*position < 0.0) *position += (double)dz->iparam[TEXTURE_OUTCHANS]; if(*position >= dz->iparam[TEXTURE_OUTCHANS]) *position -= (double)dz->iparam[TEXTURE_OUTCHANS]; return chekrang(position,dz); } /*************************** CHEKRANG ************************** * * Check variable lies within range 0.0 to 1.0. */ int chekrang(double *val,dataptr dz) { if(flteq(*val,1.0)) *val = 1.0; if(flteq(*val,0.0)) *val = 0.0; if(*val<0.0 || *val>(double)dz->iparam[TEXTURE_OUTCHANS]) { sprintf(errstr,"value [%f] outside range 0-%d: chekrang()\n",*val,dz->iparam[TEXTURE_OUTCHANS]); return(PROGRAM_ERROR); } return(FINISHED); } /************************** READ_A_NOTE_FROM_NOTEDATA_FILE ********************************/ int read_a_note_from_notedata_file(noteptr thisnote,int noteno,int motifno,double *lasttime,dataptr dz) { int exit_status; unsigned int texflag = dz->tex->txflag; char temp[200], *p, *q; double val; int start; if(dz->fp==NULL) { sprintf(errstr,"Note datafile descriptor not initialised: read_a_note_from_notedata_file()\n"); return(PROGRAM_ERROR); } if(fgets(temp,200,dz->fp)==NULL){ sprintf(errstr,"Note data line for note %d, motif %d missing in notedatafile\n",noteno,motifno); return(DATA_ERROR); } p =temp; while(isspace(*p)) p++; q = p; if(*q==ENDOFSTR) return(CONTINUE); if((exit_status = get_data_item(q,&p,&val))<0) { sprintf(errstr,"No time data for note %d, motif %d in notedatafile\n",noteno,motifno); return(DATA_ERROR); } if(exit_status==FINISHED) { sprintf(errstr,"No data after time for note %d, motif %d in notedatafile\n",noteno,motifno); return(DATA_ERROR); } thisnote->ntime = (float)val; if((noteno > 1) && (*lasttime > thisnote->ntime)) { sprintf(errstr,"Notes in reverse time order: notedata file : motif %d: notes %d & %d\n", motifno,noteno,noteno-1); return(DATA_ERROR); } *lasttime = thisnote->ntime; p++; q = p; if((exit_status = get_data_item(q,&p,&val))<0) { sprintf(errstr,"No instr_no for note %d, motif %d in notedatafile\n",noteno,motifno); return(DATA_ERROR); } if(exit_status==FINISHED) { sprintf(errstr,"No data after instr_no for note %d, motif %d in notedatafile\n",noteno,motifno); return(DATA_ERROR); } //instr_no = round(val); p++; q = p; if((exit_status = get_data_item(q,&p,&val))<0) { sprintf(errstr,"No pitch data for note %d, motif %d in notedatafile\n",noteno,motifno); return(DATA_ERROR); } if(exit_status==FINISHED) { sprintf(errstr,"No data after pitch for note %d, motif %d in notedatafile\n",noteno,motifno); return(DATA_ERROR); } thisnote->pitch = (float)val; /* NEEDS TESTING FOR MIDIRANGE: EXCEPT IN TIMING SET CASE */ if(!(texflag & ISTIMED) || motifno!=1) { if(val < MIDIMIN || val > MIDIMAX) { sprintf(errstr,"pitch value [%lf] out of range (%d to %d): motif %d: note %d\n", val,MIDIMIN,MIDIMAX,motifno,noteno); return(DATA_ERROR); } } p++; q = p; if((exit_status = get_data_item(q,&p,&val))<0) { sprintf(errstr,"No amplitude data for note %d, motif %d in notedatafile\n",noteno,motifno); return(DATA_ERROR); } if(exit_status==FINISHED) { sprintf(errstr,"No data after amp for note %d, motif %d in notedatafile\n",noteno,motifno); return(DATA_ERROR); } thisnote->amp = (float)val; /* 1999 THIS NEEDS TESTING FOR MIDIRANGE EXCEPT IN TIMING SET CASE */ if(!(texflag & ISTIMED) || motifno!=1) { if(val < MIDIMIN || val > MIDIMAX) { sprintf(errstr,"amplitude value [%lf] out of range (%d to %d): motif %d: note %d\n", val,MIDIMIN,MIDIMAX,motifno,noteno); return(DATA_ERROR); } } p++; q = p; if((exit_status = get_data_item(q,&p,&val))<0) { sprintf(errstr,"No duration data for note %d, motif %d in notedatafile\n",noteno,motifno); return(DATA_ERROR); } thisnote->dur = (float)val; if(texflag & IS_ORN_OR_MTF) { if(texflag & IS_ORNATE) { start = 2; } else { start = 1; if(texflag & ISTIMED) start++; } if(texflag & ISHARM) start++; if(motifno >= start) { if(val <= FLTERR) { sprintf(errstr,"Duration value [%lf] is too small: motif %d: note %d\n",val,motifno,noteno); return(DATA_ERROR); } } } else { thisnote->dur = 1.0f; /* default ; redundant */ } return(FINISHED); } /***************************** GENERATE_TSET_TIMES ********************************** * * Store time initially as SECONDS. * * (1) Create location for a new note. * (2) Go to that new note. * (3) Store the current time at this note. * (4) Find note-density at this time, and generate time of next event. * (5) Return nextnote. */ int generate_tset_times(double *thistime,noteptr *thisnote,dataptr dz) { int exit_status; if((exit_status = make_new_note(thisnote))<0) return(exit_status); /* 1 */ (*thisnote)->ntime = (float)(*thistime); /* 3 */ if(dz->brksize[TEXTURE_PACK]) { if((exit_status = read_value_from_brktable(*thistime,TEXTURE_PACK,dz))<0) return(exit_status); } *thistime += dz->param[TEXTURE_PACK]; /* 4 */ return(FINISHED); /* 5 */ } /********************** UN_LINK_NOTE ****************************** * * Deletes empty address space at end of notelist. */ int un_link_note(noteptr thisnote) { if(thisnote->last==(noteptr)0) { sprintf(errstr,"Problem in un_link_note()\n"); return(PROGRAM_ERROR); } thisnote = thisnote->last; free(thisnote->next); thisnote->next = (noteptr)0; return(FINISHED); } /************************ NEW_MOTIF ***************************** * * Set up next motif in a list of musical-motifs. * Set up location of first note of this motif. */ int new_motif(motifptr *thismotif) { int exit_status; motifptr newmotif; noteptr thisnote; //static int count = 1; if((newmotif = (motifptr)malloc(sizeof (struct motif)))==NULL) { sprintf(errstr,"INSUFFICIENT MEMORY to store next motif.\n"); return(MEMORY_ERROR); } (*thismotif)->next = newmotif; newmotif->last = *thismotif; newmotif->next = (motifptr)0; if((exit_status = init_note(&thisnote))<0) return(exit_status); thisnote->next = (noteptr)0; thisnote->last = (noteptr)0; newmotif->firstnote = thisnote; *thismotif = newmotif; return(FINISHED); } /********************** UNLINK_LAST_MOTIF ****************************** * * Deletes empty address space at end of motiflist. */ int unlink_last_motif(motifptr thismotif) { if(thismotif->last==(motifptr)0) { sprintf(errstr,"Problem in unlink_last_motif()\n"); return(PROGRAM_ERROR); } thismotif = thismotif->last; free(thismotif->next); thismotif->next = (motifptr)0; return(FINISHED); } /**************************** SUBTRACT_ONE_FROM_BRKVALS ****************************/ void subtract_one_from_brkvals(int paramno,dataptr dz) { double *p = dz->brk[paramno] + 1; double *pend = dz->brk[paramno] + (dz->brksize[paramno] * 2); while(p < pend) { *p -= 1.0; p += 2; } } /************************ BIGSCATTER ************************************* * * (1) The number of time-points to be randomly scattered as a group is * scatcnt. * (1a) Base time is the time from which these new scattered times are offset. * (2) Save the current position in note list as 'here'. * (3) Go forward in note list until there are scatcnt notes inclusive * between here and there, or until list runs out. * (3a) If the list runs out, modify scatcnt accordingly. * (4) Note the (original) time of the last of these events. This will * be returned as the new 'lasttime' for the next cycle of the * program. * (5) Make the time-step include the total duration of all these * events. * (5a) Generate a set of times AT RANDOM within this large timestep, sort them and store them. * (6) Replace existing times by scattered times, relative to basetime. * (6a) Convert to MIDitime. * (6b) Quantise if necessary. * (7) Replace the last time. * (9) Return the last note we worked on. */ int bigscatter(noteptr *thisnote,double thistime,double timestep,double scatter,double *lasttime,dataptr dz) { int n, scatcnt = round(scatter); /* 1 */ double *sct, *scti; double basetime = thistime - timestep; /* 1a */ noteptr here = *thisnote; /* 2 */ noteptr there = *thisnote; /* 2 */ if((scti = (double *)malloc(scatcnt * sizeof(double)))==NULL) { sprintf(errstr,"INSUFFICIENT MEMORY for scattering structure.\n"); return(MEMORY_ERROR); } sct = scti; for(n=0;n < scatcnt-1; n++) { /* 3 */ if(there->next==(noteptr)0) { scatcnt = n+1; /* 3a */ break; } there = there->next; } *lasttime = there->ntime; /* 4 */ timestep += *lasttime - thistime; /* 5 */ for(n= 0;nparam[TEXTURE_TGRID]>0.0) thistime = quantise(thistime,dz->param[TEXTURE_TGRID]); /* 6b */ here->ntime = (float)thistime; here = here->next; } thistime = basetime + *sct; /* 7 */ if(dz->param[TEXTURE_TGRID]>0.0) thistime = quantise(thistime,dz->param[TEXTURE_TGRID]); there->ntime = (float)thistime; free(scti); *thisnote = there; return(FINISHED); /* 9 */ } /************************** QUANTISE ************************************* * * Quantise time point onto a grid. */ double quantise(double thistime,double timegrid) { int gridpoint; timegrid *= MS_TO_SECS; gridpoint = round(thistime/timegrid); return((double)gridpoint * timegrid); } /************************* GET_DATA_ITEM ****************************/ int get_data_item(char *q,char **p,double *val) { int exit_status = CONTINUE; if(*q==ENDOFSTR) return(DATA_ERROR); while(isspace(**p)) { (*p)++; if(**p == ENDOFSTR) return(DATA_ERROR); } if(**p==TEXTURE_SEPARATOR) return(DATA_ERROR); while(!isspace(**p) && **p!=ENDOFSTR) { (*p)++; } if(**p==ENDOFSTR) exit_status = FINISHED; **p = ENDOFSTR; if(sscanf(q,"%lf",val)!=1) return(DATA_ERROR); return(exit_status); } /************************* INIT_NOTE **************************** * * Initialise notelist. */ int init_note(noteptr *thisnote) { if((*thisnote = (noteptr)malloc(sizeof(struct nnote)))==NULL) { sprintf(errstr,"INSUFFICIENT MEMORY for another note.\n"); return(MEMORY_ERROR); } (*thisnote)->next = (noteptr)0; (*thisnote)->last = (noteptr)0; return(FINISHED); } /********************** UPSORT ******************************* * * Sort set of doubles into ascending order. */ void upsort(double *scti,int scatcnt) { double sct; int n, m; for(n=0;n<(scatcnt-1);n++) { for(m=n+1;mamp = 0.0f; thisnote->pitch = 0.0f; thisnote->dur = 0.0f; thisnote->instr = 0; thisnote->spacepos = 0.0f; thisnote->motioncentre = 0.0f; } /************************* ASSIGN_TIMESET_HFSET_MOTIFSETS ****************************** * * Assign appropriate pointers to input motifs. * * (1) If it's a timed texture, indicate first motif in list as that * which defines the set of times (tset). * Similarly, if texture is ornamented or decorated, point to first * motif as that to BE ornamented or decorated (tset). * (2) If the texture restricted to HF(s) or HS(s), indicate next motif * as the HF-set (hfldmotif). It may be read in different ways (as HF, as * HS, or as time-varying of either type) at a later time. * (3) If texture consists of motifs, or is to use specific ornaments... * (4) count the number of motifs remaining. * (5) Set up the array of phrases to point to the appropriate motifs. */ int assign_timeset_hfset_motifsets(dataptr dz) { int exit_status; unsigned int texflag = dz->tex->txflag; motifptr here, thismotif = dz->tex->motifhead; int n; dz->tex->phrasecnt = 0; if(texflag & ORN_DEC_OR_TIMED) { if((exit_status = motifchek(thismotif))<0) return(exit_status); dz->tex->timeset = thismotif; /* 1 */ thismotif = thismotif->next; } if(texflag & ISHARM) { /* 2 */ if((exit_status = motifchek(thismotif))<0) return(exit_status); dz->tex->hfldmotif = thismotif; thismotif = thismotif->next; } if((texflag & IS_ORNATE) || (texflag & IS_MOTIFS)) { /* 3 */ if((exit_status = motifchek(thismotif))<0) return(exit_status); here = thismotif; while(thismotif!=(motifptr)0) { /* 4 */ dz->tex->phrasecnt++; thismotif = thismotif->next; } /* 5 */ if((dz->tex->phrase = (motifptr *)malloc(dz->tex->phrasecnt * sizeof(motifptr)))==NULL) { sprintf(errstr,"INSUFFICIENT MEMORY for phrase array.\n"); return(MEMORY_ERROR); } thismotif = here; n = -1; while(thismotif!=(motifptr)0) { dz->tex->phrase[++n] = thismotif; thismotif = thismotif->next; } } return(FINISHED); } /***************************** MASSAGE_PARAMS ****************************/ int massage_params(dataptr dz) { int exit_status; unsigned int texflag = dz->tex->txflag; convert_cmdline_instrnos_to_internal_representation(dz); if((exit_status = check_max_transpos_compatible_with_splicelen(dz))<0) return(exit_status); if(texflag & IS_CLUMPED) { if((exit_status = set_amptype_params(dz))<0) return(exit_status); } if(texflag & IS_DECOR) { if((exit_status = set_decor_pitchposition_params(dz))<0) return(exit_status); } return(FINISHED); } /************************* INIT_MOTIFS ***************************** * * Set up head item of a list of musical-motifs. * Set up location of first note of first motif. */ int init_motifs(dataptr dz) { int exit_status; noteptr thisnote; if((dz->tex->motifhead = (motifptr)malloc(sizeof (struct motif)))==NULL) { sprintf(errstr,"INSUFFICIENT MEMORY to store any motifs.\n"); return(MEMORY_ERROR); } dz->tex->motifhead->next = (motifptr)0; dz->tex->motifhead->last = (motifptr)0; if((exit_status = init_note(&thisnote))<0) return(exit_status); dz->tex->motifhead->firstnote = thisnote; thisnote->next = (noteptr)0; thisnote->last = (noteptr)0; return(FINISHED); } /******************************** INITPERM ********************************* * * Establish storage space for permutation parameters. * * (1) create pointers to the items within the permuted sets. Initialise to zero. * (2) Create storage for current length of each perm. Initialise to zero. * (3) Create storage for previous length of each perm. Initialise to -1 (impossible). * If new perm different length to old, space for permuted elements will need to be re-malloced. * (4) Create pointers to storage areas for each permuted set. Initialise to point nowhere. * These will be malloced when the size of each set-to-permute is known. * (5) Create storage for previous outputed val in each perm. Initialise to -1 (impossible). * This is useful at permutation boundaries, when a particular element may be repeated more * than permitted no. of times if there's no check. These constants allow no. of repets to be counted. * (6) Create counter of current no. of consecutive repets of an element in each of the (output) perms. * Initialise to 0, though this is arbitrary, as repetcnt should always be set on any call of do_perm. * (7) Create storage for max no. of allowed consecutive repets of an element in each perm-set. * Initialise to 1, which is the default if no info is given to the contrary. */ int initperm(int ***permm,dataptr dz) { int n; if((dz->iparray[TXPERMINDEX] = (int *)malloc(PERMCNT * sizeof(int)))==NULL) { /* 1 */ sprintf(errstr,"INSUFFICIENT MEMORY for permutation indeces.\n"); return(MEMORY_ERROR); } for(n=0;niparray[TXPERMINDEX][n] = 0; if((dz->iparray[TXPERMLEN] = (int *)malloc(PERMCNT * sizeof(int)))==NULL) { /* 2 */ sprintf(errstr,"INSUFFICIENT MEMORY for permutation lengths.\n"); return(MEMORY_ERROR); } for(n=0;niparray[TXPERMLEN][n] = 0; if((dz->iparray[TXLASTPERMLEN] = (int *)malloc(PERMCNT * sizeof(int)))==NULL) { /* 3 */ sprintf(errstr,"INSUFFICIENT MEMORY for last permutation lengths.\n"); return(MEMORY_ERROR); } for(n=0;niparray[TXLASTPERMLEN][n] = -1; if((*permm = (int **)malloc(PERMCNT * sizeof(int *)))==NULL) { /* 4 */ sprintf(errstr,"INSUFFICIENT MEMORY for permutations.\n"); return(MEMORY_ERROR); } for(n=0;niparray[TXLASTPERMVAL] = (int *)malloc(PERMCNT * sizeof(int)))==NULL) { /* 5 */ sprintf(errstr,"INSUFFICIENT MEMORY for last permutation values.\n"); return(MEMORY_ERROR); } for(n=0;niparray[TXLASTPERMVAL][n] = -1; if((dz->iparray[TXREPETCNT] = (int *)malloc(PERMCNT * sizeof(int)))==NULL) { /* 6 */ sprintf(errstr,"INSUFFICIENT MEMORY for permutation repetition counts.\n"); return(MEMORY_ERROR); } for(n=0;niparray[TXREPETCNT][n] = 1; if((dz->iparray[TXRPT] = (int *)malloc(PERMCNT * sizeof(int)))==NULL) { /* 7 */ sprintf(errstr,"INSUFFICIENT MEMORY for permutation repetitions.\n"); return(MEMORY_ERROR); } /* THESE ARE THE DEFAULT NUMBER OF REPETITIONS-OF-AN-ENTITY ALLOWED IN A PERM */ dz->iparray[TXRPT][PM_SPACE] = SPACE_REPETS; dz->iparray[TXRPT][PM_PITCH] = PITCH_REPETS; dz->iparray[TXRPT][PM_AMP] = AMP_REPETS; dz->iparray[TXRPT][PM_DUR] = DUR_REPETS; dz->iparray[TXRPT][PM_INSNO] = INSNO_REPETS; dz->iparray[TXRPT][PM_GPRANG] = GPRANG_REPETS; dz->iparray[TXRPT][PM_GPSIZE] = GPSIZE_REPETS; dz->iparray[TXRPT][PM_GPDENS] = GPDENS_REPETS; dz->iparray[TXRPT][PM_GPCNTR] = GPCNTR_REPETS; dz->iparray[TXRPT][PM_GPPICH] = GPPICH_REPETS; dz->iparray[TXRPT][PM_ORNPOS] = ORNPOS_REPETS; dz->iparray[TXRPT][PM_GPSPAC] = GPSPAC_REPETS; dz->iparray[TXRPT][PM_ORIENT] = ORIENT_REPETS; dz->iparray[TXRPT][PM_DECABV] = DECABV_REPETS; dz->iparray[TXRPT][PM_MULT] = MULT_REPETS; dz->iparray[TXRPT][PM_WHICH] = WHICH_REPETS; dz->iparray[TXRPT][PM_GPPICH2]= GPPICH2_REPETS; return(FINISHED); } /************************************ GENERATE_OUTPOSITIONS ************************************ * * In mode 1, output positions are preset, and permuted. */ int generate_outpositions(dataptr dz) { int *lmost = dz->iparray[dz->iarray_cnt-1], kk, jj, n, m; double *pos = dz->parray[dz->array_cnt-1], lowerpos = 0.0, dndiff, updiff, randwander, rando; kk = dz->infilecnt/dz->iparam[TEXTURE_OUTCHANS]; if((kk * dz->iparam[TEXTURE_OUTCHANS]) != dz->infilecnt) kk++; // number of positions per lspkr pair jj = 0; for(n = 0; n < dz->iparam[TEXTURE_OUTCHANS];n++) { for(m=0;m < kk;m++) { lmost[jj] = (n + (int)round(dz->param[TEXTURE_POS])) % dz->iparam[TEXTURE_OUTCHANS]; if(kk==1) pos[jj] = 0.5; else { if(m == 0) pos[jj] = 1/(double)(2*kk); // e.g kk = 3 gives 1/6 : kk = 4 gives 1/8 else pos[jj] = (1/(double)(2*kk)) + (m/(double)kk); // e.g kk = 3 gives 1/6 +1/3: kk = 4 gives 1/8+1/4, 1/8+1/2 } jj++; } if(dz->param[TEXTURE_SPRD] > 0.0) { // Do rand scatter rando = max(dz->param[TEXTURE_SPRD],1.0); jj -= kk; lowerpos = 0; for(m=0;m < kk;m++) { if(m == 0) dndiff = pos[jj]; else dndiff = (pos[jj] - lowerpos)/2.0; lowerpos = pos[jj]; if(m == kk - 1) updiff = 1 - pos[jj]; else updiff = (pos[jj+1] - pos[jj])/2.0; randwander = drand48() * rando; randwander *= 2.0; randwander -= 1.0; if(randwander < 0.0) pos[jj] += dndiff * randwander; else pos[jj] += updiff * randwander; jj++; } } } return FINISHED; }