Browse Source

changed to the intended version as per documentation. Old version renamed frfractal.c

richarddobson 4 months ago
parent
commit
bb8ea1b380
1 changed files with 1334 additions and 303 deletions
  1. 1334 303
      dev/standnew/fractal.c

+ 1334 - 303
dev/standnew/fractal.c

@@ -21,6 +21,14 @@
  02111-1307 USA
  02111-1307 USA
  *
  *
  */
  */
+
+// see HEREH
+//  TEST cmdline =
+//  _cdprogs\fractal wave 1 sin_cycle.wav testfrac.wav fracshape.brk 4 -m2
+//  Only getting 1/2-way through the pattern ... why??
+//  look at "seedata.txt" to check times advance!!!!
+//  _cdprogs\fractal spectrum zzz.ana testfrac.ana fracshape5.brk
+
 #include <stdio.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <stdlib.h>
 #include <structures.h>
 #include <structures.h>
@@ -36,6 +44,7 @@
 #include <mixxcon.h>
 #include <mixxcon.h>
 #include <osbind.h>
 #include <osbind.h>
 #include <standalone.h>
 #include <standalone.h>
+#include <science.h>
 #include <ctype.h>
 #include <ctype.h>
 #include <sfsys.h>
 #include <sfsys.h>
 #include <string.h>
 #include <string.h>
@@ -45,7 +54,36 @@
 #ifdef unix
 #ifdef unix
 #define round(x) lround((x))
 #define round(x) lround((x))
 #endif
 #endif
-#define maxfraccnt rampbrksize
+#ifndef HUGE
+#define HUGE 3.40282347e+38F
+#endif
+
+#define FRAC_SPLICELEN  50          //  Ms  
+#define FRAC_FORMANTS   4           //  No of formants used
+
+#define FRAC_SHRINK     0
+#define FRAC_OUTIMES    1
+
+#define  mintime        timemark            //  Minimum possible duration of any fractal element    
+#define  startfrq       frametime           //  Frq of first pitch in (Mode 1) fractal_pitch-pattern
+#define  maxtrnsp       is_flat             //  Maximum possible upward-transpostion of any fractal element
+#define  arraysize      rampbrksize         //  Array size for totally fractalised pattern
+#define  fracdur        minbrk              //  Input duration of the fractal template
+#define  minstep        scalefact           //  Minimum element-duration in fractal template
+#define  minfracratio   halfchwidth         //  Time shrinkage of smallest element in fractal template, when proceeding from one fractal level to next
+#define  maxfractalise  ringsize            //  Maximum degree of fractalisation
+#define  timevary       is_transpos         //  Inicates that fractal patterning varies through time
+#define  fracsize       fzeroset            //  Number of elements in current totally-fractalised pattern
+#define  convertor      chwidth
+#define  total_splice   specenv_type        //  Total number of samples used in (any) end-splice
+#define  splicesmps     deal_with_chan_data //  No of grouped-samples in (any) end-splice
+#define  maxtransshrink is_sharp            //  Time-shrinkage of the element with maximum upward transposition, when proceeding from one fractal level to next
+#define  mintransshrink minnum              //  Time-shrinkage of the element with maximum downward transposition, when proceeding from one fractal level to next
+
+#define FRACDUR     0
+#define FRACMAX     1
+#define FRACTSTR    2
+#define FRACISTR    3
 
 
 char errstr[2400];
 char errstr[2400];
 
 
@@ -72,11 +110,22 @@ static int mark_parameter_types(dataptr dz,aplptr ap);
 static int assign_file_data_storage(int infilecnt,dataptr dz);
 static int assign_file_data_storage(int infilecnt,dataptr dz);
 static int get_tk_cmdline_word(int *cmdlinecnt,char ***cmdline,char *q);
 static int get_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_process_no(char *prog_identifier_from_cmdline,dataptr dz);
-//static int get_the_mode_from_cmdline(char *str,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 setup_and_init_input_brktable_constants(dataptr dz,int brkcnt);
-static int float_array_for_fractal(int nnn,int n, float **ptr);
-static int generate_fractal_pattern(dataptr dz);
+static int handle_the_special_data(char *str,dataptr dz);
 static int create_fractal_sndbufs(dataptr dz);
 static int create_fractal_sndbufs(dataptr dz);
+static void get_max_fractalisation(dataptr dz);
+static int fractalise(dataptr dz);
+static int fractal_initialise_specenv(int *arraycnt,dataptr dz);
+static int fractal_set_specenv_frqs(int arraycnt,dataptr dz);
+static int fractal_setup_octaveband_steps(double **interval,dataptr dz);
+static int fractal_setup_low_octave_bands(int arraycnt,dataptr dz);
+static int fractal_extract_specenv(dataptr dz);
+static int fractal_tranpose_within_formant_envelope(int vc,double transpose,dataptr dz);
+static int fractal_reposition_partials_in_appropriate_channels(double transpose,dataptr dz);
+static int fractal_spectrnsf(double transpose,dataptr dz);
+static int fractal_getspecenvamp(double *thisamp,double thisfrq,dataptr dz);
+static int fractal_get_channel_corresponding_to_frq(int *chan,double thisfrq,dataptr dz);
 
 
 /**************************************** MAIN *********************************************/
 /**************************************** MAIN *********************************************/
 
 
@@ -86,7 +135,8 @@ int main(int argc,char *argv[])
     dataptr dz = NULL;
     dataptr dz = NULL;
     char **cmdline;
     char **cmdline;
     int  cmdlinecnt;
     int  cmdlinecnt;
-    int n;
+    int arraycnt = 0;
+    char specialname[1200];
 //    aplptr ap;
 //    aplptr ap;
     int is_launched = FALSE;
     int is_launched = FALSE;
     if(argc==2 && (strcmp(argv[1],"--version") == 0)) {
     if(argc==2 && (strcmp(argv[1],"--version") == 0)) {
@@ -128,8 +178,16 @@ int main(int argc,char *argv[])
             return(FAILED);
             return(FAILED);
         cmdline++;
         cmdline++;
         cmdlinecnt--;
         cmdlinecnt--;
-        dz->maxmode = 0;
-        // get_the_mode_from_cmdline
+        if(dz->process == FRACTAL) {
+            dz->maxmode = 2;
+            if((exit_status = get_the_mode_from_cmdline(cmdline[0],dz))<0) {
+                print_messages_and_close_sndfiles(exit_status,is_launched,dz);
+                return(exit_status);
+            }
+            cmdline++;
+            cmdlinecnt--;
+        } else
+            dz->maxmode = 0;
         // setup_particular_application =
         // setup_particular_application =
         if((exit_status = setup_fractal_application(dz))<0) {
         if((exit_status = setup_fractal_application(dz))<0) {
             print_messages_and_close_sndfiles(exit_status,is_launched,dz);
             print_messages_and_close_sndfiles(exit_status,is_launched,dz);
@@ -165,7 +223,22 @@ int main(int argc,char *argv[])
     }
     }
     cmdlinecnt--;
     cmdlinecnt--;
     cmdline++;
     cmdline++;
-
+    if(dz->process == FRACSPEC) {
+        dz->nyquist     = dz->infile->origrate/2.0;
+        dz->frametime   = (float)(1.0/dz->infile->arate);
+        dz->clength     = dz->wanted / 2;
+        dz->chwidth     = dz->nyquist/(double)(dz->clength-1);
+        dz->halfchwidth = dz->chwidth/2.0;
+        if((exit_status = fractal_initialise_specenv(&arraycnt,dz))<0) {    
+            print_messages_and_close_sndfiles(exit_status,is_launched,dz);  
+            return(FAILED);
+        }
+        dz->formant_bands = FRAC_FORMANTS;
+        if((exit_status = fractal_set_specenv_frqs(arraycnt,dz))<0) {   
+            print_messages_and_close_sndfiles(exit_status,is_launched,dz);  
+            return(FAILED);
+        }
+    }
 //  handle_extra_infiles() : redundant
 //  handle_extra_infiles() : redundant
     // handle_outfile() = 
     // handle_outfile() = 
     if((exit_status = handle_the_outfile(&cmdlinecnt,&cmdline,dz))<0) {
     if((exit_status = handle_the_outfile(&cmdlinecnt,&cmdline,dz))<0) {
@@ -176,36 +249,35 @@ int main(int argc,char *argv[])
 //  handle_formants()           redundant
 //  handle_formants()           redundant
 //  handle_formant_quiksearch() redundant
 //  handle_formant_quiksearch() redundant
 //  handle_special_data()       redundant
 //  handle_special_data()       redundant
+ 
+    strcpy(specialname,cmdline[0]);
+    cmdlinecnt--;
+    cmdline++;
     if((exit_status = read_parameters_and_flags(&cmdline,&cmdlinecnt,dz))<0) {      // CDP LIB
     if((exit_status = read_parameters_and_flags(&cmdline,&cmdlinecnt,dz))<0) {      // CDP LIB
         print_messages_and_close_sndfiles(exit_status,is_launched,dz);
         print_messages_and_close_sndfiles(exit_status,is_launched,dz);
         return(FAILED);
         return(FAILED);
     }
     }
-//  check_param_validity_and_consistency....
+    if((exit_status = handle_the_special_data(specialname,dz))<0) {
+        print_messages_and_close_sndfiles(exit_status,is_launched,dz);
+        return(FAILED);
+    }
+//  check_param_validity_and_consistency ..
     if((exit_status = check_fractal_param_validity_and_consistency(dz))<0) {
     if((exit_status = check_fractal_param_validity_and_consistency(dz))<0) {
         print_messages_and_close_sndfiles(exit_status,is_launched,dz);
         print_messages_and_close_sndfiles(exit_status,is_launched,dz);
         return(FAILED);
         return(FAILED);
     }
     }
     is_launched = TRUE;
     is_launched = TRUE;
-    dz->bufcnt = 3;
-    if((dz->sampbuf = (float **)malloc(sizeof(float *) * (dz->bufcnt+1)))==NULL) {
-        sprintf(errstr,"INSUFFICIENT MEMORY establishing sample buffers.\n");
-        return(MEMORY_ERROR);
-    }
-    if((dz->sbufptr = (float **)malloc(sizeof(float *) * dz->bufcnt))==NULL) {
-        sprintf(errstr,"INSUFFICIENT MEMORY establishing sample buffer pointers.\n");
-        return(MEMORY_ERROR);
-    }
-    for(n = 0;n <dz->bufcnt; n++)
-        dz->sampbuf[n] = dz->sbufptr[n] = (float *)0;
-    dz->sampbuf[n] = (float *)0;
-
-    if((exit_status = create_fractal_sndbufs(dz))<0) {                          // CDP LIB
+    if(dz->process == FRACTAL)
+        dz->bufcnt = 4;
+    else
+        dz->bufcnt = 2;
+    if((exit_status = create_fractal_sndbufs(dz))<0) {
         print_messages_and_close_sndfiles(exit_status,is_launched,dz);
         print_messages_and_close_sndfiles(exit_status,is_launched,dz);
         return(FAILED);
         return(FAILED);
     }
     }
     //param_preprocess()                        redundant
     //param_preprocess()                        redundant
     //spec_process_file =
     //spec_process_file =
-    if((exit_status = generate_fractal_pattern(dz))<0) {
+    if((exit_status = fractalise(dz))<0) {
         print_messages_and_close_sndfiles(exit_status,is_launched,dz);
         print_messages_and_close_sndfiles(exit_status,is_launched,dz);
         return(FAILED);
         return(FAILED);
     }
     }
@@ -498,16 +570,42 @@ int setup_fractal_application(dataptr dz)
         return(FAILED);
         return(FAILED);
     ap = dz->application;
     ap = dz->application;
     // SEE parstruct FOR EXPLANATION of next 2 functions
     // SEE parstruct FOR EXPLANATION of next 2 functions
-    if((exit_status = set_param_data(ap,0   ,1,1,"i"))<0)
+    if(dz->process == FRACTAL) {
+        if (dz->mode == 0)
+            exit_status = set_param_data(ap,FRACSHAPE,1,0,"0");
+        else
+            exit_status = set_param_data(ap,FRACSHAPE,1,1,"d");
+    } else
+        exit_status = set_param_data(ap,FRACSHAPE,1,0,"0");
+
+
+    
+    
+    if(exit_status<0)
         return(FAILED);
         return(FAILED);
-    if((exit_status = set_vflgs(ap,"s",1,"i","",0,0,""))<0)
+    if(dz->process == FRACTAL) {
+        if(dz->mode == 0) 
+            exit_status = set_vflgs(ap,"mti",3,"IDD","so",2,0,"00");
+        else
+            exit_status = set_vflgs(ap,"mti",3,"IDD","s",1,0,"0");
+    } else
+        exit_status = set_vflgs(ap,"mti",3,"IDD","sn",2,0,"00");
+    if(exit_status<0)
         return(FAILED);
         return(FAILED);
     // set_legal_infile_structure -->
     // set_legal_infile_structure -->
     dz->has_otherfile = FALSE;
     dz->has_otherfile = FALSE;
     // assign_process_logic -->
     // assign_process_logic -->
-    dz->input_data_type = SNDFILES_ONLY;
-    dz->process_type    = UNEQUAL_SNDFILE;  
-    dz->outfiletype     = SNDFILE_OUT;
+    if(dz->process == FRACSPEC) {
+        dz->input_data_type = ANALFILE_ONLY;
+        dz->process_type    = BIG_ANALFILE;
+        dz->outfiletype     = ANALFILE_OUT;
+        dz->maxmode = 0;
+    } else {
+        dz->input_data_type = SNDFILES_ONLY;
+        dz->process_type    = UNEQUAL_SNDFILE;  
+        dz->outfiletype     = SNDFILE_OUT;
+        dz->maxmode = 2;
+    }
     return application_init(dz);    //GLOBAL
     return application_init(dz);    //GLOBAL
 }
 }
 
 
@@ -521,13 +619,25 @@ int parse_infile_and_check_type(char **cmdline,dataptr dz)
         if((infile_info = (infileptr)malloc(sizeof(struct filedata)))==NULL) {
         if((infile_info = (infileptr)malloc(sizeof(struct filedata)))==NULL) {
             sprintf(errstr,"INSUFFICIENT MEMORY for infile structure to test file data.");
             sprintf(errstr,"INSUFFICIENT MEMORY for infile structure to test file data.");
             return(MEMORY_ERROR);
             return(MEMORY_ERROR);
-        } else if((exit_status = cdparse(cmdline[0],infile_info))<0) {
+        }
+        if((exit_status = cdparse(cmdline[0],infile_info))<0) {
             sprintf(errstr,"Failed to parse input file %s\n",cmdline[0]);
             sprintf(errstr,"Failed to parse input file %s\n",cmdline[0]);
             return(PROGRAM_ERROR);
             return(PROGRAM_ERROR);
-        } else if(infile_info->filetype != SNDFILE)  {
+        }
+        if(dz->process == FRACTAL) {
+            if(infile_info->filetype != SNDFILE)  {
+                sprintf(errstr,"File %s is not of correct type\n",cmdline[0]);
+                return(DATA_ERROR);
+            } 
+            if(dz->mode == 1 && infile_info->channels != 1)  {
+                sprintf(errstr,"File %s is not of correct type (must be mono for mode %d)\n",cmdline[0],dz->mode+1);
+                return(DATA_ERROR);
+            }
+        } else if(infile_info->filetype != ANALFILE)  {
             sprintf(errstr,"File %s is not of correct type\n",cmdline[0]);
             sprintf(errstr,"File %s is not of correct type\n",cmdline[0]);
             return(DATA_ERROR);
             return(DATA_ERROR);
-        } else if((exit_status = copy_parse_info_to_main_structure(infile_info,dz))<0) {
+        }
+        if((exit_status = copy_parse_info_to_main_structure(infile_info,dz))<0) {
             sprintf(errstr,"Failed to copy file parsing information\n");
             sprintf(errstr,"Failed to copy file parsing information\n");
             return(PROGRAM_ERROR);
             return(PROGRAM_ERROR);
         }
         }
@@ -548,13 +658,24 @@ int setup_fractal_param_ranges_and_defaults(dataptr dz)
     if((exit_status = setup_input_param_range_stores(ap->total_input_param_cnt,ap))<0)
     if((exit_status = setup_input_param_range_stores(ap->total_input_param_cnt,ap))<0)
         return(FAILED);
         return(FAILED);
     // get_param_ranges()
     // get_param_ranges()
-    ap->lo[0]   = 2;
-    ap->hi[0]   = 100;
-    ap->default_val[0]  = 8;
-    ap->lo[1]   = 2;
-    ap->hi[1]   = 50;
-    ap->default_val[1] = 15;
-    dz->maxmode = 0;
+    if(dz->process == FRACTAL && dz->mode == 1) {
+        ap->lo[FRACDUR] = 1;
+        ap->hi[FRACDUR] = FRAC_MAXDUR;
+        ap->default_val[FRACDUR] = 10;
+    }
+    ap->lo[FRACMAX] = 0;
+    ap->hi[FRACMAX] = FRAC_MAXFRACT;
+    ap->default_val[FRACMAX] = 0;
+    ap->lo[FRACTSTR]    = 1;
+    ap->hi[FRACTSTR]    = 2;
+    ap->default_val[FRACTSTR] = 1;
+    ap->lo[FRACISTR]    = 0;
+    ap->hi[FRACISTR]    = 8;
+    ap->default_val[FRACISTR] = 0;
+    if(dz->process == FRACTAL)  
+        dz->maxmode = 2;
+    else
+        dz->maxmode = 0;
     if(!sloom)
     if(!sloom)
         put_default_vals_in_all_params(dz);
         put_default_vals_in_all_params(dz);
     return(FINISHED);
     return(FINISHED);
@@ -959,40 +1080,26 @@ int get_process_no(char *prog_identifier_from_cmdline,dataptr dz)
 
 
 int usage1(void)
 int usage1(void)
 {
 {
-    usage2("fractal");
+    fprintf(stderr,
+    "USAGE: fractal NAME (mode) infile outfile parameters\n"
+    "\n"
+    "where NAME can be any one of\n"
+    "\n"
+    "wave  spectrum\n"
+    "\n"
+    "Type 'fractal wave'  for more info on fractal wave option... ETC.\n");
     return(USAGE_ONLY);
     return(USAGE_ONLY);
 }
 }
 
 
-/**************************** CHECK_FRACTAL_PARAM_VALIDITY_AND_CONSISTENCY *****************************/
-
-int check_fractal_param_validity_and_consistency(dataptr dz)
-{
-    int gpsamplen, minfracsize, maxsegcnt, maxcutcnt;
-    gpsamplen = dz->insams[0]/dz->infile->channels;                 //  Length of file in sample-groups
-    dz->iparam[FRACSPLICE] = (int)round(dz->param[FRACSPLICE] * MS_TO_SECS * dz->infile->srate);
-    minfracsize = dz->iparam[FRACSPLICE] * 3;                       //  Assume splicelen is in groupsamples
-                                                                    //  Assume min size = 3 X splicelen
-    maxsegcnt = (int)floor((double)gpsamplen/(double)(minfracsize));//  Number of segments obtained by cutting file into minlength chunks
-    maxcutcnt = 1;
-    dz->maxfraccnt = 2;                                             //  Count how many successive cuts-in-half are needed
-    while(dz->maxfraccnt < maxsegcnt) {                                 //  To generate NO MORE THAN maxfraccnt segments.
-        dz->maxfraccnt *= 2;
-        maxcutcnt++;                                                //  calculate the maximum number of divisions by 2
-    }                                                               //  which will fit INSIDE the maxsegcnt
-    dz->maxfraccnt /= 2;
-    maxcutcnt--;
-    if(dz->iparam[FRACDEPTH] > maxcutcnt) {
-        sprintf(errstr,"INFO: Maximum number of fractal cuts for this file = %d\n",maxcutcnt);
-        return DATA_ERROR;
-    }
-    return FINISHED;
-}
 
 
 /********************************************************************************************/
 /********************************************************************************************/
 
 
 int get_the_process_no(char *prog_identifier_from_cmdline,dataptr dz)
 int get_the_process_no(char *prog_identifier_from_cmdline,dataptr dz)
 {
 {
-    if(!strcmp(prog_identifier_from_cmdline,"fractal"))             dz->process = FRACTAL;
+    if(!strcmp(prog_identifier_from_cmdline,"wave"))                
+        dz->process = FRACTAL;
+    else if(!strcmp(prog_identifier_from_cmdline,"spectrum"))
+        dz->process = FRACSPEC;
     else {
     else {
         sprintf(errstr,"Unknown program identification string '%s'\n",prog_identifier_from_cmdline);
         sprintf(errstr,"Unknown program identification string '%s'\n",prog_identifier_from_cmdline);
         return(USAGE_ONLY);
         return(USAGE_ONLY);
@@ -1046,24 +1153,65 @@ int setup_and_init_input_brktable_constants(dataptr dz,int brkcnt)
 
 
 int usage2(char *str)
 int usage2(char *str)
 {
 {
-    if(!strcmp(str,"fractal")) {
+    if(!strcmp(str,"wave")) {
+        fprintf(stderr,
+        "USAGE:\n"
+        "fractal wave 1 inf outf shape     [-mmaxfrac] [-tstr] [-iwarp] [-s] [-o]\n"
+        "fractal wave 2 inf outf shape dur [-mmaxfrac] [-tstr] [-iwarp] [-s]\n"
+        "\n"
+        "Fractally distort (1 or more channel) input sound (Mode 1).\n"
+        "OR generate fractal wave from (mono) input wavecycle (Mode 2)\n"
+        "Fractal is time-pattern of transpositions (and, in Mode 1\n"
+        "causes corresponding time contractions and expansions).\n"
+        "Transposition happens over total duration specified in \"SHAPE\"\n"
+        "and is then repeated over every resulting sub-unit of pattern,\n"
+        "over every sub-sub-unit, etc. until smallest time-unit reached.\n"
+        "\n"
+        "SHAPE   Breakpoint textfile of\n"
+        "        (Mode 1) time-(semitone)transposition pairs, (Range -12 to 12)\n"
+        "        (Mode 2) time-MIDIpitch pairs, (Range 0 to 127)\n"
+        "        defining pitch-time contour of the (largest) fractal shape.\n"
+        "        Times must start at zero and increase,\n"
+        "        with final time indicating duration of pattern.\n"
+        "        (Value at final time will be ignored).\n"
+        "\n"
+        "DUR     (Mode 2) Output duration (secs) (max 2 hours).\n"
+        "MAXFRAC Max degree of fractalisation.  (Time-variable). If not set (or zero),\n"
+        "        fractalisation proceeds until min possible wavelength reached.\n"
+        "STR     Time stretch of fractal pattern (Time-variable : values >= 1).\n"
+        "        If set to zero, no timestretching is done.\n"
+        "WARP    Interval warping of fractal pattern (Time-variable).\n"
+        "        If set to zero, no warping is done.\n"
+        "\n"
+        "-s      Shrink pitch-intervals as fractal time-scales shrink.\n"
+        "-o      Brkpnt data read using time in outfile (default: Use time in infile).\n"
+        "\n");
+    } else if(!strcmp(str,"spectrum")) {
         fprintf(stderr,
         fprintf(stderr,
         "USAGE:\n"
         "USAGE:\n"
-        "fractal fractal infile outfile layers [-ssplicelen]\n"
+        "fractal spectrum inf outf shape [-mmaxfrac] [-tstr] [-iwarp] [-s] [-n]\n"
         "\n"
         "\n"
-        "Create fractalised version of sound.\n"
+        "Fractally distort input spectrum by transposition.\n"
+        "Transposition happens over total duration specified in \"SHAPE\"\n"
+        "and is then repeated over every resulting sub-unit of pattern,\n"
+        "over every sub-sub-unit, etc. until smallest time-unit reached.\n"
         "\n"
         "\n"
-        "SPLICELEN Length of splices in mS.\n"
+        "SHAPE   Breakpoint textfile of\n"
+        "        Time-(semitone)transposition pairs, (Range -12 to 12)\n"
+        "        defining pitch-time contour of the (largest) fractal shape.\n"
+        "        Times must start at zero and increase,\n"
+        "        with final time indicating duration of pattern.\n"
+        "        (Value at final time will be ignored).\n"
         "\n"
         "\n"
-        "LAYERS    Number of fractal layers in the output sound.\n"
-        "          Note that the maximum number of layers possible\n"
-        "          depends on the duration of the input sound\n"
-        "          and the size of splices used\n"
-        "          and cannot be easily predicted in advance\n"
+        "MAXFRAC Max degree of fractalisation.  (Time-variable). If not set (or zero),\n"
+        "        fractalisation proceeds until min possible wavelength reached.\n"
+        "STR     Time stretch of fractal pattern (Time-variable : values >= 1).\n"
+        "        If set to zero, no timestretching is done.\n"
+        "WARP    Interval warping of fractal pattern (Time-variable).\n"
+        "        If set to zero, no warping is done.\n"
         "\n"
         "\n"
-        "WARNINGS\n"
-        "(1) Specifying many layers will produce very long output sounds.\n"
-        "(2) Don't use very long input sounds, or you will run out of memory,\n"
+        "-s      Shrink pitch-intervals as fractal time-scales shrink.\n"
+        "-n      Transposition only (default, retain formant envelope).\n"
         "\n");
         "\n");
     } else
     } else
         fprintf(stdout,"Unknown option '%s'\n",str);
         fprintf(stdout,"Unknown option '%s'\n",str);
@@ -1076,285 +1224,1168 @@ int usage3(char *str1,char *str2)
     return(USAGE_ONLY);
     return(USAGE_ONLY);
 }
 }
 
 
-/************************** GENERATE_FRACTAL_PATTERN *************************/
+/****************************** GET_MODE *********************************/
 
 
-int generate_fractal_pattern(dataptr dz)
+int get_the_mode_from_cmdline(char *str,dataptr dz)
 {
 {
-    int exit_status, chans, segcnt, grpcnt, fracdepth, tailsize, cutcnt, splicelen;
-    int gpsamplen, patterncnt, segsize, total_used_len, obufpos, endfilestt, bufsize, starttail, origbuflen;
-    int n, j, m, z, c, thiscut, cutstt, cutend, thissegsize, patcnt, segno, insams;
-    double spliceincr;
-    float *ibuf = dz->sampbuf[0], *obuf = dz->sampbuf[1], *ovflwbuf = dz->sampbuf[2];
-    float *splicebuf, *tailbuf, **buf;
-    int *patterna, *patternb, *pattern1, *pattern2, *cutsegsize;
-
-    chans     = dz->infile->channels;
-    gpsamplen = dz->insams[0]/chans;
-    fracdepth = dz->iparam[FRACDEPTH];
-    splicelen = dz->iparam[FRACSPLICE];
-    obufpos = 0;
-
-    //  CREATE SPLICE VALUES IN BUFFER
-
-    memset((char *)obuf,0,dz->buflen * 2 * sizeof(float));              //  Initialise obuf, and ovflwbuf to zero
-    origbuflen = dz->buflen;
-    dz->buflen = dz->insams[0];
-    if((exit_status = read_samps(ibuf,dz))<0)                           //  Fill the input buffer
-        return(exit_status);
-    dz->buflen = origbuflen;
+    char temp[200], *p;
+    if(sscanf(str,"%s",temp)!=1) {
+        sprintf(errstr,"Cannot read mode of program.\n");
+        return(USAGE_ONLY);
+    }
+    p = temp + strlen(temp) - 1;
+    while(p >= temp) {
+        if(!isdigit(*p)) {
+            fprintf(stderr,"Invalid mode of program entered.\n");
+            return(USAGE_ONLY);
+        }
+        p--;
+    }
+    if(sscanf(str,"%d",&dz->mode)!=1) {
+        fprintf(stderr,"Cannot read mode of program.\n");
+        return(USAGE_ONLY);
+    }
+    if(dz->mode <= 0 || dz->mode > dz->maxmode) {
+        fprintf(stderr,"Program mode value [%d] is out of range [1 - %d].\n",dz->mode,dz->maxmode);
+        return(USAGE_ONLY);
+    }
+    dz->mode--;     /* CHANGE TO INTERNAL REPRESENTATION OF MODE NO */
+    return(FINISHED);
+}
+
+/**************************** HANDLE_THE_SPECIAL_DATA ****************************/
+
+int handle_the_special_data(char *str,dataptr dz)
+{
+    int exit_status, n, m, cnt;
+    FILE *fp;
+    char temp[200], *p;
+    double dummy = 0, lasttime = 0.0, lastmintrans = 0, lastmaxtrans = 0, mintrans = 0, maxtrans = 0, fracmax = 0.0;
+    double firstmidi = 0, lastmaxpitch = 0, lastminpitch = 0, maxpitch = 0, minpitch = 0, max_step, min_step, srate = (double)dz->infile->srate;
+    double *fractemplate, *fracintvl, *fractimes;
+    double mindur_maxtrans, mindur_mintrans, maxelement, minelement, thisdur, min_step_now, max_step_now;
+
+    if(dz->process == FRACTAL)
+        dz->mintime = (float)(4.0/srate);                   //  Minimum duration of fractal pattern (> 4 samples)
+    else {
+        dz->frametime  = (float)(1.0/dz->infile->arate);
+        dz->mintime = dz->frametime;                        //  Minimum duration of fractal pattern (> 1 analysis window)
+    }
+    dz->maxtrnsp =  256.0;                                  //  8 octaves
+    dz->maxfractalise = 0;
+    dz->minstep = HUGE;
+    if((fp = fopen(str,"r"))==NULL) {
+        sprintf(errstr,"Cannot open file %s to read clip lengths.\n",str);
+        return(DATA_ERROR);
+    }
+    cnt = 0;
+    lasttime = 0;
+    while(fgets(temp,200,fp)!=NULL) {
+        p = temp;
+        while(isspace(*p))
+            p++;
+        if(*p == ';' || *p == ENDOFSTR) //  Allow comments in file
+            continue;
+        while(get_float_from_within_string(&p,&dummy)) {
+
+            if (EVEN(cnt)) {                                //  TIMES MUST START AT ZERO AND INCREASE
+                if(cnt == 0) {
+                    if(dummy != 0.0) {
+                        sprintf(errstr,"Invalid initial time (%lf) in file %s. (Should be zero).\n",dummy,str);
+                        return DATA_ERROR;
+                    }
+                } else {
+                    if(dummy <= lasttime) {
+                        sprintf(errstr,"Times do not increase at (%lf %lf) in file %s.\n",lasttime,dummy,str);
+                        return DATA_ERROR;
+                    }
+                    dz->minstep = min(dz->minstep,dummy - lasttime);//  Find smallest time-step in fractal-pattern
+                }
+                lasttime = dummy;
+            } else {                                        //  VALUES MUSY LIE WITHIN RANGE
+                if(dz->process == FRACTAL && dz->mode == 1) {       //  as pitch-pattern
+                    if(dummy < FRAC_MINMIDI || dummy > FRAC_MAXMIDI) {
+                        sprintf(errstr,"MIDIpitch (%lf) out of range (%lf to %lf) in file %s.\n",dummy,FRAC_MINMIDI,FRAC_MAXMIDI,str);
+                        return DATA_ERROR;
+                    }   
+                    if(cnt == 1) {      
+                        firstmidi = dummy;                  //  Note initial MIDI pitch
+                        lastmaxpitch = dummy;               //  And search for max and min pitches
+                        lastminpitch = dummy;               //  NB maximum and minimum search IGNORES last value in table
+                    } else {
+                        maxpitch = lastmaxpitch;
+                        minpitch = lastminpitch;            
+                        lastmaxpitch = max(lastmaxpitch,dummy);
+                        lastminpitch = min(lastminpitch,dummy);
+                    }
+                } else {                                    //  as semitone-transposition-pattern   
+                    if(dummy < FRAC_MINTRNS || dummy > FRAC_MAXTRNS) {
+                        sprintf(errstr,"Transposition (%lf semitones) out of range (%lf to %lf) in file %s.\n",dummy,FRAC_MINTRNS,FRAC_MAXTRNS,str);
+                        return DATA_ERROR;
+                    }
+                    if(cnt == 1) {
+                        lastmintrans = dummy;               //  Search for max and min transpositions
+                        lastmaxtrans = dummy;               //  NB maximum and minimum search IGNORES last value in table
+                    } else {
+                        mintrans = lastmintrans;
+                        maxtrans = lastmaxtrans;
+                        lastmintrans = min(lastmintrans,dummy);
+                        lastmaxtrans = max(lastmaxtrans,dummy);
+                    }
+                }
+            }
+            cnt++;
+        }
+    }
+    if(cnt == 0) {                                          //  Check data count
+        sprintf(errstr,"No data found in file %s.\n",str);
+        return DATA_ERROR;
+    }
+    if(ODD(cnt)) {
+        sprintf(errstr,"Values not correctly paired in file %s.\n",str);
+        return DATA_ERROR;
+    }
+    if(cnt < 4) {
+        sprintf(errstr,"Insufficient values for a fractal shape (needs 2 times and 2 vals = 4 total) in file %s.\n",str);
+        return DATA_ERROR;
+    }
+    dz->fracdur = lasttime;                                 //  Last time in data indicates total duration of fractal-shape
+    if(dz->process == FRACTAL && dz->mode == 1)
+        dz->startfrq = (float)miditohz(firstmidi);          //  In mode 1 (fractal-template of pitches), find initial frq of pattern
 
 
-    if((exit_status = float_array_for_fractal(splicelen,-2,&splicebuf)) < 0)
-        return exit_status;                                             //  Create buffer to store splice values
-    spliceincr = 1.0/(double)splicelen;                                 //  Fill the splice buffer
-    for(m = 0; m < splicelen; m++)
-        splicebuf[m] = (float)((double)m * spliceincr);
+    dz->itemcnt = cnt/2;
 
 
-    //  FIND HOW MANY SEGMENTS NEEDED (segcnt) AND THEIR SIZE (segsize) in gpsamples
-    //  For cut-stage 0 need  2^0 = 1 segment
-    //  For cut-stage 1 need  2^1 = 2 segments
-    //  For cut-stage 2 need  2^2 = 4 segments
-    //  For cut N need  2^N segments.
+    if((dz->parray = (double **)malloc(6 * sizeof(double *)))==NULL) {
+        sprintf(errstr,"INSUFFICIENT MEMORY to create fractalisation calculation arrays.\n");
+        return(MEMORY_ERROR);
+    }
+    if((dz->parray[3] = (double *)malloc((dz->itemcnt * 2) * sizeof(double)))==NULL) {
+        sprintf(errstr,"INSUFFICIENT MEMORY to store fractalisation data.\n");      //  fractemplate : original (input) fractal template data       
+        return(MEMORY_ERROR);                                                 
+    }
+    fractemplate = dz->parray[3];   //  Original fractal template time-val pairs
+
+    cnt = 0;
+    fseek(fp,0,0);
+    while(fgets(temp,200,fp)!=NULL) {
+        p = temp;
+        while(isspace(*p))
+            p++;
+        if(*p == ';' || *p == ENDOFSTR) //  Allow comments in file
+            continue;
+        while(get_float_from_within_string(&p,&dummy))
+            fractemplate[cnt++] = dummy;
+    }
+    if(dz->process == FRACTAL && dz->mode == 1) {
+        for(n=1;n<dz->itemcnt*2;n+=2)       //  Convert pitch input to transpositions of initial pitch
+            fractemplate[n] -= firstmidi;
+    }
 
 
-    segcnt = 1;
-    for(n = 1;n < fracdepth; n++)
-        segcnt *= 2;
+    //  CHECK TIME LIMITS
 
 
-    //  HOW int ARE THE SEGMENTS, IN SAMPLES : WHAT IS THE BUFFER SIZE REQUIRED
-    
-    segsize = gpsamplen/segcnt;                 //  Sizeof segments (truncated)
-    bufsize = (segsize + splicelen) * chans;
-
-    //  STORE UNUSED TAIL OF FILE IN ITS OWN BUFFER
-
-    total_used_len = segcnt * segsize * chans;              //  How much of file used in making fractal
-    tailsize = dz->insams[0] - total_used_len;              //  How much is left
-    tailsize += splicelen * chans;                          //  Add room for upsplice
-    starttail = total_used_len - (splicelen * chans);       //  Find start of portion extended-tail-portion to copy
-    if((exit_status = float_array_for_fractal(tailsize,-1,&tailbuf)) < 0)
-        return exit_status;                                 //  Create buffer to store tail
-    for(n = 0, m = starttail;n < tailsize; n++,m++)         //  Copy tail into buffer
-        tailbuf[n] = ibuf[m];
-    for(m = 0; m < splicelen; m++) {                        //  Put upsplice on tail
-        j = m * 2;
-        for(c = 0; c < chans; c++) {
-            tailbuf[j] = (float)(tailbuf[j] * splicebuf[m]);
-            j++;
+    if(dz->process == FRACTAL && dz->mode == 1) {
+        if(dz->fracdur > FRAC_MAXDUR) {                                             
+            fprintf(stdout,"WARNING: Pattern total duration (%lf) greater than %.2lf hours, in file %s.\n",dz->fracdur,FRAC_MAXDUR/3600.0,str);
+            fflush(stdout);
         }
         }
-        if(j == tailsize)                                   //  Break, if tail is shorter than full splice
-            break;
+    }
+    if(dz->brksize[FRACTSTR]) {                             //  If fractal-shape time-stretched anywhere, get maximal tstretch,
+        if((exit_status = get_maxvalue_in_brktable(&fracmax,FRACTSTR,dz))<0)
+            return exit_status;
+        dz->param[FRACTSTR] = (int)round(fracmax);
     }
     }
 
 
-    //  SET UP ARRAY OF BUFFERS TO STORE SEGMENTS
-    
-    if((buf = (float **)malloc(segcnt * sizeof(float *)))==NULL) {
-        sprintf(errstr,"Insufficient memory to store cut segments 1.\n");
-        return(MEMORY_ERROR);
+    //  CHECK MAXIMUM FRACTALISATION
+
+    dz->minfracratio = dz->minstep/dz->fracdur;
+    get_max_fractalisation(dz);
+
+    if(dz->maxfractalise < 1) {
+        sprintf(errstr,"Smallest time-unit in pattern (%lf) too short to allow fractalisation.\n",dz->minstep);
+        return DATA_ERROR;
     }
     }
-    for(n = 0; n < segcnt; n++) {
-        if((exit_status = float_array_for_fractal(bufsize,-1,&buf[n])) < 0) //  Create buffers to store segments
+    if(dz->brksize[FRACMAX]) {                              //  If maximum fractalisation is preset by user
+        if((exit_status = get_maxvalue_in_brktable(&fracmax,FRACMAX,dz))<0)
+            return exit_status;
+        dz->iparam[FRACMAX] = (int)round(fracmax);
+    }                                                       //  compare it with the max possible fractalisation
+    if(dz->iparam[FRACMAX] >  dz->maxfractalise) {
+        fprintf(stdout,"WARNING: Max fractalisation will be restricted to %d because of time proportions in given shape data.\n",dz->maxfractalise);
+        fflush(stdout);
+    } else if (dz->iparam[FRACMAX] > 0 && dz->iparam[FRACMAX] < dz->maxfractalise)
+        dz->maxfractalise = dz->iparam[FRACMAX];
+
+    if(dz->brksize[FRACISTR]) {
+        if((exit_status = get_maxvalue_in_brktable(&fracmax,FRACISTR,dz))<0)
             return exit_status;
             return exit_status;
+        dz->param[FRACISTR] = fracmax;
     }
     }
 
 
-    //  FIND FINAL SIZE OF FRACTAL PATTERN, AND SET UP ARRAYS TO STORE (GROWING) PATTERN
-    //  At every cut, the initial_pattern of segments is copied (and reversed), and appended, to make pattern twice as int
-    //  So total pattern of segments doubles in size at every cut
+    //  CHECK RESTRICTIONS ON FRACTALISATION TRANSPOSITION-DEPTH CAUSED BY CHAINED-TRANSPOSITIONS
     
     
-    patterncnt = segcnt;
-    for(n = 0;n < fracdepth; n++)
-        patterncnt *= 2; 
-    if((patterna = (int *)malloc(patterncnt * sizeof(int)))==NULL) {
-        sprintf(errstr,"Insufficient memory to store pattern array 1.\n");
-        return(MEMORY_ERROR);
+    //  FinD time-shrinkage at maximum amd minimum pitch (transposition) elements of fractal shape
+
+    if(dz->vflag[FRAC_SHRINK]) {
+        mindur_maxtrans = HUGE;
+        mindur_mintrans = HUGE;
+        if(dz->process == FRACTAL && dz->mode == 1) {
+            maxelement = maxpitch - firstmidi;
+            minelement = minpitch - firstmidi;
+        } else {
+            maxelement = maxtrans;
+            minelement = mintrans;
+        }
+        for(n = 1; n < (dz->itemcnt -1) * 2; n+= 2) {
+            if(fractemplate[n] == maxelement) {
+                thisdur = fractemplate[n+1] - fractemplate[n-1];
+                mindur_maxtrans = min(mindur_maxtrans,thisdur);
+            }
+            if(fractemplate[n] == minelement) {
+                thisdur = fractemplate[n+1] - fractemplate[n-1];
+                mindur_mintrans = min(mindur_mintrans,thisdur);
+            }
+        }
+        if(mindur_maxtrans == HUGE || mindur_mintrans == HUGE) {
+            sprintf(errstr,"Problem determining duration of max:min elements in fractal.\n");
+            return PROGRAM_ERROR;
+        }
+        dz->maxtransshrink = mindur_maxtrans/dz->fracdur;
+        dz->mintransshrink = mindur_mintrans/dz->fracdur;
+    }
+
+    //  Check what happens to maximum and minimum transpositions, after maximium fractalisation.
+
+    if(dz->process == FRACTAL && dz->mode == 1)
+        max_step = maxpitch - firstmidi;                //  Base-pitch assumed to be first pitch of pattern
+    else
+        max_step = maxtrans;
+    if(dz->param[FRACISTR] > 1.0)
+        max_step *= dz->param[FRACISTR];
+    if(max_step > 0.0) {                                //  If highest pitch in fractal-shape is above initial pitch
+        if(dz->vflag[FRAC_SHRINK]) {
+            max_step_now = max_step;
+            max_step = 0;
+            for(n = 0;n < dz->maxfractalise;n++) {
+                max_step += max_step_now;
+                max_step_now *= dz->maxtransshrink;
+            }
+        } else
+            max_step *= dz->maxfractalise;              //  calculate how mich this will step upwards in successive fractalisations
+        if(dz->process == FRACTAL && dz->mode == 1) {
+            maxpitch += max_step ;                          
+            if(maxpitch > MIDIMAX) {
+                sprintf(errstr,"Max pitch after max fractalisation (%d times) (MIDI %.2lf) exceeds limit (127).\n",dz->maxfractalise,maxpitch);
+                return DATA_ERROR;
+            }
+        } else {                                        //  Convert to frq ratio
+            maxtrans = pow(2.0,(max_step/SEMITONES_PER_OCTAVE));
+            if(maxtrans > dz->maxtrnsp) {
+                sprintf(errstr,"Max transpos after max fractalisation (%d times) (%lf octaves) exceeds limit (8).\n",dz->maxfractalise,LOG2(maxtrans));
+                return DATA_ERROR;
+            }
+        }
     }
     }
-    if((patternb = (int *)malloc(patterncnt * sizeof(int)))==NULL) {
-        sprintf(errstr,"Insufficient memory to store pattern array 2.\n");
-        return(MEMORY_ERROR);
+    if(dz->process == FRACTAL && dz->mode == 1)
+        min_step = minpitch - firstmidi;
+    else
+        min_step = mintrans;
+    if(dz->param[FRACISTR] > 1.0)
+        min_step *= dz->param[FRACISTR];
+    if(min_step < 0.0) {                                //  If lowest pitch in fractal-shape is below initial pitch
+        if(dz->vflag[FRAC_SHRINK]) {
+            min_step_now = min_step;
+            min_step = 0;
+            for(n = 0;n < dz->maxfractalise;n++) {
+                min_step += min_step_now;
+                min_step_now *= dz->mintransshrink;
+            }
+        } else
+            min_step *= dz->maxfractalise;              //  calculate how mich this will step downwardsupwards in successive fractalisations
+        if(dz->process == FRACTAL && dz->mode == 1) {
+            minpitch += min_step;
+            if(minpitch < 0) {
+                sprintf(errstr,"Min pitch after max fractalisation (%d times) (MIDI %lf) falls below low limit (0).\n",dz->maxfractalise,minpitch);
+                return DATA_ERROR;
+            }
+        } else {
+            mintrans = pow(2.0,(mintrans/SEMITONES_PER_OCTAVE));
+            mintrans = pow(mintrans,dz->maxfractalise);
+            if(mintrans < 1.0/dz->maxtrnsp) {
+                sprintf(errstr,"Max transpos down after max fractalisation (%d times) (%lf octaves) exceeds limit (-8).\n",dz->maxfractalise,LOG2(mintrans));
+                return DATA_ERROR;
+            }
+        }
     }
     }
 
 
-    //  CREATE ARRAY TO STORE SIZES OF STORED SEGMENTS
-    
-    if((cutsegsize = (int *)malloc(segcnt * sizeof(int)))==NULL) {      //  Stores lengths of cut-segs, after splices added (or not)
-        sprintf(errstr,"Insufficient memory to store gating points.\n");
-        return(MEMORY_ERROR);
+    //  CREATE WORKING ARRAYS, now we know maximum depth of fractalisation (dz->maxfractalise)
+
+    dz->arraysize = dz->itemcnt - 1;                                        //  Number of fractal elements
+    dz->arraysize = (int)round(pow(dz->arraysize,dz->maxfractalise));       //  Number of entries needed for (largest) fractalisation
+    dz->arraysize *= 2;                                                     //  .. then include space for timing entries ....
+    dz->arraysize += 64;                                                    //  SAFETY
+
+    if((dz->parray[0] = (double *)malloc(dz->arraysize * sizeof(double)))==NULL) {
+        sprintf(errstr,"INSUFFICIENT MEMORY to create fractalisation array.\n");
+        return(MEMORY_ERROR);                                               //  fracpattern : Stores final conmplete fractalisation of data
+    }
+    if((dz->parray[1] = (double *)malloc(dz->arraysize * sizeof(double)))==NULL) {
+        sprintf(errstr,"INSUFFICIENT MEMORY to create swap buffer 1.\n");
+        return(MEMORY_ERROR);                                               //  swapbuffer1 : 1st itermediate buffers to calc fractalisation, stage by stage
+    }
+    if((dz->parray[2] = (double *)malloc(dz->arraysize * sizeof(double)))==NULL) {
+        sprintf(errstr,"INSUFFICIENT MEMORY to create swap buffer 2.\n");
+        return(MEMORY_ERROR);                                               //  swapbuffer2 : 2nd itermediate buffers to calc fractalisation, stage by stage
+    }
+    if((dz->parray[4] = (double *)malloc(dz->itemcnt * sizeof(double)))==NULL) {
+        sprintf(errstr,"INSUFFICIENT MEMORY to store transposing data.\n"); //  fracintvl : Mode 0 : Intvls in fractal template
+        return(MEMORY_ERROR);                                               //              Mode 1 : Intvls btwn pitches in orig fractal pitch-template
+    }
+    if((dz->parray[5] = (double *)malloc(dz->itemcnt * sizeof(double)))==NULL) {
+        sprintf(errstr,"INSUFFICIENT MEMORY to store element duations.\n");
+        return(MEMORY_ERROR);                                               //  fractimes : Onset times of each element in fractal template
     }
     }
 
 
-    //  FILL THE PATTERN ARRAY
+    fracintvl    = dz->parray[4];   //  Intervals between pitches in original fractal pitch-template
+    fractimes    = dz->parray[5];   //  Fractal template element-start-times
 
 
-    pattern1 = patterna;
-    pattern2 = patternb;
+    for(n=0, m=0; n < (dz->itemcnt-1) * 2; n +=2, m++) {        //  Stores dz->itemcnt-1 items
+        fractimes[m] = fractemplate[n];
+        fracintvl[m] = fractemplate[n+1];
+    }
+    dz->itemcnt--;                                              //  Last element of fractal template was needed only to specify total pattern's duration. So now ignore
+                                                                //  dz->itemcnt is number of elements in fractal-template
 
 
-    for(n = 0; n < segcnt; n++)                                 //  Initiate pattern : put all (numbered) segments in numeric order 
-        pattern1[n] = n;
-    grpcnt = segcnt;                                            //  Start off repatterning all existing segments
-    cutcnt = 1;
-    patcnt = 0;
-    for(n = 0;n < fracdepth; n++) {                             //  For every cut-stage : loop-n
-        thiscut = 0;                                            //  Specify start and end of first-cut of cutcnt repatternings
-        cutend  = grpcnt;
-        patcnt = 0;                                             //  Initialise pattern counter at start of every repatterning
+    return FINISHED;
+}
+
+/************************************* CREATE_FRACTAL_PATTERN ***************************/
 
 
-        for(j = 0; j < cutcnt;j ++) {                           //  For the number of cuts to be made at this stage : loop-j
-            if(patcnt + (grpcnt * 2) > patterncnt) {
-                sprintf(errstr,"ERROR: Error in pattern generation counting.\n");
+int create_fractal_pattern(dataptr dz)
+{
+    int fractalcnt = dz->itemcnt, total_fractalcnt, k, n, nn, t, v, ocnt = 0;
+    double *fracpattern = dz->parray[0];    //  Stores final conmplete fractalisation of data
+    double *swapbuffer1 = dz->parray[1];    //  Intermediate buffers to calc fractalisation, stage by stage
+    double *swapbuffer2 = dz->parray[2];
+    double *thisbuf = NULL, *thatbuf = NULL; 
+    double *fractemplate = dz->parray[3];   //  Original fractal template time-val pairs
+    double *fracintvl    = dz->parray[4];   //  Intervals between pitches in original fractal pitch-template
+    double *fractimes    = dz->parray[5];   //  Fractal template element-start-times
+    double starttime, startval, duration, shrinkage;
+
+    memset((char *)fracpattern,0,dz->arraysize * sizeof(double));   
+    memset((char *)swapbuffer1,0,dz->arraysize * sizeof(double));   
+    memset((char *)swapbuffer2,0,dz->arraysize * sizeof(double));
+    memcpy((char *)swapbuffer1,(char *)fractemplate,(dz->itemcnt+1) * 2 * sizeof(double));  //  Get original fractal-shape, with wraparound time
+                                                                                            //  mode 0 = semitone transpos : mode1 = MIDIpitch 
+    total_fractalcnt = fractalcnt;                                                          //  If fractalise only once, this is enough
+    if(dz->maxfractalise == 1)
+        thatbuf = swapbuffer1;
+    else {
+        for(k = 1; k < dz->maxfractalise;k++) {
+            ocnt = 0;
+            if(ODD(k))  {
+                thisbuf = swapbuffer1;
+                thatbuf = swapbuffer2;
+            } else {        
+                thisbuf = swapbuffer2;
+                thatbuf = swapbuffer1;
+            }
+            memset((char *)thatbuf,0,dz->arraysize * sizeof(double));   
+            for(n = 0, t = 0, v = 1; n < total_fractalcnt; n++,t+=2,v+=2) {     //  Fractalise every element of the "total_fractalcnt" elements existing at this stage.
+                starttime  = thisbuf[t];
+                startval   = thisbuf[v];
+                duration   = thisbuf[t+2] - thisbuf[t];                         //  There is a wrap-around time-point in orig fractal-template
+                shrinkage  = duration/dz->fracdur;
+                for(nn = 0; nn < fractalcnt; nn++) {
+                    if(ocnt + 2 >= dz->arraysize) {
+                        sprintf(errstr,"Array overrun in generating fractal.\n");
+                        return PROGRAM_ERROR;
+                    }
+                    thatbuf[ocnt++] = starttime + (fractimes[nn] * shrinkage);
+                    if(dz->vflag[FRAC_SHRINK])
+                        thatbuf[ocnt++] = startval + (fracintvl[nn] * shrinkage);
+                    else
+                        thatbuf[ocnt++] = startval + fracintvl[nn];
+                }
+            }
+            total_fractalcnt = ocnt/2;                                          //  No of fractal elements after this fractalisation now increaaed to new "total_fractalcnt"
+            if(ocnt >= dz->arraysize - 1) {
+                sprintf(errstr,"Array overrun in generating last timepoint of fractal.\n");
                 return PROGRAM_ERROR;
                 return PROGRAM_ERROR;
             }
             }
-            for(m = thiscut; m <cutend;m++)                     //  Copy pattern to new array   abcd
-                pattern2[patcnt++] = pattern1[m];               
-            for(m = cutend-1; m >= thiscut;m--)                 //  Then copy it in reverse     abcddbca
-                pattern2[patcnt++] = pattern1[m];
-            thiscut += grpcnt;                              
-            cutend  += grpcnt;                                  //  Advance start and end of cut in j-loop  
+            thatbuf[ocnt++] = fractemplate[dz->itemcnt*2];                      //  Retain wraparound time-point
         }
         }
-        if(EVEN(n)) {
-            pattern1 = patternb;                                //  Swap pattern pointers
-            pattern2 = patterna;
-        } else {                                                //  Final pattern always ends up as pattern1    
-            pattern1 = patterna;
-            pattern2 = patternb;
-        }                                                       //  ONCE ALL segs at this level are reverse-copied and abutted
-        grpcnt /= 2;                                            //  Gpsize to Cut gets smaller (by 1/2) BUT the total pattern has doubled in size
-        cutcnt *= 4;                                            //  SO The number of cuts goes up by 2 X 2 !!   
-    }
-
-    //  TRANSFER SEGMENTS TO BUFFERS, EXTENDING BACKWARDS FOR UPSPLICE, AND DO START AND END SPLICES
-
-    //      Segments extended backwards by splicelen, but not forwards
-    //          |_______  |
-    //       | /|       \ | 
-    //       |/ |        \|
-    //       |  |         |
-    //      add |         |
-    //      for | length  |
-    //    splice|specified|
-    //          |_________|
-    //                    |_______  |
-    //                   /|       \ |
-    //                  / |  next  \|
-    //                    | segment |
-    //                    |
-
-    for(n = 0; n < segcnt; n++) {                                   
-        cutstt = ((n * segsize) - splicelen) * chans;           //  Startcut is segment-index in pattern X segsize, MINUS room for splice
-        cutstt = max(cutstt,0);
-        cutend = (n + 1) * segsize * chans;                     //  Startcut is segment-index+1 
-        cutend = min(cutend,dz->insams[0]);
-        for(m = cutstt,thissegsize = 0; m < cutend; m++,thissegsize++)  //  Copy segment to Relevant buffer
-            buf[n][thissegsize] = ibuf[m];                              //  Counting the segment size with thissegsize
-        z = thissegsize - 1;
-        for(m = 0; m < splicelen; m++) {
-            if( n == 0) {                                           //  Start segment has no upsplice   
-                for(c = 0; c < chans; c++) {
-                    buf[n][z] = (float)(buf[n][z] * splicebuf[m]);
-                    z--;
-                }
+    }
+    for(n = 0, t = 0, v = 1; n < total_fractalcnt; n++,t+=2,v+=2) {
+        fracpattern[t] = thatbuf[t];
+        if((dz->brksize[FRACISTR] > 0) || (dz->param[FRACISTR] > 0.0))          //  If fractal is interval warped, do it here
+            thatbuf[v] *= dz->param[FRACISTR];
+        fracpattern[v] = pow(2.0,(thatbuf[v]/SEMITONES_PER_OCTAVE));            //  Convert to 8va-transpos
+    }
+    fracpattern[t] = thatbuf[t];                                                //  Store wraparound time-point     
+
+    if(dz->param[FRACTSTR] > 0.0) {
+        for(t=0;t <= total_fractalcnt * 2; t+=2)                                //  If fractal is time-warped, do the timewarp
+            fracpattern[t] *= dz->param[FRACTSTR];
+    }
+    dz->fracsize = total_fractalcnt;                                            //  Remember length of fractal pattern
+    return FINISHED;
+}
+
+/************************************* CHECK_FRACTAL_PARAM_VALIDITY_AND_CONSISTENCY ***************************/
+
+int check_fractal_param_validity_and_consistency(dataptr dz)
+{
+    int exit_status;
+    double minwarp = 0.0;
+    dz->timevary = 0;
+    if(dz->brksize[FRACMAX] || dz->brksize[FRACTSTR] || dz->brksize[FRACISTR])
+        dz->timevary = 1;
+    if(dz->brksize[FRACTSTR]) {
+        if((exit_status = get_minvalue_in_brktable(&minwarp,FRACTSTR,dz))<0)
+            return exit_status;
+        if(minwarp < 1.0) {
+            sprintf(errstr,"Values in timewarp table must be >= 1.0\n");
+            return DATA_ERROR;
+        }
+    } else if(dz->param[FRACTSTR] > 0.0 && dz->param[FRACTSTR] < 1.0) {
+        sprintf(errstr,"Non-zero timewarp value must be >= 1.\n");
+        return DATA_ERROR;
+    }
+    if(dz->process == FRACTAL) {
+        dz->splicesmps = (int)ceil(FRAC_SPLICELEN * MS_TO_SECS * (double)dz->infile->srate);
+        dz->total_splice = dz->splicesmps * dz->infile->channels;
+        if(dz->mode == 1) {
+            if(dz->insams[0] < dz->total_splice) {
+                fprintf(stdout,"WARNING: Infile too short to enable endsplice to be made.\n");
+                fflush(stdout);
+                dz->total_splice = 0;   //  Don't attempt endsplice
+            }
+        } else
+            dz->total_splice = 0;       //  No endsplice needed in mode 0
+    } else {
+        dz->splicesmps = 0;             //  Probably redundant
+        dz->total_splice = 0;
+    }
+    return FINISHED;
+}
+
+/************************************* FRACTALISE ***************************/
+
+int fractalise(dataptr dz)
+{
+    int exit_status, chans = dz->infile->channels, done = 0, ch, nxt, n, m;
+    double intime = 0.0, outtime = 0.0, ztime, localtime, srate = (double)dz->infile->srate;
+    int ibufpos = 0, gpibufpos = 0, obufpos = 0, fracindex = 0, bufcnt = 0, abs_input_start_samp = 0, nextfracsampcnt, zsamps;
+    int   gpbuflen = dz->buflen/chans, abs_window_cnt = 0, next_abs_window_cnt = 0;
+    double dibufpos = 0.0, localsampcnt, incr, frac, diff, spliceval, abs_time = 0, nexttime = 0.0, transpose = 1.0;
+    double *fracpattern = dz->parray[0];
+    float *ibuf, *obuf, *ovflwbuf = NULL;
+    double *val;
+    double *fractemplate = dz->parray[3];
+    if(dz->process == FRACTAL) {
+        ibuf = dz->sampbuf[0];
+        /* input overflow in = dz->sampbuf[1] */ 
+        obuf = dz->sampbuf[2];
+        ovflwbuf = dz->sampbuf[3];
+    } else {
+        ibuf = dz->sampbuf[0];
+        obuf = dz->sampbuf[1];
+    }
+    if((val = (double *)malloc(chans * sizeof(double))) == NULL) {
+        sprintf(errstr,"INSUFFICIENT MEMORY to create intermediate value storage.\n");
+        return(MEMORY_ERROR);
+    }
+    if(!dz->timevary) {                                     //  If fractal does not vary
+        if((exit_status = create_fractal_pattern(dz)) < 0)
+            return exit_status;                             //  Create fixed fractal pattern
+    }
+    if(dz->process == FRACTAL) {
+                                //  FRACTAL reads a double buffer, so that we have wraparound points to use
+        if(dz->mode == 0) {                             //  (If mode 1, source used as "table", and is already in buffer)   
+            dz->buflen *= 2;
+            if((exit_status = read_samps(ibuf,dz))<0)
+                return(exit_status);                        
+            abs_input_start_samp = 0;
+            dz->buflen /= 2;
+        }
+        for(ch = 0;ch < chans; ch++)                        //  Read initial src/table values to output value store
+            val[ch] = ibuf[ch];
+    } else {                                                //  FRACSPEC reads a single buffer of analysis samples  
+        dz->flbufptr[0] = ibuf;
+        dz->flbufptr[1] = obuf;
+        if((exit_status = read_samps(ibuf,dz))<0)
+            return(exit_status);
+        memcpy((char *)obuf,(char *)ibuf,dz->wanted * sizeof(float));
+        abs_time = dz->frametime;                           //  First window is copied (below)
+        abs_window_cnt = 1;
+        dz->flbufptr[0] += dz->wanted;                      //  flbufptrs advance
+        dz->flbufptr[1] += dz->wanted;
+    }
+    while(!done) {
+        if(dz->timevary) {                                  //  If fractal varies in time
+            if(dz->mode == 1 || (dz->process == FRACTAL && dz->vflag[FRAC_OUTIMES])) {  //  Read brkpoint data using either time in infile or time in outfile
+                if((exit_status = read_values_from_all_existing_brktables(outtime,dz))<0)
+                    return exit_status;
             } else {
             } else {
-                j = m*2;                                            //  Otherwise : do start and end splices simultaneously
-                for(c = 0; c < chans; c++) {
-                    buf[n][j] = (float)(buf[n][j] * splicebuf[m]);
-                    j++;
-                    buf[n][z] = (float)(buf[n][z] * splicebuf[m]);
-                    z--;
+                if((exit_status = read_values_from_all_existing_brktables(intime,dz))<0)
+                    return exit_status;
+            }
+            if(dz->iparam[FRACMAX] > 0)                     //  Find maximum fractalisation     
+                dz->maxfractalise = dz->iparam[FRACMAX];
+            else
+                get_max_fractalisation(dz);
+            if(dz->maxfractalise > 0)                       //  Create the fractal pattern, and remember length of fractal-pattern (dz->fracsize)
+                create_fractal_pattern(dz);
+        }
+        ztime = fractemplate[dz->itemcnt * 2];
+        if(dz->maxfractalise == 0) {
+            if(dz->process == FRACTAL) {
+                zsamps  = (int)round(ztime * srate);
+                gpibufpos = (int)round(dibufpos);               //  Approximation of interpolating pointer involved here
+                ibufpos = gpibufpos * chans;
+                for(n = 0; n <zsamps; n++) {
+                    if(ibufpos >= dz->buflen) {
+                        if(dz->mode == 0) {                 //  If reading countinuous input, advance by buflen
+                            memset((char *)ibuf,0,dz->buflen * 2 * sizeof(float));
+                            bufcnt++;
+                            if(dz->buflen * bufcnt >= dz->insams[0]) {
+                                done = 1;                           //  Exit if attempted samps_read looks beyound input file end
+                                break;
+                            }
+                            sndseekEx(dz->ifd[0],dz->buflen * bufcnt,0);
+                            dz->buflen *= 2;                        //   and read 2 * buflen (so we have wraparound)
+                            abs_input_start_samp += dz->ssampsread/2;
+                            if((exit_status = read_samps(ibuf,dz))<0)
+                                return(exit_status);
+                            dz->buflen /= 2;
+                            if(dz->ssampsread == 0) {               //  Exit if no more samples to read (should be redundant as trap at snd seek above)
+                                done = 1;
+                                break;
+                            }
+                        }
+                        ibufpos -= dz->buflen;
+                    }
+                    if(obufpos >= dz->buflen + dz->total_splice) {  //  Allow enough samples on end of output to perform splice. (ALPHA)
+                        if((exit_status = write_samps(obuf,dz->buflen,dz))<0)
+                            return(exit_status);                    //  Write to outfile, then copy back ovflow into obuf
+                        memset((char *)obuf,0,dz->buflen * sizeof(float));
+                        memcpy((char *)obuf,(char *)ovflwbuf,dz->buflen * sizeof(float));
+                        memset((char *)ovflwbuf,0,dz->buflen * sizeof(float));
+                        obufpos -= dz->buflen;                      //  and reset obufptr
+                    }
+                    for(ch = 0;ch<chans;ch++)
+                        obuf[obufpos++] = ibuf[ibufpos++];
+                }
+                gpibufpos  = ibufpos/chans;
+                dibufpos = (double)gpibufpos;
+                intime  += ztime;                                   //  overflow point in fractal template contains its duration, so advance time in input file
+                outtime += ztime;                                   //  time in output file
+            } else {    //   FRACSPEC
+                next_abs_window_cnt = (int)round(ztime/dz->frametime);
+                while(abs_window_cnt < next_abs_window_cnt) {
+                    memcpy((char *)dz->flbufptr[1],(char *)dz->flbufptr[0],dz->wanted * sizeof(float));
+                    dz->flbufptr[0] += dz->wanted;
+                    dz->flbufptr[1] += dz->wanted;
+                    if(dz->flbufptr[0] >= obuf) {
+                        if((exit_status = write_samps(obuf,dz->buflen,dz))<0)
+                            return(exit_status);
+                        memset((char *)ibuf,0,dz->buflen * sizeof(float));
+                        memset((char *)obuf,0,dz->buflen * sizeof(float));
+                        if((exit_status = read_samps(ibuf,dz))<0)
+                            return(exit_status);
+                        if(dz->ssampsread == 0) {
+                            done = 1;
+                            break;
+                        }
+                        dz->flbufptr[0] = ibuf;
+                        dz->flbufptr[1] = obuf;
+                    }
+                    abs_window_cnt++;
+                    abs_time += dz->frametime;
+                    if(abs_window_cnt >= dz->wlength) {
+                        done = 1;
+                        break;
+                    }
+                }
+            }
+        } else {
+            if(dz->process == FRACTAL) {
+                localsampcnt = 0;                                   //  This is a count in gp-samples
+                fracindex = 0;
+                while(fracindex < dz->fracsize * 2) {               //  For each unit of the fractal (2 entries - time:val - per fractal element)
+                    nextfracsampcnt = (int)round(fracpattern[fracindex + 2] * srate);
+                    while(localsampcnt > nextfracsampcnt) {
+                        fracindex += 2;
+                        if(fracindex >= dz->fracsize)
+                            break;
+                        nextfracsampcnt = (int)round(fracpattern[fracindex + 2] * srate);
+                    }
+                    incr = fracpattern[fracindex + 1];              //  Get current input-read increment
+                    while(localsampcnt < nextfracsampcnt) {         //  While we're still using the current increment
+                        for(ch = 0;ch < chans; ch++)
+                            obuf[obufpos++] = (float)val[ch];       //  Copy current value from input to output
+                        if(obufpos >= dz->buflen + dz->total_splice) {//    Allow enough samples on end of output to perform splice. (ALPHA)
+                            if((exit_status = write_samps(obuf,dz->buflen,dz))<0)
+                                return(exit_status);                //  Write to outfile, then copy back ovflow into obuf
+                            memset((char *)obuf,0,dz->buflen * sizeof(float));
+                            memcpy((char *)obuf,(char *)ovflwbuf,dz->buflen * sizeof(float));
+                            memset((char *)ovflwbuf,0,dz->buflen * sizeof(float));
+                            obufpos -= dz->buflen;                  //  and reset obufptr
+                        }
+                        if(dz->mode == 1) {
+                            dibufpos += incr * dz->convertor;       //  Advance in table-read
+                            gpibufpos = (int)floor(dibufpos);
+                            ibufpos = gpibufpos;                    //  Mono
+                        }else {
+                            dibufpos += incr;                       //  Advance pointer in infile src
+                            gpibufpos = (int)floor(dibufpos);
+                            ibufpos = gpibufpos * chans;            //  In mode 1, if run off end of input file, quit
+                            if(abs_input_start_samp + ibufpos >= dz->insams[0]) {               
+                                done = 1;
+                                break;
+                            }
+                        }
+                        frac = dibufpos - (double)gpibufpos;            
+                        if(gpibufpos >= gpbuflen) {             
+                            if(dz->mode == 0) {                     //  If reading countinuous input, advance by buflen
+                                memset((char *)ibuf,0,dz->buflen * 2 * sizeof(float));
+                                bufcnt++;
+                                if(dz->buflen * bufcnt >= dz->insams[0]) {
+                                    done = 1;                       //  Exit if attempted samps_read looks beyound input file end
+                                    break;
+                                }
+                                sndseekEx(dz->ifd[0],dz->buflen * bufcnt,0);
+                                dz->buflen *= 2;                    //   and read 2 * buflen (so we have wraparound)
+                                abs_input_start_samp += dz->ssampsread/2;
+                                if((exit_status = read_samps(ibuf,dz))<0)
+                                    return(exit_status);
+                                dz->buflen /= 2;
+                                if(dz->ssampsread == 0) {           //  Exit if no more samples to read (should be redundant as trap at snd seek above)
+                                    done = 1;
+                                    break;
+                                }
+                            }
+                            gpibufpos -= gpbuflen;
+                            dibufpos  -= (double)gpbuflen;
+                            ibufpos = gpibufpos * chans;
+                        }                                           //  Working in absolute sample-frame get interpolated value(s) from src/table
+                        for(ch = 0,nxt = chans;ch < chans;ch++,nxt++) {
+                            val[ch]  = ibuf[ibufpos + ch];
+                            diff     = ibuf[ibufpos + nxt] - val[ch];
+                            val[ch] += diff * frac;
+                        }
+                        localsampcnt += incr;                       //  Advance by given samp-time incr
+                        if(localsampcnt >= nextfracsampcnt)         //  If we reach time of next fractal (we will therefore exit inner loop)
+                            fracindex += 2;                         //  incr fracindex-value, hence advance in fractal pattern in outer loop
+                    }
+                    if(done)
+                        break;
+                }
+                intime += fracpattern[dz->fracsize];                //  overflow point in fractal table contains its duration, so advance time in input file
+                outtime = (double)((dz->total_samps_written + obufpos)/chans)/srate;    //  time in output file
+                if(dz->mode == 1) {
+                    if(outtime >= dz->param[FRACDUR])
+                        done = 1;
+                } else {
+                    if(intime >= dz->duration)
+                        done = 1;
+                }
+            } else {    //   FRACSPEC
+                localtime = 0.0;
+                fracindex = 0;
+                while(fracindex < dz->fracsize * 2) {               //  For each unit of the fractal (2 entries - time:val - per fractal element)
+                    nexttime  = fracpattern[fracindex + 2];
+                    transpose = fracpattern[fracindex + 1];
+                    while(localtime < nexttime) {
+                        if((exit_status = fractal_spectrnsf(transpose,dz))<0)
+                            return(exit_status);
+                        memcpy((char *)dz->flbufptr[1],(char *)dz->flbufptr[0],dz->wanted * sizeof(float));
+                        dz->flbufptr[0] += dz->wanted;
+                        dz->flbufptr[1] += dz->wanted;
+                        if(dz->flbufptr[0] >= obuf) {   //  obuf abutts to end of ibuf
+                            if((exit_status = write_samps(obuf,dz->buflen,dz))<0)
+                                return(exit_status);
+                            memset((char *)ibuf,0,dz->buflen * sizeof(float));
+                            memset((char *)obuf,0,dz->buflen * sizeof(float));
+                            if((exit_status = read_samps(ibuf,dz))<0)
+                                return(exit_status);
+                            if(dz->ssampsread == 0) {
+                                done = 1;
+                                break;
+                            }
+                            dz->flbufptr[0] = ibuf;
+                            dz->flbufptr[1] = obuf;
+                        }
+                        abs_window_cnt++;
+                        abs_time  += dz->frametime;
+                        localtime += dz->frametime;
+                        if(abs_time >= dz->duration) {
+                            done = 1;
+                            break;
+                        }
+                    }
+                    fracindex += 2;
+                if(done)
+                    break;
+                }
+
+            }
+        }
+    }
+    if(obufpos > 0) {
+        if(dz->process == FRACTAL) {
+            if(dz->mode == 1 && dz->total_splice > 0) {
+                for(n=0,m = obufpos - chans;n < dz->splicesmps;n++,m -= chans) {
+                    spliceval = (double)n/(double)dz->splicesmps;   
+                    for(ch = 0;ch < chans;ch++)                 //  Splice end of output
+                        obuf[m+ch] = (float)(obuf[m+ch] * spliceval);
                 }
                 }
             }
             }
         }
         }
-        cutsegsize[n] = thissegsize;
+        if((exit_status = write_samps(obuf,obufpos,dz))<0)
+            return(exit_status);                            //  Write last samples to outfile
     }
     }
+    return FINISHED;
+}
 
 
-    dz->tempsize = segsize * patcnt;                                    //  Approximate size of output
+/**************************** GET_MAX_FRACTALISATION ****************************/
 
 
-    //  JOIN SEGMENTS TOGETHER IN OUTBUF, IN ORDER OF PATTERN
+void get_max_fractalisation(dataptr dz)
+{
+    double minlen = dz->minstep;                            //  minimum duration in fractal-shape   
+    dz->maxfractalise = 0;
+    if(dz->param[FRACTSTR] > 1.0)                           //  If fractal-shape gets stretched anywhere, expand minlen appropriately
+        minlen *= dz->param[FRACTSTR];
+    while(minlen > dz->mintime) {                           //  Calculate the max possible fractalisation
+        minlen *= dz->minfracratio;
+        dz->maxfractalise++;
+    }
+}
 
 
-    obufpos = splicelen * chans;                                        //  Preset ensures baktrak for splice doesn't run off start of infile
-    for(n = 0; n < patterncnt; n++) {
-        obufpos -= splicelen * chans;                                   //  baktrak to do splice
-        segno = pattern1[n];                                            //  Find segment indicated at position "n" in pattern
-                                                                        //  and therefore get its buffer number (segno)
-        for(m = 0; m < cutsegsize[segno]; m++) {
-            obuf[obufpos] = (float)(obuf[obufpos] + buf[segno][m]);     //  Add-Copy segment to obuf (automatically overlapping splices)
-            if(++obufpos >= dz->buflen * 2) {
-                insams = dz->insams[0];                                 //  These two lines ensure that
-                dz->insams[0] = dz->tempsize;                           //  time-reports when program runs are correct
-                if((exit_status = write_samps(obuf,dz->buflen,dz))<0)
-                    return(exit_status);
-                dz->insams[0] = insams;
-                memcpy((char *)obuf,(char *)ovflwbuf,dz->buflen * sizeof(float));
-                memset((char *)ovflwbuf,0,dz->buflen * sizeof(float));
-                obufpos -= dz->buflen;
-            }
+/**************************** CREATE_FRACTAL_SNDBUFS ****************************/
+
+int create_fractal_sndbufs(dataptr dz)
+{
+    int exit_status, n;
+    int bigbufsize, secsize, m;
+    int framesize = F_SECSIZE * dz->infile->channels;
+    double srate = (double)dz->infile->srate;
+
+    if(dz->process == FRACTAL) {
+        if (dz->mode == 1)  //  Mode 1, source file is used as a table to read cyclically
+            bigbufsize = dz->insams[0] * sizeof(float);
+        else
+            bigbufsize = (int)Malloc(-1);
+     secsize = bigbufsize/framesize;
+        if(secsize * framesize < bigbufsize) {
+            secsize++;
+            bigbufsize = secsize * framesize;
         }
         }
+    } else
+        bigbufsize = dz->wanted * BUF_MULTIPLIER * sizeof(float);
+    dz->buflen = bigbufsize/sizeof(float);
+    if(bigbufsize * dz->bufcnt <= 0) {
+        if(dz->process == FRACTAL && dz->mode == 1)
+            sprintf(errstr,"Infile too large to create sound buffers.\n");
+        else
+            sprintf(errstr,"Insufficent memory to create sound buffers.\n");
+        return(PROGRAM_ERROR);
     }
     }
-    //  ADD TAIL OF SOUND
-
-    endfilestt = ((segcnt * segsize) - splicelen) * chans;
-    tailsize = dz->insams[0] - endfilestt;
-    obufpos -= splicelen * chans;
-    for(m = 0; m < tailsize; m++) {
-        obuf[obufpos] = (float)(obuf[obufpos] + ibuf[m]);
-        if(++obufpos >= dz->buflen * 2) {
-            insams = dz->insams[0];
-            dz->insams[0] = dz->tempsize;
-            if((exit_status = write_samps(obuf,dz->buflen,dz))<0)
-                return(exit_status);
-            dz->insams[0] = insams;
-            memcpy((char *)obuf,(char *)ovflwbuf,dz->buflen * sizeof(float));
-            memset((char *)ovflwbuf,0,dz->buflen * sizeof(float));
-            obufpos -= dz->buflen;
-        }
+    if((dz->bigbuf = (float *)malloc(bigbufsize * dz->bufcnt)) == NULL) {
+        sprintf(errstr,"INSUFFICIENT MEMORY to create sound buffers.\n");
+        return(PROGRAM_ERROR);
     }
     }
-    if(obufpos) {
-        insams = dz->insams[0];
-        dz->insams[0] = dz->tempsize;
-        if((exit_status = write_samps(obuf,obufpos,dz))<0)
+    if((dz->sampbuf = (float **)malloc(sizeof(float *) * (dz->bufcnt+1)))==NULL) {
+        sprintf(errstr,"INSUFFICIENT MEMORY establishing sample buffers.\n");
+        return(MEMORY_ERROR);
+    }
+    if((dz->sbufptr = (float **)malloc(sizeof(float *) * dz->bufcnt))==NULL) {
+        sprintf(errstr,"INSUFFICIENT MEMORY establishing sample buffer pointers.\n");
+        return(MEMORY_ERROR);
+    }
+    if(dz->process == FRACSPEC) {
+        if((dz->flbufptr = (float **)malloc(sizeof(float *) * dz->bufcnt))==NULL) {
+            sprintf(errstr,"INSUFFICIENT MEMORY for float sample buffers.\n");
+            return(MEMORY_ERROR);
+        }
+        for(n = 0;n <dz->bufcnt; n++)
+            dz->flbufptr[n] = NULL;
+    }
+
+    for(n=0;n<dz->bufcnt;n++)
+        dz->sbufptr[n] = dz->sampbuf[n] = dz->bigbuf + (dz->buflen * n);
+    dz->sampbuf[n] = dz->bigbuf + (dz->buflen * n);
+    // FRACTAL
+    // dz->sampbuf[0] ibuf
+    // dz->sampbuf[1] iovflwbuf
+    // dz->sampbuf[2] obuf
+    // dz->sampbuf[3] ovflwbuf      dz->sampbuf[4] end of ovflwbuf
+    // FRACSPEC
+    // dz->sampbuf[0] ibuf
+    // dz->sampbuf[1] obuf
+
+    if(dz->process == FRACTAL && dz->mode == 1) {
+        if((exit_status = read_samps(dz->sampbuf[0],dz))<0) //  Read source into buffer
             return(exit_status);
             return(exit_status);
-        dz->insams[0] = insams;
+        for(n=0, m = dz->insams[0];n < dz->infile->channels;n++,m++)
+            dz->sampbuf[0][m] = 0;                          //  wraparound points go into iovflwbuf
+        dz->convertor = (double)dz->insams[0]/srate;        //  Table-read convertor for a 1Hz read
+        dz->convertor *= dz->startfrq;                      //  Table-read convertor for a fractal-startfrq read
     }
     }
     return FINISHED;
     return FINISHED;
 }
 }
 
 
-/****************************** FLOAT_ARRAY ******************************/
+/********************************** SPECTRNSF **********************************
+ *
+ * transpose spectrum, but retain original spectral envelope.
+ */
 
 
-int float_array_for_fractal(int nnn,int n, float **ptr)
-{   /* set up a floating point array length nnn. */
-    *ptr = (float *) calloc(nnn,sizeof(float));
-    if(*ptr==NULL){
-        if(n == -2) {
-            sprintf(errstr,"pvoc: insufficient memory to store splice values.\n");
-            return(MEMORY_ERROR);
-        } else if(n == -1) {
-            sprintf(errstr,"pvoc: insufficient memory to store end-segment of sound\n");
-            return(MEMORY_ERROR);
-        } else {
-            sprintf(errstr,"pvoc: insufficient memory for segment-of-pattern %d\n",n+1);
-            return(MEMORY_ERROR);
+int fractal_spectrnsf(double transpose,dataptr dz)
+{
+    int exit_status;
+    double pre_totalamp, post_totalamp;
+    int cc, vc;
+    rectify_window(dz->flbufptr[0],dz);
+    if((exit_status = fractal_extract_specenv(dz))<0)
+        return(exit_status);
+    if((exit_status = get_totalamp(&pre_totalamp,dz->flbufptr[0],dz->wanted))<0)
+        return(exit_status);
+    if(dz->vflag[1]) {
+        for(cc = 0, vc = 0; cc < dz->clength; cc++, vc += 2)
+            dz->flbufptr[0][FREQ] = (float)(fabs(dz->flbufptr[0][FREQ])*transpose);
+    } else {
+        for(cc = 0, vc = 0; cc < dz->clength; cc++, vc += 2) {
+            if((exit_status = fractal_tranpose_within_formant_envelope(vc,transpose,dz))<0)
+                return(exit_status);
+        }
+    }
+    if((exit_status = fractal_reposition_partials_in_appropriate_channels(transpose,dz))<0)
+        return(exit_status);
+    if((exit_status = get_totalamp(&post_totalamp,dz->flbufptr[0],dz->wanted))<0)
+        return(exit_status);
+    return normalise(pre_totalamp,post_totalamp,dz);
+}
+
+    /************************** TRANPOSE_WITHIN_FORMANT_ENVELOPE *****************************/
+
+int fractal_tranpose_within_formant_envelope(int vc,double transpose,dataptr dz)
+{
+    int exit_status;
+    double thisspecamp, newspecamp, thisamp, formantamp_ratio; 
+    if((exit_status = fractal_getspecenvamp(&thisspecamp,(double)dz->flbufptr[0][FREQ],dz))<0)
+        return(exit_status);
+    dz->flbufptr[0][FREQ] = (float)(fabs(dz->flbufptr[0][FREQ])*transpose);
+    if(dz->flbufptr[0][FREQ] < dz->nyquist) {
+        if(thisspecamp < VERY_TINY_VAL)
+            dz->flbufptr[0][AMPP] = 0.0f;
+        else {
+            if((exit_status = fractal_getspecenvamp(&newspecamp,(double)dz->flbufptr[0][FREQ],dz))<0)
+                return(exit_status);
+            if(newspecamp < VERY_TINY_VAL)
+                dz->flbufptr[0][AMPP] = 0.0f;
+            else {
+                formantamp_ratio = newspecamp/thisspecamp;
+                if((thisamp = dz->flbufptr[0][AMPP] * formantamp_ratio) < VERY_TINY_VAL)
+                    dz->flbufptr[0][AMPP] = 0.0f;
+                else
+                    dz->flbufptr[0][AMPP] = (float)thisamp;
+            }
         }
         }
     }
     }
     return(FINISHED);
     return(FINISHED);
 }
 }
 
 
-/****************************** CREATE_FRACTAL_SNDBUFS ******************************/
+/************************ REPOSITION_PARTIALS_IN_APPROPRIATE_CHANNELS *************************
+ *
+ * (1)  At each pass, preset store-buffer channel amps to zero.
+ * (2)  Move frq data into appropriate channels, carrying the
+ *      amplitude information along with them.
+ *      Work down spectrum  for upward transposition, and
+ * (3)  up spectrum for downward transposition,
+ *      so that we do not overwrite transposed data before we move it.
+ * (4)  Put new frqs back into src buff.
+ */
 
 
-int create_fractal_sndbufs(dataptr dz)
+int fractal_reposition_partials_in_appropriate_channels(double transpose,dataptr dz)
 {
 {
-    int bigbufsize, splicelen;
-    int framesize;
-    framesize = F_SECSIZE * dz->infile->channels;
-    if(dz->sbufptr == 0 || dz->sampbuf==0) {
-        sprintf(errstr,"buffer pointers not allocated: create_sndbufs()\n");
+    int exit_status;
+    int truecc,truevc;
+    int cc, vc;
+    for(vc = 0, cc= 0; vc < dz->wanted; vc+=2, cc++) {                      /* 1 */
+        dz->windowbuf[0][AMPP] = 0.0f;
+        dz->windowbuf[0][FREQ] = (float)(cc * dz->chwidth);
+    }
+    if(transpose > 1.0f) {          /* 2 */
+        for(cc=dz->clength-1,vc = dz->wanted-2; cc>=0; cc--, vc-=2) {
+            if(dz->flbufptr[0][FREQ] < dz->nyquist && dz->flbufptr[0][AMPP] > 0.0f) {
+                if((exit_status = fractal_get_channel_corresponding_to_frq(&truecc,(double)dz->flbufptr[0][FREQ],dz))<0)
+                    return(exit_status);
+                truevc = truecc * 2;
+                if((exit_status = move_data_into_appropriate_channel(vc,truevc,dz->flbufptr[0][AMPP],dz->flbufptr[0][FREQ],dz))<0)
+                    return(exit_status);
+            }
+        }
+        for(vc = 0; vc < dz->wanted; vc++)
+            dz->flbufptr[0][vc] = dz->windowbuf[0][vc]; 
+    } else if(transpose < 1.0f){        /* 3 */
+        for(cc=0,vc = 0; cc < dz->clength; cc++, vc+=2) {
+            if(dz->flbufptr[0][FREQ] < dz->nyquist && dz->flbufptr[0][FREQ]>0.0) {
+                if((exit_status = fractal_get_channel_corresponding_to_frq(&truecc,(double)dz->flbufptr[0][FREQ],dz))<0)
+                    return(exit_status);
+                truevc = truecc * 2;
+                if((exit_status = move_data_into_appropriate_channel(vc,truevc,dz->flbufptr[0][AMPP],dz->flbufptr[0][FREQ],dz))<0)
+                    return(exit_status);
+            }
+        }
+        for(vc = 0; vc < dz->wanted; vc++)
+            dz->flbufptr[0][vc] = dz->windowbuf[0][vc];     /* 4 */
+    }
+    return(FINISHED);
+}
+
+/******************* ZERO_OUTOFRANGE_CHANNELS *****************/
+
+int fractal_zero_outofrange_channels(double *totalamp,double lofrq_limit,double hifrq_limit,dataptr dz)
+{
+    int cc, vc;
+    *totalamp = 0.0;
+    for(cc = 0,vc = 0; cc < dz->clength; cc++, vc += 2) {
+        if(dz->flbufptr[0][FREQ] < lofrq_limit || dz->flbufptr[0][FREQ] > hifrq_limit)
+            dz->flbufptr[0][AMPP] = 0.0f;
+        else
+            *totalamp += dz->flbufptr[0][AMPP];
+    }
+    return(FINISHED);
+}
+
+/**************************** GETSPECENVAMP *************************/
+
+int fractal_getspecenvamp(double *thisamp,double thisfrq,dataptr dz)
+{
+    double pp, ratio, ampdiff;
+    int z = 1;
+    if(thisfrq<0.0) {   /* NOT SURE THIS IS CORRECT */
+        *thisamp = 0.0; /* SHOULD WE PHASE INVERT & RETURN A -ve AMP ?? */
+        return(FINISHED);   
+    }
+    if(thisfrq<=1.0)
+        pp = 0.0;
+    else
+        pp = log10(thisfrq); 
+    while( dz->specenvpch[z] < pp){
+        z++;
+        /*RWD may need to trap on size of array? */
+        if(z == dz->infile->specenvcnt -1)
+            break;
+    }
+    ratio    = (pp - dz->specenvpch[z-1])/(dz->specenvpch[z] - dz->specenvpch[z-1]);
+    ampdiff  = dz->specenvamp[z] - dz->specenvamp[z-1];
+    *thisamp = dz->specenvamp[z-1] + (ampdiff * ratio);
+    *thisamp = max(0.0,*thisamp);
+    return(FINISHED);
+}
+
+/********************** EXTRACT_SPECENV *******************/
+
+int fractal_extract_specenv(dataptr dz)
+{
+    int    n, cc, vc, specenvcnt_less_one;
+    int    botchan, topchan;
+    double botfreq, topfreq;
+    double bwidth_in_chans;
+    specenvcnt_less_one = dz->infile->specenvcnt - 1;
+    vc = 0;
+    //  RECTIFY_CHANNEL_FRQ_ORDER
+    for(n=0;n<dz->infile->specenvcnt;n++)
+        dz->specenvamp[n] = (float)0.0;
+    topfreq = 0.0f;
+    n = 0;
+    while(n < specenvcnt_less_one) {
+        botfreq  = topfreq;
+        botchan  = (int)((botfreq + dz->halfchwidth)/dz->chwidth); /* TRUNCATE */
+        botchan -= 4;   //  CHAN_SRCHRANGE_F
+        botchan  =  max(botchan,0);
+        topfreq  = dz->specenvtop[n];
+        topchan  = (int)((topfreq + dz->halfchwidth)/dz->chwidth); /* TRUNCATE */
+        topchan += 4;   //  CHAN_SRCHRANGE_F;
+        topchan  =  min(topchan,dz->clength);
+        for(cc = botchan,vc = botchan * 2; cc < topchan; cc++,vc += 2) {
+            if(dz->flbufptr[0][FREQ] >= botfreq && dz->flbufptr[0][FREQ] < topfreq)
+                dz->specenvamp[n] = (float)(dz->specenvamp[n] + dz->flbufptr[0][AMPP]);
+        }
+        bwidth_in_chans   = (double)(topfreq - botfreq)/dz->chwidth;
+        dz->specenvamp[n] = (float)(dz->specenvamp[n]/bwidth_in_chans);
+        n++;
+    }
+    return(FINISHED);
+}
+
+/************************** INITIALISE_SPECENV *********************
+ *
+ *  MAR 1998: not sure if the follwoing comment is relevant any more
+ *  but I wont risk changing it at this stage.
+ *
+ *  WANTED and CLENGTH are calculated from scratch here, as dz->wanted
+ *  gets set equal to dz->specenvcnt for calculations on formant data,
+ *  while dz->clength may not yet be set!!      
+ */
+
+int fractal_initialise_specenv(int *arraycnt,dataptr dz)
+{
+    *arraycnt   = (dz->infile->channels/2) + 1;
+    if((dz->specenvfrq = (float *)malloc((*arraycnt) * sizeof(float)))==NULL) {
+        sprintf(errstr,"INSUFFICIENT MEMORY for formant frq array.\n");
+        return(MEMORY_ERROR);
+    }
+    if((dz->specenvpch = (float *)malloc((*arraycnt) * sizeof(float)))==NULL) {
+        sprintf(errstr,"INSUFFICIENT MEMORY for formant pitch array.\n");
+        return(MEMORY_ERROR);
+    }
+    /*RWD  zero the data */
+    memset(dz->specenvpch,0,*arraycnt * sizeof(float));
+
+    if((dz->specenvamp = (float *)malloc((*arraycnt) * sizeof(float)))==NULL) {
+        sprintf(errstr,"INSUFFICIENT MEMORY for formant aplitude array.\n");
+        return(MEMORY_ERROR);
+    }
+    if((dz->specenvtop = (float *)malloc((*arraycnt) * sizeof(float)))==NULL) {
+        sprintf(errstr,"INSUFFICIENT MEMORY for formant frq limit array.\n");
+        return(MEMORY_ERROR);
+    }
+    if((dz->windowbuf = (float **)malloc(sizeof(float *)))==NULL) {
+        sprintf(errstr,"INSUFFICIENT MEMORY for extra float sample buffers.\n");
+        return(MEMORY_ERROR);
+    }
+    if((dz->windowbuf[0] = (float *)malloc(dz->wanted * sizeof(float)))==NULL) {
+        sprintf(errstr,"INSUFFICIENT MEMORY for extra float sample buffer 0.\n");
+        return(MEMORY_ERROR);
+    }
+    return(FINISHED);
+}
+
+/************************************ FRACTAL_SET_SPECENV_FRQS ****************************/
+
+int fractal_set_specenv_frqs(int arraycnt,dataptr dz)
+{
+    int exit_status;
+    double bandbot;
+    double *interval;
+    int m, n, k = 0, cc;
+    //  PICHWISE_FORMANTS
+    if((exit_status = fractal_setup_octaveband_steps(&interval,dz))<0)
+        return(exit_status);
+    if((exit_status = fractal_setup_low_octave_bands(arraycnt,dz))<0)
+        return(exit_status);
+    k  = 4; //  TOP_OF_LOW_OCTAVE_BANDS
+    cc = 8; //  CHAN_ABOVE_LOW_OCTAVES
+    while(cc <= dz->clength) {
+        m = 0;
+        if((bandbot = dz->chwidth * (double)cc) >= dz->nyquist)
+            break;
+        for(n=0;n<dz->formant_bands;n++) {
+            if(k >= arraycnt) {
+                sprintf(errstr,"Formant array too small: fractal_set_specenv_frqs()\n");
+                return(PROGRAM_ERROR);
+            }
+            dz->specenvfrq[k]   = (float)(bandbot * interval[m++]);
+            dz->specenvpch[k]   = (float)log10(dz->specenvfrq[k]);
+            dz->specenvtop[k++] = (float)(bandbot * interval[m++]);
+        }   
+        cc *= 2;        /* 8-16: 16-32: 32-64 etc as 8vas, then split into bands */
+    }
+    dz->specenvfrq[k] = (float)dz->nyquist;
+    dz->specenvpch[k] = (float)log10(dz->nyquist);
+    dz->specenvtop[k] = (float)dz->nyquist;
+    dz->specenvamp[k] = (float)0.0;
+    k++;
+    dz->infile->specenvcnt = k;
+    return(FINISHED);
+}
+
+/************************* SETUP_OCTAVEBAND_STEPS ************************/
+
+int fractal_setup_octaveband_steps(double **interval,dataptr dz)
+{
+    double octave_step;
+    int n = 1, m = 0, halfbands_per_octave = dz->formant_bands * 2;
+    if((*interval = (double *)malloc(halfbands_per_octave * sizeof(double)))==NULL) {
+        sprintf(errstr,"INSUFFICIENT MEMORY establishing interval array for formants.\n");
+        return(MEMORY_ERROR);
+    }
+    while(n < halfbands_per_octave) {
+        octave_step   = (double)n++/(double)halfbands_per_octave;
+        (*interval)[m++] = pow(2.0,octave_step);
+    }
+    (*interval)[m] = 2.0;
+    return(FINISHED);
+}
+
+/************************ SETUP_LOW_OCTAVE_BANDS ***********************
+ *
+ * Lowest PVOC channels span larger freq steps and therefore we must
+ * group them in octave bands, rather than in anything smaller.
+ */
+
+int fractal_setup_low_octave_bands(int arraycnt,dataptr dz)
+{
+    int n;
+    if(arraycnt < LOW_OCTAVE_BANDS) {
+        sprintf(errstr,"Insufficient array space for low_octave_bands\n");
         return(PROGRAM_ERROR);
         return(PROGRAM_ERROR);
     }
     }
-    splicelen = (int)round(1.0 * MS_TO_SECS * (double)dz->infile->srate) * dz->infile->channels;
-    dz->buflen = max(2 * splicelen,4096);
-    dz->buflen = (dz->buflen / framesize)  * framesize;
+    for(n=0;n<LOW_OCTAVE_BANDS;n++) {
+        switch(n) {
+        case(0):
+            dz->specenvfrq[0] = (float)1.0;                 /* frq whose log is 0 */
+            dz->specenvpch[0] = (float)0.0;
+            dz->specenvtop[0] = (float)dz->chwidth;         /* 8VA wide bands */
+            break;
+        case(1):
+            dz->specenvfrq[1] = (float)(dz->chwidth * 1.5); /* Centre Chs 1-2 */    
+            dz->specenvpch[1] = (float)log10(dz->specenvfrq[1]);
+            dz->specenvtop[1] = (float)(dz->chwidth * 2.0);
+            break;
+        case(2):
+            dz->specenvfrq[2] = (float)(dz->chwidth * 3.0); /* Centre Chs 2-4 */
+            dz->specenvpch[2] = (float)log10(dz->specenvfrq[2]);
+            dz->specenvtop[2] = (float)(dz->chwidth * 4.0);
+            break;
+        case(3):
+            dz->specenvfrq[3] = (float)(dz->chwidth * 6.0); /* Centre Chs 4-8 */    
+            dz->specenvpch[3] = (float)log10(dz->specenvfrq[3]);
+            dz->specenvtop[3] = (float)(dz->chwidth * 8.0);
+            break;
+        default:
+            sprintf(errstr,"Insufficient low octave band setups in fractal_setup_low_octave_bands()\n");
+            return(PROGRAM_ERROR);
+        }
+    }
+    return(FINISHED);
+}
+
+/**************************** GET_CHANNEL_CORRESPONDING_TO_FRQ ***************************/
 
 
-    bigbufsize = dz->insams[0] + (2 * dz->buflen);
-    bigbufsize *= sizeof(float);
-    if((dz->bigbuf = (float *)malloc(bigbufsize)) == NULL) {
-        sprintf(errstr,"INSUFFICIENT MEMORY to create sound buffers. Don't use very big infiles\n");
+int fractal_get_channel_corresponding_to_frq(int *chan,double thisfrq,dataptr dz)
+{   
+    if(dz->chwidth <= 0.0) {
+        sprintf(errstr,"chwidth not set in fractal_get_channel_corresponding_to_frq()\n");
+        return(PROGRAM_ERROR);
+    }
+    if(thisfrq < 0.0) {
+        sprintf(errstr,"-ve frequency in fractal_get_channel_corresponding_to_frq()\n");
+        return(PROGRAM_ERROR);
+    }
+    if(thisfrq > dz->nyquist) {
+        sprintf(errstr,"frequency beyond nyquist in fractal_get_channel_corresponding_to_frq()\n");
+        return(PROGRAM_ERROR);
+    }
+    *chan = (int)((fabs(thisfrq) + dz->halfchwidth)/dz->chwidth);  /* TRUNCATE */
+    if(*chan >= dz->clength) {
+        sprintf(errstr,"chan (%d) beyond clength-1 (%d) returned: fractal_get_channel_corresponding_to_frq()\n",
+        *chan,(dz->clength)-1);
         return(PROGRAM_ERROR);
         return(PROGRAM_ERROR);
     }
     }
-    dz->sbufptr[0] = dz->sampbuf[0] = dz->bigbuf;
-    dz->sbufptr[1] = dz->sampbuf[1] = dz->sampbuf[0] + dz->insams[0];
-    dz->sbufptr[2] = dz->sampbuf[2] = dz->sampbuf[1] + dz->buflen;
-    dz->sbufptr[3] = dz->sampbuf[3] = dz->sampbuf[2] + dz->buflen;
     return(FINISHED);
     return(FINISHED);
 }
 }
+