richarddobson 3 lat temu
rodzic
commit
0e0981ebdd

+ 21 - 0
dev/modify/CMakeLists.txt

@@ -0,0 +1,21 @@
+if(APPLE)
+  set(CMAKE_C_FLAGS "-O2 -Wall -mmacosx-version-min=10.5 -Dunix")
+else()
+  if(MINGW)
+    set(CMAKE_C_FLAGS "-O2 -Wall -DWIN32")
+  else()
+    set(CMAKE_C_FLAGS "-O2 -Wall -Dlinux -Dunix")
+  endif()
+endif()
+
+link_directories(../cdp2k ../sfsys)
+
+include_directories(../../include)
+
+add_executable(modify main.c ap_modify.c brapcon.c delay.c gain.c pan.c 
+	granula1.c radical.c strans.c )
+
+target_link_libraries(modify cdp2k sfsys ${EXTRA_LIBRARIES})
+
+my_install(modify)
+

+ 1774 - 0
dev/modify/ap_modify.c

@@ -0,0 +1,1774 @@
+/*
+ * Copyright (c) 1983-2013 Trevor Wishart and Composers Desktop Project Ltd
+ * http://www.trevorwishart.co.uk
+ * http://www.composersdesktop.com
+ *
+ This file is part of the CDP System.
+
+    The CDP System is free software; you can redistribute it
+    and/or modify it under the terms of the GNU Lesser General Public
+    License as published by the Free Software Foundation; either
+    version 2.1 of the License, or (at your option) any later version.
+
+    The CDP System is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public
+    License along with the CDP System; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+    02111-1307 USA
+ *
+ */
+
+
+
+/* floatsam version */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+
+#include <structures.h>
+#include <cdpmain.h>
+#include <tkglobals.h>
+#include <pnames.h>
+#include <modify.h>
+#include <processno.h>
+#include <modeno.h>
+#include <globcon.h>
+#include <logic.h>
+#include <filetype.h>
+#include <mixxcon.h>
+#include <speccon.h>
+#include <flags.h>
+#include <arrays.h>
+#include <formants.h>
+#include <sfsys.h>
+#include <osbind.h>
+
+#include <srates.h>
+
+//TW UPDATES
+#include <arrays.h>
+#include <special.h>
+#include <limits.h>
+
+int sintab_pconsistency(dataptr dz);
+
+//TW UPDATES
+static int read_stackdata(char *str,dataptr dz);
+static double semitone_to_ratio(double val);
+static int convolve_pconsistency(dataptr dz);
+static int create_convolve_bufs(dataptr dz);
+static int read_loudness(char *str,dataptr dz);
+static int setup_and_init_brktable_constants(dataptr dz);
+/********************************************************************************************/
+/********************************** FORMERLY IN buffers.c ***********************************/
+/********************************************************************************************/
+
+static int  create_granula_buffers(dataptr dz);
+static int  grab_an_appropriate_block_of_memory(int bufdivisor,dataptr dz);
+
+/***************************************************************************************/
+/****************************** FORMERLY IN aplinit.c **********************************/
+/***************************************************************************************/
+
+/***************************** ESTABLISH_BUFPTRS_AND_EXTRA_BUFFERS **************************/
+
+int establish_bufptrs_and_extra_buffers(dataptr dz)
+{
+//  int is_spec = FALSE;
+    dz->extra_bufcnt = -1;  /* ENSURE EVERY CASE HAS A PAIR OF ENTRIES !! */
+    dz->bptrcnt = 0;
+    dz->bufcnt  = 0;
+    switch(dz->process) {
+    case(MOD_LOUDNESS):         dz->extra_bufcnt = 0;   dz->bufcnt = 1;     break;
+    case(MOD_SPACE):
+        switch(dz->mode) {
+        case(MOD_PAN):          dz->extra_bufcnt = 0;   dz->bufcnt = 3;     break;
+        case(MOD_MIRROR):       dz->extra_bufcnt = 0;   dz->bufcnt = 1;     break;
+        case(MOD_MIRRORPAN):    dz->extra_bufcnt = 0;   dz->bufcnt = 0;     break;
+        case(MOD_NARROW):       dz->extra_bufcnt = 0;   dz->bufcnt = 1;     break;
+        default:
+            sprintf(errstr,"Unknown case for MOD_SPACE in establish_bufptrs_and_extra_buffers()\n");
+            return(PROGRAM_ERROR);
+        }
+        break;              
+//TW NEW CASES
+    case(SCALED_PAN):           dz->extra_bufcnt = 0;   dz->bufcnt = 3;     break;
+    case(FIND_PANPOS):          dz->extra_bufcnt = 0;   dz->bufcnt = 1;     break;
+
+    case(MOD_PITCH):
+        switch(dz->mode) {
+        case(MOD_TRANSPOS):             dz->extra_bufcnt = 0;   dz->bufcnt = 9;     break;
+        case(MOD_TRANSPOS_SEMIT):       dz->extra_bufcnt = 0;   dz->bufcnt = 9;     break;
+        case(MOD_TRANSPOS_INFO):        dz->extra_bufcnt = 0;   dz->bufcnt = 1;     break;
+        case(MOD_TRANSPOS_SEMIT_INFO):  dz->extra_bufcnt = 0;   dz->bufcnt = 1;     break;
+        case(MOD_ACCEL):                dz->extra_bufcnt = 0;   dz->bufcnt = 9;     break;
+        case(MOD_VIBRATO):              dz->extra_bufcnt = 0;   dz->bufcnt = 9;     break;
+        default:
+            sprintf(errstr,"Unknown case for MOD_PITCH in establish_bufptrs_and_extra_buffers()\n");
+            return(PROGRAM_ERROR);
+        }
+        break;              
+    case(MOD_REVECHO):
+        switch(dz->mode) {
+        case(MOD_STADIUM):      dz->extra_bufcnt = 0;   dz->bufcnt = 4;     break;
+        default:                dz->extra_bufcnt = 0;   dz->bufcnt = 2;     break;
+        }
+        break;
+    case(MOD_RADICAL):
+        switch(dz->mode) {
+//TW SIMPLIFIED
+//      case(MOD_REVERSE):      dz->extra_bufcnt = 0;   dz->bufcnt = 2;     break;
+        case(MOD_REVERSE):      dz->extra_bufcnt = 0;   dz->bufcnt = 1;     break;
+        case(MOD_LOBIT):
+        case(MOD_LOBIT2):       dz->extra_bufcnt = 0;   dz->bufcnt = 1;     break;
+        case(MOD_SCRUB):        dz->extra_bufcnt = 0;   dz->bufcnt = 2;     break;
+        case(MOD_SHRED):        dz->extra_bufcnt = 0;   dz->bufcnt = 2;     break;
+        case(MOD_RINGMOD):      dz->extra_bufcnt = 0;   dz->bufcnt = 1;     break;
+        case(MOD_CROSSMOD):     dz->extra_bufcnt = 0;   dz->bufcnt = 3;     break;
+        }
+        break;
+    case(BRASSAGE):             dz->extra_bufcnt = 1;   dz->bufcnt = 4;     break;
+    case(SAUSAGE):              dz->extra_bufcnt = 1;   dz->bufcnt = 2;     break; /* ADD MORE LATER */
+    case(SIN_TAB):              dz->extra_bufcnt = 0;   dz->bufcnt = 0;     break; /* ADD MORE LATER */
+//TW NEW CASES
+    case(STACK):                dz->extra_bufcnt = 0;   dz->bufcnt = 2;     break;
+    case(CONVOLVE):             dz->extra_bufcnt = 0;   dz->bufcnt = 3;     break;
+    case(SHUDDER):              dz->extra_bufcnt = 0;   dz->bufcnt = 4;     break;
+
+/* TEMPORARY TEST ROUTINE */
+    case(WORDCNT):              dz->extra_bufcnt = 0;   dz->bufcnt = 0;     break;
+/* TEMPORARY TEST ROUTINE */
+    default:
+        sprintf(errstr,"Unknown program type [%d] in establish_bufptrs_and_extra_buffers()\n",dz->process);
+        return(PROGRAM_ERROR);
+    }
+
+    if(dz->extra_bufcnt < 0) {
+        sprintf(errstr,"bufcnts have not been set: establish_bufptrs_and_extra_buffers()\n");
+        return(PROGRAM_ERROR);
+    }
+    return establish_groucho_bufptrs_and_extra_buffers(dz);
+}
+
+/***************************** SETUP_INTERNAL_ARRAYS_AND_ARRAY_POINTERS **************************/
+
+int setup_internal_arrays_and_array_pointers(dataptr dz)
+{
+    int n;       
+    dz->ptr_cnt    = -1;        //base constructor...process
+    dz->array_cnt  = -1;
+    dz->iarray_cnt = -1;
+    dz->larray_cnt = -1;
+    switch(dz->process) {
+    case(MOD_LOUDNESS): dz->array_cnt=0; dz->iarray_cnt=0; dz->larray_cnt = 0; dz->ptr_cnt = 0; dz->fptr_cnt = 0; break;
+    case(MOD_SPACE):    dz->array_cnt=0; dz->iarray_cnt=0; dz->larray_cnt = 0; dz->ptr_cnt = 0; dz->fptr_cnt = 0; break;
+//TW UPDATES
+    case(SCALED_PAN):   dz->array_cnt=0; dz->iarray_cnt=0; dz->larray_cnt = 0; dz->ptr_cnt = 0; dz->fptr_cnt = 0; break;
+    case(FIND_PANPOS):  dz->array_cnt=0; dz->iarray_cnt=0; dz->larray_cnt = 0; dz->ptr_cnt = 0; dz->fptr_cnt = 0; break;
+
+    case(SIN_TAB):      dz->array_cnt=1; dz->iarray_cnt=0; dz->larray_cnt = 0; dz->ptr_cnt = 0; dz->fptr_cnt = 0; break;
+    case(MOD_PITCH):
+        switch(dz->mode) {
+        case(MOD_VIBRATO): dz->array_cnt=1;dz->iarray_cnt=0; dz->larray_cnt=0; dz->ptr_cnt = 0; dz->fptr_cnt = 0; break;
+        default:           dz->array_cnt=0;dz->iarray_cnt=0; dz->larray_cnt=0; dz->ptr_cnt = 0; dz->fptr_cnt = 0; break;
+        }
+        break;
+    case(MOD_REVECHO):
+        switch(dz->mode) {
+        case(MOD_STADIUM): dz->array_cnt=5;dz->iarray_cnt=0; dz->larray_cnt=1; dz->ptr_cnt = 0; dz->fptr_cnt = 0; break;        
+        default:           dz->array_cnt=1;dz->iarray_cnt=0; dz->larray_cnt=0; dz->ptr_cnt = 0; dz->fptr_cnt = 0; break;
+        }
+        break;
+    case(MOD_RADICAL):
+        switch(dz->mode) {
+        case(MOD_REVERSE): dz->array_cnt=0;dz->iarray_cnt=0; dz->larray_cnt=0; dz->ptr_cnt = 0; dz->fptr_cnt = 0; break;
+        case(MOD_LOBIT):
+        case(MOD_LOBIT2):  dz->array_cnt=0;dz->iarray_cnt=0; dz->larray_cnt=0; dz->ptr_cnt = 0; dz->fptr_cnt = 0; break;
+        case(MOD_SCRUB):   dz->array_cnt=2;dz->iarray_cnt=0; dz->larray_cnt=0; dz->ptr_cnt = 0; dz->fptr_cnt = 0; break;
+        case(MOD_SHRED):   dz->array_cnt=0;dz->iarray_cnt=1; dz->larray_cnt=2; dz->ptr_cnt = 0; dz->fptr_cnt = 0; break;
+        case(MOD_RINGMOD): dz->array_cnt=1;dz->iarray_cnt=0; dz->larray_cnt=0; dz->ptr_cnt = 0; dz->fptr_cnt = 0; break;
+        case(MOD_CROSSMOD): dz->array_cnt=0;dz->iarray_cnt=0; dz->larray_cnt=0; dz->ptr_cnt= 0; dz->fptr_cnt = 0; break;
+        }
+        break;
+    case(BRASSAGE): dz->array_cnt = 3; dz->iarray_cnt = 1; dz->larray_cnt = 0; dz->ptr_cnt = 0; dz->fptr_cnt = 4; break;
+    case(SAUSAGE):  dz->array_cnt = 3; dz->iarray_cnt = 2; dz->larray_cnt = 0; dz->ptr_cnt = 0; dz->fptr_cnt = 4; break;
+/* TEMPORARY TEST ROUTINE */
+    case(WORDCNT):  dz->array_cnt = 0; dz->iarray_cnt = 0; dz->larray_cnt = 0; dz->ptr_cnt = 0; dz->fptr_cnt = 0; break;
+/* TEMPORARY TEST ROUTINE */
+//TW UPDATES
+    case(STACK):    dz->array_cnt = 2; dz->iarray_cnt = 0; dz->larray_cnt = 0; dz->ptr_cnt = 0; dz->fptr_cnt = 0; break;
+    case(CONVOLVE): dz->array_cnt = 1; dz->iarray_cnt = 0; dz->larray_cnt = 0; dz->ptr_cnt = 0; dz->fptr_cnt = 0; break;
+    case(SHUDDER):  dz->array_cnt = 6; dz->iarray_cnt = 0; dz->larray_cnt = 0; dz->ptr_cnt = 0; dz->fptr_cnt = 0; break;
+
+    }
+
+/*** WARNING ***
+ANY APPLICATION DEALING WITH A NUMLIST INPUT: MUST establish AT LEAST 1 double array: i.e. dz->array_cnt = at least 1
+**** WARNING ***/
+
+
+    if(dz->array_cnt < 0 || dz->iarray_cnt < 0 || dz->larray_cnt < 0 || dz->ptr_cnt < 0 || dz->fptr_cnt < 0) {
+        sprintf(errstr,"array_cnt not set in setup_internal_arrays_and_array_pointers()\n");       
+        return(PROGRAM_ERROR);
+    }
+
+    if(dz->array_cnt > 0) {  
+        if((dz->parray  = (double **)malloc(dz->array_cnt * sizeof(double *)))==NULL) {
+            sprintf(errstr,"INSUFFICIENT MEMORY for internal double arrays.\n");
+            return(MEMORY_ERROR);
+        }
+        for(n=0;n<dz->array_cnt;n++)
+            dz->parray[n] = NULL;
+    }
+    if(dz->iarray_cnt > 0) {
+        if((dz->iparray = (int     **)malloc(dz->iarray_cnt * sizeof(int *)))==NULL) {
+            sprintf(errstr,"INSUFFICIENT MEMORY for internal int arrays.\n");
+            return(MEMORY_ERROR);
+        }
+        for(n=0;n<dz->iarray_cnt;n++)
+            dz->iparray[n] = NULL;
+    }
+    if(dz->larray_cnt > 0) {      
+        if((dz->lparray = (int    **)malloc(dz->larray_cnt * sizeof(int *)))==NULL) {
+            sprintf(errstr,"INSUFFICIENT MEMORY for internal int arrays.\n");
+            return(MEMORY_ERROR);
+        }
+        for(n=0;n<dz->larray_cnt;n++)
+            dz->lparray[n] = NULL;
+    }
+    if(dz->ptr_cnt > 0)   {       
+        if((dz->ptr     = (double  **)malloc(dz->ptr_cnt  * sizeof(double *)))==NULL) {
+            sprintf(errstr,"INSUFFICIENT MEMORY for internal pointer arrays.\n");
+            return(MEMORY_ERROR);
+        }
+        for(n=0;n<dz->ptr_cnt;n++)
+            dz->ptr[n] = NULL;
+    }
+    if(dz->fptr_cnt > 0)   {      
+        if((dz->fptr = (float  **)malloc(dz->fptr_cnt * sizeof(float *)))==NULL) {
+            sprintf(errstr,"INSUFFICIENT MEMORY for internal float-pointer arrays.\n");
+            return(MEMORY_ERROR);
+        }
+        for(n=0;n<dz->fptr_cnt;n++)
+            dz->fptr[n] = NULL;
+    }
+    return(FINISHED);
+}
+
+/****************************** ASSIGN_PROCESS_LOGIC *********************************/
+
+int assign_process_logic(dataptr dz)
+{                        
+    switch(dz->process) {
+    case(MOD_LOUDNESS):       
+        switch(dz->mode) {
+        case(LOUDNESS_GAIN):    
+        case(LOUDNESS_DBGAIN):
+        case(LOUDNESS_NORM):
+        case(LOUDNESS_SET):
+        case(LOUD_PROPOR):    
+        case(LOUD_DB_PROPOR):
+        case(LOUDNESS_PHASE):   
+            setup_process_logic(SNDFILES_ONLY,  EQUAL_SNDFILE,      SNDFILE_OUT,    dz);    break;
+        case(LOUDNESS_BALANCE): 
+            setup_process_logic(TWO_SNDFILES,   EQUAL_SNDFILE,      SNDFILE_OUT,    dz);    break;
+        case(LOUDNESS_LOUDEST): 
+            setup_process_logic(MANY_SNDFILES,  OTHER_PROCESS,      NO_OUTPUTFILE,  dz);    break;
+        case(LOUDNESS_EQUALISE): 
+            setup_process_logic(MANY_SNDFILES,  UNEQUAL_SNDFILE,    SNDFILE_OUT,    dz);    break;
+        default:
+            sprintf(errstr,"Unknown case for MOD_LOUDNESS in assign_process_logic()\n");
+            return(PROGRAM_ERROR);
+        }
+        break;
+    case(MOD_SPACE):          
+        switch(dz->mode) {
+        case(MOD_PAN):          setup_process_logic(SNDFILES_ONLY,  UNEQUAL_SNDFILE,    SNDFILE_OUT,    dz);    break;
+        case(MOD_MIRROR):       setup_process_logic(SNDFILES_ONLY,  EQUAL_SNDFILE,      SNDFILE_OUT,    dz);    break;
+        case(MOD_MIRRORPAN):    setup_process_logic(UNRANGED_BRKFILE_ONLY,TO_TEXTFILE,  TEXTFILE_OUT,   dz);    break;
+        case(MOD_NARROW):       setup_process_logic(SNDFILES_ONLY,  EQUAL_SNDFILE,      SNDFILE_OUT,    dz);    break;
+        default:
+            sprintf(errstr,"Unknown case for MOD_SPACE in assign_process_logic()\n");
+            return(PROGRAM_ERROR);
+        }
+        break;
+//TW UPDATES
+    case(SCALED_PAN):       setup_process_logic(SNDFILES_ONLY,  UNEQUAL_SNDFILE,    SNDFILE_OUT,    dz);        break;
+    case(FIND_PANPOS):      setup_process_logic(SNDFILES_ONLY,  SCREEN_MESSAGE,     NO_OUTPUTFILE,  dz);        break;
+
+    case(MOD_PITCH):          
+        switch(dz->mode) {
+        case(MOD_TRANSPOS):            setup_process_logic(SNDFILES_ONLY,UNEQUAL_SNDFILE,SNDFILE_OUT,   dz);    break;
+        case(MOD_TRANSPOS_SEMIT):      setup_process_logic(SNDFILES_ONLY,UNEQUAL_SNDFILE,SNDFILE_OUT,   dz);    break;
+        case(MOD_TRANSPOS_INFO):       setup_process_logic(SNDFILES_ONLY,SCREEN_MESSAGE, NO_OUTPUTFILE, dz);    break;
+        case(MOD_TRANSPOS_SEMIT_INFO): setup_process_logic(SNDFILES_ONLY,SCREEN_MESSAGE, NO_OUTPUTFILE, dz);    break;
+        case(MOD_ACCEL):               setup_process_logic(SNDFILES_ONLY,UNEQUAL_SNDFILE,SNDFILE_OUT,   dz);    break;
+        case(MOD_VIBRATO):             setup_process_logic(SNDFILES_ONLY,UNEQUAL_SNDFILE,SNDFILE_OUT,   dz);    break;
+        default:
+            sprintf(errstr,"Unknown case for MOD_PITCH in assign_process_logic()\n");
+            return(PROGRAM_ERROR);
+        }
+        break;
+    case(MOD_REVECHO):    setup_process_logic(SNDFILES_ONLY,        UNEQUAL_SNDFILE,    SNDFILE_OUT,    dz);    break;
+    case(MOD_RADICAL):
+        switch(dz->mode) {
+        case(MOD_REVERSE): setup_process_logic(SNDFILES_ONLY,       EQUAL_SNDFILE,      SNDFILE_OUT,    dz);    break;      
+        case(MOD_LOBIT):
+        case(MOD_LOBIT2):  setup_process_logic(SNDFILES_ONLY,       EQUAL_SNDFILE,      SNDFILE_OUT,    dz);    break;      
+        case(MOD_SCRUB):   setup_process_logic(SNDFILES_ONLY,       UNEQUAL_SNDFILE,    SNDFILE_OUT,    dz);    break;      
+        case(MOD_SHRED):   setup_process_logic(SNDFILES_ONLY,       EQUAL_SNDFILE,      SNDFILE_OUT,    dz);    break;      
+        case(MOD_RINGMOD): setup_process_logic(SNDFILES_ONLY,       EQUAL_SNDFILE,      SNDFILE_OUT,    dz);    break;      
+        case(MOD_CROSSMOD): setup_process_logic(TWO_SNDFILES,       UNEQUAL_SNDFILE,    SNDFILE_OUT,    dz);    break;      
+        }
+        break;
+    case(BRASSAGE):       setup_process_logic(SNDFILES_ONLY,        UNEQUAL_SNDFILE,    SNDFILE_OUT,    dz);    break;
+    case(SAUSAGE):        setup_process_logic(MANY_SNDFILES,        UNEQUAL_SNDFILE,    SNDFILE_OUT,    dz);    break;
+    case(SIN_TAB):        setup_process_logic(NO_FILE_AT_ALL,       TO_TEXTFILE,        TEXTFILE_OUT,   dz);    break;
+/* TEMPORARY TEST ROUTINE */
+    case(WORDCNT):        setup_process_logic(WORDLIST_ONLY,        TO_TEXTFILE,        NO_OUTPUTFILE,  dz);    break;
+/* TEMPORARY TEST ROUTINE */
+//TW UPDATES
+    case(STACK):          setup_process_logic(SNDFILES_ONLY,        UNEQUAL_SNDFILE,    SNDFILE_OUT,    dz);    break;
+    case(CONVOLVE):       setup_process_logic(TWO_SNDFILES,         UNEQUAL_SNDFILE,    SNDFILE_OUT,    dz);    break;
+    case(SHUDDER):        setup_process_logic(SNDFILES_ONLY,        UNEQUAL_SNDFILE,    SNDFILE_OUT,    dz);    break;
+ 
+    default:
+        sprintf(errstr,"Unknown process: assign_process_logic()\n");
+        return(PROGRAM_ERROR);
+        break;
+    }
+    if(dz->has_otherfile) {
+        switch(dz->input_data_type) {
+        case(ALL_FILES):
+        case(TWO_SNDFILES):
+        case(SNDFILE_AND_ENVFILE):
+        case(SNDFILE_AND_BRKFILE):
+        case(SNDFILE_AND_UNRANGED_BRKFILE):
+        case(SNDFILE_AND_DB_BRKFILE):
+            break;
+        case(MANY_SNDFILES):
+            if(dz->process==INFO_TIMELIST)
+                break;
+            /* fall thro */
+        default:
+            sprintf(errstr,"Most processes accepting files with different properties\n"
+                           "can only take 2 sound infiles.\n");
+            return(PROGRAM_ERROR);
+        }
+    }
+    return(FINISHED);
+}
+
+/***************************** SET_LEGAL_INFILE_STRUCTURE **************************
+ *
+ * Allows 2nd infile to have different props to first infile.
+ */
+
+void set_legal_infile_structure(dataptr dz)
+{
+    switch(dz->process) {
+    case(MOD_RADICAL):
+        if(dz->mode==MOD_CROSSMOD)
+            dz->has_otherfile = TRUE;
+        else 
+            dz->has_otherfile = FALSE;
+        break;
+    case(MOD_LOUDNESS):
+        if(dz->mode==LOUDNESS_BALANCE)
+            dz->has_otherfile = TRUE;
+        else 
+            dz->has_otherfile = FALSE;
+        break;
+    default:
+        dz->has_otherfile = FALSE;
+        break;
+    }
+}
+
+/***************************************************************************************/
+/****************************** FORMERLY IN internal.c *********************************/
+/***************************************************************************************/
+
+/****************************** SET_LEGAL_INTERNALPARAM_STRUCTURE *********************************/
+
+int set_legal_internalparam_structure(int process,int mode,aplptr ap)
+{
+    int exit_status = FINISHED;
+    switch(process) {
+    case(MOD_LOUDNESS):         exit_status = set_internalparam_data("",ap);        break;      
+    case(MOD_SPACE):            exit_status = set_internalparam_data("",ap);        break;      
+//TW UPDATES
+    case(SCALED_PAN):           exit_status = set_internalparam_data("",ap);        break;      
+    case(FIND_PANPOS):          exit_status = set_internalparam_data("",ap);        break;      
+
+    case(MOD_PITCH):
+        switch(mode) {
+        case(MOD_ACCEL):        exit_status = set_internalparam_data(  "iiid",ap);  break;
+        case(MOD_VIBRATO):      exit_status = set_internalparam_data( "iiiid",ap);  break;
+        default:                exit_status = set_internalparam_data("iiiiid",ap);  break;
+        }       
+        break;
+    case(MOD_REVECHO):
+        switch(mode) {
+        case(MOD_DELAY):        exit_status = set_internalparam_data("0ddidi",ap);  break;
+        case(MOD_VDELAY):       exit_status = set_internalparam_data( "ddidi",ap);  break;
+        case(MOD_STADIUM):      exit_status = set_internalparam_data( "ii"   ,ap);  break;
+        default:
+            sprintf(errstr,"Unknown case for MOD_REVECHO in set_legal_internalparam_structure()\n");
+            return(PROGRAM_ERROR);
+        }
+        break;
+    case(MOD_RADICAL):
+        switch(mode) {
+        case(MOD_REVERSE):      exit_status = set_internalparam_data("iiii",ap);            break;
+        case(MOD_SHRED):        exit_status = set_internalparam_data("iiiiiiiiiiiiiii",ap); break;
+        case(MOD_SCRUB):        exit_status = set_internalparam_data("ididdii",ap);         break;
+        case(MOD_LOBIT):
+        case(MOD_LOBIT2):       exit_status = set_internalparam_data("iiii",ap);            break;
+        case(MOD_RINGMOD):      exit_status = set_internalparam_data("",ap);                break;
+        case(MOD_CROSSMOD):     exit_status = set_internalparam_data("",ap);                break;
+        default:
+            sprintf(errstr,"Unknown case for MOD_RADICAL in set_legal_internalparam_structure()\n");
+            return(PROGRAM_ERROR);
+        }
+        break;
+    case(BRASSAGE):
+        switch(mode) {
+        case(GRS_PITCHSHIFT):   exit_status = set_internalparam_data("0000ddddiiiiiiiiiiiiiiiiii",ap);  break;
+        case(GRS_TIMESTRETCH):  exit_status = set_internalparam_data("0000ddddiiiiiiiiiiiiiiiiii",ap);  break;
+        case(GRS_REVERB):       exit_status = set_internalparam_data( "000ddddiiiiiiiiiiiiiiiiii",ap);  break;
+        case(GRS_SCRAMBLE):     exit_status = set_internalparam_data( "000ddddiiiiiiiiiiiiiiiiii",ap);  break;
+        case(GRS_GRANULATE):    exit_status = set_internalparam_data("0000ddddiiiiiiiiiiiiiiiiii",ap);  break;
+        case(GRS_BRASSAGE):     exit_status = set_internalparam_data(    "ddddiiiiiiiiiiiiiiiiii",ap);  break;
+        case(GRS_FULL_MONTY):   exit_status = set_internalparam_data(    "ddddiiiiiiiiiiiiiiiiii",ap);  break;
+        default:
+            sprintf(errstr,"Unknown case for BRASSAGE in set_legal_internalparam_structure()\n");
+            return(PROGRAM_ERROR);
+        }
+        break;                         
+    case(SAUSAGE):      exit_status = set_internalparam_data("ddddiiiiiiiiiiiiiiiiii",ap);  break;
+    case(SIN_TAB):      exit_status = set_internalparam_data("",ap);                        break;
+//TW UPDATES
+    case(STACK):        exit_status = set_internalparam_data("d",ap);                       break;
+    case(CONVOLVE):     exit_status = set_internalparam_data("",ap);                        break;
+    case(SHUDDER):      exit_status = set_internalparam_data("",ap);                        break;
+
+/* TEMPORARY TEST ROUTINE */
+    case(WORDCNT):      exit_status = set_internalparam_data("",ap);                        break;
+/* TEMPORARY TEST ROUTINE */
+    default:
+        sprintf(errstr,"Unknown process in set_legal_internalparam_structure()\n");
+        return(PROGRAM_ERROR);
+    }
+    return(exit_status);        
+}
+
+/********************************************************************************************/
+/********************************** FORMERLY IN specialin.c *********************************/
+/********************************************************************************************/
+
+/********************** READ_SPECIAL_DATA ************************/
+
+int read_special_data(char *str,dataptr dz)    
+{
+    aplptr ap = dz->application;
+
+    switch(ap->special_data) {
+//TW UPDATE
+    case(STACKDATA):    return read_stackdata(str,dz);
+    case(LOUDNESS):     return read_loudness(str,dz);
+    default:
+        sprintf(errstr,"Unknown special_data type: read_special_data()\n");
+        return(PROGRAM_ERROR);
+    }
+    return(FINISHED);   /* NOTREACHED */
+}
+
+/********************************************************************************************/
+/********************************** FORMERLY IN preprocess.c ********************************/
+/********************************************************************************************/
+
+/****************************** PARAM_PREPROCESS *********************************/
+
+int param_preprocess(dataptr dz)    
+{
+    int exit_status = FINISHED;
+#ifdef MULTICHAN
+    int n;
+#endif
+    switch(dz->process) {
+    case(MOD_LOUDNESS):
+        return(FINISHED);           
+    case(MOD_RADICAL):
+        switch(dz->mode) {
+        case(MOD_SHRED):    return shred_preprocess(dz);
+        case(MOD_SCRUB):    return scrub_preprocess(dz);
+        case(MOD_RINGMOD):  return create_rm_sintab(dz);
+        default:            return(FINISHED);           
+        }
+        break;
+    case(MOD_SPACE):        return modspace_preprocess(dz);
+
+//TW UPDATES
+    case(SCALED_PAN):   return scaledpan_preprocess(dz);
+    case(FIND_PANPOS):  return FINISHED;
+
+    case(MOD_PITCH):    return vtrans_preprocess(dz);
+    case(MOD_REVECHO):  return delay_preprocess(dz);
+    case(BRASSAGE):
+        /* RWD: create outfile here  - different chan count from infile */
+#ifdef MULTICHAN
+        n = dz->infile->channels;
+        dz->infile->channels = dz->outfile->channels;
+#endif
+        if(dz->mode==GRS_REVERB || dz->mode==GRS_BRASSAGE || dz->mode == GRS_FULL_MONTY){               
+            if((exit_status = create_sized_outfile(dz->outfilename,dz))<0)
+                return(exit_status);
+        }
+#ifdef MULTICHAN
+        dz->infile->channels = n;
+#endif
+        return FINISHED;
+    case(SAUSAGE):      return sausage_preprocess(dz);
+    case(SIN_TAB):      return FINISHED;
+//TW UPDATES
+    case(STACK):        return stack_preprocess(dz);
+    case(CONVOLVE):
+        if(dz->mode == CONV_TVAR)
+            return convolve_preprocess(dz);
+        break;
+    case(SHUDDER):      return FINISHED;
+
+/* TEMPORARY TEST ROUTINE */
+    case(WORDCNT):          
+        return FINISHED;        
+/* TEMPORARY TEST ROUTINE */
+    default:
+        sprintf(errstr,"PROGRAMMING PROBLEM: Unknown process in param_preprocess()\n");
+        return(PROGRAM_ERROR);
+    }
+    return(FINISHED);   /* NOTREACHED */
+}
+
+/********************************************************************************************/
+/********************************** FORMERLY IN procgrou.c **********************************/
+/********************************************************************************************/
+
+/**************************** GROUCHO_PROCESS_FILE ****************************/
+
+int groucho_process_file(dataptr dz)   /* FUNCTIONS FOUND IN PROCESS.C */
+{   
+    /*int exit_status = FINISHED;*/
+
+    if(dz->process==BRASSAGE || dz->process==SAUSAGE)
+        display_virtual_time(0L,dz);
+
+    switch(dz->process) {
+    case(MOD_SPACE):
+        switch(dz->mode) {
+        case(MOD_PAN):       return dopan(dz);
+        case(MOD_MIRROR):    return mirroring(dz);
+        case(MOD_MIRRORPAN): mirror_panfile(dz);    return(FINISHED);
+        case(MOD_NARROW):    return narrow_sound(dz);
+        default:
+            sprintf(errstr,"Unknown mode for MOD_SPACE in groucho_process_file()\n");
+            return(PROGRAM_ERROR);
+        }
+        break;
+//TW UPDATES
+    case(SCALED_PAN):   return dopan(dz);
+    case(FIND_PANPOS):  return findpan(dz);
+
+    case(MOD_PITCH):    return process_varispeed(dz);
+    case(MOD_REVECHO):  
+        switch(dz->mode) {
+        case(MOD_STADIUM):  return do_stadium(dz);
+        case(MOD_DELAY):
+        case(MOD_VDELAY):   return do_delay(dz);
+        default:
+            sprintf(errstr,"Unknown mode for MOD_REVECHO in groucho_process_file()\n");
+            return(PROGRAM_ERROR);
+        }
+        break;
+    case(MOD_RADICAL):  
+        switch(dz->mode) {
+        case(MOD_REVERSE):  return do_reversing(dz);
+        case(MOD_SHRED):    return shred_process(dz);
+        case(MOD_SCRUB):    return do_scrubbing(dz);
+        case(MOD_LOBIT):
+        case(MOD_LOBIT2):   return lobit_process(dz);
+        case(MOD_RINGMOD):  return ring_modulate(dz);
+        case(MOD_CROSSMOD): return cross_modulate(dz);
+        default:
+            sprintf(errstr,"Unknown mode for MOD_RADICAL in groucho_process_file()\n");
+            return(PROGRAM_ERROR);
+        }
+        break;
+    case(MOD_LOUDNESS): return loudness_process(dz);
+    case(BRASSAGE):     return granula_process(dz);
+    case(SAUSAGE):      return granula_process(dz);
+    case(SIN_TAB):      return generate_sintable(dz);
+//TW UPDATES
+    case(STACK):        return do_stack(dz);
+    case(CONVOLVE):     return do_convolve(dz);
+    case(SHUDDER):      return do_shudder(dz);
+
+    default:
+        sprintf(errstr,"Unknown case in process_file()\n");
+        return(PROGRAM_ERROR);
+    }
+    return(FINISHED);   /* NOTREACHED */
+}
+
+/********************************************************************************************/
+/********************************** FORMERLY IN pconsistency.c ******************************/
+/********************************************************************************************/
+
+/****************************** CHECK_PARAM_VALIDITY_AND_CONSISTENCY *********************************/
+
+int check_param_validity_and_consistency(dataptr dz)
+{
+/*  int exit_status = FINISHED;*/
+    handle_pitch_zeros(dz);
+    switch(dz->process) {
+    case(MOD_SPACE):    return modspace_pconsistency(dz);
+//TW UPDATE
+    case(SCALED_PAN):   
+        if(dz->infile->channels!=MONO) {
+            sprintf(errstr,"ERROR: SCALED PAN only works with MONO input files.\n");
+            return(DATA_ERROR);
+        }
+        return FINISHED;
+
+    case(MOD_REVECHO):
+        if(dz->mode==MOD_STADIUM)
+            return stadium_pconsistency(dz);
+        return FINISHED;
+    case(MOD_RADICAL):
+        switch(dz->mode) {
+        case(MOD_LOBIT):    return lobit_pconsistency(dz);
+        case(MOD_SHRED):    return shred_pconsistency(dz);
+        case(MOD_SCRUB):    return scrub_pconsistency(dz);
+        case(MOD_CROSSMOD): return crossmod_pconsistency(dz);
+        default:         return FINISHED;
+        }
+        break;
+    case(BRASSAGE):
+    case(SAUSAGE):      return granula_pconsistency(dz);
+    case(SIN_TAB):      return sintab_pconsistency(dz);
+//TW UPDATES
+    case(STACK):        return FINISHED;
+    case(CONVOLVE):     return convolve_pconsistency(dz);
+    case(SHUDDER):      return FINISHED;
+    case(FIND_PANPOS):  return FINISHED;
+
+/* TEMPORARY TEST ROUTINE */
+    case(WORDCNT):      return FINISHED;        
+/* TEMPORARY TEST ROUTINE */
+    }
+    return(FINISHED);
+}
+
+/********************************************************************************************/
+/********************************** FORMERLY IN buffers.c ***********************************/
+/********************************************************************************************/
+
+/**************************** ALLOCATE_LARGE_BUFFERS ******************************/
+
+int allocate_large_buffers(dataptr dz)
+{
+    switch(dz->process) {
+    case(MOD_LOUDNESS):         
+        return create_sndbufs(dz);
+    case(MOD_SPACE):            
+        if(dz->mode!=MOD_MIRRORPAN)
+            return create_sndbufs(dz);
+        return(FINISHED);
+//TW UPDATE
+    case(SCALED_PAN):   return create_sndbufs(dz);
+
+    case(MOD_PITCH):    return create_modspeed_buffers(dz);
+    case(MOD_REVECHO):  return create_delay_buffers(dz);
+    case(MOD_RADICAL):
+        switch(dz->mode) {
+        case(MOD_REVERSE):  return create_reversing_buffers(dz);
+        case(MOD_SHRED):    return create_shred_buffers(dz);
+        case(MOD_SCRUB):    return create_scrub_buffers(dz);
+        case(MOD_LOBIT):
+        case(MOD_LOBIT2):   return create_sndbufs(dz);
+        case(MOD_RINGMOD):  return create_sndbufs(dz);
+        case(MOD_CROSSMOD): return create_crossmod_buffers(dz);
+        }
+        break;
+    case(BRASSAGE):     return create_granula_buffers(dz);
+    case(SAUSAGE):      return create_sausage_buffers(dz);
+    case(SIN_TAB):      return FINISHED;
+//TW UPDATES
+    case(FIND_PANPOS):  return create_sndbufs(dz);
+    case(STACK):        return create_sndbufs(dz);
+    case(CONVOLVE):     return create_convolve_bufs(dz);
+    case(SHUDDER):      return create_sndbufs(dz);
+
+/* TEMPORARY TEST ROUTINE */
+    case(WORDCNT):          
+        return(FINISHED);
+/* TEMPORARY TEST ROUTINE */
+    default:
+        sprintf(errstr,"Unknown program no. in allocate_large_buffers()\n");
+        return(PROGRAM_ERROR);
+    }
+    return(FINISHED);
+}
+
+/*************************** CREATE_GRANULA_BUFFERS **************************/
+
+#ifndef MULTICHAN
+
+int create_granula_buffers(dataptr dz)
+{
+    int   exit_status,enough_memory;
+    int   convert_to_stereo = FALSE, overall_size = 0, bufdivisor = 0;
+    float *tailend;
+    int  stereo_buflen = 0, stereo_bufxs = 0, outbuflen, bbb_size;
+//TW All buffers are in floats, so this not needed
+//  int   lfactor = sizeof(int)/sizeof(float);
+    if(dz->iparray[GRS_FLAGS][G_SPACE_FLAG])
+        convert_to_stereo = TRUE;                           
+    if((dz->extrabuf[GRS_GBUF] = (float *)malloc(dz->iparam[GRS_GLBUF_SMPXS] * sizeof(float)))==NULL) {
+        sprintf(errstr,"INSUFFICIENT MEMORY to create grain buffer.\n");     /* GRAIN BUFFER */
+        return(MEMORY_ERROR);
+    }
+                /* CALCULATE NUMBER OF BUFFER CHUNKS REQUIRED : bufdivisor */
+
+    if(dz->iparam[GRS_CHANNELS]>0)
+        bufdivisor += 2;                
+//TW All buffers are in floats
+//  bufdivisor += 1 + 1 + lfactor;      
+    bufdivisor += 3;        
+    if(convert_to_stereo)
+//TW All buffers are in floats
+//      bufdivisor += 1 + lfactor;      
+        bufdivisor += 2;        
+
+    enough_memory = 0;
+    if((exit_status = grab_an_appropriate_block_of_memory(bufdivisor,dz))<0)
+        return(exit_status);
+    bbb_size = /*dz->bigbufsize*/dz->buflen;
+    while(!enough_memory) {
+                    /* CALCULATE AND ALLOCATE TOTAL MEMORY REQUIRED : overall_size */
+        if ((overall_size = /*dz->bigbufsize*/dz->buflen * bufdivisor) < 0) {       /* overflow */
+            sprintf(errstr,"INSUFFICIENT MEMORY to create sound buffers.\n");
+            return(MEMORY_ERROR);
+        }
+        if ((overall_size += (dz->iparam[GRS_BUF_SMPXS] + dz->iparam[GRS_LBUF_SMPXS])) < 0) {       /* overflow */
+            sprintf(errstr,"INSUFFICIENT MEMORY to create sound buffers.\n");
+            return(MEMORY_ERROR);
+        }
+        if(dz->iparam[GRS_CHANNELS])                
+            overall_size += 2 * dz->iparam[GRS_BUF_SMPXS];  
+        if(overall_size<0) {                                                 /* overflow */
+            sprintf(errstr,"INSUFFICIENT MEMORY for sound buffers.\n"); 
+            return(MEMORY_ERROR);
+        }
+        if((dz->bigbuf=(float *)malloc(overall_size * sizeof(float)))==NULL) {
+            sprintf(errstr,"INSUFFICIENT MEMORY to create sound buffers.\n");
+            return(MEMORY_ERROR);
+        }
+                    /* SET SIZE OF inbuf, outbuf, AND Lbuf (FOR CALCS IN LONGS) */
+        outbuflen   = dz->buflen;
+        if(convert_to_stereo)                   
+            outbuflen *= 2;
+        if(dz->iparam[GRS_CHANNELS]) {
+            stereo_buflen = dz->buflen * 2;
+            stereo_bufxs  = dz->iparam[GRS_BUF_SMPXS] * 2;      /**** CHANGED MAY 1998 ****/
+        }                                        
+        dz->iparam[GRS_LONGS_BUFLEN] = outbuflen;           
+        if(dz->iparam[GRS_LBUF_SMPXS] <= dz->iparam[GRS_LONGS_BUFLEN])                                      
+            enough_memory = 1;
+        else {
+            if((/*dz->bigbufsize*/dz->buflen += bbb_size) < 0) {    /* overflow */
+                sprintf(errstr,"INSUFFICIENT MEMORY to create sound buffers.\n");
+                return(MEMORY_ERROR);
+            }
+        }
+    }
+                /* DIVIDE UP ALLOCATED MEMORY IN SPECIALISED BUFFERS */ 
+                                                                    
+    if(dz->iparam[GRS_CHANNELS]) {                      
+        dz->sampbuf[GRS_SBUF] = dz->bigbuf;                                  
+        dz->sampbuf[GRS_BUF]  = dz->sampbuf[GRS_SBUF] + stereo_buflen + stereo_bufxs;            
+    } else                                               
+        dz->sampbuf[GRS_BUF]     = dz->bigbuf;                      /* buf: complete input buffer with wrap-around space */                 
+    dz->sbufptr[GRS_BUF]   = dz->sampbuf[GRS_BUF] + dz->buflen;                /* bufend:   start of wrap-around area */
+    tailend                = dz->sbufptr[GRS_BUF] + dz->iparam[GRS_BUF_SMPXS]; /* tailend:  end of wrap-around area */
+    dz->sampbuf[GRS_IBUF]  = dz->sampbuf[GRS_BUF] + dz->iparam[GRS_BUF_SMPXS]; /* ibuf: input buffer 'base' after wrap-around begins */                  
+    dz->fptr[GRS_LBUF]     = /*(int *)*/tailend;                                   /* Lbuf: buffer for calculations */
+    dz->fptr[GRS_LBUFEND]  = dz->fptr[GRS_LBUF] + dz->iparam[GRS_LONGS_BUFLEN];/* Lbufend:  start of Lbuf wrap-around area */ 
+    dz->fptr[GRS_LTAILEND] = dz->fptr[GRS_LBUFEND] + dz->iparam[GRS_LBUF_SMPXS];/* Ltailend: end of Lbuf wrap-around area */
+    dz->fptr[GRS_LBUFMID]  = dz->fptr[GRS_LBUF]    + dz->iparam[GRS_LBUF_SMPXS];/* Lbufmid:  Lbuf 'base' after wrap-around begins */
+    dz->sampbuf[GRS_OBUF]  = (dz->fptr[GRS_LTAILEND]);                  /* obuf:     output buffer */
+
+                                /* INITIALISE BUFFERS */
+
+    memset((char *)dz->bigbuf,0,overall_size * sizeof(float));
+    return(FINISHED);
+}
+
+#else
+
+int create_granula_buffers(dataptr dz)
+{
+    int   exit_status,enough_memory;
+    int   spatialise_output = FALSE, overall_size = 0, bufdivisor = 0, chans = dz->infile->channels;
+    float *tailend;
+    int  multichan_buflen = 0, multichan_bufxs = 0, grainbuflen, bbb_size;
+    if(dz->iparray[GRS_FLAGS][G_SPACE_FLAG])
+        spatialise_output = TRUE;                           
+    if((dz->extrabuf[GRS_GBUF] = (float *)malloc(dz->iparam[GRS_GLBUF_SMPXS] * sizeof(float)))==NULL) {
+        sprintf(errstr,"INSUFFICIENT MEMORY to create grain buffer.\n");     /* GRAIN BUFFER */
+        return(MEMORY_ERROR);
+    }
+                /* CALCULATE NUMBER OF BUFFER CHUNKS REQUIRED : bufdivisor */
+
+    if(dz->iparam[GRS_CHANNELS]>0)
+        bufdivisor += chans;                
+    bufdivisor += 3;        
+
+// MARCH 2010
+//  if(spatialise_output)
+        bufdivisor += dz->out_chans;
+
+    enough_memory = 0;
+    if((exit_status = grab_an_appropriate_block_of_memory(bufdivisor,dz))<0)
+        return(exit_status);
+    bbb_size = dz->buflen;
+    while(!enough_memory) {
+                    /* CALCULATE AND ALLOCATE TOTAL MEMORY REQUIRED : overall_size */
+        if ((overall_size = dz->buflen * bufdivisor) < 0) {     /* overflow */
+            sprintf(errstr,"INSUFFICIENT MEMORY to create sound buffers.\n");
+            return(MEMORY_ERROR);
+        }
+        if ((overall_size += (dz->iparam[GRS_BUF_SMPXS] + dz->iparam[GRS_LBUF_SMPXS])) < 0) {       /* overflow */
+            sprintf(errstr,"INSUFFICIENT MEMORY to create sound buffers.\n");
+            return(MEMORY_ERROR);
+        }
+        if(dz->iparam[GRS_CHANNELS])                
+            overall_size += chans * dz->iparam[GRS_BUF_SMPXS];  
+        if(overall_size<0) {                                                 /* overflow */
+            sprintf(errstr,"INSUFFICIENT MEMORY for sound buffers.\n"); 
+            return(MEMORY_ERROR);
+        }
+        if((dz->bigbuf=(float *)malloc(overall_size * sizeof(float)))==NULL) {
+            sprintf(errstr,"INSUFFICIENT MEMORY to create sound buffers.\n");
+            return(MEMORY_ERROR);
+        }
+                    /* SET SIZE OF inbuf, outbuf, AND Lbuf (FOR CALCS IN LONGS) */
+    
+        grainbuflen   = dz->buflen * dz->iparam[GRS_INCHANS];   
+        if(dz->iparam[GRS_CHANNELS]) {
+            multichan_buflen = dz->buflen * chans;
+            multichan_bufxs  = dz->iparam[GRS_BUF_SMPXS] * chans;       /**** CHANGED MAY 1998 ****/
+        }                                        
+        dz->iparam[GRS_LONGS_BUFLEN] = grainbuflen;         
+        if(dz->iparam[GRS_LBUF_SMPXS] <= dz->iparam[GRS_LONGS_BUFLEN])                                      
+            enough_memory = 1;
+        else {
+            if((dz->buflen += bbb_size) < 0) {  /* overflow */
+                sprintf(errstr,"INSUFFICIENT MEMORY to create sound buffers.\n");
+                return(MEMORY_ERROR);
+            }
+        }
+    }
+                /* DIVIDE UP ALLOCATED MEMORY IN SPECIALISED BUFFERS */ 
+                                                                    
+    if(dz->iparam[GRS_CHANNELS]) {                      
+        dz->sampbuf[GRS_SBUF] = dz->bigbuf;                                  
+        dz->sampbuf[GRS_BUF]  = dz->sampbuf[GRS_SBUF] + multichan_buflen + multichan_bufxs;          
+    } else                                               
+        dz->sampbuf[GRS_BUF]     = dz->bigbuf;                      /* buf: complete input buffer with wrap-around space */                 
+    dz->sbufptr[GRS_BUF]   = dz->sampbuf[GRS_BUF] + dz->buflen;                /* bufend:   start of wrap-around area */
+    tailend                = dz->sbufptr[GRS_BUF] + dz->iparam[GRS_BUF_SMPXS]; /* tailend:  end of wrap-around area */
+    dz->sampbuf[GRS_IBUF]  = dz->sampbuf[GRS_BUF] + dz->iparam[GRS_BUF_SMPXS]; /* ibuf: input buffer 'base' after wrap-around begins */                  
+    dz->fptr[GRS_LBUF]     = /*(int *)*/tailend;                                   /* Lbuf: buffer for calculations */
+    dz->fptr[GRS_LBUFEND]  = dz->fptr[GRS_LBUF] + dz->iparam[GRS_LONGS_BUFLEN];/* Lbufend:  start of Lbuf wrap-around area */ 
+    dz->fptr[GRS_LTAILEND] = dz->fptr[GRS_LBUFEND] + dz->iparam[GRS_LBUF_SMPXS];/* Ltailend: end of Lbuf wrap-around area */
+    dz->fptr[GRS_LBUFMID]  = dz->fptr[GRS_LBUF]    + dz->iparam[GRS_LBUF_SMPXS];/* Lbufmid:  Lbuf 'base' after wrap-around begins */
+    dz->sampbuf[GRS_OBUF]  = (dz->fptr[GRS_LTAILEND]);                  /* obuf:     output buffer */
+
+                                /* INITIALISE BUFFERS */
+
+    memset((char *)dz->bigbuf,0,overall_size * sizeof(float));
+    return(FINISHED);
+}
+
+#endif
+
+/*  INPUT BUFFER :-     
+ *
+ *  |-----------BUFLEN-----------|
+ *
+ *  buf      ibuf          bufend    tailend
+ *  |_________|__________________|buf_smpxs|  ..... (obuf->)
+ *                               /
+ *  |buf_smpxs|           <<-COPY_________/
+ *
+ *            |-----------BUFLEN-----------|
+ *
+ *
+ *
+ *  OUTPUT LONGS BUFFER:-
+ *
+ *  Lbuf       Lbufmid    Lbufend
+ *  |____________|_______________|_Lbuf_smpxs_|
+ *                               /
+ *  |_Lbuf_smpxs_|         <<-COPY___________/  
+ *
+ */
+
+/*************************** GRAB_AN_APPROPRIATE_BLOCK_OF_MEMORY **************************/
+
+#ifndef MULTICHAN
+
+int grab_an_appropriate_block_of_memory(int bufdivisor,dataptr dz)
+{
+    int this_bloksize, standard_block = (int) ((long)Malloc(-1));
+    int  sector_blok;
+    standard_block /= sizeof(float);
+    this_bloksize = standard_block;
+    dz->buflen = 0;
+    while(dz->buflen <= 0){
+        if((dz->buflen = this_bloksize)< 0) {   /* arithmetic overflow */
+            sprintf(errstr,"INSUFFICIENT MEMORY for sound buffers.\n");
+            return(MEMORY_ERROR);
+        }
+        this_bloksize += standard_block;
+                /* CALCULATE SIZE OF BUFFER REQUIRED : dz->bigbufsize */
+
+        dz->buflen -= dz->iparam[GRS_BUF_SMPXS] + dz->iparam[GRS_LBUF_SMPXS];   /* Allow for overflow areas */
+        if(dz->iparam[GRS_CHANNELS])                
+            dz->buflen -= 2 * dz->iparam[GRS_BUF_SMPXS];    /* Allow for overflow space in additional stereo inbuf */
+        dz->buflen /= bufdivisor;                           /* get unit buffersize */
+        sector_blok = F_SECSIZE;                            /* Read and write buf sizes must be multiples of SECSIZE ... for now */
+        if(dz->iparam[GRS_CHANNELS])                        /* If reading stereo: 2* SECSIZE reduces to single mono SECSIZE */
+            sector_blok *= 2;                               /* So dz->bigbufsize must be a multiple of (2 * SECSIZE) */
+        dz->buflen = (dz->buflen/sector_blok) * sector_blok;
+    }
+    return(FINISHED);
+}
+
+#else
+
+int grab_an_appropriate_block_of_memory(int bufdivisor,dataptr dz)
+{
+    int this_bloksize, standard_block = (int)Malloc(-1);
+    int  sector_blok, chans = dz->infile->channels;
+    standard_block /= sizeof(float);
+    this_bloksize = standard_block;
+    dz->buflen = 0;
+    while(dz->buflen <= 0){
+        if((dz->buflen = this_bloksize)< 0) {   /* arithmetic overflow */
+            sprintf(errstr,"INSUFFICIENT MEMORY for sound buffers.\n");
+            return(MEMORY_ERROR);
+        }
+        this_bloksize += standard_block;
+                /* CALCULATE SIZE OF BUFFER REQUIRED : dz->bigbufsize */
+
+        dz->buflen -= dz->iparam[GRS_BUF_SMPXS] + dz->iparam[GRS_LBUF_SMPXS];   /* Allow for overflow areas */
+        if(dz->iparam[GRS_CHANNELS])                
+            dz->buflen -= chans * dz->iparam[GRS_BUF_SMPXS];    /* Allow for overflow space in additional multichannel inbuf */
+        dz->buflen /= bufdivisor;                           /* get unit buffersize */
+        sector_blok = F_SECSIZE;                            /* Read and write buf sizes must be multiples of SECSIZE ... for now */
+        if(dz->iparam[GRS_CHANNELS])                        /* If reading multichan: chans * SECSIZE reduces to single mono SECSIZE */
+            sector_blok *= chans;                               /* So dz->bigbufsize must be a multiple of (chans * SECSIZE) */
+        dz->buflen = (dz->buflen/sector_blok) * sector_blok;
+    }
+    return(FINISHED);
+}
+
+#endif
+
+/********************************************************************************************/
+/********************************** FORMERLY IN cmdline.c ***********************************/
+/********************************************************************************************/
+
+int get_process_no(char *prog_identifier_from_cmdline,dataptr dz)
+{
+    if     (!strcmp(prog_identifier_from_cmdline,"loudness"))       dz->process = MOD_LOUDNESS;
+    else if(!strcmp(prog_identifier_from_cmdline,"space"))          dz->process = MOD_SPACE;
+//TW UPDATES
+    else if(!strcmp(prog_identifier_from_cmdline,"scaledpan"))      dz->process = SCALED_PAN;
+    else if(!strcmp(prog_identifier_from_cmdline,"findpan"))        dz->process = FIND_PANPOS;
+
+    else if(!strcmp(prog_identifier_from_cmdline,"speed"))          dz->process = MOD_PITCH;
+    else if(!strcmp(prog_identifier_from_cmdline,"revecho"))        dz->process = MOD_REVECHO;
+    else if(!strcmp(prog_identifier_from_cmdline,"radical"))        dz->process = MOD_RADICAL;
+    else if(!strcmp(prog_identifier_from_cmdline,"brassage"))       dz->process = BRASSAGE;
+    else if(!strcmp(prog_identifier_from_cmdline,"sausage"))        dz->process = SAUSAGE;
+//TW UPDATE (originally missing from cmdlinr list
+    else if(!strcmp(prog_identifier_from_cmdline,"spaceform"))      dz->process = SIN_TAB;
+//TW UPDATES
+    else if(!strcmp(prog_identifier_from_cmdline,"stack"))          dz->process = STACK;
+    else if(!strcmp(prog_identifier_from_cmdline,"convolve"))       dz->process = CONVOLVE;
+    else if(!strcmp(prog_identifier_from_cmdline,"shudder"))        dz->process = SHUDDER;
+
+/* TEMPORARY TEST ROUTINE */
+    else if(!strcmp(prog_identifier_from_cmdline,"wordcnt"))        dz->process = WORDCNT;
+/* TEMPORARY TEST ROUTINE */
+    else {
+        sprintf(errstr,"Unknown program identification string '%s'\n",prog_identifier_from_cmdline);
+        return(USAGE_ONLY);
+    }
+    /*RWD 9:2001 need retval */
+    return FINISHED;
+}
+
+/********************************************************************************************/
+/********************************** FORMERLY IN usage.c *************************************/
+/********************************************************************************************/
+
+/******************************** USAGE1 ********************************/
+
+int usage1(void)
+{
+    sprintf(errstr,
+    "USAGE: modify NAME (mode) infile outfile (datafile) parameters\n"
+    "\n"
+    "where NAME can be any one of\n"
+    "\n"
+    "loudness   space     speed     revecho\n"
+//TW UPDATE
+//  "brassage   sausage   radical\n"
+    "brassage     sausage     radical     spaceform\n"
+//TW UPDATE
+    "scaledpan    findpan    convolve    stack       shudder\n"
+    "\n"
+    "Type 'modify  brassage'  for more info on modify  brassage option... ETC.\n");
+    return(USAGE_ONLY);
+}
+
+/******************************** USAGE2 ********************************/
+ /*RWD 9:2001 usage message changes for loudness */
+int usage2(char *str)
+{
+    if (!strcmp(str,"loudness")) {       
+        fprintf(stdout,
+        "ADJUST LOUDNESS OF A SOUNDFILE\n\n"
+        "USAGE: modify loudness 1 infile         outfile gain\n"
+        "OR:    modify loudness 11-12 infile     outfile gain\n"
+        "OR:    modify loudness 2 infile         outfile gain\n"        /* NORMALISE IF NESS */
+        "OR:    modify loudness 3 infile         outfile [-llevel]\n"       /* NORMALISE IF NESS */
+        "OR:    modify loudness 4 infile         outfile [-llevel]\n"       /* FORCE TO SET LEVEL */
+        "OR:    modify loudness 5 infile infile2 outfile\n"                 /* BALANCE */
+        "OR:    modify loudness 6 infile outfile\n"                         /* INVERT PHASE */
+        "OR:    modify loudness 7 infile infile2 etc.\n"                    /* FIND LOUDEST */
+        "OR:    modify loudness 8 infile infile2 etc. outfile\n\n"          /* NORMALISE TO LOUDEST */
+        "WHERE MODES ARE\n"
+        "1) GAIN:         adjust level by factor GAIN.\n"
+        "2) dBGAIN:       adjust level by GAIN dB. Range +-96.0\n"
+        "3) NORMALISE:    force level (if ness) to max possible, or to LEVEL given.\n"
+        "4) FORCE LEVEL:  force level to maximum possible, or to LEVEL given.\n"
+        "5) BALANCE:      force max level of file1 to max level of file 2.\n"
+        "6) INVERT PHASE: Invert phase of the sound.\n"
+        "7) FIND LOUDEST: find loudest file.\n"
+        "8) EQUALISE:     force all files to level of loudest file.\n"
+        "11) PROPORTIONAL:    adjust level with envelope stretched to dur of sound.\n"
+        "12) PROPORTIONAL dB: adjust level with dB envelope stretched to dur of sound.\n"
+        "                 Infiles are rescaled in input order, with output names as\n" 
+//TW    "                 outfile, outfile1, outfile2, outfile3 etc.\n"     
+        "                 outfile0, outfile1, outfile2, outfile3 etc.\n"        
+        );
+    } else if(!strcmp(str,"space")) {        
+        fprintf(stdout,
+        "CREATE OR ALTER DISTRIBUTION OF SOUND IN STEREO SPACE\n\n"
+        "USAGE: modify space 1 infile outfile pan [-pprescale]\n"
+        "OR:    modify space 2 infile outfile\n"
+        "OR:    modify space 3 infile outfile\n"        
+        "OR:    modify space 4 infile outfile narrowing\n\n"
+        "WHERE MODES ARE\n"
+        "1) PAN:         Position or move mono sound in a stereo field.\n"
+        "                Prescale reduces inlevel to avoid clipping (default 0.7)\n"
+        "2) MIRROR:      Invert stereo positions in a stereo file.\n"
+        "3) MIRRORPAN:   Invert stereo positions in a pan data file.\n"
+        "4) NARROW:      Narrow the stereo image of a sound.\n"
+        "                NARROWING range, -1 to 1\n"
+        "                1   leaves stereo image as it is.\n"
+        "                .5  narrows stereo image by half.\n"
+        "                0   converts stereo image to mono.\n"
+        "                -ve vals work similarly, but also invert stereo image.\n");
+//TW UPDATES
+    } else if(!strcmp(str,"spaceform")) {        
+        fprintf(stdout,
+        "CREATE A SINUSOIDAL SPATIAL DISTRIBUTION DATA FILE\n\n"
+        "USAGE: modify spaceform outpanfile cyclelen width dur quantisation phase\n\n"
+        "CYCLELEN     is the duration of one complete sinusoidal pan cycle\n"
+        "WIDTH        is the width of the pan (from 0 to full width,1)\n"
+        "DUR          is the duration of the output file.\n" 
+        "QUANTISATION is time step between successive space-position specifications.\n" 
+        "PHASE        is the angular position at which the pan starts.\n" 
+        "             0 is full left, 360 is full right.\n" 
+        "cyclelen and width may vary over time\n");
+    } else if(!strcmp(str,"scaledpan")) {        
+        fprintf(stdout,
+        "DISTRIBUTE SOUND IN STEREO SPACE, SCALING PAN DATA TO SNDFILE DURATION\n\n"
+        "USAGE: modify scaledpan infile outfile pan [-pprescale]\n\n"
+        "PAN      breakpoint file of time, position pairs.\n"
+        "         Positions sound in a stereo field, from -1 (Left) to 1 (Right) or beyond.\n"
+        "PRESCALE reduces input level to avoid clipping (default 0.7)\n");
+    } else if(!strcmp(str,"findpan")) {      
+        fprintf(stdout,
+        "FIND STEREO-PAN POSITION OF A SOUND IN A STEREO FILE\n\n"
+        "USAGE: modify findpan infile time\n\n"
+        "Process assumes file contains a sound which has previously been panned to a position\n"
+        "in the stereo field. The process will give misleading results if this is not the case.\n");
+    } else if(!strcmp(str,"stack")) {        
+        fprintf(stdout,
+        "CREATE A MIX WHICH STACKS TRANPOSED VERSIONS OF SOURCE ON ONE ANOTHER\n\n"
+        "USAGE: modify stack infile outfile transpos count lean atk-offset gain dur [-s] [-n]\n\n"
+        "TRANSPOS   when numeric, is (semitone) transposition between successive copies\n"
+        "           or (as a file) a set of transposition values for each stack component.\n"
+        "COUNT      is the number of copies in the stack.\n"
+        "LEAN       is the loudness of the highest component, relative to the lowest.\n" 
+        "ATK_OFFSET is time at which attack of sound occurs.\n" 
+        "GAIN       is an overall amplifying factor on the ouptut sound.\n"
+        "DUR        how much of the output to make (a proportion, from 0 to 1).\n"
+        "-s         see the relative levels of the layers in the stack.\n"
+        "-n         Normalise the output.\n");
+    } else if(!strcmp(str,"convolve")) {         
+        fprintf(stdout,
+        "CONVOLVE THE FIRST SOUND WITH THE SECOND\n\n"
+        "USAGE: modify convolve 1 infile1 infile2 outfile\n"
+        "OR:    modify convolve 2 infile1 infile2 outfile tranposfile\n\n"
+        "TRANSPOSFILE is textfile of time / semitone-transposition pairs\n"
+        "infile2 must NOT be longer than infile1\n"
+        "and both files must have the same channel count.\n");
+    } else if(!strcmp(str,"shudder")) {      
+        fprintf(stdout,
+        "SHUDDER A STEREO FILE\n\n"
+        "USAGE: modify shudder infile outfile\n"
+        "         starttime  frq  scatter  stereo_spread  mindepth  maxdepth  minwidth  maxwidth [-b]\n\n"
+        "START_TIME    is time when Shuddering will begin.\n"
+        "FREQUENCY     is (average) frequency of the shuddering.\n"
+        "SCATTER       randomises the shudder events, in time. (0 - 1)\n"
+        "STEREO_SPREAD positions the shudder events in space. (0 - 1)\n"
+        "DEPTH         amplitude of shudders (each gets randval btwn MIN & MAX) Range 0-1\n"
+        "EVENT WIDTH   durations of shudder events (each gets randval btwn MIN & MAX)\n"
+        "-b            Balance average level of the stereo channels\n");
+    } else if(!strcmp(str,"speed")) {        
+        fprintf(stdout,
+        "CHANGE THE SPEED & PITCH OF THE SRC SOUND.\n\n"
+        "USAGE: modify speed 1 infile outfile     speed             [-o]\n"
+        "OR:    modify speed 2 infile outfile     semitone-transpos [-o]\n"
+        "OR:    modify speed 3 infile outtextfile speed             [-o]\n"
+        "OR:    modify speed 4 infile outtextfile semitone-transpos [-o]\n"
+        "OR:    modify speed 5 infile outfile     accel  goaltime   [-sstarttime]\n"
+        "OR:    modify speed 6 infile outfile    vibrate vibdepth\n"
+        "WHERE MODES ARE\n"
+        "1)  Vary speed/pitch of a sound.\n"
+        "2)  Vary speed/pitch by constant (fractional) no. of semitones.\n"
+        "3)  Get information on varying speed in a time-changing manner.\n"
+        "4)  Get info on time-variable speedchange in semitones.\n"
+        "    -o  brkpnt times read as outfile times (default: as infile times).\n"
+        "5)  Accelerate or decelerate a sound.\n"
+        "    ACCEL:     multiplication of speed reached by GOALTIME.\n"
+        "    GOALTIME:  time in OUTPUT file at which accelerated speed reached.\n"
+        "               If infile not exhausted there, it continues to accel.\n"
+        "               If insound finishes before GOALTIME reached,\n"
+        "               outfile won't reach specified acceleration value.\n"
+        "    STARTTIME: time in input/output file at which accel begins.\n"
+        "6)  Add vibrato to a sound.\n"
+        "    VIBRATE:   is rate of vibrato shaking in cycles-per-second.\n"
+        "    VIBDEPTH:  is vibrato depth in (possibly fractional) semitones.\n"
+        "    both of these may vary in time.\n"); 
+    } else if(!strcmp(str,"revecho")) {      
+        fprintf(stdout,
+        "CREATE REVERB, ECHO, OR RESONANCE AROUND SOUND\n\n"
+        "USAGE: modify revecho 1 infl outfl delay mix feedback tail [-pprescale] [-i]\n"
+        "OR:    modify revecho 2 infl outfl delay mix feedback\n"
+        "                                   lfomod lfofreq lfophase lfodelay\n"
+        "                                   tail [-pprescale] [-sseed]\n"
+        "OR:    modify revecho 3 infl outfl [-ggain] [-rroll_off] [-ssize] [-ecount] [-n]\n\n"
+        "WHERE MODES ARE\n"
+        "1) STANDARD DELAY with feedback, & mix (0=dry) of original & delayed signal.\n"
+        "2) VARYING DELAY  with low frequency oscillator varying delay time.\n"
+        "3) STADIUM ECHO   create stadium P.A. type echos.\n\n"
+        "DELAY     Delay time, in milliseconds.\n"
+        "MIX       amount of delayed signal in final mix: 0 gives 'dry' result.\n"
+        "FEEDBACK  produces resonance related to delay time (with short times).\n"
+        "TAIL      is time to allow delayed signal to decay to zero.\n"
+        "PRESCALE  prescales input level, to avoid overload.\n"
+        "-i        inverts the dry signal (for phasing effects).\n"
+        "LFOMOD    is the depth of delay-variation sweep.\n"
+        "LFOFREQ   is the freq of the sweep: -ve vals give random oscillations.\n"
+        "LFOPHASE  is the start phase of the sweep.\n"
+        "LFODELAY  is the time before the seep begins.\n"
+        "SEED      Nonzero value gives reproducible output (with same seed)\n"
+        "          where random oscillations are used.\n"
+        "GAIN      to apply to input signal: Default is %lf\n"
+        "SIZE      multiplies average time between echoes: (Default time 0.1 secs).\n"
+        "ROLL_OFF  rate of loss of level across stadium (default 1)\n"
+        "COUNT     number of stadium echoes: Default (max) is %d\n"
+        "-n        Normalise the output, preventing overload,\n",STAD_PREGAIN_DFLT,MAX_ECHOCNT);
+    } else if(!strcmp(str,"radical")) {      
+        fprintf(stdout,
+        "RADICAL CHANGES TO THE SOUND.\n\n"
+        "USAGE: modify radical 1 infile outfile\n"
+        "OR:    modify radical 2 infile outfile repeats chunklen [-sscatter] [-n]\n"
+        "OR:    modify radical 3 infile outfile dur [-ldown] [-hup] [-sstart] [-eend] [-f]\n"
+        "OR:    modify radical 4 infile outfile  bit_resolution  srate_division\n"
+        "OR:    modify radical 5 infile outfile  modulating-frq\n"
+        "OR:    modify radical 6 infile1 infile2 outfile\n\n"
+        "OR:    modify radical 7 infile1 outfile bit_resolution\n\n"
+        "MODES ARE\n"
+        "1) REVERSE:         sound plays backwards.\n"
+        "2) SHRED:           sound is shredded, within its existing duration.\n"
+        "                    REPEATS   no. of repeats of shredding process.\n"
+        "                    CHUNKLEN  average length of chunks to cut & permute.\n"
+        "                    SCATTER   randomisation of cuts (0 to K): default 1.\n"
+        "                    where K = total no. of chunks (snd-duration/chunklen).\n"
+        "                    If scatter = 0, reorders without shredding.\n"
+        "                    NB:  chunklen * scatter MUST be < program's snd buffer.\n"
+        "                    NB2: If Input sound > internal buffer len,\n"
+        "                    each buffer of sound shredded independently.\n"
+        "                    -n flag gives a slightly smoother output\n"
+        "3) SCRUB BACK & FORTH: as if handwinding over a tape-head.\n"
+        "                    DUR       is minimum length of outfile required.\n"
+        "                    DOWN      is lowest downward transposition (semitones).\n"
+        "                    UP        is highest upward transposition (semitones).\n"
+        "                    START     scrubs starts before time 'start' secs.\n"
+        "                    END       scrubs end after time 'end' secs.\n"
+        "                    -f        single forwards scrub only (ignores \"DUR\")\n"
+        "4) LOSE RESOLUTION: sound converted to lower srate, or bit-resolution.\n"
+        "                    BIT_RESOLUTION  range(1 - 16): default 16-bit.\n"
+        "                    SRATE_DIVISION  range(1-256): default 1 (normal)\n"
+        "                    entered value will be rounded to a power of 2.\n"
+        "5) RING MODULATE:   against input modulating frequency, creating sidebands.\n"
+        "6) CROSS MODULATE:  Two infiles are multiplied, creating complex sidebands.\n"
+        "                    Any combo of mono & stereo files works but,\n"
+        "                    files with more channels must have same channel count.\n"
+        "7) QUANTISE:        sound converted to specific bit-resolution (mid-rise).\n"
+        "                    BIT_RESOLUTION  range(1 - 16): default 16-bit.\n");
+    } else if(!strcmp(str,"brassage")) {         /* BRASSAGE = GRANULA */
+        fprintf(stdout, /* NB has to use direct fprintf as 2 screenfulls */
+        "GRANULAR RECONSTITUTION OF SOUNDFILE\n\n"
+        "MODES ARE...\n"
+        "1) PITCHSHIFT      4) SCRAMBLE\n"
+        "2) TIMESTRETCH     5) GRANULATE\n"
+        "3) REVERB          6) BRASSAGE\n"
+        "                   7) FULL MONTY\n"
+//TW temporary cmdline restriction
+        "USAGE:\n"
+        "modify brassage 1 infile outfile pitchshift\n"
+        "modify brassage 2 infile outfile velocity\n"
+        "modify brassage 3 infile outfile density pitch amp [-rrange]\n"
+        "modify brassage 4 infile outfile grainsize [-rrange]\n"
+        "modify brassage 5 infile outfile density \n\n"
+        "modify brassage 6 infile outfile velocity density grainsize pitchshft amp space\n"
+        "          bsplice esplice\n"
+        "          [-rrange] [-jjitter] [-loutlength] [-cchannel] [-x] [-n]\n\n"
+        "modify brassage 7 infile outfile velocity density hvelocity hdensity\n"
+        "          grainsize  pitchshift  amp  space  bsplice  esplice\n"
+        "          hgrainsize hpitchshift hamp hspace hbsplice hesplice\n"
+        "          [-rrange] [-jjitter] [-loutlength] [-cchannel] [-x] [-n]\n"
+        "\n"
+
+#ifdef IS_PC
+        "MORE??? ----- (hit keyboard)\n");
+        while(!kbhit())
+            ;
+        if(kbhit()) {
+#else
+        "\n");
+#endif
+
+            fprintf(stdout,
+            "VELOCITY:  speed of advance in infile, relative to outfile. (>=0)\n"
+            "           This is inverse of timestretch, (& permits infinite timestretch).\n"
+            "DENSITY:   amount of grain overlap (>0 : <1 leaves intergrain silence)\n"
+            "           Extremely small values will cease to perform predictably.\n"
+            "GRAINSIZE: grainsize in MS (must be > 2 * splicelen) (Default %.0lf)\n"
+            "PITCHSHIFT:is pitchshift in +|- (fractions of) semitones.\n"
+            "AMP:       is gain on grains (range 0-1)             (Default 1.0)\n"
+            "           use only if you want amp to vary (over a range &/or in time)\n"
+            "BSPLICE:   length of startsplices on grains,in MS (Default %.0lf)\n"
+            "ESPLICE:   length of endsplices   on grains,in MS (Default %.0lf)\n"
+            "SPACE:     set stereo position in outputfile. 0=L,1=R    (Range 0-1).\n"
+#ifndef MULTICHAN
+            "           Space flag on STEREO input, mixes it to mono before acting.\n"
+#else
+            "           Set space param to zero, to force multichan output.\n"
+            "           Otherwise multichan input mixes to mono\n"
+            "           (or selects 1 channel of your choice - see below)\n"
+            "           before generating a spatialised stereo output.\n"
+#endif
+            "RANGE:     of search for nextgrain, before infile 'now'  (Default 0 MS).\n"
+            "JITTER:    Randomisation of grain position (Range 0-1) Default (%.2lf).\n"
+            "OUTLENGTH: maximum outfile length (if end of data not reached).\n"
+            "           Set to zero (Default) for this parameter to be ignored.\n"
+            "           BUT if VELOCITY is ANYWHERE 0: OUTLENGTH must be given.\n"
+#ifndef MULTICHAN
+            "CHANNEL    Extract & work on just 1 channel of stereo snd: Range(1-2).\n"
+#else
+            "CHANNEL    Extract/work on 1 chan of multichan snd: Range(1-chancnt) OR\n"
+            "           (For -ve values) e.g. val -N, spatialise to N-channel space.\n"
+#endif
+            "           Set to zero (Default) for this parameter to be ignored.\n"
+            "-x:        do exponential splices           (Default: linear).\n"
+            "-n:        no interpolation for pitch vals, (quick but dirty).\n"
+            "\n"
+            "HVELOCITY,HDENSITY,HGRAINSIZE,HPITCHSHIFT,HAMP,HBSPLICE,HESPLICE,HSPACE\n"
+            "allow a range of values to be specified for any of these params. e.g. With\n"
+            "PITCHSHIFT & HPITCHSHIFT set, random pitchshift chosen between these limits.\n"
+            "AND NB PITCHSHIFT & HPITCHSHIFT can both vary through time.\n\n"
+            "All params, except OUTLENGTH and CHANNEL, can vary through time.\n",
+            GRS_DEFAULT_GRAINSIZE,GRS_DEFAULT_SPLICELEN,GRS_DEFAULT_SPLICELEN,GRS_DEFAULT_SCATTER);
+
+#ifdef IS_PC
+        }
+#endif
+
+     } else if (!strcmp(str,"sausage")) {
+        fprintf(stdout, 
+        "GRANULAR RECONSTITUTION OF SEVERAL SOUNDFILES SCRAMBLED TOGETHER.\n\n"
+//TW temporary cmdline restriction
+        "USAGE       (name of outfile must NOT end with a '1')\n"
+        "modify sausage infile [infile2 ...] outfile velocity density\n"
+        "  hvelocity hdensity grainsize  pitchshift  amp  space  bsplice  esplice\n"
+        "  hgrainsize hpitchshift hamp hspace hbsplice hesplice\n"
+        "  [-rrange] [-jjitter] [-loutlength] [-cchannel] [-d] [-x] [-n]\n\n"
+        "VELOCITY:  speed of advance in infiles, relative to outfile. (>=0)\n"
+        "           inverse of timestretch, (permits infinite timestretch).\n"
+        "DENSITY:   grain overlap (>0 : <1 leaves intergrain silence)\n"
+        "           Extremely small values don't perform predictably.\n"
+        "GRAINSIZE: grainsize in MS (must be > 2 * splicelen) (Default %.0lf)\n"
+        "PITCHSHIFT:pitchshift in +|- (fractions of) semitones.\n"
+        "AMP:       gain on grains (range 0-1) (Default 1.0)\n"
+        "           use if amp variation required (over a range &/or in time)\n"
+        "BSPLICE:   grain-startsplice length,in MS (Default %.0lf)\n"
+        "ESPLICE:   grain-endsplice length,in MS (Default %.0lf)\n"
+        "SPACE:     stereo position in outputfile. 0=L,1=R    (Range 0-1).\n"
+#ifndef MULTICHAN
+        "           Space flag on STEREO input, mixes to mono before acting.\n"
+#else
+        "           Set all space params to zero, to force multichan output.\n"
+        "           Otherwise multichan input mixes to mono\n"
+        "           (or selects 1 channel of your choice - see below)\n"
+        "           before generating a spatialised stereo output.\n"
+#endif
+        "RANGE:     of search for nextgrain, before infile 'now'  (Default 0 MS).\n"
+        "JITTER:    Randomisation of grain position (Range 0-1) Default (%.2lf).\n"
+        "OUTLENGTH: max outfile length (if end of data not reached).\n"
+        "           Set to zero (Default) to ignore.\n"
+        "           BUT if VELOCITY is ANYWHERE 0: OUTLENGTH must be given.\n"
+#ifndef MULTICHAN
+        "CHANNEL:   work on just 1 channel of stereo snd: Range(1-2).\n"
+#else
+        "CHANNEL:   work on just 1 chan of multichan snd: Range(1-chancnt).\n"
+        "           or (for -ve vals) e.g val -N, spatialise to N-channel space.\n"
+#endif
+        "           Set to zero (Default) to ignore.\n"
+        "-x:        do exponential splices           (Default: linear).\n"
+        "-n:        no interpolation for pitch vals, (quick but dirty).\n"
+        "\n"
+        "HVELOCITY,HDENSITY,HGRAINSIZE,HPITCHSHIFT,HAMP,HBSPLICE,HESPLICE,HSPACE\n"
+        "allow a range of values to be specified for any of these params. e.g. With\n"
+        "PITCHSHIFT & HPITCHSHIFT set, random pitchshift chosen between these limits.\n"
+        "AND NB PITCHSHIFT & HPITCHSHIFT can both vary through time.\n\n"
+        "All params, except OUTLENGTH and CHANNEL, can vary through time.\n",
+        GRS_DEFAULT_GRAINSIZE,GRS_DEFAULT_SPLICELEN,GRS_DEFAULT_SPLICELEN,GRS_DEFAULT_SCATTER);
+    } else
+        fprintf(stdout,"Unknown option '%s'\n",str);
+    return(USAGE_ONLY);
+}
+
+/******************************** USAGE3 ********************************/
+
+int usage3(char *str1,char *str2)
+{
+    sprintf(errstr,"Insufficient parameters on command line.\n");
+    return(USAGE_ONLY);
+}
+
+/******************************** SINTAB_PCONSISTENCY  ********************************/
+
+int sintab_pconsistency(dataptr dz)
+{
+    int exit_status;
+    double val;
+    if(dz->brksize[SIN_FRQ]) {
+        if((exit_status = get_maxvalue(SIN_FRQ,&val,dz))<0)
+            return exit_status;
+    } else
+        val = dz->param[SIN_FRQ];
+//TW SIN_FRQ parameter is actually the duration of a cycle = 1/frq. already
+//  val = 1.0/val;
+    val /= 2.0;
+    if (val <= dz->param[SIN_QUANT]) {
+        sprintf(errstr,"You must reduce the quantisation time to handle the maximum frequency you've specified.\n");
+        return(DATA_ERROR);
+    }
+    return(FINISHED);
+}
+
+/******************************** INNER_LOOP (redundant)  ********************************/
+
+int inner_loop
+(int *peakscore,int *descnt,int *in_start_portion,int *least,int *pitchcnt,int windows_in_buf,dataptr dz)
+{
+    return(FINISHED);
+}
+
+/******************************** READ_STACKDATA ********************************/
+
+#define SMALLARRAY 16
+
+int read_stackdata(char *str,dataptr dz)
+{
+    aplptr ap = dz->application;
+    int do_file = 0;
+    int arraysize = SMALLARRAY;
+    double *p, dummy = 0.0;
+    char temp[200], *q;
+    int n = 0, m;
+    FILE *fp;
+
+    if(!sloom) {                
+    /* NEW CMDLINE convention: filenames CAN start with numbers: */
+    /* BUT can't BE numbers in their entirety (e.g. 123.456) */
+        if(value_is_numeric(str)) {
+            if(sscanf(str,"%lf",&dummy)!=1) {
+                sprintf(errstr,"Failed to read a numeric value [%s] for transposition\n",str);
+                return(DATA_ERROR);
+            }
+        } else {
+//TW Now traps bad pathnames, and names starting with '-', only
+            if(file_has_invalid_startchar(str)) {
+                sprintf(errstr,"Invalid characters in filename '%s'\n",str);
+                return(DATA_ERROR);
+            }
+            do_file = 1;
+        }   
+    } else {                    /* TK convention, all numeric values are preceded by NUMERICVAL_MARKER */
+        if(str[0]==NUMERICVAL_MARKER) {      
+            str++;              
+            if(strlen(str)<=0 || sscanf(str,"%lf",&dummy)!=1) {
+                sprintf(errstr,"Invalid parameter value (%s) encountered.\n",str);
+                return(DATA_ERROR);
+            }
+        } else 
+            do_file = 1;
+    }
+    if(do_file) {
+        if((fp = fopen(str,"r"))==NULL) {
+            sprintf(errstr, "Can't open datafile %s to read data.\n",str);
+            return(DATA_ERROR);
+        }
+        if((dz->parray[STACK_TRANS] = (double *)malloc(arraysize * sizeof(double)))==NULL) {
+            sprintf(errstr,"INSUFFICIENT MEMORY for transposition data in file %s.\n",str);
+            return(MEMORY_ERROR);
+        }
+        p = dz->parray[STACK_TRANS];
+        while(fgets(temp,200,fp)==temp) {
+            q = temp;
+            if(*q == ';')   //  Allow comments in file
+                continue;
+            while(get_float_from_within_string(&q,p)) {
+                if(*p < ap->min_special || *p > ap->max_special) {
+                    sprintf(errstr,"Transposition value no %ld (%lf) out of range (%lf to %lf)\n",
+                        n+1L,*p,ap->min_special,ap->max_special);
+                    return(DATA_ERROR);
+                }
+                *p = semitone_to_ratio(*p);
+                p++;
+                if(++n >= arraysize) {
+                    arraysize += SMALLARRAY;
+                    if((dz->parray[STACK_TRANS] = 
+                    (double *)realloc((char *)(dz->parray[STACK_TRANS]),arraysize * sizeof(double)))==NULL) {
+                        sprintf(errstr,"INSUFFICIENT MEMORY to reallocate transposition data from file %s.\n",str);
+                        return(MEMORY_ERROR);
+                    }
+                    p = dz->parray[STACK_TRANS] + n;        
+                }
+            }
+        }       
+        if(n == 0) {
+            sprintf(errstr,"No data in file %s\n",str);
+            return(DATA_ERROR);
+        }
+        if((dz->parray[STACK_TRANS] = (double *)realloc((char *)(dz->parray[STACK_TRANS]),n * sizeof(double)))==NULL) {
+            sprintf(errstr,"INSUFFICIENT MEMORY to reallocate transposition data from file %s.\n",str);
+            return(MEMORY_ERROR);
+        }
+        if(fclose(fp)<0) {
+            fprintf(stdout,"WARNING: Failed to close transposition file %s.\n",str);
+            fflush(stdout);
+        }
+        dz->itemcnt = n;
+        p = dz->parray[STACK_TRANS];        /* sort : smallest at foot */
+        for(n=0;n<dz->itemcnt-1;n++) {
+            for(m=1;m<dz->itemcnt;m++) {
+                if(p[m] < p[n]) {
+                    dummy = p[n];
+                    p[n]  = p[m];
+                    p[m]  = dummy;
+                }
+            }
+        }
+    } else  {
+        if(dummy > ap->max_special || dummy < ap->min_special) {
+            sprintf(errstr,"Transposition value (%lf) out of range (%lf to %lf)\n",
+            dummy,ap->min_special,ap->max_special);
+                return(DATA_ERROR);
+        }
+        dummy = semitone_to_ratio(dummy);
+        if((dz->parray[STACK_TRANS] = (double *)malloc(sizeof(double)))==NULL) {
+            sprintf(errstr,"INSUFFICIENT MEMORY for transposition data\n");
+            return(MEMORY_ERROR);
+        }
+        dz->parray[STACK_TRANS][0] = dummy;
+        dz->itemcnt = 0;
+    }
+    return(FINISHED);
+}
+
+/******************************** SEMITONE_TO_RATIO ********************************/
+
+double semitone_to_ratio(double val) {
+    val /= 12.0;
+    val = pow(2.0,val);
+    return val;
+}
+
+/******************************** CONVOLVE_PCONSISTENCY ********************************/
+
+int convolve_pconsistency(dataptr dz)
+{
+    int exit_status;
+    double minval;
+    switch(dz->mode) {
+    case(CONV_NORMAL):
+        if(dz->insams[1] > dz->insams[0]) {
+            sprintf(errstr,"Convolving file cannot be larger than file to be convolved.\n");
+            return(DATA_ERROR);
+        }
+        break;
+    case(CONV_TVAR):
+        if(dz->brksize[CONV_TRANS]) {
+            if((exit_status = get_minvalue_in_brktable(&minval,CONV_TRANS,dz))<0)
+                return(exit_status);
+        } else
+            minval = dz->param[CONV_TRANS];
+        if(((double)dz->insams[1]/minval) > (double)(dz->insams[0])) {
+            sprintf(errstr,"Convolving file, at lowest transposition, cannot be larger than file to be convolved.\n");
+            return(DATA_ERROR);
+        }
+        break;
+    }
+    return(FINISHED);
+}
+
+/******************************** CREATE_CONVOLVE_BUFS ********************************/
+
+//TW ADDED AND CONVERTED
+int create_convolve_bufs(dataptr dz)
+{
+    int bigbufsize, seccnt, cfile_len, cfile_size = dz->insams[1] * sizeof(float),total_bufsize;
+    double limit;
+    int sum;
+    int fsecbytesize = F_SECSIZE * sizeof(float);
+
+    if(cfile_size < 0) {
+        sprintf(errstr,"Size of convolving file will cause numerical overflow in calculating required memory space.\n");
+        return(MEMORY_ERROR);
+    }
+    seccnt = cfile_size/fsecbytesize;
+    if(seccnt * fsecbytesize < cfile_size)
+        seccnt++;
+    cfile_size = seccnt * fsecbytesize;
+    if(cfile_size < 0) {
+        sprintf(errstr,"Size of convolving file will cause numerical overflow in calculating required memory space.\n");
+        return(MEMORY_ERROR);
+    }
+    if((bigbufsize = (int)((long)Malloc(-1))) < cfile_size)
+        bigbufsize = cfile_size;
+    else {
+        seccnt = bigbufsize/fsecbytesize;
+        if(seccnt * fsecbytesize < bigbufsize)
+            seccnt++;
+        bigbufsize = seccnt * fsecbytesize;
+    }
+    if(bigbufsize < 0) {
+        sprintf(errstr,"Insufficient memory for sound buffers.\n");
+        return(MEMORY_ERROR);
+    }
+    cfile_size += (dz->infile->channels * sizeof(float));   /* additional space for wrap_around points */
+    if(cfile_size < 0) {
+        sprintf(errstr,"Size of convolving file will cause numerical overflow in calculating required memory space.\n");
+        return(MEMORY_ERROR);
+    }
+    if((total_bufsize = bigbufsize * 2) < 0) {
+        sprintf(errstr,"Insufficient memory for sound buffers.\n");
+        return(MEMORY_ERROR);
+    }
+#if 0
+    if((total_bufsize += cfile_size) < total_bufsize) {
+        sprintf(errstr,"Size of convolving file will cause numerical overflow in calculating required memory space.\n");
+        return(MEMORY_ERROR);
+    }
+#endif
+    dz->buflen = bigbufsize/sizeof(float);
+    if((dz->bigbuf = (float *)Malloc(total_bufsize)) <= 0) {
+        sprintf(errstr,"Insufficient memory for sound buffers.\n");
+        return(MEMORY_ERROR);
+    }
+    cfile_len = cfile_size/sizeof(float);
+    dz->sampbuf[0] = dz->bigbuf;
+    dz->sampbuf[1] = dz->sampbuf[0] + dz->buflen;
+    dz->sampbuf[2] = dz->sampbuf[1] + cfile_len;
+    memset(dz->bigbuf,0,((dz->buflen * 2) + cfile_len) * sizeof(float));
+    sum = dz->buflen + dz->insams[1]; /* total no. of vals convolving buffer of 1st file with all 2nd file */
+    if((dz->tempsize = dz->insams[0] + dz->insams[1]) < 0)
+        dz->tempsize = INT_MAX;
+    limit = floor((double) INT_MAX/(double)sizeof(double));
+    if((double)sum > limit) {
+        sprintf(errstr,"Size of convolving file will cause numerical overflow in calculating required memory space.\n");
+        return(MEMORY_ERROR);
+    }
+    if((dz->parray[0] = (double *)malloc(sum * sizeof(double)))==NULL) {
+        sprintf(errstr,"Insufficent memory for convolve calculations buffer.\n");
+        return(MEMORY_ERROR);
+    }
+    memset((char *)dz->parray[0],0,sum * sizeof(double));
+    return(FINISHED);
+}
+
+/******************************** READ_LOUDNESS ********************************/
+
+int read_loudness(char *str,dataptr dz)
+{
+    int istime, exit_status;
+    int arraysize = BIGARRAY;
+    double *p, lasttime = 0;
+    char temp[200], *q;
+    int n = 0;
+    FILE *fp;
+
+    if((fp = fopen(str,"r"))==NULL) {
+        sprintf(errstr, "Can't open datafile %s to read data.\n",str);
+        return(DATA_ERROR);
+    }
+    if((exit_status = setup_and_init_brktable_constants(dz)) < 0)
+        return(exit_status);
+    if((dz->brk[LOUD_GAIN] = (double *)malloc(arraysize * sizeof(double)))==NULL) {
+        sprintf(errstr,"Cannot create memory for loudness breaktable\n");
+        return(MEMORY_ERROR);
+    }
+    p = dz->brk[LOUD_GAIN];
+    istime = 1;
+    while(fgets(temp,200,fp)==temp) {
+        q = temp;
+        if(*q == ';')   //  Allow comments in file
+            continue;
+        while(get_float_from_within_string(&q,p)) {
+            if(istime) {
+                if(*p < 0.0) {
+                    sprintf(errstr,"INVALID TIME (%lf) IN LOUDNESS ENVELOPE DATA.\n",*p);
+                    return(DATA_ERROR);
+                }
+                if(n == 0) {
+                    if(!flteq(*p,0.0)) {
+                        sprintf(errstr,"LOUDNESS ENVELOPE MUST BEGIN AT TIME ZERO.\n");
+                        return(DATA_ERROR);
+                    }
+                } else if(*p <= lasttime) {
+                    sprintf(errstr,"TIMES DO NOT ADVANCE IN LOUDNESS ENVELOPE (AT TIME %lf)\n",*p);
+                    return(DATA_ERROR);
+                }
+                lasttime = *p;
+            } else {
+                switch(dz->mode) {
+                case(LOUD_PROPOR):
+                    if(*p < 0.0) {
+                        sprintf(errstr,"INVALID LOUDNESS VALUE (%lf) IN LOUDNESS ENVELOPE DATA.\n",*p);
+                        return(DATA_ERROR);
+                    }
+                    break;
+                case(LOUD_DB_PROPOR):
+                    *p = dbtogain(*p);
+                    break;
+                }
+            }
+            p++;
+            if(++n >= arraysize) {
+                arraysize += BIGARRAY;
+                if((dz->brk[LOUD_GAIN] = (double *)realloc((char *)(dz->brk[LOUD_GAIN]),arraysize * sizeof(double)))==NULL) {
+                    sprintf(errstr,"INSUFFICIENT MEMORY to reallocate loudness data from file %s.\n",str);
+                    return(MEMORY_ERROR);
+                }
+                p = dz->brk[LOUD_GAIN] + n;     
+            }
+            istime = !istime;
+        }
+    }
+    if((dz->brk[LOUD_GAIN] = (double *)realloc((char *)(dz->brk[LOUD_GAIN]),n * sizeof(double)))==NULL) {
+        sprintf(errstr,"INSUFFICIENT MEMORY to reallocate loudness data from file %s.\n",str);
+        return(MEMORY_ERROR);
+    }
+    if(fclose(fp)<0) {
+        fprintf(stdout,"WARNING: Failed to close loudness file %s.\n",str);
+        fflush(stdout);
+    }
+    if(n == 0) {
+        sprintf(errstr,"No data in file %s\n",str);
+        return(DATA_ERROR);
+    }
+    if(!EVEN(n)) {
+        sprintf(errstr,"LOUDNESS ENVELOPE DATA INCORRECTLY PAIRED IN FILE %s.\n",str);
+        return(DATA_ERROR);
+    }
+    dz->brksize[0] = n/2;
+    return(FINISHED);
+}
+
+/******************************** SETUP_AND_INIT_BRKTABLE_CONSTANTS ********************************/
+
+int setup_and_init_brktable_constants(dataptr dz)
+{
+    if((dz->brk      = (double **)malloc(sizeof(double *)))==NULL) {
+        sprintf(errstr,"setup_and_init_input_brktable_constants(): 1\n");
+        return(MEMORY_ERROR);
+    }
+    if((dz->brkptr   = (double **)malloc(sizeof(double *)))==NULL) {
+        sprintf(errstr,"setup_and_init_input_brktable_constants(): 6\n");
+        return(MEMORY_ERROR);
+    }
+    if((dz->brksize  = (int    *)malloc(sizeof(int)    ))==NULL) {
+        sprintf(errstr,"setup_and_init_input_brktable_constants(): 2\n");
+        return(MEMORY_ERROR);
+    }
+    if((dz->firstval = (double  *)malloc(sizeof(double)  ))==NULL) {
+        sprintf(errstr,"setup_and_init_input_brktable_constants(): 3\n");
+        return(MEMORY_ERROR);                                                 
+    }
+    if((dz->lastind  = (double  *)malloc(sizeof(double)  ))==NULL) {
+        sprintf(errstr,"setup_and_init_input_brktable_constants(): 4\n");
+        return(MEMORY_ERROR);
+    }
+    if((dz->lastval  = (double  *)malloc(sizeof(double)  ))==NULL) {
+        sprintf(errstr,"setup_and_init_input_brktable_constants(): 5\n");
+        return(MEMORY_ERROR);
+    }
+    if((dz->brkinit  = (int     *)malloc(sizeof(int)     ))==NULL) {
+        sprintf(errstr,"setup_and_init_input_brktable_constants(): 7\n");
+        return(MEMORY_ERROR);
+    }
+    dz->brk[0]     = NULL;
+    dz->brkptr[0]  = NULL;
+    dz->brkinit[0] = 0;
+    dz->brksize[0] = 0;
+    return(FINISHED);
+}

+ 999 - 0
dev/modify/brapcon.c

@@ -0,0 +1,999 @@
+/*
+ * Copyright (c) 1983-2013 Trevor Wishart and Composers Desktop Project Ltd
+ * http://www.trevorwishart.co.uk
+ * http://www.composersdesktop.com
+ *
+ This file is part of the CDP System.
+
+    The CDP System is free software; you can redistribute it
+    and/or modify it under the terms of the GNU Lesser General Public
+    License as published by the Free Software Foundation; either
+    version 2.1 of the License, or (at your option) any later version.
+
+    The CDP System is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public
+    License along with the CDP System; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+    02111-1307 USA
+ *
+ */
+
+
+
+/* floatsam version*/
+#include <stdio.h>
+#include <stdlib.h>
+#include <limits.h>
+#include <structures.h>
+#include <tkglobals.h>
+#include <globcon.h>
+#include <processno.h>
+#include <modeno.h>
+#include <arrays.h>
+#include <modify.h>
+
+#include <sfsys.h>
+#include <osbind.h>
+
+#if defined unix || defined __GNUC__
+#define round(x) lround((x))
+#endif
+
+#define SAFETY   ((long)4096)
+#define OSAFETY  ((long)256)
+static int  initialise_unused_brassage_vflags(dataptr dz);
+static void initialise_user_inaccessible_params(dataptr dz);
+static void param_check_and_convert(int *zerovel,dataptr dz);
+static void convert_pitch(int paramno,dataptr dz);
+static int  initialise_data(dataptr dz);
+static int  set_internal_flags(dataptr dz);
+static void initialise_channel_configuration(dataptr dz);
+static int  granula_setup(dataptr dz);
+static int  check_for_zeroes(int paramno,dataptr dz);
+static void convert_value_to_int(int paramno,double convertor,dataptr dz);
+static int  make_splice_tables(dataptr dz);
+static void set_ranges(dataptr dz);
+static int  calc_overflows(dataptr dz);
+static void set_this_range(int rangeno,int hino, int lono, int flagno, dataptr dz);
+static void set_this_drange(int rangeno,int hino, int lono, int flagno, dataptr dz);
+static int  calc_max_scatter(int mgi,long *max_scatlen, dataptr dz);
+static void adjust_overflows(long mscat, dataptr dz);
+#ifdef MULTICHAN
+static int check_spatialisation_data(dataptr dz);
+#endif
+
+/********************************* GRANULA_PCONSISTENCY *************************************/
+
+int granula_pconsistency(dataptr dz)
+{
+	int exit_status;
+	int zerovel      = FALSE;
+	int total_flags  = SFLAGCNT+FLAGCNT;
+/*	int total_params = dz->application->max_param_cnt + dz->application->option_cnt;*/
+	int n;
+	long min_infilesize = LONG_MAX;
+
+	initrand48();
+
+	if(dz->application->vflag_cnt < GRS_MAX_VFLAGS
+	&&(exit_status = initialise_unused_brassage_vflags(dz))<0) 
+		return(exit_status);	/* Create flags inaccessible to user in certain modes */
+
+	initialise_user_inaccessible_params(dz);
+
+	switch(dz->process) {	/* infilesize counted in mono samples OR STEREO sample-pairs */
+	case(BRASSAGE):
+    	dz->iparam[ORIG_SMPSIZE] = dz->insams[0]/dz->infile->channels;
+		break;					 
+	case(SAUSAGE):
+		for(n=0;n<dz->infilecnt;n++)	
+			min_infilesize = min(min_infilesize,dz->insams[n]);
+		if(min_infilesize == LONG_MAX) {
+			sprintf(errstr,"Problem estimating min infilesize.\n");
+			return(PROGRAM_ERROR);
+		}
+    	dz->iparam[ORIG_SMPSIZE] = min_infilesize/dz->infile->channels;
+		break;					 
+	}
+	if((dz->iparray[GRS_FLAGS]=(int *)malloc(total_flags * sizeof(int)))==NULL) {
+		sprintf(errstr,"INSUFFICEINT MEMORY for brassage internal flags.\n");
+		return(MEMORY_ERROR);		/* establish internal flagging */
+	}
+	for(n=0;n<total_flags;n++)
+		dz->iparray[GRS_FLAGS][n] = 0;
+
+	param_check_and_convert(&zerovel,dz);
+
+	if(sloom) {
+		if(zerovel) {
+		 	if(dz->mode == GRS_TIMESTRETCH) {
+				fprintf(stdout,"INFO: Infinite time-stretch (zero squeeze) found : Creating file of length 2.0 secs\n");
+			 	fflush(stdout);
+				dz->param[GRS_OUTLEN] = 2.0;
+/* NEW Mar 24: 2002*/
+				dz->brksize[GRS_OUTLEN] = 0;
+				convert_value_to_int(GRS_OUTLEN,(double)dz->infile->srate,dz);
+			} else if(dz->param[GRS_OUTLEN] == 0.0) {
+				sprintf(errstr,	"Infinite time-stretch (zero squeeze) found : Outfile length must be specified.\n");
+				return(USER_ERROR);
+			}
+		}
+	} else {
+		if(zerovel && dz->param[GRS_OUTLEN]==0.0) {
+			sprintf(errstr,	"Zero VELOCITY found: Outfile length must be specified.\n");
+			return(USER_ERROR);
+		}
+	}
+
+#ifdef MULTICHAN
+	dz->out_chans = 2;
+	if (dz->iparam[GRS_CHAN_TO_XTRACT] < 0) {	/* setup multichan output */
+		dz->out_chans = -dz->iparam[GRS_CHAN_TO_XTRACT];	
+		dz->iparam[GRS_CHAN_TO_XTRACT] = 0;		/* Force input to mix to mono (if not mono already) */
+	}
+	if((exit_status = check_spatialisation_data(dz))<0)
+		return(exit_status);
+#endif
+	if(dz->infile->channels ==MONO)
+		dz->iparam[GRS_CHAN_TO_XTRACT] = 0;		/* even if user has set it, in error */
+
+	convert_pitch(GRS_PITCH,dz);
+	convert_pitch(GRS_HPITCH,dz);
+
+	dz->iparam[GRS_ARRAYSIZE] = BIGARRAY;
+	if((exit_status = initialise_data(dz))<0) 			/* before setup_environment */
+		return(exit_status);
+	if((exit_status = set_internal_flags(dz))<0)
+		return(exit_status);
+	initialise_channel_configuration(dz);
+#ifndef MULTICHAN
+	dz->infile->channels = dz->iparam[GRS_OUTCHANS];	/* set channel count for OUTPUT */
+#else
+	dz->outfile->channels = dz->iparam[GRS_OUTCHANS];	/* preset channel count for OUTPUT */
+#endif
+
+	if((exit_status = granula_setup(dz))<0)
+		return(exit_status);							/* has to be done before buffers.c */
+	if(dz->process==SAUSAGE) {
+		dz->bufcnt += (dz->infilecnt * 2);
+		if((dz->sampbuf = (float **)realloc((char *)dz->sampbuf,dz->bufcnt * sizeof(float *)))==NULL
+		|| (dz->sbufptr = (float **)realloc((char *)dz->sbufptr,dz->bufcnt * sizeof(float *)))==NULL) {
+			sprintf(errstr,"INSUFFICIENT MEMORY to reallocate space for sausage.\n");
+			return(MEMORY_ERROR);
+		}
+	}
+	return(FINISHED);
+}
+
+/************************* INITIALISE_UNUSED_BRASSAGE_VFLAGS *************************/
+
+int initialise_unused_brassage_vflags(dataptr dz)
+{
+	int n;
+	if(dz->vflag==NULL) {
+		if((dz->vflag  = (char *)malloc(GRS_MAX_VFLAGS * sizeof(char)))==NULL) {
+			sprintf(errstr,"INSUFFICEINT MEMORY for brassage flags.\n");
+			return(MEMORY_ERROR);
+		}
+	} else {
+		if((dz->vflag  = (char *)realloc(dz->vflag,GRS_MAX_VFLAGS * sizeof(char)))==NULL) {
+			sprintf(errstr,"INSUFFICEINT MEMORY to reallocate brassage flags.\n");
+			return(MEMORY_ERROR);
+		}
+	}
+	for(n=dz->application->vflag_cnt;n<GRS_MAX_VFLAGS;n++) 
+		dz->vflag[n]  = FALSE;
+	return(FINISHED);
+}
+
+/************************* INITIALISE_USER_INACCESSIBLE_PARAMS *************************/
+
+void initialise_user_inaccessible_params(dataptr dz)
+{
+	switch(dz->mode) {
+	case(GRS_PITCHSHIFT):	
+	case(GRS_TIMESTRETCH):		/* Initialise search param, inaccessible to user in these modes */
+	case(GRS_GRANULATE):
+	 	dz->param[GRS_SRCHRANGE] = 0.0;		/* NOT STRICTLY NECESSARY: as should not be used */
+		/* fall thro */
+	case(GRS_REVERB):			/* Initialise scatter param, inaccessible to user in these modes */
+	case(GRS_SCRAMBLE):		
+	    dz->param[GRS_SCATTER]  = GRS_DEFAULT_SCATTER;
+		break;
+	}
+}
+
+/************************** PARAM_CHECK_AND_CONVERT ************************************/
+
+void param_check_and_convert(int *zerovel,dataptr dz)
+{
+	double sr = (double)dz->infile->srate;
+	int paramno, total_params = dz->application->max_param_cnt + dz->application->option_cnt;
+	for(paramno = 0;paramno < total_params; paramno++) {
+		switch(paramno) {
+		case(GRS_VELOCITY):
+		case(GRS_HVELOCITY):
+			if(*zerovel == FALSE)
+				*zerovel = check_for_zeroes(paramno,dz);
+			break;	
+		case(GRS_AMP):
+		case(GRS_HAMP):
+			/* not required for floats */
+			/*convert_value_to_int(paramno,TWO_POW_15,dz);*/
+			break;
+		case(GRS_OUTLEN):
+			convert_value_to_int(paramno,sr,dz);
+			break;
+		case(GRS_SRCHRANGE):
+		case(GRS_GRAINSIZE):
+		case(GRS_HGRAINSIZE):
+		case(GRS_BSPLICE):
+		case(GRS_HBSPLICE):
+		case(GRS_ESPLICE):
+		case(GRS_HESPLICE):
+			convert_value_to_int(paramno,MS_TO_SECS * sr,dz);
+			break;						 
+		}
+	}
+}
+
+/************************** CONVERT_PITCH ************************************/
+
+void convert_pitch(int paramno,dataptr dz)
+{
+	double *p, *end;
+	if(dz->brksize[paramno]) {
+		p   = dz->brk[paramno] + 1;		
+		end = dz->brk[paramno] + (dz->brksize[paramno] * 2);
+		while(p < end) {
+			*p *= OCTAVES_PER_SEMITONE;
+			p += 2;
+		}
+	} else
+		dz->param[paramno] = dz->param[paramno] * OCTAVES_PER_SEMITONE;
+}
+
+/******************************* INITIALISE_DATA **************************/
+
+int initialise_data(dataptr dz)
+{
+	/* NEED TO BE INITALISED (??) AS THEY ARE INTERNAL */
+	dz->param[GRS_VRANGE] 		= 0.0;
+	dz->param[GRS_DRANGE] 		= 0.0;
+	dz->param[GRS_PRANGE]		= 0.0;
+	dz->param[GRS_SPRANGE]		= 0.0;
+	dz->iparam[GRS_ARANGE] 		= 0;
+	dz->iparam[GRS_GRANGE] 		= 0;
+	dz->iparam[GRS_BRANGE]		= 0;
+	dz->iparam[GRS_ERANGE]		= 0;
+	dz->iparam[GRS_LONGS_BUFLEN]= 0;
+	dz->iparam[GRS_BUF_XS] 		= 0;
+	dz->iparam[GRS_LBUF_XS] 	= 0;
+	dz->iparam[GRS_BUF_SMPXS] 	= 0;
+	dz->iparam[GRS_LBUF_SMPXS] 	= 0;
+	dz->iparam[GRS_GLBUF_SMPXS] = 0;
+	dz->iparam[SAMPS_IN_INBUF]  = 0;
+
+	dz->iparam[GRS_IS_BTAB]		= FALSE;
+	dz->iparam[GRS_IS_ETAB]		= FALSE;
+																		
+    if((dz->parray[GRS_NORMFACT] = (double *)malloc(dz->iparam[GRS_ARRAYSIZE] * sizeof(double)))==NULL) {
+		sprintf(errstr,"initialise_data()\n");
+		return(PROGRAM_ERROR);
+	}
+	return(FINISHED);
+}
+
+/************************** SET_INTERNAL_FLAGS ************************************/
+
+int set_internal_flags(dataptr dz)
+{
+	if(dz->process==SAUSAGE) {
+		if(dz->brksize[GRS_HVELOCITY])  dz->iparray[GRS_FLAGS][G_VELOCITY_FLAG]  |= G_VARIABLE_HI_BOUND;
+		else 							dz->iparray[GRS_FLAGS][G_VELOCITY_FLAG]  |= G_HI_BOUND;
+
+		if(dz->brksize[GRS_HDENSITY])   dz->iparray[GRS_FLAGS][G_DENSITY_FLAG]   |= G_VARIABLE_HI_BOUND;
+		else 							dz->iparray[GRS_FLAGS][G_DENSITY_FLAG]   |= G_HI_BOUND;
+
+		if(dz->brksize[GRS_HGRAINSIZE]) dz->iparray[GRS_FLAGS][G_GRAINSIZE_FLAG] |= G_VARIABLE_HI_BOUND;
+		else  							dz->iparray[GRS_FLAGS][G_GRAINSIZE_FLAG] |= G_HI_BOUND;
+
+		if(dz->brksize[GRS_HPITCH])  	dz->iparray[GRS_FLAGS][G_PITCH_FLAG]     |= G_VARIABLE_HI_BOUND;
+		else 							dz->iparray[GRS_FLAGS][G_PITCH_FLAG]     |= G_HI_BOUND;
+
+		if(dz->brksize[GRS_HAMP])  		dz->iparray[GRS_FLAGS][G_AMP_FLAG]       |= G_VARIABLE_HI_BOUND;
+		else 							dz->iparray[GRS_FLAGS][G_AMP_FLAG]       |= G_HI_BOUND;
+
+		if(dz->brksize[GRS_HSPACE])  	dz->iparray[GRS_FLAGS][G_SPACE_FLAG]     |= G_VARIABLE_HI_BOUND;
+		else 							dz->iparray[GRS_FLAGS][G_SPACE_FLAG]     |= G_HI_BOUND;
+
+		if(dz->brksize[GRS_HBSPLICE])  	dz->iparray[GRS_FLAGS][G_BSPLICE_FLAG]   |= G_VARIABLE_HI_BOUND;
+		else 							dz->iparray[GRS_FLAGS][G_BSPLICE_FLAG]   |= G_HI_BOUND;
+
+		if(dz->brksize[GRS_HESPLICE])  	dz->iparray[GRS_FLAGS][G_ESPLICE_FLAG]   |= G_VARIABLE_HI_BOUND;
+		else 							dz->iparray[GRS_FLAGS][G_ESPLICE_FLAG]   |= G_HI_BOUND;
+
+		if(dz->brksize[GRS_VELOCITY])	dz->iparray[GRS_FLAGS][G_VELOCITY_FLAG]  |= G_VARIABLE_VAL;
+		else							dz->iparray[GRS_FLAGS][G_VELOCITY_FLAG]  |= G_FIXED_VAL;
+
+		if(dz->brksize[GRS_DENSITY])	dz->iparray[GRS_FLAGS][G_DENSITY_FLAG]   |= G_VARIABLE_VAL;
+		else							dz->iparray[GRS_FLAGS][G_DENSITY_FLAG]   |= G_FIXED_VAL;
+
+		if(dz->brksize[GRS_GRAINSIZE])	dz->iparray[GRS_FLAGS][G_GRAINSIZE_FLAG] |= G_VARIABLE_VAL;
+		else							dz->iparray[GRS_FLAGS][G_GRAINSIZE_FLAG] |= G_FIXED_VAL;
+
+		if(dz->brksize[GRS_PITCH])		dz->iparray[GRS_FLAGS][G_PITCH_FLAG]     |= G_VARIABLE_VAL;
+		else							dz->iparray[GRS_FLAGS][G_PITCH_FLAG]     |= G_FIXED_VAL;
+
+		if(dz->brksize[GRS_AMP])		dz->iparray[GRS_FLAGS][G_AMP_FLAG]       |= G_VARIABLE_VAL;
+		else							dz->iparray[GRS_FLAGS][G_AMP_FLAG]       |= G_FIXED_VAL;
+
+		if(dz->brksize[GRS_SPACE])		dz->iparray[GRS_FLAGS][G_SPACE_FLAG]     |= G_VARIABLE_VAL;
+		else							dz->iparray[GRS_FLAGS][G_SPACE_FLAG]     |= G_FIXED_VAL;
+
+		if(dz->brksize[GRS_BSPLICE])	dz->iparray[GRS_FLAGS][G_BSPLICE_FLAG]   |= G_VARIABLE_VAL;
+		else							dz->iparray[GRS_FLAGS][G_BSPLICE_FLAG]   |= G_FIXED_VAL;
+
+		if(dz->brksize[GRS_ESPLICE])	dz->iparray[GRS_FLAGS][G_ESPLICE_FLAG]   |= G_VARIABLE_VAL;
+		else							dz->iparray[GRS_FLAGS][G_ESPLICE_FLAG]   |= G_FIXED_VAL;
+
+		if(dz->brksize[GRS_SRCHRANGE])	dz->iparray[GRS_FLAGS][G_RANGE_FLAG]     |= G_VARIABLE_VAL;
+		else							dz->iparray[GRS_FLAGS][G_RANGE_FLAG]     |= G_FIXED_VAL;
+
+		if(dz->brksize[GRS_SCATTER])	dz->iparray[GRS_FLAGS][G_SCATTER_FLAG]   |= G_VARIABLE_VAL;
+		else							dz->iparray[GRS_FLAGS][G_SCATTER_FLAG]   |= G_FIXED_VAL;
+
+		return(FINISHED);
+	}
+
+	switch(dz->mode) {
+	case(GRS_FULL_MONTY):
+		if(dz->brksize[GRS_HVELOCITY])  dz->iparray[GRS_FLAGS][G_VELOCITY_FLAG]  |= G_VARIABLE_HI_BOUND;
+		else 							dz->iparray[GRS_FLAGS][G_VELOCITY_FLAG]  |= G_HI_BOUND;
+
+		if(dz->brksize[GRS_HDENSITY])   dz->iparray[GRS_FLAGS][G_DENSITY_FLAG]   |= G_VARIABLE_HI_BOUND;
+		else 							dz->iparray[GRS_FLAGS][G_DENSITY_FLAG]   |= G_HI_BOUND;
+
+		if(dz->brksize[GRS_HGRAINSIZE]) dz->iparray[GRS_FLAGS][G_GRAINSIZE_FLAG] |= G_VARIABLE_HI_BOUND;
+		else  							dz->iparray[GRS_FLAGS][G_GRAINSIZE_FLAG] |= G_HI_BOUND;
+
+		if(dz->brksize[GRS_HPITCH])  	dz->iparray[GRS_FLAGS][G_PITCH_FLAG]     |= G_VARIABLE_HI_BOUND;
+		else 							dz->iparray[GRS_FLAGS][G_PITCH_FLAG]     |= G_HI_BOUND;
+
+		if(dz->brksize[GRS_HAMP])  		dz->iparray[GRS_FLAGS][G_AMP_FLAG]       |= G_VARIABLE_HI_BOUND;
+		else 							dz->iparray[GRS_FLAGS][G_AMP_FLAG]       |= G_HI_BOUND;
+
+		if(dz->brksize[GRS_HSPACE])  	dz->iparray[GRS_FLAGS][G_SPACE_FLAG]     |= G_VARIABLE_HI_BOUND;
+		else 							dz->iparray[GRS_FLAGS][G_SPACE_FLAG]     |= G_HI_BOUND;
+
+		if(dz->brksize[GRS_HBSPLICE])  	dz->iparray[GRS_FLAGS][G_BSPLICE_FLAG]   |= G_VARIABLE_HI_BOUND;
+		else 							dz->iparray[GRS_FLAGS][G_BSPLICE_FLAG]   |= G_HI_BOUND;
+
+		if(dz->brksize[GRS_HESPLICE])  	dz->iparray[GRS_FLAGS][G_ESPLICE_FLAG]   |= G_VARIABLE_HI_BOUND;
+		else 							dz->iparray[GRS_FLAGS][G_ESPLICE_FLAG]   |= G_HI_BOUND;
+		/* fall thro */
+	case(GRS_BRASSAGE):
+		if(dz->brksize[GRS_VELOCITY])	dz->iparray[GRS_FLAGS][G_VELOCITY_FLAG]  |= G_VARIABLE_VAL;
+		else							dz->iparray[GRS_FLAGS][G_VELOCITY_FLAG]  |= G_FIXED_VAL;
+
+		if(dz->brksize[GRS_DENSITY])	dz->iparray[GRS_FLAGS][G_DENSITY_FLAG]   |= G_VARIABLE_VAL;
+		else							dz->iparray[GRS_FLAGS][G_DENSITY_FLAG]   |= G_FIXED_VAL;
+
+		if(dz->brksize[GRS_GRAINSIZE])	dz->iparray[GRS_FLAGS][G_GRAINSIZE_FLAG] |= G_VARIABLE_VAL;
+		else							dz->iparray[GRS_FLAGS][G_GRAINSIZE_FLAG] |= G_FIXED_VAL;
+
+		if(dz->brksize[GRS_PITCH])		dz->iparray[GRS_FLAGS][G_PITCH_FLAG]     |= G_VARIABLE_VAL;
+		else							dz->iparray[GRS_FLAGS][G_PITCH_FLAG]     |= G_FIXED_VAL;
+
+		if(dz->brksize[GRS_AMP])		dz->iparray[GRS_FLAGS][G_AMP_FLAG]       |= G_VARIABLE_VAL;
+		else							dz->iparray[GRS_FLAGS][G_AMP_FLAG]       |= G_FIXED_VAL;
+
+		if(dz->brksize[GRS_SPACE])		dz->iparray[GRS_FLAGS][G_SPACE_FLAG]     |= G_VARIABLE_VAL;
+		else							dz->iparray[GRS_FLAGS][G_SPACE_FLAG]     |= G_FIXED_VAL;
+
+		if(dz->brksize[GRS_BSPLICE])	dz->iparray[GRS_FLAGS][G_BSPLICE_FLAG]   |= G_VARIABLE_VAL;
+		else							dz->iparray[GRS_FLAGS][G_BSPLICE_FLAG]   |= G_FIXED_VAL;
+
+		if(dz->brksize[GRS_ESPLICE])	dz->iparray[GRS_FLAGS][G_ESPLICE_FLAG]   |= G_VARIABLE_VAL;
+		else							dz->iparray[GRS_FLAGS][G_ESPLICE_FLAG]   |= G_FIXED_VAL;
+
+		if(dz->brksize[GRS_SRCHRANGE])	dz->iparray[GRS_FLAGS][G_RANGE_FLAG]     |= G_VARIABLE_VAL;
+		else							dz->iparray[GRS_FLAGS][G_RANGE_FLAG]     |= G_FIXED_VAL;
+
+		if(dz->brksize[GRS_SCATTER])	dz->iparray[GRS_FLAGS][G_SCATTER_FLAG]   |= G_VARIABLE_VAL;
+		else							dz->iparray[GRS_FLAGS][G_SCATTER_FLAG]   |= G_FIXED_VAL;
+
+		break;
+	case(GRS_PITCHSHIFT):
+		if(dz->brksize[GRS_PITCH])		dz->iparray[GRS_FLAGS][G_PITCH_FLAG]     |= G_VARIABLE_VAL;
+		else							dz->iparray[GRS_FLAGS][G_PITCH_FLAG]     |= G_FIXED_VAL;
+		dz->iparray[GRS_FLAGS][G_SCATTER_FLAG] |= G_FIXED_VAL;
+		break;
+	case(GRS_TIMESTRETCH):
+		if(dz->brksize[GRS_VELOCITY])   dz->iparray[GRS_FLAGS][G_VELOCITY_FLAG]  |= G_VARIABLE_VAL;
+		else						    dz->iparray[GRS_FLAGS][G_VELOCITY_FLAG]  |= G_FIXED_VAL;
+		dz->iparray[GRS_FLAGS][G_SCATTER_FLAG] |= G_FIXED_VAL;
+		break;
+	case(GRS_GRANULATE):
+		if(dz->brksize[GRS_DENSITY])	dz->iparray[GRS_FLAGS][G_DENSITY_FLAG]   |= G_VARIABLE_VAL;
+		else							dz->iparray[GRS_FLAGS][G_DENSITY_FLAG]   |= G_FIXED_VAL;
+		dz->iparray[GRS_FLAGS][G_SCATTER_FLAG] |= G_FIXED_VAL;
+		break;
+	case(GRS_SCRAMBLE):
+		if(dz->brksize[GRS_SRCHRANGE])
+			dz->iparray[GRS_FLAGS][G_RANGE_FLAG]     |= G_VARIABLE_VAL;
+		else
+			dz->iparray[GRS_FLAGS][G_RANGE_FLAG]     |= G_FIXED_VAL;
+		dz->iparray[GRS_FLAGS][G_SCATTER_FLAG] |= G_FIXED_VAL;
+
+		/* RWD Nov 2003 */
+		if(dz->brksize[GRS_GRAINSIZE])	
+			dz->iparray[GRS_FLAGS][G_GRAINSIZE_FLAG] |= G_VARIABLE_VAL;
+		else
+			dz->iparray[GRS_FLAGS][G_GRAINSIZE_FLAG] |= G_FIXED_VAL;
+
+
+	 	break;
+	case(GRS_REVERB):
+		if(dz->brksize[GRS_DENSITY])	dz->iparray[GRS_FLAGS][G_DENSITY_FLAG]   |= G_VARIABLE_VAL;
+		else							dz->iparray[GRS_FLAGS][G_DENSITY_FLAG]   |= G_FIXED_VAL;
+
+		if(dz->brksize[GRS_PITCH])		dz->iparray[GRS_FLAGS][G_PITCH_FLAG]     |= G_VARIABLE_VAL;
+		else							dz->iparray[GRS_FLAGS][G_PITCH_FLAG]     |= G_FIXED_VAL;
+
+		if(dz->brksize[GRS_AMP])		dz->iparray[GRS_FLAGS][G_AMP_FLAG]       |= G_VARIABLE_VAL;
+		else							dz->iparray[GRS_FLAGS][G_AMP_FLAG]       |= G_FIXED_VAL;
+
+		if(dz->brksize[GRS_SRCHRANGE])	dz->iparray[GRS_FLAGS][G_RANGE_FLAG]     |= G_VARIABLE_VAL;
+		else							dz->iparray[GRS_FLAGS][G_RANGE_FLAG]     |= G_FIXED_VAL;
+
+		dz->iparray[GRS_FLAGS][G_SCATTER_FLAG] |= G_FIXED_VAL;
+		dz->iparray[GRS_FLAGS][G_SPACE_FLAG]   |= G_HI_BOUND;
+		dz->iparray[GRS_FLAGS][G_SPACE_FLAG]   |= G_FIXED_VAL;
+
+	 	break;
+	default:
+		sprintf(errstr,"Unknown mode in set_internal_flags()\n");
+		return(PROGRAM_ERROR);
+	}
+#ifdef MULTICHAN
+	switch(dz->mode) {
+	case(GRS_FULL_MONTY):
+		if(dz->param[GRS_HSPACE] == 0.0 && dz->param[GRS_SPACE] == 0)
+			dz->iparray[GRS_FLAGS][G_SPACE_FLAG]  = 0;		
+		break;
+	case(GRS_BRASSAGE):
+		if(dz->param[GRS_SPACE] == 0)
+			dz->iparray[GRS_FLAGS][G_SPACE_FLAG]  = 0;		
+		break;
+	}
+#endif
+	return(FINISHED);
+}
+
+/**************************** INITIALISE_CHANNEL_CONFIGURATION *******************************/
+
+#ifndef MULTICHAN
+
+void initialise_channel_configuration(dataptr dz)
+{
+	if(dz->infile->channels == STEREO) {
+		dz->iparam[GRS_CHANNELS] = TRUE;	 /** added MAY 1998 **/
+		if(dz->iparray[GRS_FLAGS][G_SPACE_FLAG]) {
+			dz->iparam[GRS_CHAN_TO_XTRACT] 	= BOTH_CHANNELS;	/* force stereo input to be mixed to mono */
+			dz->iparam[GRS_INCHANS]  		= MONO;   	/* input mixed to mono */
+			dz->iparam[GRS_OUTCHANS] 		= STEREO;	/* output spatialised to stereo */
+		} else if(dz->iparam[GRS_CHAN_TO_XTRACT]) {		/* specifies which stereo channel to select */
+			dz->iparam[GRS_INCHANS]  		= MONO;		/* input is single channel of stereo */
+			dz->iparam[GRS_OUTCHANS] 		= MONO;		/* not spatialised */
+		} else {
+			dz->iparam[GRS_INCHANS]  		= STEREO;	/* input is stereo */
+			dz->iparam[GRS_OUTCHANS] 		= STEREO;	/* output is stereo */
+		}
+	} else {
+		dz->iparam[GRS_CHANNELS] = FALSE;
+		dz->iparam[GRS_INCHANS]  			= MONO;		/* input is mono */
+		if(dz->iparray[GRS_FLAGS][G_SPACE_FLAG])
+			dz->iparam[GRS_OUTCHANS] 		= STEREO;	/* output spatialised to stereo */ 
+		else
+			dz->iparam[GRS_OUTCHANS] 		= MONO;		/* not spatialised */
+	}
+}
+
+#else
+
+void initialise_channel_configuration(dataptr dz)
+{
+	if(dz->infile->channels > MONO) {
+		dz->iparam[GRS_CHANNELS] = TRUE;
+		if(dz->iparam[GRS_CHAN_TO_XTRACT]) {				/* specifies which multichan channel to select */
+			dz->iparam[GRS_INCHANS]  		= MONO;			/* input is single channel of multichan, grain is mono */
+			if(dz->iparray[GRS_FLAGS][G_SPACE_FLAG])
+				dz->iparam[GRS_OUTCHANS] 	= dz->out_chans;	/* output spatialised to multichan */
+			else
+				dz->iparam[GRS_OUTCHANS] 	= MONO;			/* not spatialised */
+			
+		} else if(dz->iparray[GRS_FLAGS][G_SPACE_FLAG]) {	/* if spatialising, but NOT extracting a specific channel */
+			dz->iparam[GRS_CHAN_TO_XTRACT] 	= ALL_CHANNELS;	/* force multichan input to be mixed to mono */
+			dz->iparam[GRS_INCHANS]  		= MONO;   		/* input mixed to mono, grain is mono */
+			dz->iparam[GRS_OUTCHANS] 		= dz->out_chans;/* output spatialised to multichan */
+		} else {											
+			dz->iparam[GRS_INCHANS]  		= dz->infile->channels;	/* Otherwise, grain is multichan */
+			dz->iparam[GRS_OUTCHANS] 		= dz->infile->channels;	/* output is same-multichan */
+		}
+	} else {
+		dz->iparam[GRS_CHANNELS] = FALSE;
+		dz->iparam[GRS_INCHANS]  			= MONO;			/* input is mono, grain is mono */
+		if(dz->iparray[GRS_FLAGS][G_SPACE_FLAG])
+			dz->iparam[GRS_OUTCHANS] 		= dz->out_chans;/* output spatialised to multichan */
+		else
+			dz->iparam[GRS_OUTCHANS] 		= MONO;			/* not spatialised, remains mono */
+	}
+}
+
+#endif
+
+/*************************** GRANULA_SETUP ***********************/
+
+#ifndef MULTICHAN
+
+int granula_setup(dataptr dz)
+{
+	int exit_status;
+	
+	if((exit_status = make_splice_tables(dz))<0)
+		return(exit_status);
+	set_ranges(dz);
+	if((exit_status = calc_overflows(dz))<0)
+		return(exit_status);
+
+	dz->iparam[GRS_BUF_SMPXS]   *= dz->iparam[GRS_INCHANS];
+	dz->iparam[GRS_BUF_XS]      *= dz->iparam[GRS_INCHANS];
+	dz->iparam[GRS_GLBUF_SMPXS] *= dz->iparam[GRS_INCHANS];
+	dz->iparam[GRS_LBUF_SMPXS]  *= dz->iparam[GRS_OUTCHANS];		 /* SEPT 1996 */
+	dz->iparam[GRS_LBUF_XS]     *= dz->iparam[GRS_OUTCHANS];
+	return(FINISHED);
+}
+
+#else
+
+int granula_setup(dataptr dz)
+{
+	int exit_status;
+	
+	if((exit_status = make_splice_tables(dz))<0)
+		return(exit_status);
+	set_ranges(dz);
+	if((exit_status = calc_overflows(dz))<0)
+		return(exit_status);
+
+	dz->iparam[GRS_BUF_SMPXS]   *= dz->iparam[GRS_INCHANS];		//	extra space in INPUT buffer (must accept all input channels)
+//	dz->iparam[GRS_BUF_XS]      *= dz->iparam[GRS_INCHANS];		//	 TW this is redundant
+	dz->iparam[GRS_GLBUF_SMPXS] *= dz->iparam[GRS_INCHANS];		//	extra space in the GRAIN buffer is either mono 
+																//	(where channel is extracted, or all channels mixed to mono) 
+																//	or it is multichannel: GRS_INCHANS knows this
+	dz->iparam[GRS_LBUF_SMPXS]  *= dz->iparam[GRS_OUTCHANS];	//	The output grain can be multichan via spatialisation, or via using multichan input
+																//	or multichan if multichan input goes direct to multichan output
+//	dz->iparam[GRS_LBUF_XS]     *= dz->iparam[GRS_OUTCHANS];	//	TW : this is redundant
+	return(FINISHED);
+}
+
+#endif
+
+/************************** CHECK_FOR_ZEROES ************************************/
+
+int check_for_zeroes(int paramno,dataptr dz)
+{
+	double *p, *end;
+	if(dz->brksize[paramno]) {
+		p   = dz->brk[paramno] + 1;		
+		end = dz->brk[paramno] + (dz->brksize[paramno] * 2);
+		while(p < end) {
+			if(flteq(*p,0.0))
+				return TRUE;
+			p++;
+		}
+	} else  {
+		if(flteq(dz->param[paramno],0.0))
+			return TRUE;
+	}
+	return (FALSE);
+}
+
+/************************** CONVERT_VALUE_TO_INT ************************************/
+
+void convert_value_to_int(int paramno,double convertor,dataptr dz)
+{
+	double *p, *end;
+	if(dz->brksize[paramno]) {
+		p   = dz->brk[paramno] + 1;		
+		end = dz->brk[paramno] + (dz->brksize[paramno] * 2);
+		while(p < end) {
+			*p = (double)round(*p * convertor);
+			p += 2;
+		}
+		dz->is_int[paramno] = TRUE;
+	} else
+		dz->iparam[paramno] = round(dz->param[paramno] * convertor);
+}
+
+/************************ MAKE_SPLICE_TABLES ******************************/
+
+int make_splice_tables(dataptr dz)
+{						 	/* rwd: changed to eliminate f/p division */
+	long n;					/* plus quasi-exponential option */
+	double dif,val,lastval;
+	double length, newsum,lastsum,twodif;
+	double *local_btabptr;	/* better safe than sorry! */
+	double *local_etabptr;
+
+	if(dz->iparray[GRS_FLAGS][G_BSPLICE_FLAG]<=1) {
+		if(dz->iparam[GRS_BSPLICE]==0) {
+			dz->iparam[GRS_IS_BTAB] = TRUE;	/* even though it's empty */
+			return(FINISHED);
+		}
+		if((dz->parray[GRS_BSPLICETAB] = (double *)malloc(dz->iparam[GRS_BSPLICE] * sizeof(double)))==NULL) {
+			sprintf(errstr,"make_splice_tables(): 1\n");
+			return(PROGRAM_ERROR);
+		}
+		local_btabptr = dz->parray[GRS_BSPLICETAB];
+		val = 0.0;
+		length = (double)dz->iparam[GRS_BSPLICE];
+		if(!dz->vflag[GRS_EXPON]) {
+			dif = 1.0/length;
+			lastval = dif;
+			*local_btabptr++ = val;
+			*local_btabptr++ = lastval;
+			for(n=2;n<dz->iparam[GRS_BSPLICE];n++) {
+				val = lastval + dif;
+				lastval = val;
+				*local_btabptr++ = val;
+			}
+		} else {			/* do quasi-exponential splice */
+			dif = 1.0/(length*length);
+			twodif = dif*2.0;
+			lastsum = 0.0;
+			lastval = dif;
+			*local_btabptr++ = val;
+			*local_btabptr++ = lastval;
+			for(n=2;n<dz->iparam[GRS_BSPLICE];n++) {
+				newsum = lastsum + twodif;
+				val = lastval + newsum + dif;
+				*local_btabptr++ = val;
+				lastval = val;
+				lastsum = newsum;
+			}
+		}   
+		dz->iparam[GRS_IS_BTAB] = TRUE;
+	}
+	if(dz->iparray[GRS_FLAGS][G_ESPLICE_FLAG]<=1) {
+		if(dz->iparam[GRS_ESPLICE]==0) {
+			dz->iparam[GRS_IS_ETAB] = TRUE;	/* even thogh it's empty! */
+			return(FINISHED);
+		}
+		if((dz->parray[GRS_ESPLICETAB] = (double *)malloc(dz->iparam[GRS_ESPLICE] * sizeof(double)))==NULL) {
+			sprintf(errstr,"make_splice_tables(): 2\n");
+			return(PROGRAM_ERROR);
+		}
+		local_etabptr = dz->parray[GRS_ESPLICETAB] + dz->iparam[GRS_ESPLICE];
+		val = 0.0;
+		length = (double)dz->iparam[GRS_ESPLICE];
+		if(!dz->vflag[GRS_EXPON]) {
+			dif = 1.0/length;
+			lastsum = dif;
+			*--local_etabptr = val;
+			*--local_etabptr = lastsum;
+			for(n=dz->iparam[GRS_ESPLICE]-3;n>=0;n--){
+				val = lastsum + dif;
+				lastsum = val;	
+				*--local_etabptr = val;
+			}
+		} else {
+			dif = 1.0/(length*length);
+			twodif = dif*2.0;
+			lastsum = 0.0;
+			lastval = dif;
+			*--local_etabptr = val;
+			*--local_etabptr = lastval;
+			for(n=dz->iparam[GRS_ESPLICE]-3;n>=0;n--) {
+				newsum = lastsum + twodif;
+				val = lastval + newsum + dif;
+				*--local_etabptr = val;
+				lastval = val;
+				lastsum = newsum;
+			}
+		}   
+		dz->iparam[GRS_IS_ETAB] = TRUE;
+    }
+	return(FINISHED);
+}
+
+/************************* SET_RANGES *****************************/
+
+void set_ranges(dataptr dz)
+{
+	int n;
+	for(n=0;n<SFLAGCNT;n++) {		
+		if(dz->iparray[GRS_FLAGS][n]==RANGED) {
+			switch(n) {
+			case(G_VELOCITY_FLAG):
+				set_this_drange(GRS_VRANGE,GRS_HVELOCITY,GRS_VELOCITY,G_VELOCITY_FLAG,dz);
+				break;
+			case(G_DENSITY_FLAG):
+				set_this_drange(GRS_DRANGE,GRS_HDENSITY,GRS_DENSITY,G_DENSITY_FLAG,dz);
+				break;
+			case(G_GRAINSIZE_FLAG):
+				set_this_range(GRS_GRANGE,GRS_HGRAINSIZE,GRS_GRAINSIZE,G_GRAINSIZE_FLAG,dz);
+ 				break;
+			case(G_BSPLICE_FLAG):
+				set_this_range(GRS_BRANGE,GRS_HBSPLICE,GRS_BSPLICE,G_BSPLICE_FLAG,dz);
+				break;
+			case(G_ESPLICE_FLAG):
+				set_this_range(GRS_ERANGE,GRS_HESPLICE,GRS_ESPLICE,G_ESPLICE_FLAG,dz);
+				break;
+			case(G_PITCH_FLAG):
+				set_this_drange(GRS_PRANGE,GRS_HPITCH,GRS_PITCH,G_PITCH_FLAG,dz);
+				break;
+			case(G_AMP_FLAG):
+				/*set_this_range*/set_this_drange(GRS_ARANGE,GRS_HAMP,GRS_AMP,G_AMP_FLAG,dz);
+				break;
+			case(G_SPACE_FLAG):
+				set_this_drange(GRS_SPRANGE,GRS_HSPACE,GRS_SPACE,G_SPACE_FLAG,dz);
+				break;
+			}
+		}
+	}
+}
+
+/************************ CALC_OVERFLOWS *************************
+ *
+ * We will attempt to put data into output buffer until we reach its 'end'.
+ * But out grain will extend GRAINSIZE beyond this> So we must have
+ * an overflow area on the buffer equal to the maximum grainsize.
+ *
+ * On the input side, we will attempt to read from input buffer until we
+ * get to its end, BUT, grainsize extends beyond this. Also, to create
+ * an output of GRAINSIZE we need to use an input size of 
+ * (grainsize*transposition). So overflow on input buffer = maximum val
+ * of (grainsize*transposition).
+ * Lbuf_smpxs  = overflow in Lbuf
+ * gLbuf_smpxs = MAXIMUM GRAINSIZE
+ * buf_smpxs   = overflow in inbuf
+ */
+
+
+int calc_overflows(dataptr dz)	/* DO THIS AFTER THE CONVERSION OF PITCH from SEMITONES */
+{
+	int exit_status;
+	long max_scatter;
+	double mt = 1.0;	/* MAXIMUM TRANSPOSITION */
+	double mg = 1.0;	/* MAXIMUM GRAINSIZE     */
+	double max1, max2;
+	int mgi;
+	switch(dz->iparray[GRS_FLAGS][G_PITCH_FLAG]) {
+	case(NOT_SET):   
+		mt = 1.0;
+		break;
+	case(FIXED):     
+		mt = dz->param[GRS_PITCH];   		  								
+		break;
+	case(VARIABLE):
+		if((exit_status = get_maxvalue_in_brktable(&max1,GRS_PITCH,dz))<0)
+			return(exit_status);
+	  	mt = max1;
+	  	break;
+	case(RANGED):    
+		mt = max(dz->param[GRS_HPITCH],dz->param[GRS_PITCH]);		   		
+		break;
+	case(RANGE_VLO):
+		if((exit_status = get_maxvalue_in_brktable(&max1,GRS_PITCH,dz))<0)
+			return(exit_status);
+		mt = max(max1,dz->param[GRS_HPITCH]);  											
+		break;
+	case(RANGE_VHI): 
+		if((exit_status = get_maxvalue_in_brktable(&max2,GRS_HPITCH,dz))<0)
+			return(exit_status);
+		mt = max(max2,dz->param[GRS_PITCH]);  											
+		break;
+	case(RANGE_VHILO):
+		if((exit_status = get_maxvalue_in_brktable(&max1,GRS_PITCH,dz))<0)
+			return(exit_status);
+		if((exit_status = get_maxvalue_in_brktable(&max2,GRS_HPITCH,dz))<0)
+			return(exit_status);
+		mt = max(max1,max2);		
+		break;
+	}
+	mt = pow(2.0,mt);	/* CONVERT OCTAVES TO TRANSPOSITION RATIO */
+
+	switch(dz->iparray[GRS_FLAGS][G_GRAINSIZE_FLAG]) {
+	case(NOT_SET):
+	case(FIXED):     
+		mg = (double)dz->iparam[GRS_GRAINSIZE];			       	   						
+	   	break;
+	case(VARIABLE):  
+		if((exit_status = get_maxvalue_in_brktable(&max1,GRS_GRAINSIZE,dz))<0)
+			return(exit_status);
+		mg = max1;		  					
+		break;
+	case(RANGED):    
+// BUG: OCtober 2009
+		mg = max(dz->iparam[GRS_HGRAINSIZE],dz->iparam[GRS_GRAINSIZE]);  			       							
+		break;
+	case(RANGE_VLO): 
+		if((exit_status = get_maxvalue_in_brktable(&max1,GRS_GRAINSIZE,dz))<0)
+			return(exit_status);
+		mg = max(max1,(double)dz->iparam[GRS_HGRAINSIZE]);		
+		break;
+	case(RANGE_VHI): 
+		if((exit_status = get_maxvalue_in_brktable(&max2,GRS_HGRAINSIZE,dz))<0)
+			return(exit_status);
+		mg = max(max2,(double)dz->iparam[GRS_GRAINSIZE]);		
+		break;
+	case(RANGE_VHILO):
+		if((exit_status = get_maxvalue_in_brktable(&max1,GRS_GRAINSIZE,dz))<0)
+			return(exit_status);
+		if((exit_status = get_maxvalue_in_brktable(&max2,GRS_HGRAINSIZE,dz))<0)
+			return(exit_status);
+		mg = max(max1,max2);  
+		break;
+	}
+	mgi = round(mg)+1;
+	dz->iparam[GRS_GLBUF_SMPXS] = mgi;						/* Overflow in outbuf = MAX-grainsize */
+	dz->iparam[GRS_BUF_SMPXS]   = round((double)mgi * mt);	/* Overflow in inbuf  = MAX-grainsize * transpos */
+	if((exit_status = calc_max_scatter(mgi,&max_scatter,dz))<0)
+		return(exit_status);
+	adjust_overflows(max_scatter,dz);
+	return(FINISHED);
+}
+
+/************************ SET_THIS_RANGE ******************************/
+
+void set_this_range(int rangeno,int hino, int lono, int flagno, dataptr dz)
+{
+	dz->iparam[rangeno]  = dz->iparam[hino] - dz->iparam[lono];
+	if(dz->iparam[rangeno]==0)
+		dz->iparray[GRS_FLAGS][flagno] = FIXED;
+}
+
+/************************ SET_THIS_DRANGE ******************************/
+
+void set_this_drange(int rangeno,int hino, int lono, int flagno, dataptr dz)
+{
+	dz->param[rangeno]  = dz->param[hino] - dz->param[lono];
+	if(flteq(dz->param[rangeno],0.0))
+		dz->iparray[GRS_FLAGS][flagno] = FIXED;
+}
+
+/******************************** CALC_MAX_SCATTER ****************************/
+
+int calc_max_scatter(int mgi,long *max_scatlen, dataptr dz)		 /* mgi = MAX GRAIN SIZE */
+{
+
+#define GRS_ROUNDUP	(0.9999)
+
+	int exit_status;
+	long os = 0;
+	double sc = 0.0;
+	double min1, min2, minn/*, sr = (double)dz->infile->srate*/;
+	int k = dz->iparray[GRS_FLAGS][G_DENSITY_FLAG];	
+	switch(k) {
+	case(NOT_SET):
+	case(FIXED):
+	case(RANGED):      
+		os = (long)(((double)mgi/dz->param[GRS_DENSITY]) + GRS_ROUNDUP);	/* ROUND UP */						
+		break;
+	case(VARIABLE):    
+		if((exit_status = get_minvalue_in_brktable(&min1,GRS_DENSITY,dz))<0)
+			return(exit_status);
+		os = (long)(((double)mgi/min1) + GRS_ROUNDUP);		  						
+		break;
+	case(RANGE_VLO):   
+		if((exit_status = get_minvalue_in_brktable(&min1,GRS_DENSITY,dz))<0)
+			return(exit_status);
+		minn = min(min1,dz->param[GRS_HDENSITY]);			
+		os = (long)(((double)mgi/minn) + GRS_ROUNDUP); 	
+		break;
+	case(RANGE_VHI):   
+		if((exit_status = get_minvalue_in_brktable(&min2,GRS_HDENSITY,dz))<0)
+			return(exit_status);
+		minn = min(min2,dz->param[GRS_DENSITY]);			
+		os = (long)(((double)mgi/minn) + GRS_ROUNDUP); 	
+		break;
+	case(RANGE_VHILO): 
+		if((exit_status = get_minvalue_in_brktable(&min1,GRS_DENSITY,dz))<0)
+			return(exit_status);
+		if((exit_status = get_minvalue_in_brktable(&min2,GRS_HDENSITY,dz))<0)
+			return(exit_status);
+		minn = min(min1,min2);			
+		os = (long)(((double)mgi/minn) + GRS_ROUNDUP); 	
+		break;
+	}
+	switch(dz->iparray[GRS_FLAGS][G_SCATTER_FLAG]) {
+	case(NOT_SET):
+	case(FIXED):     
+		sc = dz->param[GRS_SCATTER];   		   	   		
+		break;
+	case(VARIABLE):  
+		if((exit_status = get_maxvalue_in_brktable(&sc,GRS_SCATTER,dz))<0)
+			return(exit_status);
+		break;
+	}
+	*max_scatlen = (long)(((double)os * sc) + GRS_ROUNDUP); /* ROUND UP */
+	return(FINISHED);
+}
+
+/************************ ADJUST_OVERFLOWS ***************************
+ * GRS_LBUF_SMPXS		   = overflow in calculation buffer Lbuf 
+ * iparam[GRS_GLBUF_SMPXS] = MAXIMUM GRAINSIZE 
+ * GRS_BUF_SMPXS		   = overflow in inbuf
+ */
+ /* RW NB we eliminate almost everything! */
+void adjust_overflows(long mscat, dataptr dz)
+{
+	dz->iparam[GRS_BUF_SMPXS]   += SAFETY;							/* ADD SAFETY MARGINS !! */
+	dz->iparam[GRS_GLBUF_SMPXS] += OSAFETY;
+	dz->iparam[GRS_LBUF_SMPXS]   = dz->iparam[GRS_GLBUF_SMPXS] + mscat;
+}
+
+#ifdef MULTICHAN
+
+/************************** CHECK_SPATIALISATION_DATA ************************************/
+
+int check_spatialisation_data(dataptr dz)
+{
+	int exit_status;
+	double maxspace, maxspaceh = 0.0;
+
+	if(dz->process==SAUSAGE) {
+		if(dz->brksize[GRS_HSPACE]) {
+			if((exit_status = get_maxvalue_in_brktable(&maxspaceh,GRS_HSPACE,dz))<0)
+				return(exit_status);
+		} else
+			maxspaceh = dz->param[GRS_HSPACE];
+		if(dz->brksize[GRS_SPACE]) {
+			if((exit_status = get_maxvalue_in_brktable(&maxspace,GRS_SPACE,dz))<0)
+				return(exit_status);
+		} else
+			maxspace = dz->param[GRS_SPACE];
+		maxspace = max(maxspace,maxspaceh);
+	} else {
+		switch(dz->mode) {
+		case(GRS_FULL_MONTY):
+			if(dz->brksize[GRS_HSPACE]) {
+				if((exit_status = get_maxvalue_in_brktable(&maxspaceh,GRS_HSPACE,dz))<0)
+					return(exit_status);
+			} else
+				maxspaceh = dz->param[GRS_HSPACE];
+			/* fall thro */
+		case(GRS_BRASSAGE):
+			if(dz->brksize[GRS_SPACE]) {
+				if((exit_status = get_maxvalue_in_brktable(&maxspace,GRS_SPACE,dz))<0)
+					return(exit_status);
+			} else
+				maxspace = dz->param[GRS_SPACE];
+			break;
+		default:
+			return FINISHED;
+		}
+		if(dz->mode == GRS_FULL_MONTY)
+			maxspace = max(maxspace,maxspaceh);
+	}
+	if(dz->out_chans == 2)  {
+		if(maxspace > 1.0) {
+			sprintf(errstr,"SPATIAL DATA MAX VALUE (%lf) INCOMPATIBLE WITH OUTPUT CHANNEL-CNT (STEREO) (data range for stereo 0-1)\n",maxspace);
+			return(DATA_ERROR);
+		}
+	} else {
+		if(maxspace > dz->out_chans) {
+			sprintf(errstr,"SPATIAL DATA MAX VALUE (%lf) INCOMPATIBLE WITH OUTPUT CHANNEL CNT (dz->out_chans) SPECIFIED\n",maxspace);
+			return(DATA_ERROR);
+		}
+	}
+	return(FINISHED);
+}
+
+#endif

+ 2273 - 0
dev/modify/delay.c

@@ -0,0 +1,2273 @@
+/*
+ * Copyright (c) 1983-2013 Trevor Wishart and Composers Desktop Project Ltd
+ * http://www.trevorwishart.co.uk
+ * http://www.composersdesktop.com
+ *
+ This file is part of the CDP System.
+
+    The CDP System is free software; you can redistribute it
+    and/or modify it under the terms of the GNU Lesser General Public
+    License as published by the Free Software Foundation; either
+    version 2.1 of the License, or (at your option) any later version.
+
+    The CDP System is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public
+    License along with the CDP System; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+    02111-1307 USA
+ *
+ */
+
+
+
+/* floatsam version */
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+#include <time.h>
+#include <memory.h>
+#include <structures.h>
+#include <tkglobals.h>
+#include <globcon.h>
+#include <cdpmain.h>
+#include <modify.h>
+#include <modeno.h>
+#include <pnames.h>
+#include <flags.h>
+#include <arrays.h>
+#include <sfsys.h>
+#include <cdplib.h>
+#include <osbind.h>
+
+/*RWD January 2009:
+   delay:
+       replaced domono and dostereo with domulti  for full m/c support
+       corrected trailtime calc  (counts frames, not samples )
+   vdelay:
+        replaced do_vdelay with do_vdelay_multi, ditto
+        replaced triangle lfo with sine lfo
+        revised  random mod to use modulated  sine osc
+        randfac revised to use 1/f  noise (average of successive  rands)
+   stadium:
+        added error return if inout more than 2 chans
+*/
+
+#ifdef unix
+#define round(x) lround((x))
+#endif
+
+#define DELAY_BUFLEN    (4096)
+#define ROOTLEN_DELBUF  (2)
+#define ROOTLEN_VDELBUF (4)
+
+/*RWD January 2009 */
+static int  domulti(int trailtime,int delay,double gain,double fdbk,double fdfrwd,double prescale,dataptr dz);
+int do_vdelay_multi(int trailtime,int delay,double gain,double fdbk,double fdfrwd,double prescale,
+double modlen,double lfophase,int mdelay,dataptr dz);
+static int  count(int num,int *counter);
+static double randfac(double length,double phase,int delay,int *ikindex,int *counter,double *rout,double *diff);
+static int domultiv(int trailtime,int delay,double prescale,dataptr dz);
+
+static int  setup_stadium(dataptr dz);
+static int  generate_delays(dataptr dz);
+static void generate_gains(dataptr dz);
+
+#ifndef M_PI
+#define M_PI  (3.1415926535897932)
+#endif
+
+#ifndef M_TWOPI
+#define M_TWOPI (2.0 * M_PI)
+#endif
+
+typedef  struct soscil_
+{
+    double phase;
+    double sr;   
+    double incr;
+    double val;
+    unsigned int count;
+    unsigned int delay;
+} SOSCIL;
+
+SOSCIL*  new_soscil(double srate,double startphase, double  freq,unsigned int delay)
+{
+    SOSCIL*  osc = (SOSCIL*) malloc(sizeof(SOSCIL));
+    if(osc==NULL)
+        return NULL;
+    osc->sr = srate;
+    osc->phase = M_TWOPI * startphase;
+    osc->incr =  M_TWOPI/srate * freq;
+    osc->delay = delay;
+    osc->count = 0;
+    osc->val = sin(osc->phase);
+    return osc;
+}
+
+double  soscil_tick(SOSCIL* osc)
+{
+    if(osc->count >= osc->delay){
+        osc->phase+= osc->incr;
+        if(osc->phase >= M_PI)
+            osc->phase -= M_TWOPI;
+        osc->val = sin(osc->phase);
+    }
+    else
+        osc->count++;
+    return osc->val;
+}
+
+double  soscil_tickf(SOSCIL* osc,double freqmod)
+{
+    double nuincr;
+    if(osc->count >= osc->delay){
+        nuincr =  osc->incr * freqmod;
+        osc->phase+= nuincr;
+        if(osc->phase >= M_PI)
+            osc->phase -= M_TWOPI;
+        osc->val = sin(osc->phase);
+    }
+    else
+        osc->count++;
+    return osc->val;
+}
+
+/********************************** DELAY_PREPROCESS *****************************/
+
+int delay_preprocess(dataptr dz)
+{
+    int exit_status;      /*RWD*/
+
+    double sr;
+    switch(dz->mode) {
+    case(MOD_DELAY):
+        dz->param[DELAY_INVERT] = 1.0;
+        if(dz->vflag[DELAY_INVERT_FLAG])
+            dz->param[DELAY_INVERT] = -1.0;
+        break;
+    case(MOD_VDELAY):
+        sr = (double)dz->infile->srate;
+        if(dz->param[DELAY_LFOFRQ]<0.0)
+            dz->iparam[DELAY_LFOFLAG] = 0;
+        else
+            dz->iparam[DELAY_LFOFLAG] = 1;
+        dz->param[DELAY_MODLEN] = 0.0;
+        if(dz->param[DELAY_LFOFRQ] !=0.0)
+            dz->param[DELAY_MODLEN] = sr/fabs(dz->param[DELAY_LFOFRQ]);
+        dz->iparam[DELAY_MDELAY] = (int)(sr*dz->param[DELAY_LFODELAY]);
+        break;
+        /*RWD create outfile here in this case: props changed */
+    case(MOD_STADIUM):
+        /* create stereo outfile here! */
+        /* RWD 4:2002  now we can open outfile with corect params! */
+        dz->infile->channels = STEREO;  /* ARRGH! */
+        if((exit_status = create_sized_outfile(dz->outfilename,dz))<0)
+            return(exit_status);
+        break;
+    }
+    return(FINISHED);
+}
+
+/********************************** CREATE_DELAY_BUFFERS *****************************/
+
+int create_delay_buffers(dataptr dz)    /* USES small bufs to allow max space for delay buffer */
+{
+    int bigbufsize;
+
+    if(dz->mode==MOD_STADIUM)
+        return create_stadium_buffers(dz);
+/* MULTICHAN 2009 --> */
+//  bigbufsize = DELAY_BUFLEN * 2;
+    bigbufsize = DELAY_BUFLEN * dz->infile->channels * 2;
+    if((dz->bigbuf = (float *)malloc(bigbufsize * sizeof(float)))==NULL) {
+        sprintf(errstr,"INSUFFICIENT MEMORY for sound buffers.\n");
+        return(MEMORY_ERROR);
+    }
+    bigbufsize /= 2;
+    dz->buflen = bigbufsize;
+    dz->sampbuf[0] = dz->bigbuf;
+    dz->sampbuf[1] = dz->sampbuf[0] + dz->buflen;
+    return(FINISHED);
+}
+
+
+/********************************** DO_DELAY *****************************/
+
+int do_delay(dataptr dz)
+{
+    int exit_status = FINISHED;
+    double rescale, gain, fdbk, fdfrwd, prescale;
+    double sr = (double)dz->infile->srate;
+    int chans = dz->infile->channels, root_delay = 0;
+    int trailtime, delay, delbuflen;
+    time_t longtime;
+    delay = round(dz->param[DELAY_DELAY] * sr * MS_TO_SECS);
+/* nb delaysamps is per channel here    */
+/*  fdfrwd = ((1.0 - dz->param[DELAY_MIX])*dz->param[DELAY_INVERT]);    */
+    if((exit_status = read_values_from_all_existing_brktables(0.0,dz))<0)
+        return(exit_status);                        /* read value 1 bloklength ahead */
+    fdfrwd = 1.0 - dz->param[DELAY_MIX];
+    gain = dz->param[DELAY_MIX];
+    fdbk    =  dz->param[DELAY_FEEDBACK];
+    rescale = (1.0 / (fdbk + 1.0)); /* i/p compensation */
+    prescale = dz->param[DELAY_PRESCALE] * rescale;
+    fdfrwd /= rescale;
+    trailtime = round(dz->param[DELAY_TRAILTIME] * sr);
+    switch(dz->mode) {
+    case(MOD_DELAY):
+        /* RWD Jan 2009:  trailtime counts frames, not samples */
+    /*  if(chans==STEREO) 
+            trailtime *= 2;
+    */
+        delay *= chans;
+        root_delay = ROOTLEN_DELBUF;
+        root_delay *= chans;        /*RWD Jan 2009 */
+        /*RWD */
+        fdfrwd *= dz->param[DELAY_INVERT];
+        break;
+    case(MOD_VDELAY):
+        delay *= chans;
+        root_delay = ROOTLEN_VDELBUF;
+        root_delay *= chans;
+//TW added, following RWD's modifications above
+        fdfrwd *= dz->param[DELAY_INVERT];
+        break;
+    }
+    delbuflen = delay + root_delay;
+    if((dz->parray[DELAY_BUF] = (double *)calloc(delbuflen,sizeof(double)))==NULL){
+       sprintf(errstr,"INSUFFICIENT MEMORY for main delay buffer.");
+       return(MEMORY_ERROR);
+    }
+
+    switch(dz->mode) {
+    case(MOD_DELAY):
+        if(dz->brksize[DELAY_MIX] > 0 || dz->brksize[DELAY_FEEDBACK] > 0)
+            exit_status = domultiv(trailtime,delay,prescale,dz);
+        else
+            exit_status = domulti(trailtime,delay,gain,fdbk,fdfrwd,prescale,dz);
+        break;
+    case(MOD_VDELAY):
+        if(dz->iparam[DELAY_SEED]==0) {
+            time(&longtime);
+            dz->iparam[DELAY_SEED] = (int)longtime;
+        }
+#if defined(_WIN32) || defined(__SC__)
+        srand(dz->iparam[DELAY_SEED]);
+#else
+        srand48(dz->iparam[DELAY_SEED]);
+#endif
+        dz->param[DELAY_MODRANGE] = 0.0;        
+        if(dz->param[DELAY_LFOMOD]>0.0) {
+            dz->param[DELAY_MODRANGE] = (double) (delay/chans) * dz->param[DELAY_LFOMOD];
+            if(dz->param[DELAY_MODRANGE] >= (double)(delay/chans))      /* never exactly 100% mod */
+                dz->param[DELAY_MODRANGE] = (double)(delay/chans) - 1.0;
+        }
+        /*RWD Jan 2009 */
+        exit_status = do_vdelay_multi(trailtime,delay,gain,fdbk,fdfrwd,prescale,
+                        dz->param[DELAY_MODLEN],dz->param[DELAY_LFOPHASE],dz->iparam[DELAY_MDELAY],dz);
+        break;
+    }
+    return(exit_status);    
+}
+
+/************************************* DOMONO ************************************/
+
+int domono(int trailtime,int delay,double gain,double fdbk,double fdfrwd,double prescale,dataptr dz)
+{
+    int exit_status;
+    register int i; 
+    double  input,output;
+    int ipptr=0,opptr=0;
+    float   *inbuf  = dz->sampbuf[0];
+    float   *outbuf = dz->sampbuf[1];
+    double  *delbuf = dz->parray[DELAY_BUF];
+    while(dz->samps_left > 0) {
+        if((exit_status = read_samps(inbuf,dz))<0)
+            return(exit_status);
+        for(i=0;i<dz->ssampsread;i++) {
+            input = (double)inbuf[i] * prescale;
+            output = (input * fdfrwd) + (delbuf[opptr] * gain);
+            delbuf[ipptr] = delbuf[opptr++] * fdbk; 
+            delbuf[ipptr++] += input;
+            outbuf[i] = (float) output;
+            if(ipptr >= delay) 
+                ipptr -= delay;
+            if(opptr >= delay) 
+                opptr -= delay;
+            if(ipptr < 0 || opptr < 0) {
+                sprintf(errstr,"Internal error, ipptr=%d,opptr=%d\n",ipptr,opptr);
+                return(PROGRAM_ERROR);
+            }
+        }
+        if(dz->ssampsread == dz->buflen) {     /* If full buffer, write it */
+            if((exit_status = write_samps(outbuf,dz->ssampsread,dz))<0)
+                return(exit_status); 
+        }
+    }
+    i = dz->ssampsread % dz->buflen;        /* i = position in buffer if not written, or 0 if just written */
+            /* now do trailer   */
+    while(trailtime>0) {
+        for(;i<dz->buflen;i++) {
+            output=(delbuf[opptr] * gain);
+            delbuf[ipptr++] = delbuf[opptr++] *fdbk;
+            outbuf[i] = (float)output;
+            if(ipptr >= delay) 
+                ipptr -= delay;
+            if(opptr >= delay) 
+                opptr -= delay;
+            if(--trailtime <=0)     /* if got to end of trailer, break out */
+                break;
+        }
+        if(trailtime > 0) {         /* if not at end of trailer, but at end of buf,  write buf */
+            if((exit_status = write_samps(outbuf,dz->buflen,dz))<0)
+                return(exit_status); 
+            i = 0;                  /* and reset bufptr to 0 */
+        }
+    }       /* if no trailer or at end of trailer, and not at start of buf, write rest of buf */
+    if(i>0 && (exit_status = write_samps(outbuf, i, dz))<0)
+        return(exit_status); 
+    return(FINISHED);
+}                   
+
+/************************************* DOSTEREO ************************************/
+
+int dostereo(int trailtime,int delay,double gain,double fdbk,double fdfrwd,double prescale,dataptr dz)
+{
+    int exit_status;
+    int     i;  
+    double  Linput,Rinput;
+    double  Loutput,Routput;
+    int Lipptr = 0,Ripptr = 1;
+    int Lopptr = 0,Ropptr = 1;
+    double  *delbuf = dz->parray[DELAY_BUF];
+    float   *inbuf = dz->sampbuf[0];
+    float   *outbuf= dz->sampbuf[1];
+
+    while(dz->samps_left > 0) {
+        if((exit_status = read_samps(inbuf,dz))<0)
+            return(exit_status);
+        for(i=0;i<(dz->ssampsread-1);i+=2) {
+            Linput = inbuf[i]*prescale;
+            Rinput = inbuf[i+1]*prescale;
+            Loutput=(Linput*fdfrwd) + (delbuf[Lopptr]*gain);
+            Routput=(Rinput*fdfrwd) + (delbuf[Ropptr]*gain);
+            delbuf[Lipptr] = delbuf[Lopptr]*fdbk;
+            Lopptr+=2;
+            delbuf[Ripptr] = delbuf[Ropptr]*fdbk;
+            Ropptr+=2;
+            delbuf[Lipptr]+=Linput;
+            delbuf[Ripptr]+=Rinput;
+            Lipptr+=2;
+            Ripptr+=2;
+            outbuf[i] = (float) Loutput;
+            outbuf[i+1] = (float) Routput;
+
+            if(Lipptr >= delay)     Lipptr -= delay;
+            if(Ripptr >= delay)     Ripptr -= delay;
+            if(Lopptr >= delay)     Lopptr -= delay;
+            if(Ropptr >= delay)     Ropptr -= delay;
+        }
+        if(dz->ssampsread == dz->buflen) {
+            if((exit_status = write_samps(outbuf,dz->ssampsread,dz))<0)
+                return(exit_status); 
+        }
+    }
+    i = dz->ssampsread % dz->buflen;
+            /* now do trailer   */
+    while(trailtime>0) {
+        for(;i<dz->buflen-1;i+=2) {
+            Loutput = delbuf[Lopptr]*gain;
+            Routput = delbuf[Ropptr]*gain;
+            delbuf[Lipptr] = delbuf[Lopptr]*fdbk;
+            delbuf[Ripptr] = delbuf[Ropptr]*fdbk;
+            Lopptr+=2;
+            Ropptr+=2;
+            Lipptr+=2;
+            Ripptr+=2;
+            outbuf[i] = (float) Loutput;
+            outbuf[i+1] = (float) Routput;
+            if(Lipptr >= delay) Lipptr -= delay;
+            if(Ripptr >= delay) Ripptr -= delay;
+            if(Lopptr >= delay) Lopptr -= delay;
+            if(Ropptr >= delay) Ropptr -= delay;
+            if(--trailtime <=0)
+                break;
+        }
+        if(trailtime > 0) {
+            if((exit_status = write_samps(outbuf,dz->buflen,dz))<0)
+                return(exit_status); 
+            i = 0;
+        }
+    }
+    if(i>0 && (exit_status = write_samps(outbuf,i ,dz))<0)
+        return(exit_status); 
+    return(FINISHED);
+}
+
+/*RWD Jan 2009  multichannel version */
+int domulti(int trailtime,int delay,double gain,double fdbk,double fdfrwd,double prescale,dataptr dz)
+{
+    int exit_status;
+    int     i,j;        
+    double* inputs;
+    double* outputs;    
+    int* lipptr;
+    int*  lopptr;
+    int chans = dz->infile->channels;
+    int adjust = chans-1;
+    double  *delbuf = dz->parray[DELAY_BUF];
+    float   *inbuf = dz->sampbuf[0];
+    float   *outbuf= dz->sampbuf[1];
+
+    inputs  = (double*) malloc(chans * sizeof(double));
+    outputs = (double*) malloc(chans * sizeof(double));
+    lipptr  = (int*)   malloc(chans * sizeof(int));
+    lopptr  = (int*)   malloc(chans * sizeof(int));
+    for(i=0;i < chans;i++){
+        inputs[i] = outputs[i] = 0.0;
+        lipptr[i] = lopptr[i] = i;
+    }
+
+    while(dz->samps_left > 0) {
+        if((exit_status = read_samps(inbuf,dz))<0)
+            return(exit_status);
+        for(i=0;i < dz->ssampsread-adjust; i+=chans) {
+            for(j=0;j < chans;j++){
+                inputs[j] = inbuf[i+j]*prescale;                
+                outputs[j] =(inputs[j]*fdfrwd) + (delbuf[lopptr[j]] * gain);                
+                delbuf[lipptr[j]] = delbuf[lopptr[j]]*fdbk;
+                lopptr[j] += chans;             
+                delbuf[lipptr[j]] += inputs[j];             
+                lipptr[j] += chans;             
+                outbuf[i+j] = (float) outputs[j];               
+                if(lipptr[j] >= delay)  
+                    lipptr[j] -= delay;             
+                if(lopptr[j] >= delay) 
+                    lopptr[j] -= delay;             
+            }
+        }
+        if(dz->ssampsread == dz->buflen) {
+            if((exit_status = write_samps(outbuf,dz->ssampsread,dz))<0)
+                return(exit_status); 
+        }
+    }
+    i = dz->ssampsread % dz->buflen;
+            /* now do trailer   */
+    while(trailtime>0) {
+        for(;i<dz->buflen-adjust;i+=chans) {
+            for(j=0;j < chans;j++){
+                outputs[j] = delbuf[lopptr[j]]*gain;                
+                delbuf[lipptr[j]] = delbuf[lopptr[j]] * fdbk;               
+                lopptr[j]+=chans;               
+                lipptr[j]+=chans;               
+                outbuf[i+j] = (float) outputs[j];               
+                if(lipptr[j] >= delay) lipptr[j] -= delay;              
+                if(lopptr[j] >= delay) lopptr[j] -= delay;              
+            }
+            if(--trailtime <=0)
+                break;
+        }
+        if(trailtime > 0) {
+            if((exit_status = write_samps(outbuf,dz->buflen,dz))<0)
+                return(exit_status); 
+            i = 0;
+        }
+    }
+    if(i>0 && (exit_status = write_samps(outbuf,i ,dz))<0)
+        return(exit_status); 
+    free(inputs);
+    free(outputs);
+    free(lipptr);
+    free(lopptr);
+
+    return(FINISHED);
+}
+
+/*TW 2010: variable feedback, feedfrwd version */
+int domultiv(int trailtime,int delay,double prescale,dataptr dz)
+{
+    int exit_status;
+    int     i,j;        
+    double* inputs;
+    double* outputs;    
+    int* lipptr;
+    int*  lopptr;
+    int chans = dz->infile->channels;
+    int adjust = chans-1;
+    double  *delbuf = dz->parray[DELAY_BUF];
+    float   *inbuf = dz->sampbuf[0];
+    float   *outbuf= dz->sampbuf[1];
+    int vstep = 128 * chans, samps_processed = 0;
+    double srate = (double)dz->infile->srate, thistime;
+    double gain, fdbk, fdfrwd;
+    if((exit_status = read_values_from_all_existing_brktables(0.0,dz))<0)
+        return(exit_status);
+    fdfrwd = 1.0 - dz->param[DELAY_MIX];
+    gain   = dz->param[DELAY_MIX];
+    fdbk   = dz->param[DELAY_FEEDBACK];
+
+    inputs  = (double*) malloc(chans * sizeof(double));
+    outputs = (double*) malloc(chans * sizeof(double));
+    lipptr  = (int*)   malloc(chans * sizeof(int));
+    lopptr  = (int*)   malloc(chans * sizeof(int));
+    for(i=0;i < chans;i++){
+        inputs[i] = outputs[i] = 0.0;
+        lipptr[i] = lopptr[i] = i;
+    }
+
+    while(dz->samps_left > 0) {
+        if((exit_status = read_samps(inbuf,dz))<0)
+            return(exit_status);
+        for(i=0;i < dz->ssampsread-adjust; i+=chans) {
+            if(samps_processed % vstep == 0) {
+                thistime = (double)(samps_processed/chans)/srate;
+                if((exit_status = read_values_from_all_existing_brktables(thistime,dz))<0)
+                    return(exit_status);
+                fdfrwd = 1.0 - dz->param[DELAY_MIX];
+                gain   = dz->param[DELAY_MIX];
+                fdbk   = dz->param[DELAY_FEEDBACK];
+            }
+            for(j=0;j < chans;j++){
+                inputs[j] = inbuf[i+j]*prescale;                
+                outputs[j] =(inputs[j]*fdfrwd) + (delbuf[lopptr[j]] * gain);                
+                delbuf[lipptr[j]] = delbuf[lopptr[j]]*fdbk;
+                lopptr[j] += chans;             
+                delbuf[lipptr[j]] += inputs[j];             
+                lipptr[j] += chans;             
+                outbuf[i+j] = (float) outputs[j];               
+                if(lipptr[j] >= delay)  
+                    lipptr[j] -= delay;             
+                if(lopptr[j] >= delay) 
+                    lopptr[j] -= delay;             
+            }
+            samps_processed += chans;
+        }
+        if(dz->ssampsread == dz->buflen) {
+            if((exit_status = write_samps(outbuf,dz->ssampsread,dz))<0)
+                return(exit_status); 
+        }
+    }
+    i = dz->ssampsread % dz->buflen;
+            /* now do trailer   */
+    while(trailtime>0) {
+        for(;i<dz->buflen-adjust;i+=chans) {
+            for(j=0;j < chans;j++){
+                outputs[j] = delbuf[lopptr[j]]*gain;                
+                delbuf[lipptr[j]] = delbuf[lopptr[j]] * fdbk;               
+                lopptr[j]+=chans;               
+                lipptr[j]+=chans;               
+                outbuf[i+j] = (float) outputs[j];               
+                if(lipptr[j] >= delay) lipptr[j] -= delay;              
+                if(lopptr[j] >= delay) lopptr[j] -= delay;              
+            }
+            if(--trailtime <=0)
+                break;
+        }
+        if(trailtime > 0) {
+            if((exit_status = write_samps(outbuf,dz->buflen,dz))<0)
+                return(exit_status); 
+            i = 0;
+        }
+    }
+    if(i>0 && (exit_status = write_samps(outbuf,i ,dz))<0)
+        return(exit_status); 
+    free(inputs);
+    free(outputs);
+    free(lipptr);
+    free(lopptr);
+
+    return(FINISHED);
+}
+ 
+/************************************* DO_VDELAY_MULTI ************************************/
+
+int do_vdelay_multi(int trailtime,int delay,double gain,double fdbk,double fdfrwd,double prescale,
+double modlen,double lfophase,int mdelay,dataptr dz)
+{
+    int exit_status;
+    float  *inbuf = dz->sampbuf[0];
+    float  *obuf  = dz->sampbuf[1];
+    int     i,j,chans =  dz->infile->channels;
+    int adjust = chans-1;
+    int    *ipptr;
+    int    *opptr;
+    int    optr1, optr2;
+    int    framedelay = delay/chans;
+    double  val, offset;
+    double  *input;
+    double  *output;
+    double  *delbuf = dz->parray[DELAY_BUF];
+    double  *dinterp;
+    double  rout = 0.0, diff = 0.0;
+    int     ikindex= 0, counter = 0;
+    SOSCIL*  osc;
+
+    ipptr = (int*) malloc(chans * sizeof(int));
+    opptr = (int*) malloc(chans * sizeof(int));
+    input = (double*) malloc(chans * sizeof(double));
+    output = (double*) malloc(chans * sizeof(double));
+    dinterp = (double*) malloc(chans * sizeof(double));
+    for(j=0;j < chans;j++){
+        ipptr[j] = opptr[j] = j;        
+        dinterp[j] = 0.0;
+        input[j] = output[j] = 0.0;
+    }
+
+    osc = new_soscil(dz->infile->srate,lfophase,dz->param[DELAY_LFOFRQ],(unsigned int) mdelay);
+    if(osc==NULL){
+        return MEMORY_ERROR;
+    }
+
+    while(dz->samps_left > 0) {
+
+        if((exit_status = read_samps(inbuf,dz))<0)
+            return(exit_status);
+        for(i = 0; i < dz->ssampsread-adjust; i += chans) {
+            if(dz->iparam[DELAY_LFOFLAG])           
+                val = 0.5 + (0.5 * soscil_tick(osc));
+            else  {
+                val = randfac(modlen,lfophase,mdelay,&ikindex,&counter,&rout,&diff);
+                val = 0.5 + (0.5 * soscil_tickf(osc,val));
+            }
+            /*  same fac for all chans */
+            offset = dz->param[DELAY_MODRANGE] * val;
+            for(j=0;j < chans;j++){
+                input[j] = ((double) (inbuf[i+j])) * prescale;
+                if(ipptr[j] >= framedelay)  
+                    ipptr[j] -= framedelay;
+                if(opptr[j] >= framedelay)  
+                    opptr[j] -= framedelay;
+                optr1 = opptr[j] + (int) offset;
+                if(optr1 >= framedelay) 
+                    optr1 -= framedelay;
+                optr2 = optr1 + 1;
+                if(optr2 >= framedelay) 
+                    optr2 -= framedelay;
+                dinterp[j] =(double) delbuf[optr1*chans +j] + 
+                    (fmod(offset,1.0)*((double)delbuf[optr2*chans +j] - (double)delbuf[optr1*chans +j]));               
+                output[j] = (input[j] * fdfrwd) + (dinterp[j] * gain);
+                delbuf[ipptr[j]*chans+j] = (float)(dinterp[j] * fdbk); 
+                delbuf[ipptr[j]*chans +j] += (float)input[j] ;
+                ipptr[j]++;
+                obuf[i+j] = (float)output[j];
+                opptr[j]++;                
+            }           
+        }
+        if(dz->ssampsread == dz->buflen) {     /* If full buffer, write it */
+            if((exit_status = write_samps(obuf,dz->ssampsread,dz))<0)
+                return(exit_status); 
+        }
+    }
+
+    i = dz->ssampsread % dz->buflen;        /* i = position in buffer if not written, or 0 if just written */
+            /* now do trailer   */
+    while(trailtime>0) {
+        for(; i < dz->buflen-adjust; i+= chans) {
+            if(dz->iparam[DELAY_LFOFLAG]) 
+             val = 0.5 + (0.5 * soscil_tick(osc));
+            else  {
+                val = randfac(modlen,lfophase,mdelay,&ikindex,&counter,&rout,&diff);
+                val = 0.5 + (0.5 * soscil_tickf(osc,val));
+            }
+
+            offset = dz->param[DELAY_MODRANGE] * val;
+            for(j=0; j < chans; j++){
+                if(ipptr[j] >= framedelay) 
+                    ipptr[j] -= framedelay;
+                if(opptr[j] >= framedelay) 
+                    opptr[j] -= framedelay;
+                optr1 = opptr[j] + (int) offset;
+                if(optr1 >= framedelay) 
+                    optr1 -= framedelay;
+                optr2 = optr1 +1;
+                if(optr2 >= framedelay) 
+                    optr2 -= framedelay;
+                dinterp[j] =(double) delbuf[optr1*chans +j] + 
+                    (fmod(offset,1.0)*((double)delbuf[optr2*chans+j] - (double)delbuf[optr1*chans+j]));
+                output[j] = (dinterp[j] * gain);
+                delbuf[ipptr[j]*chans+j] = (float)(dinterp[j] * fdbk);
+                ipptr[j]++;
+                obuf[i+j] = (float)output[j];
+                opptr[j]++;
+            }
+            if(--trailtime <=0)     /* if got to end of trailer, break out */
+                break;
+        }   /* for loop */
+        if(trailtime > 0) {         /* if not at end of trailer, but at end of buf,  write buf */
+            if((exit_status = write_samps(obuf,dz->buflen,dz))<0)
+                return(exit_status); 
+            i = 0;                  /* and reset bufptr to 0 */
+        }
+    }       
+    free(osc);
+    free(ipptr);
+    free(opptr);
+    free(input);
+    free(output);
+    free(dinterp);
+    /* if no trailer or at end of trailer, and not at start of buf, write rest of buf */
+    if(i>0 && (exit_status = write_samps(obuf,i ,dz))<0)
+        return(exit_status); 
+    return(FINISHED);
+}
+
+
+
+
+/************************************* COUNT ************************************/
+
+int count(int num,int *counter)
+{
+    if(*counter<=num) {
+        num -= (*counter);
+        (*counter)++;
+        return(num);
+    }
+    return 0;
+}
+
+/************************************* RANDFAC ************************************/
+
+double randfac(double length,double phase,int delay,int *ikindex,int *counter,double *rout,double *diff)
+{
+    double temp;
+    volatile double dummy;
+    if(!count(delay,counter)) {
+        if(*ikindex==0) {       /* start of cycle */
+            dummy = drand48();  /* kludge to kickstart drand48() */
+            temp  = drand48();
+            // *diff  = *rout - temp;
+            /* RWD january 2009 : extended  to  use 1/f random vals */
+            *diff = *rout - (0.5 * (dummy + temp));
+        }
+        *rout -= (*diff)/length;
+        (*ikindex)++;
+        if(*ikindex>=(int)length) 
+            *ikindex = 0;
+        return *rout;
+    }
+    return phase;
+}
+
+/************************** STADIUM_PCONSISTENCY ****************************/
+
+int stadium_pconsistency(dataptr dz)
+{
+    int exit_status;
+    dz->itemcnt = dz->infile->channels;
+    dz->infile->channels = STEREO;  /* for output!! */
+    if((exit_status = setup_stadium(dz))<0)
+        return(exit_status);
+    if((exit_status = generate_delays(dz))<0)
+        return(exit_status);
+    dz->iparam[STAD_MAXDELAY] = dz->lparray[STAD_DELAY][dz->iparam[STAD_ECHOCNT]-1];
+    generate_gains(dz);
+    return(FINISHED);
+}
+
+/*************************** SETUP_STADIUM  ***************************/
+
+int setup_stadium(dataptr dz)
+{
+//TW UPDATE TO 100 possible echoes
+//  double *tdelay, *gain, *pan;
+    double *tdelay, *gain, *pan, top, bot, interval;
+    int n;
+
+    if((dz->parray[STAD_TDELAY] = malloc(MAX_ECHOCNT * sizeof(double)))==NULL
+    || (dz->parray[STAD_GAIN]   = malloc(MAX_ECHOCNT * sizeof(double)))==NULL
+    || (dz->parray[STAD_GAINL]  = malloc(MAX_ECHOCNT * sizeof(double)))==NULL
+    || (dz->parray[STAD_GAINR]  = malloc(MAX_ECHOCNT * sizeof(double)))==NULL
+    || (dz->parray[STAD_PAN]    = malloc(MAX_ECHOCNT * sizeof(double)))==NULL) {
+        sprintf(errstr,"Insufficient memory for stadium arrays.\n");
+        return(MEMORY_ERROR);
+    }
+    tdelay = dz->parray[STAD_TDELAY];
+    gain   = dz->parray[STAD_GAIN];
+    pan    = dz->parray[STAD_PAN];
+//TW UPDATE TO 10 possible echoes
+    if(dz->iparam[STAD_ECHOCNT] <= REASONABLE_ECHOCNT) {
+        tdelay[0]  = 0.000000;  gain[0]  = 1.000000;    pan[0]  = -1;
+        tdelay[1]  = 0.131832;  gain[1]  = 1.000000;    pan[1]  =  1;
+        tdelay[2]  = 0.215038;  gain[2]  = 0.354813;    pan[2]  = .5;
+        tdelay[3]  = 0.322274;  gain[3]  = 0.354813;    pan[3]  = -.5;
+        tdelay[4]  = 0.414122;  gain[4]  = 0.251189;    pan[4]  = 0;
+        tdelay[5]  = 0.504488;  gain[5]  = 0.125893;    pan[5]  = .7;
+        tdelay[6]  = 0.637713;  gain[6]  = 0.125893;    pan[6]  = -.7;
+        tdelay[7]  = 0.730468;  gain[7]  = 0.063096;    pan[7]  = .3;
+        tdelay[8]  = 0.808751;  gain[8]  = 0.063096;    pan[8]  = -.3;
+        tdelay[9]  = 0.910460;  gain[9]  = 0.031623;    pan[9]  = .15;
+        tdelay[10] = 1.027041;  gain[10] = 0.031623;    pan[10] = -.15;
+        tdelay[11] = 1.132028;  gain[11] = 0.012589;    pan[11] = .85;
+        tdelay[12] = 1.244272;  gain[12] = 0.012589;    pan[12] = -.85;
+        tdelay[13] = 1.336923;  gain[13] = 0.005012;    pan[13] = .4;
+        tdelay[14] = 1.427700;  gain[14] = 0.005012;    pan[14] = -.4;
+        tdelay[15] = 1.528503;  gain[15] = 0.002512;    pan[15] = .6;
+        tdelay[16] = 1.618661;  gain[16] = 0.002512;    pan[16] = -.6;
+        tdelay[17] = 1.715413;  gain[17] = 0.002512;    pan[17] = .225;
+        tdelay[18] = 1.814730;  gain[18] = 0.002512;    pan[18] = -.225;
+        tdelay[19] = 1.914843;  gain[19] = 0.002512;    pan[19] = .775;
+        tdelay[20] = 2.000258;  gain[20] = 0.002512;    pan[20] = -.775;
+        tdelay[21] = 2.135363;  gain[21] = 0.002512;    pan[21] = .125;
+        tdelay[22] = 2.230554;  gain[22] = 0.002512;    pan[22] = -.125;
+    } else {
+        top = log(1.0);
+        bot = log(.0001);
+        interval = (top - bot)/(dz->iparam[STAD_ECHOCNT] - 1);
+        gain[0] = 1.0;
+        for(n=1;n<(dz->iparam[STAD_ECHOCNT] - 1);n++) {
+            top -= interval;
+            gain[n] = exp(top);
+        }
+        gain[n] = .0001;
+        for(n=0;n<dz->iparam[STAD_ECHOCNT];n++) {
+            switch(n) {
+            case(0):    tdelay[0] = 0.000000;  pan[0] = -1;     break;
+            case(1):    tdelay[1] = 0.131832;  pan[1] = 1;      break;
+            case(2):    tdelay[2] = 0.215038;  pan[2] = .5;     break;
+            case(3):    tdelay[3] = 0.322274;  pan[3] = -.5;    break;
+            case(4):    tdelay[4] = 0.414122;  pan[4] = 0;      break;
+            case(5):    tdelay[5] = 0.504488;  pan[5] = .7;     break;
+            case(6):    tdelay[6] = 0.637713;  pan[6] = -.7;    break;
+            case(7):    tdelay[7] = 0.730468;  pan[7] = .3;     break;
+            case(8):    tdelay[8] = 0.808751;  pan[8] = -.3;    break;
+            case(9):    tdelay[9] = 0.910460;  pan[9] = .15;    break;
+            case(10):   tdelay[10] = 1.027041; pan[10] = -.15;  break;
+            case(11):   tdelay[11] = 1.132028; pan[11] = .85;   break;
+            case(12):   tdelay[12] = 1.244272; pan[12] = -.85;  break;
+            case(13):   tdelay[13] = 1.336923; pan[13] = .4;    break;
+            case(14):   tdelay[14] = 1.427700; pan[14] = -.4;   break;
+            case(15):   tdelay[15] = 1.528503; pan[15] = .6;    break;
+            case(16):   tdelay[16] = 1.618661; pan[16] = -.6;   break;
+            case(17):   tdelay[17] = 1.715413; pan[17] = .225;  break;
+            case(18):   tdelay[18] = 1.814730; pan[18] = -.225; break;
+            case(19):   tdelay[19] = 1.914843; pan[19] = .775;  break;
+            case(20):   tdelay[20] = 2.000258; pan[20] = -.775; break;
+            case(21):   tdelay[21] = 2.135363; pan[21] = .125;  break;
+            case(22):   tdelay[22] = 2.230554; pan[22] = -.125; break;
+            case(23):   tdelay[23] = 2.290000; pan[23] = -.65;  break;
+            case(24):   tdelay[24] = 2.372498; pan[24] = .65;   break;
+            case(25):   tdelay[25] = 2.445365; pan[25] = .35;   break;
+            case(26):   tdelay[26] = 2.571897; pan[26] = -.35;  break;
+            case(27):   tdelay[27] = 2.627656; pan[27] = -.1;   break;
+            case(28):   tdelay[28] = 2.695809; pan[28] = .1;    break;
+            case(29):   tdelay[29] = 2.758350; pan[29] = -.8;   break;
+            case(30):   tdelay[30] = 2.880984; pan[30] = .8;    break;
+            case(31):   tdelay[31] = 2.975910; pan[31] = -.55;  break;
+            case(32):   tdelay[32] = 3.043894; pan[32] = .55;   break;
+            case(33):   tdelay[33] = 3.143261; pan[33] = -.25;  break;
+            case(34):   tdelay[34] = 3.268126; pan[34] = .25;   break;
+            case(35):   tdelay[35] = 3.366093; pan[35] = -.45;  break;
+            case(36):   tdelay[36] = 3.480461; pan[36] = .45;   break;
+            case(37):   tdelay[37] = 3.577198; pan[37] = .05;   break;
+            case(38):   tdelay[38] = 3.666871; pan[38] = -.9;   break;
+            case(39):   tdelay[39] = 3.779061; pan[39] = -.05;  break;
+            case(40):   tdelay[40] = 3.852884; pan[40] = .9;    break;
+            case(41):   tdelay[41] = 3.966519; pan[41] = -.425; break;
+            case(42):   tdelay[42] = 4.043514; pan[42] = .425;  break;
+            case(43):   tdelay[43] = 4.147562; pan[43] = .75;   break;
+            case(44):   tdelay[44] = 4.241538; pan[44] = -.75;  break;
+            case(45):   tdelay[45] = 4.358808; pan[45] = .275;  break;
+            case(46):   tdelay[46] = 4.470554; pan[46] = -.275; break;
+            case(47):   tdelay[47] = 4.540000; pan[47] = -.625; break;
+            case(48):   tdelay[48] = 4.612729; pan[48] = .625;  break;
+            case(49):   tdelay[49] = 4.693888; pan[49] = .375;  break;
+            case(50):   tdelay[50] = 4.750479; pan[50] = -.375; break;
+            case(51):   tdelay[51] = 4.834122; pan[51] = -.116; break;
+            case(52):   tdelay[52] = 4.894456; pan[52] = .116;  break;
+            case(53):   tdelay[53] = 4.978112; pan[53] = -.825; break;
+            case(54):   tdelay[54] = 5.107199; pan[54] = .825;  break;
+            case(55):   tdelay[55] = 5.217554; pan[55] = -.535; break;
+            case(56):   tdelay[56] = 5.282567; pan[56] = .535;  break;
+            case(57):   tdelay[57] = 5.387678; pan[57] = -.265; break;
+            case(58):   tdelay[58] = 5.493642; pan[58] = .265;  break;
+            case(59):   tdelay[59] = 5.610009; pan[59] = -.475; break;
+            case(60):   tdelay[60] = 5.720302; pan[60] = .475;  break;
+            case(61):   tdelay[61] = 5.818331; pan[61] = .11;   break;
+            case(62):   tdelay[62] = 5.911186; pan[62] = -.77;  break;
+            case(63):   tdelay[63] = 6.013019; pan[63] = -.11;  break;
+            case(64):   tdelay[64] = 6.089382; pan[64] = .77;   break;
+            case(65):   tdelay[65] = 6.192071; pan[65] = -.475; break;
+            case(66):   tdelay[66] = 6.288516; pan[66] = .475;  break;
+            case(67):   tdelay[67] = 6.403337; pan[67] = .725;  break;
+            case(68):   tdelay[68] = 6.474009; pan[68] = -.725; break;
+            case(69):   tdelay[69] = 6.613701; pan[69] = .235;  break;
+            case(70):   tdelay[70] = 6.710554; pan[70] = -.235; break;
+            case(71):   tdelay[71] = 6.800000; pan[71] = -.685; break;
+            case(72):   tdelay[72] = 6.933349; pan[72] = .685;  break;
+            case(73):   tdelay[73] = 7.032532; pan[73] = .315;  break;
+            case(74):   tdelay[74] = 7.122216; pan[74] = -.315; break;
+            case(75):   tdelay[75] = 7.194122; pan[75] = -.136; break;
+            case(76):   tdelay[76] = 7.265021; pan[76] = .136;  break;
+            case(77):   tdelay[77] = 7.358764; pan[77] = -.635; break;
+            case(78):   tdelay[78] = 7.445276; pan[78] = .635;  break;
+            case(79):   tdelay[79] = 7.539293; pan[79] = -.435; break;
+            case(80):   tdelay[80] = 7.609978; pan[80] = .435;  break;
+            case(81):   tdelay[81] = 7.710640; pan[81] = -.765; break;
+            case(82):   tdelay[82] = 7.831968; pan[82] = .765;  break;
+            case(83):   tdelay[83] = 7.933759; pan[83] = -.575; break;
+            case(84):   tdelay[84] = 8.031102; pan[84] = .575;  break;
+            case(85):   tdelay[85] = 8.120963; pan[85] = .215;  break;
+            case(86):   tdelay[86] = 8.230907; pan[86] = -.692; break;
+            case(87):   tdelay[87] = 8.322181; pan[87] = -.215; break;
+            case(88):   tdelay[88] = 8.426997; pan[88] = .692;  break;
+            case(89):   tdelay[89] = 8.531689; pan[89] = -.435; break;
+            case(90):   tdelay[90] = 8.607012; pan[90] = .435;  break;
+            case(91):   tdelay[91] = 8.715148; pan[91] = .675;  break;
+            case(92):   tdelay[92] = 8.803142; pan[92] = -.675; break;
+            case(93):   tdelay[93] = 8.951037; pan[93] = .265;  break;
+            case(94):   tdelay[94] = 9.018695; pan[94] = -.265; break;
+            case(95):   tdelay[95] = 9.107151; pan[95] = -.555; break;
+            case(96):   tdelay[96] = 9.240962; pan[96] = .555;  break;
+            case(97):   tdelay[97] = 9.312251; pan[97] = .333;  break;
+            case(98):   tdelay[98] = 9.422676; pan[98] = -.333; break;
+            case(99):   tdelay[99] = 9.514122; pan[99] = 0.0;   break;
+            case(100):  tdelay[100] = 9.637713;  pan[100] = -1;     break;
+            case(101):  tdelay[101] = 9.730468;  pan[101] = 1;      break;
+            case(102):  tdelay[102] = 9.808751;  pan[102] = .5;     break;
+            case(103):  tdelay[103] = 9.910460;  pan[103] = -.5;    break;
+            case(104):  tdelay[104] = 10.027041;  pan[104] = 0;     break;
+            case(105):  tdelay[105] = 10.132028;  pan[105] = .7;    break;
+            case(106):  tdelay[106] = 10.244272;  pan[106] = -.7;   break;
+            case(107):  tdelay[107] = 10.336923;  pan[107] = .3;    break;
+            case(108):  tdelay[108] = 10.427700;  pan[108] = -.3;   break;
+            case(109):  tdelay[109] = 10.528503;  pan[109] = .15;   break;
+            case(110):  tdelay[110] = 10.618661; pan[110] = -.15;   break;
+            case(111):  tdelay[111] = 10.715413; pan[111] = .85;    break;
+            case(112):  tdelay[112] = 10.814730; pan[112] = -.85;   break;
+            case(113):  tdelay[113] = 10.914843; pan[113] = .4;     break;
+            case(114):  tdelay[114] = 11.000258; pan[114] = -.4;    break;
+            case(115):  tdelay[115] = 11.135363; pan[115] = .6;     break;
+            case(116):  tdelay[116] = 11.230554; pan[116] = -.6;    break;
+            case(117):  tdelay[117] = 11.290000; pan[117] = .225;   break;
+            case(118):  tdelay[118] = 11.372498; pan[118] = -.225;  break;
+            case(119):  tdelay[119] = 11.445365; pan[119] = .775;   break;
+            case(120):  tdelay[120] = 11.571897; pan[120] = -.775;  break;
+            case(121):  tdelay[121] = 11.627656; pan[121] = .125;   break;
+            case(122):  tdelay[122] = 11.695809; pan[122] = -.125;  break;
+            case(123):  tdelay[123] = 11.758350; pan[123] = -.65;   break;
+            case(124):  tdelay[124] = 11.880984; pan[124] = .65;    break;
+            case(125):  tdelay[125] = 11.975910; pan[125] = .35;    break;
+            case(126):  tdelay[126] = 12.043894; pan[126] = -.35;   break;
+            case(127):  tdelay[127] = 12.143261; pan[127] = -.1;    break;
+            case(128):  tdelay[128] = 12.268126; pan[128] = .1;     break;
+            case(129):  tdelay[129] = 12.366093; pan[129] = -.8;    break;
+            case(130):  tdelay[130] = 12.480461; pan[130] = .8;     break;
+            case(131):  tdelay[131] = 12.577198; pan[131] = -.55;   break;
+            case(132):  tdelay[132] = 12.666871; pan[132] = .55;    break;
+            case(133):  tdelay[133] = 12.779061; pan[133] = -.25;   break;
+            case(134):  tdelay[134] = 12.852884; pan[134] = .25;    break;
+            case(135):  tdelay[135] = 12.966519; pan[135] = -.45;   break;
+            case(136):  tdelay[136] = 13.043514; pan[136] = .45;    break;
+            case(137):  tdelay[137] = 13.147562; pan[137] = .05;    break;
+            case(138):  tdelay[138] = 13.241538; pan[138] = -.9;    break;
+            case(139):  tdelay[139] = 13.358808; pan[139] = -.05;   break;
+            case(140):  tdelay[140] = 13.470554; pan[140] = .9;     break;
+            case(141):  tdelay[141] = 13.540000; pan[141] = -.425;  break;
+            case(142):  tdelay[142] = 13.612729; pan[142] = .425;   break;
+            case(143):  tdelay[143] = 13.693888; pan[143] = .75;    break;
+            case(144):  tdelay[144] = 13.750479; pan[144] = -.75;   break;
+            case(145):  tdelay[145] = 13.834122; pan[145] = .275;   break;
+            case(146):  tdelay[146] = 13.894456; pan[146] = -.275;  break;
+            case(147):  tdelay[147] = 13.978112; pan[147] = -.625;  break;
+            case(148):  tdelay[148] = 14.107199; pan[148] = .625;   break;
+            case(149):  tdelay[149] = 14.217554; pan[149] = .375;   break;
+            case(150):  tdelay[150] = 14.282567; pan[150] = -.375;  break;
+            case(151):  tdelay[151] = 14.387678; pan[151] = -.116;  break;
+            case(152):  tdelay[152] = 14.493642; pan[152] = .116;   break;
+            case(153):  tdelay[153] = 14.610009; pan[153] = -.825;  break;
+            case(154):  tdelay[154] = 14.720302; pan[154] = .825;   break;
+            case(155):  tdelay[155] = 14.818331; pan[155] = -.535;  break;
+            case(156):  tdelay[156] = 14.911186; pan[156] = .535;   break;
+            case(157):  tdelay[157] = 15.013019; pan[157] = -.265;  break;
+            case(158):  tdelay[158] = 15.089382; pan[158] = .265;   break;
+            case(159):  tdelay[159] = 15.192071; pan[159] = -.475;  break;
+            case(160):  tdelay[160] = 15.288516; pan[160] = .475;   break;
+            case(161):  tdelay[161] = 15.403337; pan[161] = .11;    break;
+            case(162):  tdelay[162] = 15.474009; pan[162] = -.77;   break;
+            case(163):  tdelay[163] = 15.613701; pan[163] = -.11;   break;
+            case(164):  tdelay[164] = 15.710554; pan[164] = .77;    break;
+            case(165):  tdelay[165] = 15.800000; pan[165] = -.475;  break;
+            case(166):  tdelay[166] = 15.933349; pan[166] = .475;   break;
+            case(167):  tdelay[167] = 16.032532; pan[167] = .725;   break;
+            case(168):  tdelay[168] = 16.122216; pan[168] = -.725;  break;
+            case(169):  tdelay[169] = 16.194122; pan[169] = .235;   break;
+            case(170):  tdelay[170] = 16.265021; pan[170] = -.235;  break;
+            case(171):  tdelay[171] = 16.358764; pan[171] = -.685;  break;
+            case(172):  tdelay[172] = 16.445276; pan[172] = .685;   break;
+            case(173):  tdelay[173] = 16.539293; pan[173] = .315;   break;
+            case(174):  tdelay[174] = 16.609978; pan[174] = -.315;  break;
+            case(175):  tdelay[175] = 16.710640; pan[175] = -.136;  break;
+            case(176):  tdelay[176] = 16.831968; pan[176] = .136;   break;
+            case(177):  tdelay[177] = 16.933759; pan[177] = -.635;  break;
+            case(178):  tdelay[178] = 17.031102; pan[178] = .635;   break;
+            case(179):  tdelay[179] = 17.120963; pan[179] = -.435;  break;
+            case(180):  tdelay[180] = 17.230907; pan[180] = .435;   break;
+            case(181):  tdelay[181] = 17.322181; pan[181] = -.765;  break;
+            case(182):  tdelay[182] = 17.426997; pan[182] = .765;   break;
+            case(183):  tdelay[183] = 17.531689; pan[183] = -.575;  break;
+            case(184):  tdelay[184] = 17.607012; pan[184] = .575;   break;
+            case(185):  tdelay[185] = 17.715148; pan[185] = .215;   break;
+            case(186):  tdelay[186] = 17.803142; pan[186] = -.692;  break;
+            case(187):  tdelay[187] = 17.951037; pan[187] = -.215;  break;
+            case(188):  tdelay[188] = 18.018695; pan[188] = .692;   break;
+            case(189):  tdelay[189] = 18.107151; pan[189] = -.435;  break;
+            case(190):  tdelay[190] = 18.240962; pan[190] = .435;   break;
+            case(191):  tdelay[191] = 18.312251; pan[191] = .675;   break;
+            case(192):  tdelay[192] = 18.422676; pan[192] = -.675;  break;
+            case(193):  tdelay[193] = 18.514122; pan[193] = .265;   break;
+            case(194):  tdelay[194] = 18.637713; pan[194] = -.265;  break;
+            case(195):  tdelay[195] = 18.730468; pan[195] = -.555;  break;
+            case(196):  tdelay[196] = 18.808751; pan[196] = .555;   break;
+            case(197):  tdelay[197] = 18.910460; pan[197] = .333;   break;
+            case(198):  tdelay[198] = 19.000000; pan[198] = -.333;  break;
+            case(199):  tdelay[199] = 19.131832; pan[199] = 0.0;    break;
+            case(200):  tdelay[200] = 19.215038;  pan[200] = -1;    break;
+            case(201):  tdelay[201] = 19.322274;  pan[201] = 1;     break;
+            case(202):  tdelay[202] = 19.414122;  pan[202] = .5;    break;
+            case(203):  tdelay[203] = 19.504488;  pan[203] = -.5;   break;
+            case(204):  tdelay[204] = 19.637713;  pan[204] = 0;     break;
+            case(205):  tdelay[205] = 19.730468;  pan[205] = .7;    break;
+            case(206):  tdelay[206] = 19.808751;  pan[206] = -.7;   break;
+            case(207):  tdelay[207] = 19.910460;  pan[207] = .3;    break;
+            case(208):  tdelay[208] = 20.027041;  pan[208] = -.3;   break;
+            case(209):  tdelay[209] = 20.132028;  pan[209] = .15;   break;
+            case(210):  tdelay[210] = 20.244272; pan[210] = -.15;   break;
+            case(211):  tdelay[211] = 20.336923; pan[211] = .85;    break;
+            case(212):  tdelay[212] = 20.427700; pan[212] = -.85;   break;
+            case(213):  tdelay[213] = 20.528503; pan[213] = .4;     break;
+            case(214):  tdelay[214] = 20.618661; pan[214] = -.4;    break;
+            case(215):  tdelay[215] = 20.715413; pan[215] = .6;     break;
+            case(216):  tdelay[216] = 20.814730; pan[216] = -.6;    break;
+            case(217):  tdelay[217] = 20.914843; pan[217] = .225;   break;
+            case(218):  tdelay[218] = 21.000258; pan[218] = -.225;  break;
+            case(219):  tdelay[219] = 21.135363; pan[219] = .775;   break;
+            case(220):  tdelay[220] = 21.230554; pan[220] = -.775;  break;
+            case(221):  tdelay[221] = 21.290000; pan[221] = .125;   break;
+            case(222):  tdelay[222] = 21.372498; pan[222] = -.125;  break;
+            case(223):  tdelay[223] = 21.445365; pan[223] = -.65;   break;
+            case(224):  tdelay[224] = 21.571897; pan[224] = .65;    break;
+            case(225):  tdelay[225] = 21.627656; pan[225] = .35;    break;
+            case(226):  tdelay[226] = 21.695809; pan[226] = -.35;   break;
+            case(227):  tdelay[227] = 21.758350; pan[227] = -.1;    break;
+            case(228):  tdelay[228] = 21.880984; pan[228] = .1;     break;
+            case(229):  tdelay[229] = 21.975910; pan[229] = -.8;    break;
+            case(230):  tdelay[230] = 22.043894; pan[230] = .8;     break;
+            case(231):  tdelay[231] = 22.143261; pan[231] = -.55;   break;
+            case(232):  tdelay[232] = 22.268126; pan[232] = .55;    break;
+            case(233):  tdelay[233] = 22.366093; pan[233] = -.25;   break;
+            case(234):  tdelay[234] = 22.480461; pan[234] = .25;    break;
+            case(235):  tdelay[235] = 22.577198; pan[235] = -.45;   break;
+            case(236):  tdelay[236] = 22.666871; pan[236] = .45;    break;
+            case(237):  tdelay[237] = 22.779061; pan[237] = .05;    break;
+            case(238):  tdelay[238] = 22.852884; pan[238] = -.9;    break;
+            case(239):  tdelay[239] = 22.966519; pan[239] = -.05;   break;
+            case(240):  tdelay[240] = 23.043514; pan[240] = .9;     break;
+            case(241):  tdelay[241] = 23.147562; pan[241] = -.425;  break;
+            case(242):  tdelay[242] = 23.241538; pan[242] = .425;   break;
+            case(243):  tdelay[243] = 23.358808; pan[243] = .75;    break;
+            case(244):  tdelay[244] = 23.470554; pan[244] = -.75;   break;
+            case(245):  tdelay[245] = 23.540000; pan[245] = .275;   break;
+            case(246):  tdelay[246] = 23.612729; pan[246] = -.275;  break;
+            case(247):  tdelay[247] = 23.693888; pan[247] = -.625;  break;
+            case(248):  tdelay[248] = 23.750479; pan[248] = .625;   break;
+            case(249):  tdelay[249] = 23.834122; pan[249] = .375;   break;
+            case(250):  tdelay[250] = 23.894456; pan[250] = -.375;  break;
+            case(251):  tdelay[251] = 23.978112; pan[251] = -.116;  break;
+            case(252):  tdelay[252] = 24.107199; pan[252] = .116;   break;
+            case(253):  tdelay[253] = 24.217554; pan[253] = -.825;  break;
+            case(254):  tdelay[254] = 24.282567; pan[254] = .825;   break;
+            case(255):  tdelay[255] = 24.387678; pan[255] = -.535;  break;
+            case(256):  tdelay[256] = 24.493642; pan[256] = .535;   break;
+            case(257):  tdelay[257] = 24.610009; pan[257] = -.265;  break;
+            case(258):  tdelay[258] = 24.720302; pan[258] = .265;   break;
+            case(259):  tdelay[259] = 24.818331; pan[259] = -.475;  break;
+            case(260):  tdelay[260] = 24.911186; pan[260] = .475;   break;
+            case(261):  tdelay[261] = 25.013019; pan[261] = .11;    break;
+            case(262):  tdelay[262] = 25.089382; pan[262] = -.77;   break;
+            case(263):  tdelay[263] = 25.192071; pan[263] = -.11;   break;
+            case(264):  tdelay[264] = 25.288516; pan[264] = .77;    break;
+            case(265):  tdelay[265] = 25.403337; pan[265] = -.475;  break;
+            case(266):  tdelay[266] = 25.474009; pan[266] = .475;   break;
+            case(267):  tdelay[267] = 25.613701; pan[267] = .725;   break;
+            case(268):  tdelay[268] = 25.710554; pan[268] = -.725;  break;
+            case(269):  tdelay[269] = 25.800000; pan[269] = .235;   break;
+            case(270):  tdelay[270] = 25.933349; pan[270] = -.235;  break;
+            case(271):  tdelay[271] = 26.032532; pan[271] = -.685;  break;
+            case(272):  tdelay[272] = 26.122216; pan[272] = .685;   break;
+            case(273):  tdelay[273] = 26.194122; pan[273] = .315;   break;
+            case(274):  tdelay[274] = 26.265021; pan[274] = -.315;  break;
+            case(275):  tdelay[275] = 26.358764; pan[275] = -.136;  break;
+            case(276):  tdelay[276] = 26.445276; pan[276] = .136;   break;
+            case(277):  tdelay[277] = 26.539293; pan[277] = -.635;  break;
+            case(278):  tdelay[278] = 26.609978; pan[278] = .635;   break;
+            case(279):  tdelay[279] = 26.710640; pan[279] = -.435;  break;
+            case(280):  tdelay[280] = 26.831968; pan[280] = .435;   break;
+            case(281):  tdelay[281] = 26.933759; pan[281] = -.765;  break;
+            case(282):  tdelay[282] = 27.031102; pan[282] = .765;   break;
+            case(283):  tdelay[283] = 27.120963; pan[283] = -.575;  break;
+            case(284):  tdelay[284] = 27.230907; pan[284] = .575;   break;
+            case(285):  tdelay[285] = 27.322181; pan[285] = .215;   break;
+            case(286):  tdelay[286] = 27.426997; pan[286] = -.692;  break;
+            case(287):  tdelay[287] = 27.531689; pan[287] = -.215;  break;
+            case(288):  tdelay[288] = 27.607012; pan[288] = .692;   break;
+            case(289):  tdelay[289] = 27.715148; pan[289] = -.435;  break;
+            case(290):  tdelay[290] = 27.803142; pan[290] = .435;   break;
+            case(291):  tdelay[291] = 27.951037; pan[291] = .675;   break;
+            case(292):  tdelay[292] = 28.018695; pan[292] = -.675;  break;
+            case(293):  tdelay[293] = 28.107151; pan[293] = .265;   break;
+            case(294):  tdelay[294] = 28.240962; pan[294] = -.265;  break;
+            case(295):  tdelay[295] = 28.312251; pan[295] = -.555;  break;
+            case(296):  tdelay[296] = 28.422676; pan[296] = -.333;  break;
+            case(297):  tdelay[297] = 28.514122; pan[297] = 0.0;    break;
+            case(298):  tdelay[298] = 28.637713;  pan[298] = -1;    break;
+            case(299):  tdelay[299] = 28.730468;  pan[299] = 1;     break;
+            case(300):  tdelay[300] = 28.808751;  pan[300] = .5;    break;
+            case(301):  tdelay[301] = 28.910460;  pan[301] = -.5;   break;
+            case(302):  tdelay[302] = 29.027041;  pan[302] = 0;     break;
+            case(303):  tdelay[303] = 29.132028;  pan[303] = .7;    break;
+            case(304):  tdelay[304] = 29.244272;  pan[304] = -.7;   break;
+            case(305):  tdelay[305] = 29.336923;  pan[305] = .3;    break;
+            case(306):  tdelay[306] = 29.427700;  pan[306] = -.3;   break;
+            case(307):  tdelay[307] = 29.528503;  pan[307] = .15;   break;
+            case(308):  tdelay[308] = 29.618661; pan[308] = -.15;   break;
+            case(309):  tdelay[309] = 29.715413; pan[309] = .85;    break;
+            case(310):  tdelay[310] = 29.814730; pan[310] = -.85;   break;
+            case(311):  tdelay[311] = 29.914843; pan[311] = .4;     break;
+            case(312):  tdelay[312] = 30.000258; pan[312] = -.4;    break;
+            case(313):  tdelay[313] = 30.135363; pan[313] = .6;     break;
+            case(314):  tdelay[314] = 30.230554; pan[314] = -.6;    break;
+            case(315):  tdelay[315] = 30.290000; pan[315] = .225;   break;
+            case(316):  tdelay[316] = 30.372498; pan[316] = -.225;  break;
+            case(317):  tdelay[317] = 30.445365; pan[317] = .775;   break;
+            case(318):  tdelay[318] = 30.571897; pan[318] = -.775;  break;
+            case(319):  tdelay[319] = 30.627656; pan[319] = .125;   break;
+            case(320):  tdelay[320] = 30.695809; pan[320] = -.125;  break;
+            case(321):  tdelay[321] = 30.758350; pan[321] = -.65;   break;
+            case(322):  tdelay[322] = 30.880984; pan[322] = .65;    break;
+            case(323):  tdelay[323] = 30.975910; pan[323] = .35;    break;
+            case(324):  tdelay[324] = 31.043894; pan[324] = -.35;   break;
+            case(325):  tdelay[325] = 31.143261; pan[325] = -.1;    break;
+            case(326):  tdelay[326] = 31.268126; pan[326] = .1;     break;
+            case(327):  tdelay[327] = 31.366093; pan[327] = -.8;    break;
+            case(328):  tdelay[328] = 31.480461; pan[328] = .8;     break;
+            case(329):  tdelay[329] = 31.577198; pan[329] = -.55;   break;
+            case(330):  tdelay[330] = 31.666871; pan[330] = .55;    break;
+            case(331):  tdelay[331] = 31.779061; pan[331] = -.25;   break;
+            case(332):  tdelay[332] = 31.852884; pan[332] = .25;    break;
+            case(333):  tdelay[333] = 31.966519; pan[333] = -.45;   break;
+            case(334):  tdelay[334] = 32.043514; pan[334] = .45;    break;
+            case(335):  tdelay[335] = 32.147562; pan[335] = .05;    break;
+            case(336):  tdelay[336] = 32.241538; pan[336] = -.9;    break;
+            case(337):  tdelay[337] = 32.358808; pan[337] = -.05;   break;
+            case(338):  tdelay[338] = 32.470554; pan[338] = .9;     break;
+            case(339):  tdelay[339] = 32.540000; pan[339] = -.425;  break;
+            case(340):  tdelay[340] = 32.612729; pan[340] = .425;   break;
+            case(341):  tdelay[341] = 32.693888; pan[341] = .75;    break;
+            case(342):  tdelay[342] = 32.750479; pan[342] = -.75;   break;
+            case(343):  tdelay[343] = 32.834122; pan[343] = .275;   break;
+            case(344):  tdelay[344] = 32.894456; pan[344] = -.275;  break;
+            case(345):  tdelay[345] = 32.978112; pan[345] = -.625;  break;
+            case(346):  tdelay[346] = 33.107199; pan[346] = .625;   break;
+            case(347):  tdelay[347] = 33.217554; pan[347] = .375;   break;
+            case(348):  tdelay[348] = 33.282567; pan[348] = -.375;  break;
+            case(349):  tdelay[349] = 33.387678; pan[349] = -.116;  break;
+            case(350):  tdelay[350] = 33.493642; pan[350] = .116;   break;
+            case(351):  tdelay[351] = 33.610009; pan[351] = -.825;  break;
+            case(352):  tdelay[352] = 33.720302; pan[352] = .825;   break;
+            case(353):  tdelay[353] = 33.818331; pan[353] = -.535;  break;
+            case(354):  tdelay[354] = 33.911186; pan[354] = .535;   break;
+            case(355):  tdelay[355] = 34.013019; pan[355] = -.265;  break;
+            case(356):  tdelay[356] = 34.089382; pan[356] = .265;   break;
+            case(357):  tdelay[357] = 34.192071; pan[357] = -.475;  break;
+            case(358):  tdelay[358] = 34.288516; pan[358] = .475;   break;
+            case(359):  tdelay[359] = 34.403337; pan[359] = .11;    break;
+            case(360):  tdelay[360] = 34.474009; pan[360] = -.77;   break;
+            case(361):  tdelay[361] = 34.613701; pan[361] = -.11;   break;
+            case(362):  tdelay[362] = 34.710554; pan[362] = .77;    break;
+            case(363):  tdelay[363] = 34.800000; pan[363] = -.475;  break;
+            case(364):  tdelay[364] = 34.933349; pan[364] = .475;   break;
+            case(365):  tdelay[365] = 35.032532; pan[365] = .725;   break;
+            case(366):  tdelay[366] = 35.122216; pan[366] = -.725;  break;
+            case(367):  tdelay[367] = 35.194122; pan[367] = .235;   break;
+            case(368):  tdelay[368] = 35.265021; pan[368] = -.235;  break;
+            case(369):  tdelay[369] = 35.358764; pan[369] = -.685;  break;
+            case(370):  tdelay[370] = 35.445276; pan[370] = .685;   break;
+            case(371):  tdelay[371] = 35.539293; pan[371] = .315;   break;
+            case(372):  tdelay[372] = 35.609978; pan[372] = -.315;  break;
+            case(373):  tdelay[373] = 35.710640; pan[373] = -.136;  break;
+            case(374):  tdelay[374] = 35.831968; pan[374] = .136;   break;
+            case(375):  tdelay[375] = 35.933759; pan[375] = -.635;  break;
+            case(376):  tdelay[376] = 36.031102; pan[376] = .635;   break;
+            case(377):  tdelay[377] = 36.120963; pan[377] = -.435;  break;
+            case(378):  tdelay[378] = 36.230907; pan[378] = .435;   break;
+            case(379):  tdelay[379] = 36.322181; pan[379] = -.765;  break;
+            case(380):  tdelay[380] = 36.426997; pan[380] = .765;   break;
+            case(381):  tdelay[381] = 36.531689; pan[381] = -.575;  break;
+            case(382):  tdelay[382] = 36.607012; pan[382] = .575;   break;
+            case(383):  tdelay[383] = 36.715148; pan[383] = .215;   break;
+            case(384):  tdelay[384] = 36.803142; pan[384] = -.692;  break;
+            case(385):  tdelay[385] = 36.951037; pan[385] = -.215;  break;
+            case(386):  tdelay[386] = 37.088695; pan[386] = .692;   break;
+            case(387):  tdelay[387] = 37.240962; pan[387] = -.435;  break;
+            case(388):  tdelay[388] = 37.312251; pan[388] = .435;   break;
+            case(389):  tdelay[389] = 37.422676; pan[389] = .675;   break;
+            case(390):  tdelay[390] = 37.514122; pan[390] = -.675;  break;
+            case(391):  tdelay[391] = 37.637713; pan[391] = .265;   break;
+            case(392):  tdelay[392] = 37.730468; pan[392] = -.265;  break;
+            case(393):  tdelay[393] = 37.808751; pan[393] = -.555;  break;
+            case(394):  tdelay[394] = 37.910460; pan[394] = .555;   break;
+            case(395):  tdelay[395] = 38.000000; pan[395] = .333;   break;
+            case(396):  tdelay[396] = 38.131832; pan[396] = -.333;  break;
+            case(397):  tdelay[397] = 38.215038; pan[397] = 0.0;    break;
+            case(398):  tdelay[398] = 38.322274;  pan[398] = -1;    break;
+            case(399):  tdelay[399] = 38.414122;  pan[399] = 1;     break;
+            case(400):  tdelay[400] = 38.504488;  pan[400] = .5;    break;
+            case(401):  tdelay[401] = 38.637713;  pan[401] = -.5;   break;
+            case(402):  tdelay[402] = 38.730468;  pan[402] = 0;     break;
+            case(403):  tdelay[403] = 38.808751;  pan[403] = .7;    break;
+            case(404):  tdelay[404] = 38.910460;  pan[404] = -.7;   break;
+            case(405):  tdelay[405] = 39.027041;  pan[405] = .3;    break;
+            case(406):  tdelay[406] = 39.132028;  pan[406] = -.3;   break;
+            case(407):  tdelay[407] = 39.244272;  pan[407] = .15;   break;
+            case(408):  tdelay[408] = 39.336923; pan[408] = -.15;   break;
+            case(409):  tdelay[409] = 39.427700; pan[409] = .85;    break;
+            case(410):  tdelay[410] = 39.528503; pan[410] = -.85;   break;
+            case(411):  tdelay[411] = 39.618661; pan[411] = .4;     break;
+            case(412):  tdelay[412] = 39.715413; pan[412] = -.4;    break;
+            case(413):  tdelay[413] = 39.814730; pan[413] = .6;     break;
+            case(414):  tdelay[414] = 39.914843; pan[414] = -.6;    break;
+            case(415):  tdelay[415] = 40.000258; pan[415] = .225;   break;
+            case(416):  tdelay[416] = 40.135363; pan[416] = -.225;  break;
+            case(417):  tdelay[417] = 40.230554; pan[417] = .775;   break;
+            case(418):  tdelay[418] = 40.290000; pan[418] = -.775;  break;
+            case(419):  tdelay[419] = 40.372498; pan[419] = .125;   break;
+            case(420):  tdelay[420] = 40.445365; pan[420] = -.125;  break;
+            case(421):  tdelay[421] = 40.571897; pan[421] = -.65;   break;
+            case(422):  tdelay[422] = 40.627656; pan[422] = .65;    break;
+            case(423):  tdelay[423] = 40.695809; pan[423] = .35;    break;
+            case(424):  tdelay[424] = 40.758350; pan[424] = -.35;   break;
+            case(425):  tdelay[425] = 40.880984; pan[425] = -.1;    break;
+            case(426):  tdelay[426] = 40.975910; pan[426] = .1;     break;
+            case(427):  tdelay[427] = 41.043894; pan[427] = -.8;    break;
+            case(428):  tdelay[428] = 41.143261; pan[428] = .8;     break;
+            case(429):  tdelay[429] = 41.268126; pan[429] = -.55;   break;
+            case(430):  tdelay[430] = 41.366093; pan[430] = .55;    break;
+            case(431):  tdelay[431] = 41.480461; pan[431] = -.25;   break;
+            case(432):  tdelay[432] = 41.577198; pan[432] = .25;    break;
+            case(433):  tdelay[433] = 41.666871; pan[433] = -.45;   break;
+            case(434):  tdelay[434] = 41.779061; pan[434] = .45;    break;
+            case(435):  tdelay[435] = 41.852884; pan[435] = .05;    break;
+            case(436):  tdelay[436] = 41.966519; pan[436] = -.9;    break;
+            case(437):  tdelay[437] = 42.043514; pan[437] = -.05;   break;
+            case(438):  tdelay[438] = 42.147562; pan[438] = .9;     break;
+            case(439):  tdelay[439] = 42.241538; pan[439] = -.425;  break;
+            case(440):  tdelay[440] = 42.358808; pan[440] = .425;   break;
+            case(441):  tdelay[441] = 42.470554; pan[441] = .75;    break;
+            case(442):  tdelay[442] = 42.540000; pan[442] = -.75;   break;
+            case(443):  tdelay[443] = 42.612729; pan[443] = .275;   break;
+            case(444):  tdelay[444] = 42.693888; pan[444] = -.275;  break;
+            case(445):  tdelay[445] = 42.750479; pan[445] = -.625;  break;
+            case(446):  tdelay[446] = 42.834122; pan[446] = .625;   break;
+            case(447):  tdelay[447] = 42.894456; pan[447] = .375;   break;
+            case(448):  tdelay[448] = 42.978112; pan[448] = -.375;  break;
+            case(449):  tdelay[449] = 43.107199; pan[449] = -.116;  break;
+            case(450):  tdelay[450] = 43.217554; pan[450] = .116;   break;
+            case(451):  tdelay[451] = 43.282567; pan[451] = -.825;  break;
+            case(452):  tdelay[452] = 43.387678; pan[452] = .825;   break;
+            case(453):  tdelay[453] = 43.493642; pan[453] = -.535;  break;
+            case(454):  tdelay[454] = 43.610009; pan[454] = .535;   break;
+            case(455):  tdelay[455] = 43.720302; pan[455] = -.265;  break;
+            case(456):  tdelay[456] = 43.818331; pan[456] = .265;   break;
+            case(457):  tdelay[457] = 43.911186; pan[457] = -.475;  break;
+            case(458):  tdelay[458] = 44.013019; pan[458] = .475;   break;
+            case(459):  tdelay[459] = 44.089382; pan[459] = .11;    break;
+            case(460):  tdelay[460] = 44.192071; pan[460] = -.77;   break;
+            case(461):  tdelay[461] = 44.288516; pan[461] = -.11;   break;
+            case(462):  tdelay[462] = 44.403337; pan[462] = .77;    break;
+            case(463):  tdelay[463] = 44.474009; pan[463] = -.475;  break;
+            case(464):  tdelay[464] = 44.613701; pan[464] = .475;   break;
+            case(465):  tdelay[465] = 44.710554; pan[465] = .725;   break;
+            case(466):  tdelay[466] = 44.800000; pan[466] = -.725;  break;
+            case(467):  tdelay[467] = 44.933349; pan[467] = .235;   break;
+            case(468):  tdelay[468] = 45.032532; pan[468] = -.235;  break;
+            case(469):  tdelay[469] = 45.122216; pan[469] = -.685;  break;
+            case(470):  tdelay[470] = 45.194122; pan[470] = .685;   break;
+            case(471):  tdelay[471] = 45.265021; pan[471] = .315;   break;
+            case(472):  tdelay[472] = 45.358764; pan[472] = -.315;  break;
+            case(473):  tdelay[473] = 45.445276; pan[473] = -.136;  break;
+            case(474):  tdelay[474] = 45.539293; pan[474] = .136;   break;
+            case(475):  tdelay[475] = 45.609978; pan[475] = -.635;  break;
+            case(476):  tdelay[476] = 45.710640; pan[476] = .635;   break;
+            case(477):  tdelay[477] = 45.831968; pan[477] = -.435;  break;
+            case(478):  tdelay[478] = 45.933759; pan[478] = .435;   break;
+            case(479):  tdelay[479] = 46.031102; pan[479] = -.765;  break;
+            case(480):  tdelay[480] = 46.120963; pan[480] = .765;   break;
+            case(481):  tdelay[481] = 46.230907; pan[481] = -.575;  break;
+            case(482):  tdelay[482] = 46.322181; pan[482] = .575;   break;
+            case(483):  tdelay[483] = 46.426997; pan[483] = .215;   break;
+            case(484):  tdelay[484] = 46.531689; pan[484] = -.692;  break;
+            case(485):  tdelay[485] = 46.607012; pan[485] = -.215;  break;
+            case(486):  tdelay[486] = 46.715148; pan[486] = .692;   break;
+            case(487):  tdelay[487] = 46.803142; pan[487] = -.435;  break;
+            case(488):  tdelay[488] = 46.951037; pan[488] = .435;   break;
+            case(489):  tdelay[489] = 47.018695; pan[489] = .675;   break;
+            case(490):  tdelay[490] = 47.107151; pan[490] = -.675;  break;
+            case(491):  tdelay[491] = 47.240962; pan[491] = .265;   break;
+            case(492):  tdelay[492] = 47.312251; pan[492] = -.265;  break;
+            case(493):  tdelay[493] = 47.422676; pan[493] = -.555;  break;
+            case(494):  tdelay[494] = 47.514122; pan[494] = .555;   break;
+            case(495):  tdelay[495] = 47.637713; pan[495] = .333;   break;
+            case(496):  tdelay[496] = 47.730468; pan[496] = -.333;  break;
+            case(497):  tdelay[497] = 47.808751; pan[497] = 0.0;    break;
+            case(498):  tdelay[498] = 47.910460; pan[498] = -1;     break;
+            case(499):  tdelay[499] = 48.027041; pan[499] = 1;      break;
+            case(500):  tdelay[500] = 48.132028; pan[500] = .5;     break;
+            case(501):  tdelay[501] = 48.244272; pan[501] = -.5;    break;
+            case(502):  tdelay[502] = 48.336923; pan[502] = 0;      break;
+            case(503):  tdelay[503] = 48.427700; pan[503] = .7;     break;
+            case(504):  tdelay[504] = 48.528503; pan[504] = -.7;    break;
+            case(505):  tdelay[505] = 48.618661; pan[505] = .3;     break;
+            case(506):  tdelay[506] = 48.715413; pan[506] = -.3;    break;
+            case(507):  tdelay[507] = 48.814730; pan[507] = .15;    break;
+            case(508):  tdelay[508] = 48.914843; pan[508] = -.15;   break;
+            case(509):  tdelay[509] = 49.000258; pan[509] = .85;    break;
+            case(510):  tdelay[510] = 49.135363; pan[510] = -.85;   break;
+            case(511):  tdelay[511] = 49.230554; pan[511] = .4;     break;
+            case(512):  tdelay[512] = 49.290000; pan[512] = -.4;    break;
+            case(513):  tdelay[513] = 49.372498; pan[513] = .6;     break;
+            case(514):  tdelay[514] = 49.445365; pan[514] = -.6;    break;
+            case(515):  tdelay[515] = 49.571897; pan[515] = .225;   break;
+            case(516):  tdelay[516] = 49.627656; pan[516] = -.225;  break;
+            case(517):  tdelay[517] = 49.695809; pan[517] = .775;   break;
+            case(518):  tdelay[518] = 49.758350; pan[518] = -.775;  break;
+            case(519):  tdelay[519] = 49.880984; pan[519] = .125;   break;
+            case(520):  tdelay[520] = 49.975910; pan[520] = -.125;  break;
+            case(521):  tdelay[521] = 50.043894; pan[521] = -.65;   break;
+            case(522):  tdelay[522] = 50.143261; pan[522] = .65;    break;
+            case(523):  tdelay[523] = 50.268126; pan[523] = .35;    break;
+            case(524):  tdelay[524] = 50.366093; pan[524] = -.35;   break;
+            case(525):  tdelay[525] = 50.480461; pan[525] = -.1;    break;
+            case(526):  tdelay[526] = 50.577198; pan[526] = .1;     break;
+            case(527):  tdelay[527] = 50.666871; pan[527] = -.8;    break;
+            case(528):  tdelay[528] = 50.779061; pan[528] = .8;     break;
+            case(529):  tdelay[529] = 50.852884; pan[529] = -.55;   break;
+            case(530):  tdelay[530] = 50.966519; pan[530] = .55;    break;
+            case(531):  tdelay[531] = 51.043514; pan[531] = -.25;   break;
+            case(532):  tdelay[532] = 51.147562; pan[532] = .25;    break;
+            case(533):  tdelay[533] = 51.241538; pan[533] = -.45;   break;
+            case(534):  tdelay[534] = 51.358808; pan[534] = .45;    break;
+            case(535):  tdelay[535] = 51.470554; pan[535] = .05;    break;
+            case(536):  tdelay[536] = 51.540000; pan[536] = -.9;    break;
+            case(537):  tdelay[537] = 51.612729; pan[537] = -.05;   break;
+            case(538):  tdelay[538] = 51.693888; pan[538] = .9;     break;
+            case(539):  tdelay[539] = 51.750479; pan[539] = -.425;  break;
+            case(540):  tdelay[540] = 51.834122; pan[540] = .425;   break;
+            case(541):  tdelay[541] = 51.894456; pan[541] = .75;    break;
+            case(542):  tdelay[542] = 51.978112; pan[542] = -.75;   break;
+            case(543):  tdelay[543] = 52.107199; pan[543] = .275;   break;
+            case(544):  tdelay[544] = 52.217554; pan[544] = -.275;  break;
+            case(545):  tdelay[545] = 52.282567; pan[545] = -.625;  break;
+            case(546):  tdelay[546] = 52.387678; pan[546] = .625;   break;
+            case(547):  tdelay[547] = 52.493642; pan[547] = .375;   break;
+            case(548):  tdelay[548] = 52.610009; pan[548] = -.375;  break;
+            case(549):  tdelay[549] = 52.720302; pan[549] = -.116;  break;
+            case(550):  tdelay[550] = 52.818331; pan[550] = .116;   break;
+            case(551):  tdelay[551] = 52.911186; pan[551] = -.825;  break;
+            case(552):  tdelay[552] = 53.013019; pan[552] = .825;   break;
+            case(553):  tdelay[553] = 53.089382; pan[553] = -.535;  break;
+            case(554):  tdelay[554] = 53.192071; pan[554] = .535;   break;
+            case(555):  tdelay[555] = 53.288516; pan[555] = -.265;  break;
+            case(556):  tdelay[556] = 53.403337; pan[556] = .265;   break;
+            case(557):  tdelay[557] = 53.474009; pan[557] = -.475;  break;
+            case(558):  tdelay[558] = 53.613701; pan[558] = .475;   break;
+            case(559):  tdelay[559] = 53.710554; pan[559] = .11;    break;
+            case(560):  tdelay[560] = 53.800000; pan[560] = -.77;   break;
+            case(561):  tdelay[561] = 53.933349; pan[561] = -.11;   break;
+            case(562):  tdelay[562] = 54.032532; pan[562] = .77;    break;
+            case(563):  tdelay[563] = 54.122216; pan[563] = -.475;  break;
+            case(564):  tdelay[564] = 54.194122; pan[564] = .475;   break;
+            case(565):  tdelay[565] = 54.265021; pan[565] = .725;   break;
+            case(566):  tdelay[566] = 54.358764; pan[566] = -.725;  break;
+            case(567):  tdelay[567] = 54.445276; pan[567] = .235;   break;
+            case(568):  tdelay[568] = 54.539293; pan[568] = -.235;  break;
+            case(569):  tdelay[569] = 54.609978; pan[569] = -.685;  break;
+            case(570):  tdelay[570] = 54.710640; pan[570] = .685;   break;
+            case(571):  tdelay[571] = 54.831968; pan[571] = .315;   break;
+            case(572):  tdelay[572] = 54.933759; pan[572] = -.315;  break;
+            case(573):  tdelay[573] = 55.031102; pan[573] = -.136;  break;
+            case(574):  tdelay[574] = 55.120963; pan[574] = .136;   break;
+            case(575):  tdelay[575] = 55.230907; pan[575] = -.635;  break;
+            case(576):  tdelay[576] = 55.322181; pan[576] = .635;   break;
+            case(577):  tdelay[577] = 55.426997; pan[577] = -.435;  break;
+            case(578):  tdelay[578] = 55.531689; pan[578] = .435;   break;
+            case(579):  tdelay[579] = 55.607012; pan[579] = -.765;  break;
+            case(580):  tdelay[580] = 55.715148; pan[580] = .765;   break;
+            case(581):  tdelay[581] = 55.803142; pan[581] = -.575;  break;
+            case(582):  tdelay[582] = 55.951037; pan[582] = .575;   break;
+            case(583):  tdelay[583] = 56.018695; pan[583] = .215;   break;
+            case(584):  tdelay[584] = 56.107151; pan[584] = -.692;  break;
+            case(585):  tdelay[585] = 56.240962; pan[585] = -.215;  break;
+            case(586):  tdelay[586] = 56.312251; pan[586] = .692;   break;
+            case(587):  tdelay[587] = 56.422676; pan[587] = -.435;  break;
+            case(588):  tdelay[588] = 56.514122; pan[588] = .435;   break;
+            case(589):  tdelay[589] = 56.637713; pan[589] = .675;   break;
+            case(590):  tdelay[590] = 56.730468; pan[590] = -.675;  break;
+            case(591):  tdelay[591] = 56.808751; pan[591] = .265;   break;
+            case(592):  tdelay[592] = 56.910460; pan[592] = -.265;  break;
+            case(593):  tdelay[593] = 57.027041; pan[593] = -.555;  break;
+            case(594):  tdelay[594] = 57.132028; pan[594] = .555;   break;
+            case(595):  tdelay[595] = 57.244272; pan[595] = .333;   break;
+            case(596):  tdelay[596] = 57.336923; pan[596] = -.333;  break;
+            case(597):  tdelay[597] = 57.427700; pan[597] = 0.0;    break;
+            case(598):  tdelay[598] = 57.528503;  pan[598] = -1;    break;
+            case(599):  tdelay[599] = 57.618661;  pan[599] = 1;     break;
+            case(600):  tdelay[600] = 57.715413;  pan[600] = .5;    break;
+            case(601):  tdelay[601] = 57.814730;  pan[601] = -.5;   break;
+            case(602):  tdelay[602] = 57.914843;  pan[602] = 0;     break;
+            case(603):  tdelay[603] = 58.000258;  pan[603] = .7;    break;
+            case(604):  tdelay[604] = 58.135363;  pan[604] = -.7;   break;
+            case(605):  tdelay[605] = 58.230554;  pan[605] = .3;    break;
+            case(606):  tdelay[606] = 58.290000;  pan[606] = -.3;   break;
+            case(607):  tdelay[607] = 58.372498;  pan[607] = .15;   break;
+            case(608):  tdelay[608] = 58.445365; pan[608] = -.15;   break;
+            case(609):  tdelay[609] = 58.571897; pan[609] = .85;    break;
+            case(610):  tdelay[610] = 58.627656; pan[610] = -.85;   break;
+            case(611):  tdelay[611] = 58.695809; pan[611] = .4;     break;
+            case(612):  tdelay[612] = 58.758350; pan[612] = -.4;    break;
+            case(613):  tdelay[613] = 58.880984; pan[613] = .6;     break;
+            case(614):  tdelay[614] = 58.975910; pan[614] = -.6;    break;
+            case(615):  tdelay[615] = 59.043894; pan[615] = .225;   break;
+            case(616):  tdelay[616] = 59.143261; pan[616] = -.225;  break;
+            case(617):  tdelay[617] = 59.268126; pan[617] = .775;   break;
+            case(618):  tdelay[618] = 59.366093; pan[618] = -.775;  break;
+            case(619):  tdelay[619] = 59.480461; pan[619] = .125;   break;
+            case(620):  tdelay[620] = 59.577198; pan[620] = -.125;  break;
+            case(621):  tdelay[621] = 59.666871; pan[621] = -.65;   break;
+            case(622):  tdelay[622] = 59.779061; pan[622] = .65;    break;
+            case(623):  tdelay[623] = 59.852884; pan[623] = .35;    break;
+            case(624):  tdelay[624] = 59.966519; pan[624] = -.35;   break;
+            case(625):  tdelay[625] = 60.043514; pan[625] = -.1;    break;
+            case(626):  tdelay[626] = 60.147562; pan[626] = .1;     break;
+            case(627):  tdelay[627] = 60.241538; pan[627] = -.8;    break;
+            case(628):  tdelay[628] = 60.358808; pan[628] = .8;     break;
+            case(629):  tdelay[629] = 60.470554; pan[629] = -.55;   break;
+            case(630):  tdelay[630] = 60.540000; pan[630] = .55;    break;
+            case(631):  tdelay[631] = 60.612729; pan[631] = -.25;   break;
+            case(632):  tdelay[632] = 60.693888; pan[632] = .25;    break;
+            case(633):  tdelay[633] = 60.750479; pan[633] = -.45;   break;
+            case(634):  tdelay[634] = 60.834122; pan[634] = .45;    break;
+            case(635):  tdelay[635] = 60.894456; pan[635] = .05;    break;
+            case(636):  tdelay[636] = 60.978112; pan[636] = -.9;    break;
+            case(637):  tdelay[637] = 61.107199; pan[637] = -.05;   break;
+            case(638):  tdelay[638] = 61.217554; pan[638] = .9;     break;
+            case(639):  tdelay[639] = 61.282567; pan[639] = -.425;  break;
+            case(640):  tdelay[640] = 61.387678; pan[640] = .425;   break;
+            case(641):  tdelay[641] = 61.493642; pan[641] = .75;    break;
+            case(642):  tdelay[642] = 61.610009; pan[642] = -.75;   break;
+            case(643):  tdelay[643] = 61.720302; pan[643] = .275;   break;
+            case(644):  tdelay[644] = 61.818331; pan[644] = -.275;  break;
+            case(645):  tdelay[645] = 61.911186; pan[645] = -.625;  break;
+            case(646):  tdelay[646] = 62.013019; pan[646] = .625;   break;
+            case(647):  tdelay[647] = 62.089382; pan[647] = .375;   break;
+            case(648):  tdelay[648] = 62.192071; pan[648] = -.375;  break;
+            case(649):  tdelay[649] = 62.288516; pan[649] = -.116;  break;
+            case(650):  tdelay[650] = 62.403337; pan[650] = .116;   break;
+            case(651):  tdelay[651] = 62.474009; pan[651] = -.825;  break;
+            case(652):  tdelay[652] = 62.613701; pan[652] = .825;   break;
+            case(653):  tdelay[653] = 62.710554; pan[653] = -.535;  break;
+            case(654):  tdelay[654] = 62.800000; pan[654] = .535;   break;
+            case(655):  tdelay[655] = 62.933349; pan[655] = -.265;  break;
+            case(656):  tdelay[656] = 63.032532; pan[656] = .265;   break;
+            case(657):  tdelay[657] = 63.122216; pan[657] = -.475;  break;
+            case(658):  tdelay[658] = 63.194122; pan[658] = .475;   break;
+            case(659):  tdelay[659] = 63.265021; pan[659] = .11;    break;
+            case(660):  tdelay[660] = 63.358764; pan[660] = -.77;   break;
+            case(661):  tdelay[661] = 63.445276; pan[661] = -.11;   break;
+            case(662):  tdelay[662] = 63.539293; pan[662] = .77;    break;
+            case(663):  tdelay[663] = 63.609978; pan[663] = -.475;  break;
+            case(664):  tdelay[664] = 63.710640; pan[664] = .475;   break;
+            case(665):  tdelay[665] = 63.831968; pan[665] = .725;   break;
+            case(666):  tdelay[666] = 63.933759; pan[666] = -.725;  break;
+            case(667):  tdelay[667] = 64.031102; pan[667] = .235;   break;
+            case(668):  tdelay[668] = 64.120963; pan[668] = -.235;  break;
+            case(669):  tdelay[669] = 64.230907; pan[669] = -.685;  break;
+            case(670):  tdelay[670] = 64.322181; pan[670] = .685;   break;
+            case(671):  tdelay[671] = 64.426997; pan[671] = .315;   break;
+            case(672):  tdelay[672] = 64.531689; pan[672] = -.315;  break;
+            case(673):  tdelay[673] = 64.607012; pan[673] = -.136;  break;
+            case(674):  tdelay[674] = 64.715148; pan[674] = .136;   break;
+            case(675):  tdelay[675] = 64.803142; pan[675] = -.635;  break;
+            case(676):  tdelay[676] = 64.951037; pan[676] = .635;   break;
+            case(677):  tdelay[677] = 65.018695; pan[677] = -.435;  break;
+            case(678):  tdelay[678] = 65.107151; pan[678] = .435;   break;
+            case(679):  tdelay[679] = 65.240962; pan[679] = -.765;  break;
+            case(680):  tdelay[680] = 65.312251; pan[680] = .765;   break;
+            case(681):  tdelay[681] = 65.422676; pan[681] = -.575;  break;
+            case(682):  tdelay[682] = 65.514122; pan[682] = .575;   break;
+            case(683):  tdelay[683] = 65.637713; pan[683] = .215;   break;
+            case(684):  tdelay[684] = 65.730468; pan[684] = -.692;  break;
+            case(685):  tdelay[685] = 65.808751; pan[685] = -.215;  break;
+            case(686):  tdelay[686] = 65.910460; pan[686] = .692;   break;
+            case(687):  tdelay[687] = 66.000000; pan[687] = -.435;  break;
+            case(688):  tdelay[688] = 66.131832; pan[688] = .435;   break;
+            case(689):  tdelay[689] = 66.215038; pan[689] = .675;   break;
+            case(690):  tdelay[690] = 66.322274; pan[690] = -.675;  break;
+            case(691):  tdelay[691] = 66.414122; pan[691] = .265;   break;
+            case(692):  tdelay[692] = 66.504488; pan[692] = -.265;  break;
+            case(693):  tdelay[693] = 66.637713; pan[693] = -.555;  break;
+            case(694):  tdelay[694] = 66.730468; pan[694] = .555;   break;
+            case(695):  tdelay[695] = 66.808751; pan[695] = .333;   break;
+            case(696):  tdelay[696] = 66.910460; pan[696] = -.333;  break;
+            case(697):  tdelay[697] = 67.027041; pan[697] = 0.0;    break;
+            case(698):  tdelay[698] = 67.132028; pan[698] = -1;     break;
+            case(699):  tdelay[699] = 67.244272; pan[699] = 1;      break;
+            case(700):  tdelay[700] = 67.336923; pan[700] = .5;     break;
+            case(701):  tdelay[701] = 67.427700; pan[701] = -.5;    break;
+            case(702):  tdelay[702] = 67.528503; pan[702] = 0;      break;
+            case(703):  tdelay[703] = 67.618661; pan[703] = .7;     break;
+            case(704):  tdelay[704] = 67.715413; pan[704] = -.7;    break;
+            case(705):  tdelay[705] = 67.814730; pan[705] = .3;     break;
+            case(706):  tdelay[706] = 67.914843; pan[706] = -.3;    break;
+            case(707):  tdelay[707] = 68.000258; pan[707] = .15;    break;
+            case(708):  tdelay[708] = 68.135363; pan[708] = -.15;   break;
+            case(709):  tdelay[709] = 68.230554; pan[709] = .85;    break;
+            case(710):  tdelay[710] = 68.290000; pan[710] = -.85;   break;
+            case(711):  tdelay[711] = 68.372498; pan[711] = .4;     break;
+            case(712):  tdelay[712] = 68.445365; pan[712] = -.4;    break;
+            case(713):  tdelay[713] = 68.571897; pan[713] = .6;     break;
+            case(714):  tdelay[714] = 68.627656; pan[714] = -.6;    break;
+            case(715):  tdelay[715] = 68.695809; pan[715] = .225;   break;
+            case(716):  tdelay[716] = 68.758350; pan[716] = -.225;  break;
+            case(717):  tdelay[717] = 68.880984; pan[717] = .775;   break;
+            case(718):  tdelay[718] = 68.975910; pan[718] = -.775;  break;
+            case(719):  tdelay[719] = 69.043894; pan[719] = .125;   break;
+            case(720):  tdelay[720] = 69.143261; pan[720] = -.125;  break;
+            case(721):  tdelay[721] = 69.268126; pan[721] = -.65;   break;
+            case(722):  tdelay[722] = 69.366093; pan[722] = .65;    break;
+            case(723):  tdelay[723] = 69.480461; pan[723] = .35;    break;
+            case(724):  tdelay[724] = 69.577198; pan[724] = -.35;   break;
+            case(725):  tdelay[725] = 69.666871; pan[725] = -.1;    break;
+            case(726):  tdelay[726] = 69.779061; pan[726] = .1;     break;
+            case(727):  tdelay[727] = 69.852884; pan[727] = -.8;    break;
+            case(728):  tdelay[728] = 69.966519; pan[728] = .8;     break;
+            case(729):  tdelay[729] = 70.043514; pan[729] = -.55;   break;
+            case(730):  tdelay[730] = 70.147562; pan[730] = .55;    break;
+            case(731):  tdelay[731] = 70.241538; pan[731] = -.25;   break;
+            case(732):  tdelay[732] = 70.358808; pan[732] = .25;    break;
+            case(733):  tdelay[733] = 70.470554; pan[733] = -.45;   break;
+            case(734):  tdelay[734] = 70.540000; pan[734] = .45;    break;
+            case(735):  tdelay[735] = 70.612775; pan[735] = .05;    break;
+            case(736):  tdelay[736] = 70.697583; pan[736] = -.9;    break;
+            case(737):  tdelay[737] = 70.750379; pan[737] = -.05;   break;
+            case(738):  tdelay[738] = 70.834122; pan[738] = .9;     break;
+            case(739):  tdelay[739] = 70.894456; pan[739] = -.425;  break;
+            case(740):  tdelay[740] = 70.978112; pan[740] = .425;   break;
+            case(741):  tdelay[741] = 71.107199; pan[741] = .75;    break;
+            case(742):  tdelay[742] = 71.217554; pan[742] = -.75;   break;
+            case(743):  tdelay[743] = 71.282567; pan[743] = .275;   break;
+            case(744):  tdelay[744] = 71.387678; pan[744] = -.275;  break;
+            case(745):  tdelay[745] = 71.493642; pan[745] = -.625;  break;
+            case(746):  tdelay[746] = 71.610009; pan[746] = .625;   break;
+            case(747):  tdelay[747] = 71.720302; pan[747] = .375;   break;
+            case(748):  tdelay[748] = 71.818331; pan[748] = -.375;  break;
+            case(749):  tdelay[749] = 71.911186; pan[749] = -.116;  break;
+            case(750):  tdelay[750] = 72.013019; pan[750] = .116;   break;
+            case(751):  tdelay[751] = 72.089382; pan[751] = -.825;  break;
+            case(752):  tdelay[752] = 72.192071; pan[752] = .825;   break;
+            case(753):  tdelay[753] = 72.288516; pan[753] = -.535;  break;
+            case(754):  tdelay[754] = 72.403337; pan[754] = .535;   break;
+            case(755):  tdelay[755] = 72.474009; pan[755] = -.265;  break;
+            case(756):  tdelay[756] = 72.613701; pan[756] = .265;   break;
+            case(757):  tdelay[757] = 72.710554; pan[757] = -.475;  break;
+            case(758):  tdelay[758] = 72.800000; pan[758] = .475;   break;
+            case(759):  tdelay[759] = 72.933349; pan[759] = .11;    break;
+            case(760):  tdelay[760] = 73.032532; pan[760] = -.77;   break;
+            case(761):  tdelay[761] = 73.122216; pan[761] = -.11;   break;
+            case(762):  tdelay[762] = 73.194122; pan[762] = .77;    break;
+            case(763):  tdelay[763] = 73.265021; pan[763] = -.475;  break;
+            case(764):  tdelay[764] = 73.358764; pan[764] = .475;   break;
+            case(765):  tdelay[765] = 73.445276; pan[765] = .725;   break;
+            case(766):  tdelay[766] = 73.539293; pan[766] = -.725;  break;
+            case(767):  tdelay[767] = 73.609978; pan[767] = .235;   break;
+            case(768):  tdelay[768] = 73.710640; pan[768] = -.235;  break;
+            case(769):  tdelay[769] = 73.831968; pan[769] = -.685;  break;
+            case(770):  tdelay[770] = 73.933759; pan[770] = .685;   break;
+            case(771):  tdelay[771] = 74.031102; pan[771] = .315;   break;
+            case(772):  tdelay[772] = 74.120963; pan[772] = -.315;  break;
+            case(773):  tdelay[773] = 74.230907; pan[773] = -.136;  break;
+            case(774):  tdelay[774] = 74.322181; pan[774] = .136;   break;
+            case(775):  tdelay[775] = 74.426997; pan[775] = -.635;  break;
+            case(776):  tdelay[776] = 74.531689; pan[776] = .635;   break;
+            case(777):  tdelay[777] = 74.607012; pan[777] = -.435;  break;
+            case(778):  tdelay[778] = 74.715148; pan[778] = .435;   break;
+            case(779):  tdelay[779] = 74.803142; pan[779] = -.765;  break;
+            case(780):  tdelay[780] = 74.951037; pan[780] = .765;   break;
+            case(781):  tdelay[781] = 75.018695; pan[781] = -.575;  break;
+            case(782):  tdelay[782] = 75.107151; pan[782] = .575;   break;
+            case(783):  tdelay[783] = 75.240962; pan[783] = .215;   break;
+            case(784):  tdelay[784] = 75.312251; pan[784] = -.692;  break;
+            case(785):  tdelay[785] = 75.422676; pan[785] = -.435;  break;
+            case(786):  tdelay[786] = 75.514122; pan[786] = .435;   break;
+            case(787):  tdelay[787] = 75.637713; pan[787] = .675;   break;
+            case(788):  tdelay[788] = 75.730468; pan[788] = -.675;  break;
+            case(789):  tdelay[789] = 75.808751; pan[789] = .265;   break;
+            case(790):  tdelay[790] = 75.910460; pan[790] = -.265;  break;
+            case(791):  tdelay[791] = 76.027041; pan[791] = -.555;  break;
+            case(792):  tdelay[792] = 76.132028; pan[792] = .555;   break;
+            case(793):  tdelay[793] = 76.244272; pan[793] = .333;   break;
+            case(794):  tdelay[794] = 76.336923; pan[794] = -.333;  break;
+            case(795):  tdelay[795] = 76.427700; pan[795] = 0.0;    break;
+            case(796):  tdelay[796] = 76.528503; pan[796] = -1;     break;
+            case(797):  tdelay[797] = 76.618661; pan[797] = 1;      break;
+            case(798):  tdelay[798] = 76.715413; pan[798] = .5;     break;
+            case(799):  tdelay[799] = 76.814730; pan[799] = -.5;    break;
+            case(800):  tdelay[800] = 76.914843; pan[800] = 0;      break;
+            case(801):  tdelay[801] = 77.000258; pan[801] = .7;     break;
+            case(802):  tdelay[802] = 77.135363; pan[802] = -.7;    break;
+            case(803):  tdelay[803] = 77.230554; pan[803] = .3;     break;
+            case(804):  tdelay[804] = 77.290000; pan[804] = -.3;    break;
+            case(805):  tdelay[805] = 77.372498; pan[805] = .15;    break;
+            case(806):  tdelay[806] = 77.445365; pan[806] = -.15;   break;
+            case(807):  tdelay[807] = 77.571897; pan[807] = .85;    break;
+            case(808):  tdelay[808] = 77.627656; pan[808] = -.85;   break;
+            case(809):  tdelay[809] = 77.695809; pan[809] = .4;     break;
+            case(810):  tdelay[810] = 77.758350; pan[810] = -.4;    break;
+            case(811):  tdelay[811] = 77.880984; pan[811] = .6;     break;
+            case(812):  tdelay[812] = 77.975910; pan[812] = -.6;    break;
+            case(813):  tdelay[813] = 78.043894; pan[813] = .225;   break;
+            case(814):  tdelay[814] = 78.143261; pan[814] = -.225;  break;
+            case(815):  tdelay[815] = 78.268126; pan[815] = .775;   break;
+            case(816):  tdelay[816] = 78.366093; pan[816] = -.775;  break;
+            case(817):  tdelay[817] = 78.480461; pan[817] = .125;   break;
+            case(818):  tdelay[818] = 78.577198; pan[818] = -.125;  break;
+            case(819):  tdelay[819] = 78.666871; pan[819] = -.65;   break;
+            case(820):  tdelay[820] = 78.779061; pan[820] = .65;    break;
+            case(821):  tdelay[821] = 78.852884; pan[821] = .35;    break;
+            case(822):  tdelay[822] = 78.966519; pan[822] = -.35;   break;
+            case(823):  tdelay[823] = 79.043514; pan[823] = -.1;    break;
+            case(824):  tdelay[824] = 79.147562; pan[824] = .1;     break;
+            case(825):  tdelay[825] = 79.241538; pan[825] = -.8;    break;
+            case(826):  tdelay[826] = 79.358808; pan[826] = .8;     break;
+            case(827):  tdelay[827] = 79.470554; pan[827] = -.55;   break;
+            case(828):  tdelay[828] = 79.540000; pan[828] = .55;    break;
+            case(829):  tdelay[829] = 79.612729; pan[829] = -.25;   break;
+            case(830):  tdelay[830] = 79.693888; pan[830] = .25;    break;
+            case(831):  tdelay[831] = 79.750479; pan[831] = -.45;   break;
+            case(832):  tdelay[832] = 79.834122; pan[832] = .45;    break;
+            case(833):  tdelay[833] = 79.894456; pan[833] = .05;    break;
+            case(834):  tdelay[834] = 79.978112; pan[834] = -.9;    break;
+            case(835):  tdelay[835] = 80.107199; pan[835] = -.05;   break;
+            case(836):  tdelay[836] = 80.217554; pan[836] = .9;     break;
+            case(837):  tdelay[837] = 80.282567; pan[837] = -.425;  break;
+            case(838):  tdelay[838] = 80.387678; pan[838] = .425;   break;
+            case(839):  tdelay[839] = 80.493642; pan[839] = .75;    break;
+            case(840):  tdelay[840] = 80.610009; pan[840] = -.75;   break;
+            case(841):  tdelay[841] = 80.720302; pan[841] = .275;   break;
+            case(842):  tdelay[842] = 80.818331; pan[842] = -.275;  break;
+            case(843):  tdelay[843] = 80.911186; pan[843] = -.625;  break;
+            case(844):  tdelay[844] = 81.013019; pan[844] = .625;   break;
+            case(845):  tdelay[845] = 81.089382; pan[845] = .375;   break;
+            case(846):  tdelay[846] = 81.192071; pan[846] = -.375;  break;
+            case(847):  tdelay[847] = 81.288516; pan[847] = -.116;  break;
+            case(848):  tdelay[848] = 81.403337; pan[848] = .116;   break;
+            case(849):  tdelay[849] = 81.474009; pan[849] = -.825;  break;
+            case(850):  tdelay[850] = 81.613701; pan[850] = .825;   break;
+            case(851):  tdelay[851] = 81.710554; pan[851] = -.535;  break;
+            case(852):  tdelay[852] = 81.800000; pan[852] = .535;   break;
+            case(853):  tdelay[853] = 81.933349; pan[853] = -.265;  break;
+            case(854):  tdelay[854] = 82.032532; pan[854] = .265;   break;
+            case(855):  tdelay[855] = 82.122216; pan[855] = -.475;  break;
+            case(856):  tdelay[856] = 82.194122; pan[856] = .475;   break;
+            case(857):  tdelay[857] = 82.265021; pan[857] = .11;    break;
+            case(858):  tdelay[858] = 82.358764; pan[858] = -.77;   break;
+            case(859):  tdelay[859] = 82.445276; pan[859] = -.11;   break;
+            case(860):  tdelay[860] = 82.539293; pan[860] = .77;    break;
+            case(861):  tdelay[861] = 82.609978; pan[861] = -.475;  break;
+            case(862):  tdelay[862] = 82.710640; pan[862] = .475;   break;
+            case(863):  tdelay[863] = 82.831968; pan[863] = .725;   break;
+            case(864):  tdelay[864] = 82.933759; pan[864] = -.725;  break;
+            case(865):  tdelay[865] = 83.031102; pan[865] = .235;   break;
+            case(866):  tdelay[866] = 83.120963; pan[866] = -.235;  break;
+            case(867):  tdelay[867] = 83.230907; pan[867] = -.685;  break;
+            case(868):  tdelay[868] = 83.322181; pan[868] = .685;   break;
+            case(869):  tdelay[869] = 83.426997; pan[869] = .315;   break;
+            case(870):  tdelay[870] = 83.531689; pan[870] = -.315;  break;
+            case(871):  tdelay[871] = 83.607012; pan[871] = -.136;  break;
+            case(872):  tdelay[872] = 83.715148; pan[872] = .136;   break;
+            case(873):  tdelay[873] = 83.803142; pan[873] = -.635;  break;
+            case(874):  tdelay[874] = 83.951037; pan[874] = .635;   break;
+            case(875):  tdelay[875] = 84.018695; pan[875] = -.435;  break;
+            case(876):  tdelay[876] = 84.160962; pan[876] = .435;   break;
+            case(877):  tdelay[877] = 84.312251; pan[877] = -.765;  break;
+            case(878):  tdelay[878] = 84.422676; pan[878] = .765;   break;
+            case(879):  tdelay[879] = 84.514122; pan[879] = -.575;  break;
+            case(880):  tdelay[880] = 84.637713; pan[880] = .575;   break;
+            case(881):  tdelay[881] = 84.730468; pan[881] = .215;   break;
+            case(882):  tdelay[882] = 84.808751; pan[882] = -.692;  break;
+            case(883):  tdelay[883] = 84.910460; pan[883] = -.215;  break;
+            case(884):  tdelay[884] = 85.000000; pan[884] = .692;   break;
+            case(885):  tdelay[885] = 85.131832; pan[885] = -.435;  break;
+            case(886):  tdelay[886] = 85.215038; pan[886] = .435;   break;
+            case(887):  tdelay[887] = 85.322274; pan[887] = .675;   break;
+            case(888):  tdelay[888] = 85.414122; pan[888] = -.675;  break;
+            case(889):  tdelay[889] = 85.504488; pan[889] = .265;   break;
+            case(890):  tdelay[890] = 85.637713; pan[890] = -.265;  break;
+            case(891):  tdelay[891] = 85.730468; pan[891] = -.555;  break;
+            case(892):  tdelay[892] = 85.808751; pan[892] = .555;   break;
+            case(893):  tdelay[893] = 85.910460; pan[893] = .333;   break;
+            case(894):  tdelay[894] = 86.027041; pan[894] = -.333;  break;
+            case(895):  tdelay[895] = 86.132028; pan[895] = 0.0;    break;
+            case(896):  tdelay[896] = 86.244272;  pan[896] = -1;    break;
+            case(897):  tdelay[897] = 86.336923;  pan[897] = 1;     break;
+            case(898):  tdelay[898] = 86.427700;  pan[898] = .5;    break;
+            case(899):  tdelay[899] = 86.528503;  pan[899] = -.5;   break;
+            case(900):  tdelay[900] = 86.618661;  pan[900] = 0;     break;
+            case(901):  tdelay[901] = 86.715413;  pan[901] = .7;    break;
+            case(902):  tdelay[902] = 86.814730;  pan[902] = -.7;   break;
+            case(903):  tdelay[903] = 86.914843;  pan[903] = .3;    break;
+            case(904):  tdelay[904] = 87.000258;  pan[904] = -.3;   break;
+            case(905):  tdelay[905] = 87.135363;  pan[905] = .15;   break;
+            case(906):  tdelay[906] = 87.230554; pan[906] = -.15;   break;
+            case(907):  tdelay[907] = 87.290000; pan[907] = .85;    break;
+            case(908):  tdelay[908] = 87.372498; pan[908] = -.85;   break;
+            case(909):  tdelay[909] = 87.445365; pan[909] = .4;     break;
+            case(910):  tdelay[910] = 87.571897; pan[910] = -.4;    break;
+            case(911):  tdelay[911] = 87.627656; pan[911] = .6;     break;
+            case(912):  tdelay[912] = 87.695809; pan[912] = -.6;    break;
+            case(913):  tdelay[913] = 87.758350; pan[913] = .225;   break;
+            case(914):  tdelay[914] = 87.880984; pan[914] = -.225;  break;
+            case(915):  tdelay[915] = 87.975910; pan[915] = .775;   break;
+            case(916):  tdelay[916] = 88.043894; pan[916] = -.775;  break;
+            case(917):  tdelay[917] = 88.143261; pan[917] = .125;   break;
+            case(918):  tdelay[918] = 88.268126; pan[918] = -.125;  break;
+            case(919):  tdelay[919] = 88.366093; pan[919] = -.65;   break;
+            case(920):  tdelay[920] = 88.480461; pan[920] = .65;    break;
+            case(921):  tdelay[921] = 88.577198; pan[921] = .35;    break;
+            case(922):  tdelay[922] = 88.666871; pan[922] = -.35;   break;
+            case(923):  tdelay[923] = 88.779061; pan[923] = -.1;    break;
+            case(924):  tdelay[924] = 88.852884; pan[924] = .1;     break;
+            case(925):  tdelay[925] = 88.966519; pan[925] = -.8;    break;
+            case(926):  tdelay[926] = 89.043514; pan[926] = .8;     break;
+            case(927):  tdelay[927] = 89.147562; pan[927] = -.55;   break;
+            case(928):  tdelay[928] = 89.241538; pan[928] = .55;    break;
+            case(929):  tdelay[929] = 89.358808; pan[929] = -.25;   break;
+            case(930):  tdelay[930] = 89.470554; pan[930] = .25;    break;
+            case(931):  tdelay[931] = 89.540000; pan[931] = -.45;   break;
+            case(932):  tdelay[932] = 89.612729; pan[932] = .45;    break;
+            case(933):  tdelay[933] = 89.693888; pan[933] = .05;    break;
+            case(934):  tdelay[934] = 89.750479; pan[934] = -.9;    break;
+            case(935):  tdelay[935] = 89.834122; pan[935] = -.05;   break;
+            case(936):  tdelay[936] = 89.894456; pan[936] = .9;     break;
+            case(937):  tdelay[937] = 89.978112; pan[937] = -.425;  break;
+            case(938):  tdelay[938] = 90.107199; pan[938] = .425;   break;
+            case(939):  tdelay[939] = 90.217554; pan[939] = .75;    break;
+            case(940):  tdelay[940] = 90.282567; pan[940] = -.75;   break;
+            case(941):  tdelay[941] = 90.387678; pan[941] = .275;   break;
+            case(942):  tdelay[942] = 90.493642; pan[942] = -.275;  break;
+            case(943):  tdelay[943] = 90.610009; pan[943] = -.625;  break;
+            case(944):  tdelay[944] = 90.720302; pan[944] = .625;   break;
+            case(945):  tdelay[945] = 90.818331; pan[945] = .375;   break;
+            case(946):  tdelay[946] = 90.911186; pan[946] = -.375;  break;
+            case(947):  tdelay[947] = 91.013019; pan[947] = -.116;  break;
+            case(948):  tdelay[948] = 91.089382; pan[948] = .116;   break;
+            case(949):  tdelay[949] = 91.192071; pan[949] = -.825;  break;
+            case(950):  tdelay[950] = 91.288516; pan[950] = .825;   break;
+            case(951):  tdelay[951] = 91.403337; pan[951] = -.535;  break;
+            case(952):  tdelay[952] = 91.474009; pan[952] = .535;   break;
+            case(953):  tdelay[953] = 91.613701; pan[953] = -.265;  break;
+            case(954):  tdelay[954] = 91.710554; pan[954] = .265;   break;
+            case(955):  tdelay[955] = 91.800000; pan[955] = -.475;  break;
+            case(956):  tdelay[956] = 91.933349; pan[956] = .475;   break;
+            case(957):  tdelay[957] = 92.032532; pan[957] = .11;    break;
+            case(958):  tdelay[958] = 92.122216; pan[958] = -.77;   break;
+            case(959):  tdelay[959] = 92.194122; pan[959] = -.11;   break;
+            case(960):  tdelay[960] = 92.265021; pan[960] = .77;    break;
+            case(961):  tdelay[961] = 92.358764; pan[961] = -.475;  break;
+            case(962):  tdelay[962] = 92.445276; pan[962] = .475;   break;
+            case(963):  tdelay[963] = 92.539293; pan[963] = .725;   break;
+            case(964):  tdelay[964] = 92.609978; pan[964] = -.725;  break;
+            case(965):  tdelay[965] = 92.710640; pan[965] = .235;   break;
+            case(966):  tdelay[966] = 92.831968; pan[966] = -.235;  break;
+            case(967):  tdelay[967] = 92.933759; pan[967] = -.685;  break;
+            case(968):  tdelay[968] = 93.031102; pan[968] = .685;   break;
+            case(969):  tdelay[969] = 93.120963; pan[969] = .315;   break;
+            case(970):  tdelay[970] = 93.230907; pan[970] = -.315;  break;
+            case(971):  tdelay[971] = 93.322181; pan[971] = -.136;  break;
+            case(972):  tdelay[972] = 93.426997; pan[972] = .136;   break;
+            case(973):  tdelay[973] = 93.531689; pan[973] = -.635;  break;
+            case(974):  tdelay[974] = 93.607012; pan[974] = .635;   break;
+            case(975):  tdelay[975] = 93.715148; pan[975] = -.435;  break;
+            case(976):  tdelay[976] = 93.803142; pan[976] = .435;   break;
+            case(977):  tdelay[977] = 93.951037; pan[977] = -.765;  break;
+            case(978):  tdelay[978] = 94.018695; pan[978] = .765;   break;
+            case(979):  tdelay[979] = 94.107151; pan[979] = -.575;  break;
+            case(980):  tdelay[980] = 94.240962; pan[980] = .575;   break;
+            case(981):  tdelay[981] = 94.312251; pan[981] = .215;   break;
+            case(982):  tdelay[982] = 94.422676; pan[982] = -.692;  break;
+            case(983):  tdelay[983] = 94.514122; pan[983] = -.215;  break;
+            case(984):  tdelay[984] = 94.637713; pan[984] = .692;   break;
+            case(985):  tdelay[985] = 94.730468; pan[985] = -.435;  break;
+            case(986):  tdelay[986] = 94.808751; pan[986] = .435;   break;
+            case(987):  tdelay[987] = 94.933759; pan[987] = .675;   break;
+            case(988):  tdelay[988] = 95.013019; pan[988] = -.675;  break;
+            case(989):  tdelay[989] = 95.107151; pan[989] = .265;   break;
+            case(990):  tdelay[990] = 95.240962; pan[990] = -.265;  break;
+            case(991):  tdelay[991] = 95.312251; pan[991] = -.555;  break;
+            case(992):  tdelay[992] = 95.422676; pan[992] = .555;   break;
+            case(993):  tdelay[993] = 95.514122; pan[993] = .333;   break;
+            case(994):  tdelay[994] = 95.637713; pan[994] = -.333;  break;
+            case(995):  tdelay[995] = 95.730468; pan[995] = 0.0;    break;
+            case(996):  tdelay[996] = 95.831968; pan[996] = -1;     break;
+            case(997):  tdelay[997] = 95.933759; pan[997] = 1;      break;
+            case(998):  tdelay[998] = 96.000000; pan[998] = .475;   break;
+            case(999):  tdelay[999] = 96.103567; pan[999] = -.475;  break;
+            }
+        }
+    }
+    return(FINISHED);
+}
+
+/************************** GENERATE_DELAYS ****************************/
+
+int generate_delays(dataptr dz)
+{
+    int    n;
+    int    eccnt = dz->iparam[STAD_ECHOCNT];
+    int   *delay;
+    double *tdelay = dz->parray[STAD_TDELAY];
+    double sr = (double)dz->infile->srate;
+    /*RWD Jan 2009 - trap files with more than  2 chans! */
+    if(dz->itemcnt > 2){
+        sprintf(errstr,"File has more than two channels.\n");
+        return GOAL_FAILED;
+
+    }
+    if((dz->lparray[STAD_DELAY] = malloc(MAX_ECHOCNT * sizeof(int)))==NULL) {
+        sprintf(errstr,"Insufficient memory for stadium arrays.\n");
+        return(MEMORY_ERROR);
+    }
+    delay = dz->lparray[STAD_DELAY];
+    for(n=0;n<eccnt;n++) {
+        if((delay[n] = (int)round(tdelay[n] * sr * dz->param[STAD_SIZE]) * STEREO)<0) {
+            sprintf(errstr,"Delay time too long.\n");
+            return(GOAL_FAILED);
+        }
+    }
+    return(FINISHED);
+}
+
+/************************** GENERATE_GAINS ****************************/
+
+void generate_gains(dataptr dz)
+{
+    int n;
+    double pregain = dz->param[STAD_PREGAIN];
+    double *gain   = dz->parray[STAD_GAIN];
+    double *gainl  = dz->parray[STAD_GAINL];
+    double *gainr  = dz->parray[STAD_GAINR];
+    double *pan    = dz->parray[STAD_PAN];
+    double rolloff = dz->param[STAD_ROLLOFF];
+    int    eccnt   = dz->iparam[STAD_ECHOCNT];
+    if(rolloff<1.0) {
+        for(n=0;n<eccnt;n++)
+            gain[n] = pow(gain[n],rolloff);
+    }
+    for(n=0;n<eccnt;n++) {
+        if(pan[n] < 0.0) {  /* LEFTWARDS */
+            gainl[n] = gain[n] * pregain;
+            gainr[n] = gain[n] * pregain * (1.0+pan[n]);
+        } else {           /* RIGHTWARDS */
+            gainl[n] = gain[n] * pregain * (1.0-pan[n]);
+            gainr[n] = gain[n] * pregain;
+        }
+    }
+}
+
+/******************************** CREATE_STADIUM_BUFFERS **********************************/
+
+#define IBUF    (0)
+#define OBUF    (1)
+#define OBUFEND (2)
+#define PADSTRT (3)
+
+int create_stadium_buffers(dataptr dz)
+{
+    int bigbufsize,bufwanted;
+    int obuflen;
+    int cnt;
+    float *ibufend;
+    int overflowlen;
+    dz->iparam[STAD_OVFLWSZ] = dz->iparam[STAD_MAXDELAY] * sizeof(float) ;
+    if(dz->itemcnt == 1)    /* storing channel-count of infile */
+        cnt = 3;
+    else
+        cnt = 4;
+    overflowlen  = dz->iparam[STAD_MAXDELAY];
+    bigbufsize = (int)(long) Malloc(-1);
+// TW modified overflow check, to include dz->iparam[STAD_OVFLWSZ]
+    if((bufwanted = bigbufsize + dz->iparam[STAD_OVFLWSZ]) < 0) {
+        sprintf(errstr,"Insufficient memory for delay buffer & snd buffers.\n");
+        return(MEMORY_ERROR);
+    }
+    if((dz->bigbuf = (float *) malloc(bufwanted))==NULL){
+        sprintf(errstr,"Unable to acquire %d samps for delay and sound buffers.\n",bufwanted);
+        return MEMORY_ERROR;
+    }
+    bigbufsize /= cnt;
+    dz->buflen  = bigbufsize/sizeof(float);
+    obuflen     = dz->buflen * STEREO;
+    dz->sampbuf[IBUF]    = dz->bigbuf;
+    ibufend              = dz->sampbuf[IBUF] + (dz->buflen * dz->itemcnt);
+    dz->sampbuf[OBUF]    = ibufend;
+    dz->sampbuf[OBUFEND] = dz->sampbuf[OBUF] + obuflen;
+    dz->sampbuf[PADSTRT] = dz->sampbuf[OBUF] + overflowlen;
+    memset((char *)dz->bigbuf,0,(dz->buflen * sizeof(float) * cnt) + dz->iparam[STAD_OVFLWSZ]);
+    return(FINISHED);
+}
+
+/******************************** DO_STADIUM **********************************/
+
+int do_stadium(dataptr dz)
+{
+    int exit_status;
+    int n, m, chans = dz->itemcnt; /* stores channel-cnt of infile */
+    double sum, maxinsamp = 0.0, maxoutsamp = 0.0, normaliser = 1.0;
+    int icnt, ocnt, sampcnt = 0, samps_to_write, samps_left = 0, k;
+    int   *delay  = dz->lparray[STAD_DELAY];
+    double *gainl  = dz->parray[STAD_GAINL];
+    double *gainr  = dz->parray[STAD_GAINR];
+    /*int   ibuflen = dz->buflen;*/
+    int   obuflen = dz->buflen * STEREO;
+    float  *ibuf   = dz->sampbuf[IBUF];
+    float  *obuf   = dz->sampbuf[OBUF];
+    int    eccnt   = dz->iparam[STAD_ECHOCNT];
+    
+    if(dz->vflag[0]) {
+        if(sloom) {
+            fprintf(stdout,"INFO: Checking output level\n");
+            fflush(stdout);
+        }
+        while((dz->ssampsread  = fgetfbufEx(ibuf,(dz->buflen * dz->itemcnt),dz->ifd[0],0)) > 0) {
+            if(chans >= 2) {
+                sum = 0.0;
+                for(n = 0,m = 0; n < dz->ssampsread; n+=chans, m++) {
+                    for(k=0;k<chans;k++)
+                        sum += ibuf[n+k];
+                    ibuf[m] = (float)(sum/(double)chans);
+                    if(fabs(ibuf[m]) > maxinsamp)
+                        maxinsamp = fabs(ibuf[m]);
+                }
+                dz->ssampsread /= chans;
+            } else {
+                for(n = 0; n < dz->ssampsread; n++) {
+                    if(fabs(ibuf[n]) > maxinsamp)
+                        maxinsamp = fabs(ibuf[n]);
+                }
+            }
+            for(n=0;n<eccnt;n++) {
+                for(icnt=0,ocnt=0;icnt<dz->ssampsread;icnt++,ocnt+=STEREO) {
+                    sampcnt = ocnt + delay[n];
+                    obuf[sampcnt] += (float) /*round*/(ibuf[icnt] * gainl[n]);
+                    sampcnt++;
+                    obuf[sampcnt] += (float) /*round*/(ibuf[icnt] * gainr[n]);
+                }
+            }
+            sampcnt++;
+            if((samps_to_write = min(obuflen,sampcnt))>0) {
+                for(k=0;k < samps_to_write;k++) {
+                    if(fabs(obuf[k]) > maxoutsamp)
+                        maxoutsamp = fabs(obuf[k]);
+                }
+            }
+            samps_left = sampcnt - obuflen;
+            memcpy((char *)obuf,(char *)dz->sampbuf[OBUFEND],dz->iparam[STAD_OVFLWSZ]);
+            memset((char *)dz->sampbuf[PADSTRT],0,obuflen * sizeof(float));
+        }
+        if(dz->ssampsread < 0) {
+            sprintf(errstr,"Sound read error.\n");
+            return(SYSTEM_ERROR);
+        }
+        if(samps_left > 0) {
+            for(k=0;k < samps_left;k++) {
+                if(fabs(obuf[k]) > maxoutsamp)
+                    maxoutsamp = fabs(obuf[k]);
+            }
+        }
+        if(flteq(maxinsamp,0.0) || flteq(maxoutsamp,0.0)) {
+            sprintf(errstr,"No significant level in input file.\n");
+            return DATA_ERROR;
+        }
+        if(maxoutsamp > 0.95)
+            normaliser = 0.95/maxoutsamp;
+        else if(maxoutsamp < maxinsamp)
+            normaliser = maxoutsamp/maxinsamp;
+        memset((char *)dz->bigbuf,0,(dz->buflen * sizeof(float) * 3) + dz->iparam[STAD_OVFLWSZ]);
+        sndseekEx(dz->ifd[0],0,0);
+        reset_filedata_counters(dz);
+        if(sloom) {
+            fprintf(stdout,"INFO: Generating stadium reverb.\n");
+            fflush(stdout);
+        }
+    }
+    while((dz->ssampsread  = fgetfbufEx(ibuf,(dz->buflen * dz->itemcnt),dz->ifd[0],0)) > 0) {
+        if(chans >= 2) {
+            for(n = 0,m = 0; n < dz->ssampsread; n+=chans, m++) {
+                sum = 0.0;
+                for(k=0;k<chans;k++)
+                    sum += ibuf[n+k];
+                ibuf[m] = (float)(sum/(double)chans);
+            }
+            dz->ssampsread /= chans;
+        }
+        for(n=0;n<eccnt;n++) {
+            for(icnt=0,ocnt=0;icnt<dz->ssampsread;icnt++,ocnt+=STEREO) {
+                sampcnt = ocnt + delay[n];
+                obuf[sampcnt] += (float) /*round*/(ibuf[icnt] * gainl[n]);
+                sampcnt++;
+                obuf[sampcnt] += (float) /*round*/(ibuf[icnt] * gainr[n]);
+            }
+        }
+        sampcnt++;
+        if((samps_to_write = min(obuflen,sampcnt))>0) {
+            if(dz->vflag[0]) {
+                for(k=0;k < samps_to_write;k++)
+                    obuf[k] = (float)(obuf[k] * normaliser);
+            }
+            if((exit_status = write_samps(obuf,samps_to_write,dz))<0)
+                return(exit_status);
+        }
+        samps_left = sampcnt - obuflen;
+        memcpy((char *)obuf,(char *)dz->sampbuf[OBUFEND],dz->iparam[STAD_OVFLWSZ]);
+        memset((char *)dz->sampbuf[PADSTRT],0,obuflen * sizeof(float));
+    }
+    if(dz->ssampsread < 0) {
+        sprintf(errstr,"Sound read error.\n");
+        return(SYSTEM_ERROR);
+    }
+    if(samps_left > 0) {
+        if(dz->vflag[0]) {
+            for(k=0;k < samps_left;k++)
+                obuf[k] = (float)(obuf[k] * normaliser);
+        }
+        return write_samps(obuf,samps_left,dz);
+    }
+    return(FINISHED);
+}
+
+//TW UPDATE : NEW FUNCTIONS (converted for flotsams)
+/******************************** DO_CONVOLVE **********************************/
+int do_convolve(dataptr dz)
+{
+    int exit_status, chans = dz->infile->channels, k;
+    int n = 0, m = 0, dl, yy, ynext, nn, mm, samps_read, maxwrite, tt = 0;
+    double *dbuf, scaler, maxval = 0.0, d, cbufval, clumpcnt = (double)(dz->insams[1]/chans);
+    double timeincr = 1.0/(double)dz->infile->srate, thistime;
+    float *cbuf, *ibuf, *obuf;
+    int cfile_len = dz->insams[1], samps_to_write;
+    unsigned int dblovflw = cfile_len * sizeof(double);
+    dz->total_samps_read = 0;
+    if((samps_read  = fgetfbufEx(dz->sampbuf[1],dz->insams[1],dz->ifd[1],0)) < 0) {     
+        sprintf(errstr,"Can't read samps from soundfile to be convolved.\n");
+        return(SYSTEM_ERROR);
+    }
+    dz->total_samps_read += samps_read;
+    if((samps_read  = fgetfbufEx(dz->sampbuf[0],dz->buflen,dz->ifd[0],0)) < 0) {        
+        sprintf(errstr,"Can't read samps from convolving soundfile.\n");
+        return(SYSTEM_ERROR);
+    }
+    if(samps_read == 0) {
+        sprintf(errstr,"No data found in soundfile to be convolved.\n");
+        return(SYSTEM_ERROR);
+    }
+    dz->ssampsread = samps_read;
+    dz->total_samps_read += samps_read;
+    print_outmessage_flush("Calculating scaling factor. (This is a SLOW process)\n");
+    do {
+        for(k=0;k<chans;k++) {
+            ibuf = dz->sampbuf[0] + k;
+            dbuf = dz->parray[0] + k;
+            switch(dz->mode) {
+            case(CONV_NORMAL):
+                for(n = k; n < dz->ssampsread; n+=chans,tt++) {
+                    nn = n - k;
+                    cbuf = dz->sampbuf[1] + k;
+                    for(m = k; m < dz->insams[1]; m+=chans) {
+                        mm = m - k;
+                        dbuf[nn+mm] += *ibuf * *cbuf;
+                        cbuf += chans;
+                    }
+                    ibuf += chans;
+                    if(tt % dz->infile->srate == 0)
+                        display_virtual_time(tt,dz);
+                }
+                break;
+            case(CONV_TVAR):
+                for(n = k, thistime = 0.0; n < dz->ssampsread; n+=chans, thistime += timeincr,tt++) {
+                    nn = n - k;
+                    if(dz->brksize[CONV_TRANS] && !(nn%256)) {
+                        if((exit_status = read_value_from_brktable(thistime,CONV_TRANS,dz))<0)
+                            return(exit_status);
+                    }
+//TW Omission corrected DEC 2002
+                    cbuf = dz->sampbuf[1] + k;
+                    for(m = k, d = 0.0; d <= clumpcnt; m+=chans, d+= dz->param[CONV_TRANS]) {
+                        mm = m - k;
+                        d += max(dz->param[CONV_TRANS],0.0);
+                        dl = (int)floor(d);
+                        yy = dl * chans;
+                        ynext = yy+chans;
+                        cbufval = (double)cbuf[yy] + ((d - (double)dl) * (double)(cbuf[ynext] - cbuf[yy]));
+                        dbuf[nn+mm] += *ibuf * cbufval;
+                    }
+                    ibuf += chans;
+                    if(tt % dz->infile->srate == 0)
+                        display_virtual_time(tt,dz);
+                }
+                break;
+            }
+        }
+        maxwrite = (n-chans) + (m-chans) + 1;
+        dbuf = dz->parray[0];
+        if (samps_read >= dz->buflen) {
+            for(n = 0; n < dz->ssampsread; n++)
+                maxval = max(maxval,fabs(dbuf[n]));
+//          display_virtual_time(dz->total_samps_read,dz);
+            memset((char *)dbuf,0,dz->buflen * sizeof(double));
+            memcpy((char *)dbuf,(char *)(dbuf + dz->buflen),dblovflw);
+            memset((char *)(dbuf + dz->buflen),0,dblovflw);
+            maxwrite -= dz->buflen;
+            if((samps_read  = fgetfbufEx(dz->sampbuf[0],dz->buflen,dz->ifd[0],0)) < 0) {        
+                sprintf(errstr,"Can't read samps from convolving soundfile.\n");
+                return(SYSTEM_ERROR);
+            }
+            dz->ssampsread = samps_read;
+            dz->total_samps_read += samps_read;
+            display_virtual_time(dz->total_samps_read,dz);
+        } else {
+            if(maxwrite > 0) {
+                for(n = 0; n < maxwrite; n++)
+                    maxval = max(maxval,fabs(dbuf[n]));
+            }
+            break;
+        }               
+    } while(samps_read > 0);
+    dbuf = dz->parray[0];
+    scaler = F_MAXSAMP/maxval;
+    memset((char *)dbuf,0,((dz->buflen + cfile_len) * sizeof(double)));
+    dz->total_samps_read = 0;
+    display_virtual_time(0,dz);
+    print_outmessage_flush("Doing the convolution. (This is an even SLOWER process)\n");
+    sndseekEx(dz->ifd[0],0,0);
+    if((samps_read  = fgetfbufEx(dz->sampbuf[0],dz->buflen,dz->ifd[0],0)) < 0) {        
+        sprintf(errstr,"Can't read samps from convolving soundfile.\n");
+        return(SYSTEM_ERROR);
+    }
+    dz->ssampsread = samps_read;
+    dz->total_samps_read += samps_read;
+    if(samps_read == 0) {
+        sprintf(errstr,"No data found in soundfile to be convolved, on 2nd pass.\n");
+        return(SYSTEM_ERROR);
+    }
+    obuf = dz->sampbuf[2];
+    tt = 0;
+    do {
+        for(k=0;k<chans;k++) {
+            ibuf = dz->sampbuf[0] + k;
+            dbuf = dz->parray[0] + k;
+            switch(dz->mode) {
+            case(CONV_NORMAL):
+                for(n = k; n < dz->ssampsread; n+=chans,tt++) {
+                    nn = n - k;
+                    cbuf = dz->sampbuf[1] + k;
+                    for(m = k; m < dz->insams[1]; m+=chans) {
+                        mm = m - k;
+                        dbuf[nn+mm] += *ibuf * *cbuf;
+                        cbuf += chans;
+                    }
+                    ibuf += chans;
+                    if(tt % dz->infile->srate == 0)
+                        display_virtual_time(tt,dz);
+                }
+                break;
+            case(CONV_TVAR):
+                for(n = k, thistime = 0.0; n < dz->ssampsread; n+=chans, thistime += timeincr,tt++) {
+                    nn = n - k;
+                    if(dz->brksize[CONV_TRANS] && !(nn%256)) {
+                        if((exit_status = read_value_from_brktable(thistime,CONV_TRANS,dz))<0)
+                            return(exit_status);
+                    }
+//TW Omission corrected DEC 2002
+                    cbuf = dz->sampbuf[1] + k;
+                    for(mm = 0, d = 0.0; d <= clumpcnt; mm+=chans, d+= dz->param[CONV_TRANS]) {
+                        d += max(dz->param[CONV_TRANS],0.0);
+                        dl = (int)floor(d);
+                        yy = dl * chans;
+                        ynext = yy+chans;
+                        cbufval = (double)cbuf[yy] + ((d - (double)dl) * (double)(cbuf[ynext] - cbuf[yy]));
+                        dbuf[nn+mm] += *ibuf * cbufval;
+                    }
+                    ibuf += chans;
+                    if(tt % dz->infile->srate == 0)
+                        display_virtual_time(tt,dz);
+                }
+                break;
+            }
+        }
+        maxwrite = (n-chans) + (m-chans) + 1;
+        dbuf = dz->parray[0];
+        if(samps_read >= dz->buflen) {
+            for(n=0;n<dz->ssampsread;n++)
+                obuf[n] = (float)(dbuf[n] * scaler);
+            if((exit_status = write_samps(dz->sampbuf[2],samps_read,dz))<0)
+                return(exit_status);
+//          display_virtual_time(dz->total_samps_written,dz);
+            memset((char *)dz->parray[0],0,dz->buflen * sizeof(double));
+            memcpy((char *)dz->parray[0],(char *)(dz->parray[0] + dz->buflen),dblovflw);
+            memset((char *)(dz->parray[0] + dz->buflen),0,dblovflw);
+            maxwrite -= dz->buflen;
+            if((samps_read = fgetfbufEx(dz->sampbuf[0],dz->buflen,dz->ifd[0],0)) < 0) {     
+                sprintf(errstr,"Can't read samps from convolving soundfile.\n");
+                return(SYSTEM_ERROR);
+            }
+            dz->ssampsread = samps_read;
+            dz->total_samps_read += samps_read;
+            display_virtual_time(dz->total_samps_read,dz);
+        } else {
+            m = 0;
+            while(maxwrite > 0) {
+                samps_to_write = min(maxwrite,dz->buflen);
+                for(n=0;n<samps_to_write;n++) {
+                    obuf[n] = (float)(dbuf[m++] * scaler);
+                }
+                if((exit_status = write_samps(dz->sampbuf[2],samps_to_write,dz))<0)
+                    return(exit_status);
+                display_virtual_time(dz->total_samps_written,dz);
+                maxwrite -= samps_to_write;
+            }
+            break;
+        }
+    } while(samps_read > 0);
+    return(FINISHED);
+}
+
+/******************************** CONVOLVE_PREPROCESS **********************************/
+
+int convolve_preprocess(dataptr dz)
+{
+    double *p, *brkend;
+    if(dz->brksize[CONV_TRANS]) {
+        brkend = dz->brk[CONV_TRANS] + (2 * dz->brksize[CONV_TRANS]);
+        p = dz->brk[CONV_TRANS] + 1;
+        while(p < brkend) {
+            *p = pow(2.0,(*p/SEMITONES_PER_OCTAVE));
+            p += 2;
+        }
+    } else
+        dz->param[CONV_TRANS] = pow(2.0,(dz->param[CONV_TRANS]/SEMITONES_PER_OCTAVE));
+    return(FINISHED);
+}

+ 589 - 0
dev/modify/gain.c

@@ -0,0 +1,589 @@
+/*
+ * Copyright (c) 1983-2013 Trevor Wishart and Composers Desktop Project Ltd
+ * http://www.trevorwishart.co.uk
+ * http://www.composersdesktop.com
+ *
+ This file is part of the CDP System.
+
+    The CDP System is free software; you can redistribute it
+    and/or modify it under the terms of the GNU Lesser General Public
+    License as published by the Free Software Foundation; either
+    version 2.1 of the License, or (at your option) any later version.
+
+    The CDP System is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public
+    License along with the CDP System; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+    02111-1307 USA
+ *
+ */
+
+
+
+/* floatsam version*/
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <structures.h>
+#include <tkglobals.h>
+#include <cdpmain.h>
+#include <modify.h>
+#include <modeno.h>
+#include <globcon.h>
+#include <modify.h>
+
+#include <sfsys.h>
+
+ /* RWD added do_clip, peak (later, sort out nChans PEAK stuff... */
+static void gain(long samples,double multiplier,double maxnoclip,long *numclipped,
+				 int do_clip,double *peak,dataptr dz);
+static int find_max(double *maxfound,dataptr dz);
+static int  find_maximum(int infile,long *maxloc,long *maxrep,double *maxsamp,dataptr dz);
+static void	get_max(double *,long,long,long *,long *,dataptr dz);
+static int  balance(double mratio,dataptr dz);
+//TW replaced by peakchunk
+//static int	write_maxsamp_properties(double,long,long,dataptr dz);
+static int  do_balance(dataptr dz);
+static int  gain_process(dataptr dz);
+static int  get_normalisation_gain(dataptr dz);
+static void do_normalise(dataptr dz);
+static void do_phase_invert(dataptr dz);
+static void find_maxsamp(double *maxfound,dataptr dz);
+static int  do_multifile_loudness(dataptr dz);
+
+
+#define	MAX_DBGAIN	 (90)
+
+//TW UPDATE: further updated for floatsams and new-style clipping detection
+int gainenv(long samples,long *last_total,double maxnoclip,long *numclipped,int do_clip,double *peak,dataptr dz);
+
+/************************** LOUDNESS_PROCESS *******************************/
+
+int loudness_process(dataptr dz)
+{
+	long n, m;
+	double maxtime,intime, ratio;  /*RWD April 2004 needed to add these  */ 
+	switch(dz->mode) {
+	case(LOUD_PROPOR):
+	case(LOUD_DB_PROPOR):
+		maxtime = dz->brk[LOUD_GAIN][(dz->brksize[LOUD_GAIN] - 1) * 2];
+		intime = (double)(dz->insams[0]/dz->infile->channels)/(double)dz->infile->srate;
+		ratio = intime/maxtime;
+		for(n=0,m = 0;n < dz->brksize[LOUD_GAIN];n++,m+=2)
+			dz->brk[LOUD_GAIN][m] = dz->brk[LOUD_GAIN][m] * ratio;
+		dz->mode = LOUDNESS_GAIN;
+		break;
+	case(LOUDNESS_DBGAIN):
+		if(dz->brksize[LOUD_GAIN]) {
+			for(n=0,m=1;n < dz->brksize[LOUD_GAIN];n++,m+=2)
+				dz->brk[LOUD_GAIN][m] = dbtogain(dz->brk[LOUD_GAIN][m]);
+		} else {
+			dz->param[LOUD_GAIN] = dbtogain(dz->param[LOUD_GAIN]);
+		}
+		break;
+	}
+	switch(dz->mode) {
+	case(LOUDNESS_LOUDEST):
+	case(LOUDNESS_EQUALISE): 	return do_multifile_loudness(dz);
+	case(LOUDNESS_BALANCE): 	return do_balance(dz);
+	default:				 	return gain_process(dz);
+	}
+	return(FINISHED);	/* NOTREACHED */
+}
+
+/************************** GAIN_PROCESS *******************************/
+
+int gain_process(dataptr dz)
+{
+	int exit_status;
+	double maxnoclip = F_MAXSAMP, peakval = 0.0;
+//TW UPDATE
+	long numclipped = 0, last_total = 0;
+	int clipsamps = 1;
+	float *buffer = dz->sampbuf[0];
+
+	if(dz->true_outfile_stype == SAMP_FLOAT)
+		if(dz->clip_floatsams == 0)
+			clipsamps = 0;
+
+	switch(dz->mode) {
+	case(LOUDNESS_NORM):
+	case(LOUDNESS_SET):
+		if((exit_status = get_normalisation_gain(dz))!=CONTINUE)
+			return(exit_status);
+		break;
+	}
+	display_virtual_time(0,dz);
+	while(dz->samps_left > 0) {
+		if((exit_status = read_samps(buffer,dz))<0) {
+			sprintf(errstr,"Cannot read data from sndfile.\n");
+			return(PROGRAM_ERROR);
+		}
+		switch(dz->mode) {
+		case(LOUDNESS_GAIN):
+		case(LOUDNESS_DBGAIN):
+//TW UPDATE >>
+			if(dz->brksize[LOUD_GAIN])
+				gainenv(dz->ssampsread,&last_total,maxnoclip,&numclipped,clipsamps,&peakval,dz);
+			else if(dz->param[LOUD_GAIN] <= FLTERR) {
+				sprintf(errstr,"With gain of %lf the soundfile will be reduced to SILENCE!\n",dz->param[LOUD_GAIN]);
+				return(DATA_ERROR);
+			} else
+//<< TW UPDATE
+				gain(dz->ssampsread,dz->param[LOUD_GAIN],maxnoclip,&numclipped,clipsamps,&peakval,dz);
+			break;
+		case(LOUDNESS_NORM):
+		case(LOUDNESS_SET):
+			do_normalise(dz);
+			break;
+		case(LOUDNESS_PHASE):
+			do_phase_invert(dz);
+			break;
+		}
+		if(dz->ssampsread > 0) {
+			if((exit_status = write_exact_samps(buffer,dz->ssampsread,dz))<0)
+				return(exit_status);
+		}
+	}
+	if(clipsamps && (numclipped > 0))
+		sprintf(errstr, "WARNING: %ld samples were clipped.\n", numclipped);
+	dz->peak_fval = peakval;
+	/*will get written to header automatically*/
+	return(FINISHED);
+}
+
+/************************** GAIN *******************************/
+
+void gain(long samples,double multiplier,double maxnoclip,long *numclipped,
+		  int do_clip,double *peak,dataptr dz)
+{
+	long i;            
+	double s, buf_peak = *peak;
+	float *buffer = dz->sampbuf[0];
+	if(multiplier < 0.0) 
+		multiplier = -multiplier;
+	for(i = 0; i < samples; i++) {
+		s = buffer[i] * multiplier;
+		if(s >= 0) {
+			if(do_clip && (s > maxnoclip)) {
+				(*numclipped)++;
+				s = F_MAXSAMP;
+			}
+			buf_peak = max(buf_peak,s);
+		} else {
+			if(do_clip && (-s > maxnoclip)) {
+				(*numclipped)++;
+				s = -F_MAXSAMP;
+			}
+			buf_peak = max(buf_peak,-s);
+		}
+		buffer[i] = (float) s;
+		*peak = buf_peak;
+	}
+	
+}
+
+/**************************** DO_NORMALISE ***************************/
+/* RWD NB my old floatsam version added a peak_val arg */
+void do_normalise(dataptr dz)
+{   
+	register long i;
+
+	float *buffer = dz->sampbuf[0];
+	float dgain = (float) dz->param[LOUD_GAIN];
+    for(i = 0; i < dz->ssampsread; i++) {
+//TW	float sampl;
+//TW   	sampl  = buffer[i] * dgain;
+//TW   	buffer[i] =  sampl;
+//TW must cast to float anyway, as multiply gives double
+	   	buffer[i] =  (float)(buffer[i] * dgain);
+    }
+}
+
+/**************************** DO_PHASE_INVERT ***************************/
+
+void do_phase_invert(dataptr dz)
+{   register long i;
+	double samplong;
+	float *buffer = dz->sampbuf[0];
+    for(i = 0; i < dz->ssampsread; i++) {
+    	samplong  = -buffer[i];
+		samplong = min(samplong,(double)F_MAXSAMP);
+    	buffer[i] = (float)(samplong);
+    }
+}
+
+/****************************** FIND_MAX *************************/
+
+int find_max(double *maxfound,dataptr dz)
+{
+	int exit_status;
+	float *buffer = dz->sampbuf[0];
+	display_virtual_time(0L,dz);
+	while(dz->samps_left != 0) {
+		if((exit_status = read_samps(buffer,dz))<0) {
+			sprintf(errstr,"Cannot read data from sndfile.\n");
+			return(PROGRAM_ERROR);
+		}
+		find_maxsamp(maxfound,dz);
+		display_virtual_time(dz->total_samps_read,dz);
+    }
+	/*RWD NB this is a weird step, specifically for this program - balances to
+	 * MAXSAMP if sfile is actually higher than that.
+	 * must delete next line for a generic version!
+	 */
+	*maxfound = min(*maxfound,(double)F_MAXSAMP); /* e.g. found -32768: substitute 32767 */
+	return(FINISHED);
+}
+
+/**************************** MAXSAMP ***************************/
+
+void find_maxsamp(double *maxfound,dataptr dz)
+{   register long i;
+    double k;				 
+	float *buffer = dz->sampbuf[0];
+    for(i = 0; i < dz->ssampsread; i++) {
+	if((k = fabs(buffer[i])) > *maxfound)
+	    *maxfound = k;
+    }
+	return;
+}
+
+/**************************** GET_NORMALISATION_GAIN ***************************/
+
+int get_normalisation_gain(dataptr dz)
+{
+	int exit_status;
+	double maxfound = 0.0;
+	double loud_level = dz->param[LOUD_LEVEL] * (double)F_MAXSAMP;
+	
+	print_outmessage_flush("Finding maximum amplitude.\n");
+    if((exit_status = find_max(&maxfound,dz))<0)
+		return(exit_status);
+    if(flteq(maxfound,loud_level)) {
+		sprintf(errstr,"File is already at the specified level.\n");
+		return(GOAL_FAILED);
+    }
+    if((maxfound > loud_level) && dz->mode == LOUDNESS_NORM) {
+		sprintf(errstr,"File is already above the specified level.\n");
+		return(GOAL_FAILED);
+    }
+
+    dz->param[LOUD_GAIN]  = loud_level/maxfound;
+
+	display_virtual_time(0L,dz);
+	sprintf(errstr,"Normalising with Gain Factor = %lf\n", dz->param[LOUD_GAIN]);
+	print_outmessage_flush(errstr);
+	if(sndseekEx(dz->ifd[0],0L,0)<0) {
+		sprintf(errstr,"sndseek() failed.\n");
+		return(SYSTEM_ERROR);
+    }
+	reset_filedata_counters(dz);
+	return(CONTINUE);
+}
+
+/***************************** DO_BALANCE ************************/
+
+int do_balance(dataptr dz)
+{
+	int exit_status;
+	long maxloc1, maxloc;
+	long maxrep1, maxrep;
+	double max1, max2;
+	double mratio;
+	display_virtual_time(0,dz);
+	print_outmessage_flush("Getting max level from file 1.\n");
+	if((exit_status = find_maximum(dz->ifd[0],&maxloc,&maxrep,&max1,dz))<0)
+		return(exit_status);
+	if(max1 <= 0) {
+		sprintf(errstr,"First file has zero amplitude: can't proceed.\n");
+		return(GOAL_FAILED);
+	}
+	maxloc1 = maxloc;
+	maxrep1 = maxrep;
+	reset_filedata_counters(dz);
+	dz->samps_left = dz->insams[1];
+	display_virtual_time(0,dz);
+	print_outmessage_flush("Getting max level from file 2.\n");
+	if((exit_status = find_maximum(dz->ifd[1],&maxloc,&maxrep,&max2,dz))<0)
+		return(exit_status);
+	mratio = max2/max1;
+	if(sndseekEx(dz->ifd[0],0,0)<0) {
+		sprintf(errstr,"sndseek failed.\n");
+		return(SYSTEM_ERROR);
+	}
+	reset_filedata_counters(dz);
+	display_virtual_time(0,dz);
+	sprintf(errstr,"Adjusting gain of 1st infile by %lf\n",mratio);
+	print_outmessage_flush(errstr);
+	if((exit_status = balance(mratio,dz))< 0)	
+		return(exit_status);
+//TW No longer required: takes place in PEAK procedure
+//	if((exit_status = write_maxsamp_properties(max2,maxloc1,maxrep1,dz))<0)
+//		return(exit_status);
+	return(FINISHED);
+}
+
+/***************************** BALANCE ************************/
+
+int balance(double mratio,dataptr dz)
+{
+	int exit_status;
+	long /*samps_read,*/ ssampsread, n;
+	/*double maxsamp = 0;*/
+	float *buffer = dz->sampbuf[0];
+	while((ssampsread = fgetfbufEx(buffer, dz->buflen,dz->ifd[0],0)) > 0) {		
+		for(n=0;n<ssampsread;n++)
+			buffer[n] = (float) /*round*/((double)buffer[n] * mratio);
+		if((exit_status = write_exact_samps(buffer,ssampsread,dz))<0)
+			return(exit_status);
+	}
+	if(ssampsread<0) {
+		sprintf(errstr,"Sound read error.\n");
+		return(SYSTEM_ERROR);
+	}
+	return(FINISHED);
+}
+
+/***************************** FIND_MAXIMUM ************************/
+
+int find_maximum(int infile,long *maxloc,long *maxrep,double *maxsamp,dataptr dz)
+{
+	long  ssampsread, last_total_ssampsread = 0, total_samps_read = 0;
+	float *buffer = dz->sampbuf[0];
+	*maxsamp = 0;
+	while((ssampsread = fgetfbufEx(buffer, dz->buflen,infile,0)) > 0) {
+		total_samps_read += ssampsread;		
+		get_max(maxsamp,ssampsread,last_total_ssampsread,maxloc,maxrep,dz);
+		last_total_ssampsread += ssampsread;
+		display_virtual_time(total_samps_read,dz);
+	}
+	if(ssampsread<0) {
+		sprintf(errstr,"Sound read error.\n");
+		return(SYSTEM_ERROR);
+	}
+	return(FINISHED);
+}
+
+/***************************** GET_MAX ************************/
+
+void get_max(double *maxsamp,long ssampsread,long last_total_ssampsread, long *maxloc, long *maxrep,dataptr dz)
+{
+	register long n;
+	float thisamp;
+	float *buffer = dz->sampbuf[0];
+	for(n=0;n<ssampsread;n++) {
+		if((thisamp = (float)fabs(buffer[n])) > *maxsamp) {
+			*maxsamp = thisamp;
+			*maxloc  = last_total_ssampsread + n;
+			*maxrep = 1;
+		} else if(flteq(thisamp,*maxsamp)) {
+			(*maxrep)++;
+		}
+	}
+	return;
+}
+
+/********************** WRITE_MAXSAMP_PROPERTIES ***************************/
+//
+//int write_maxsamp_properties(double max1,long maxloc,long maxrep,dataptr dz)
+//{
+//
+//	float maxpfamp = (float)max1;
+//
+//	if(maxloc<0 || maxrep<0) {
+//		sprintf(errstr,"Failed to establish location and/or repetition-count of max-sample\n");
+//		return(GOAL_FAILED);
+//	}
+	/* TODO: scrap all this for the PEAK chunk instead! */
+//* don't store in 'maxamp' as this is (long) in old files: 
+//	if(sndputprop(dz->ofd, "maxpfamp", (char *)&maxpfamp, sizeof(float)) < 0) {
+//		sprintf(errstr,"Can't write new max-sample to sndfile.\n");
+//		return(PROGRAM_ERROR);
+//	}
+//	if(sndputprop(dz->ofd, "maxloc", (char *)&maxloc, sizeof(long)) < 0) {
+//		sprintf(errstr,"Can't write location of max-sample to sndfile.\n");
+//		return(PROGRAM_ERROR);
+//	}
+//	if(sndputprop(dz->ofd, "maxrep", (char *)&maxrep, sizeof(long)) < 0) {
+//		sprintf(errstr,"Can't write repeat-count of max-sample to sndfile.\n");
+//		return(PROGRAM_ERROR);
+//	}
+//	return(FINISHED);
+//}
+
+/********************** DO_MULTIFILE_LOUDNESS ***************************/
+
+int do_multifile_loudness(dataptr dz)
+{
+	int exit_status;
+	double *greater, greatest = 0.0, maxfound;
+	/*RWD*/
+	double dbamp;
+	int clipsamps = 1;
+	double peak_val = 0.0;
+
+	int orig_ifd = dz->ifd[0];
+ //TW REVISED Dec 2002
+//	int n, do_gain, namelen, maxno = 0;
+	int n, do_gain, maxno = 0;
+//TW REVISED Dec 2002
+//	char outfilename[256], *outfilenumber;	   /* RWD fname was only [64] */
+	char outfilename[256];
+	long numclipped = 0;
+	double this_gain = 1.0, maxnoclip = 1.0;
+
+	if((greater = (double *)malloc(dz->infilecnt * sizeof(double)))==NULL) {
+		sprintf(errstr,"Insufficient memory to store file maxima\n");
+		return(MEMORY_ERROR);
+	}
+
+	if(dz->true_outfile_stype == SAMP_FLOAT)
+		if(dz->clip_floatsams == 0)
+			clipsamps = 0;
+
+	fprintf(stdout,"INFO: Finding loudest file\n");
+	fflush(stdout);
+	for(n=0;n<dz->infilecnt;n++) {
+		maxfound = 0.0;
+		dz->ifd[0] = dz->ifd[n];
+		dz->total_samps_written = 0;
+		dz->samps_left = dz->insams[n];
+		dz->total_samps_read = 0;		
+	    if((exit_status = find_max(&maxfound,dz))<0) {
+			dz->ifd[0] = orig_ifd;
+			return(exit_status);
+		}
+		if(maxfound > greatest) {
+			greatest = maxfound;
+			maxno = n;
+		}
+		greater[n] = maxfound/F_MAXSAMP;
+	}
+	greatest /= F_MAXSAMP;
+	dz->ifd[0] = orig_ifd;
+	dbamp = 20 * log10(greatest);  /*RWD*/
+	if(dz->mode==LOUDNESS_LOUDEST) {
+		fprintf(stdout,"INFO: loudest file is %s with level %lf (%.3f dB)\n",dz->wordstor[maxno],greatest,dbamp);
+		fflush(stdout);
+		return(FINISHED);
+	}
+	fprintf(stdout,"INFO: Equalising levels\n");
+	fflush(stdout);
+	for(n=0;n<dz->infilecnt;n++) {
+		dz->ssampsread = 0;
+		dz->total_samps_read = 0;
+		dz->ifd[0] = dz->ifd[n];
+		if(sndseekEx(dz->ifd[0],0L,0)<0) {
+			sprintf(errstr,"sndseekEx() failed.\n");
+			return(SYSTEM_ERROR);
+	    }
+		dz->total_samps_written = 0;
+		dz->samps_left = dz->insams[n];
+		dz->total_samps_read = 0;		
+		if(!flteq(greatest,greater[n])) {
+			this_gain = greatest/greater[n];
+			maxnoclip  = fabs((double)F_MAXSAMP/this_gain);
+			do_gain = 1;
+		} else {
+			do_gain = 0;
+		}
+		if(n>0) {
+			strcpy(outfilename,dz->wordstor[dz->infilecnt]);
+			/* RWD 9:2001 the -1 is unsafe if outname is only one char! */
+//TW This is a sloom requirement,as standard sloom temp outfile name is 'cdptest0'
+// and temporary-file housekeeping requires files to be named cdptestN in numeric order of N
+// However, we can do it differently for cmdline case....
+			if(sloom)
+				insert_new_number_at_filename_end(outfilename,n,1);
+			else
+				insert_new_number_at_filename_end(outfilename,n,0);
+			if((exit_status = create_sized_outfile(outfilename,dz))<0) {
+				sprintf(errstr,"Cannot open output file %s\n", outfilename);
+				dz->ifd[0] = orig_ifd;
+				return(DATA_ERROR);
+			}
+		}
+		while(dz->samps_left > 0) {
+			if((exit_status = read_samps(dz->sampbuf[0],dz))<0) {
+				sprintf(errstr,"Cannot read data from sndfile %d\n",n+1);
+				dz->ifd[0] = orig_ifd;
+				return(PROGRAM_ERROR);
+			}
+			if(do_gain)
+				gain(dz->ssampsread,this_gain,maxnoclip,&numclipped,clipsamps,&peak_val,dz);
+			if(dz->ssampsread > 0) {
+				if((exit_status = write_samps(dz->sampbuf[0],dz->ssampsread,dz))<0) {
+					dz->ifd[0] = orig_ifd;
+					return(exit_status);
+				}
+			}
+		}
+		if(n < dz->infilecnt - 1) {
+			if((exit_status = headwrite(dz->ofd,dz))<0) {
+				dz->ifd[0] = orig_ifd;
+				return(exit_status);
+			}
+			if((exit_status = reset_peak_finder(dz))<0)
+				return(exit_status);
+			if(sndcloseEx(dz->ofd) < 0) {
+				fprintf(stdout,"WARNING: Can't close output soundfile %s\n",outfilename);
+				fflush(stdout);
+			}
+			dz->ofd = -1;
+		}
+	}
+	dz->ifd[0] = orig_ifd;
+	/*RWD*/
+	if(clipsamps && (numclipped > 0))
+		sprintf(errstr, "WARNING: %ld samples were clipped.\n", numclipped);
+	dz->peak_fval = peak_val;
+	/*will get written to header automatically*/
+	return(FINISHED);
+}
+
+
+//TW NEW FUNCTION, updated for floatsams and new-style clipping detection
+/********************** GAINENV ***************************/
+
+int gainenv(long samples,long *last_total,double maxnoclip,long *numclipped,int do_clip,double *peak,dataptr dz)
+{
+	int exit_status;
+	register long i;            
+	double s, buf_peak = *peak;
+	double timeincr = 1.0/(double)dz->infile->srate;
+	float *buffer = dz->sampbuf[0];
+	double time = (double)(*last_total/dz->infile->channels)/(double)dz->infile->srate;
+
+	for(i = 0; i < samples; i++) {
+		if(i % dz->infile->channels == 0) {
+			if((exit_status = read_value_from_brktable(time,LOUD_GAIN,dz))<0)
+				return(exit_status);
+			time += timeincr;
+		}
+		s = buffer[i];
+		s *= dz->param[LOUD_GAIN];
+		if(s >= 0) {
+			if(do_clip && (s > maxnoclip)) {
+				(*numclipped)++;
+				s = 1.0;
+			}
+			buf_peak = max(buf_peak,s);
+		} else {
+			if(do_clip && (s < -maxnoclip)) {
+				(*numclipped)++;
+				s = -1.0;
+			}
+			buf_peak = max(buf_peak,-s);
+		}
+		buffer[i] = (float)s;
+	}
+	*peak = buf_peak;
+	*last_total = dz->total_samps_read;
+	return(FINISHED);
+}
+

+ 2666 - 0
dev/modify/granula1.c

@@ -0,0 +1,2666 @@
+/*
+ * Copyright (c) 1983-2013 Trevor Wishart and Composers Desktop Project Ltd
+ * http://www.trevorwishart.co.uk
+ * http://www.composersdesktop.com
+ *
+ This file is part of the CDP System.
+
+    The CDP System is free software; you can redistribute it
+    and/or modify it under the terms of the GNU Lesser General Public
+    License as published by the Free Software Foundation; either
+    version 2.1 of the License, or (at your option) any later version.
+
+    The CDP System is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public
+    License along with the CDP System; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+    02111-1307 USA
+ *
+ */
+
+
+
+/*
+ *	ABOUT THIS PROCESS
+ *
+ *	There are (up to) 5 buffers invloved here.....
+ *	GRS_SBUF into which the input data is read  from the file.
+ *	GRS_BUF	 into which the input data is mixed down to mono, where necessary. Otherwise, initial reads go directly to this buffer.
+ *		This buffer has an overflow sector of GRS_BUF_SMPXS samples.
+ *		The 1st read fills the buffer and the overflow.
+ *		After the first read these overflow samples are copied to the bufstart, and a new input buffer start is marked, overflow-samples into the GRS_BUF..
+ *	GRS_IBUF is then the point at which further samples are read into the input buffer.
+ *	GRS_LBUF is buffer into which grains are copied for processing to the output, (they are timestretched, pshifted or and spliced).
+ *	GRS_OBUF is the buffer into which the finished grains are copied ready for output.
+ *
+ *	GRS_INCHANS is the number of channels in the input grains i.e. after they have (or have not) been mixed down to mono.
+ *	GRS_OUTCHANS is the number of channels in the output, which can be
+ *		Mono, where no spatial processing takes place, and the input is mono
+ *		Multichannel, where spatial processing takes place and the input, is
+ *			(a) Mono
+ *			(b) A selected (mono) channel from a multichannel input.
+ *			(c)	A mix down of a multichannel input into a mono source.
+ *		Multichannel, where the input is multichannel, and no spatialisation is requested.
+ */
+
+/* floatsam version */
+#include <stdio.h>
+#include <stdlib.h>
+#include <limits.h>
+#include <string.h>
+#include <structures.h>
+#include <tkglobals.h>
+#include <globcon.h>
+#include <processno.h>
+#include <modeno.h>
+#include <arrays.h>
+#include <filetype.h>
+#include <modify.h>
+#include <cdpmain.h>
+
+#include <sfsys.h>
+#include <osbind.h>
+
+#ifdef unix
+#define round(x) lround((x))
+#endif
+
+#define SAUS_SBUF		(0)
+#define SAUS_OBUF		(1)
+#define	SAUS_BUF(x)		(((x)*2)+2)
+#define	SAUS_IBUF(x)	(((x)*2)+3)
+
+static int    read_samps_granula(int firsttime,dataptr dz);
+static int    granulate(int *thissnd,long *aipc,long *aopc,float **iiiiptr,float **LLLLptr,
+				double inv_sr,long *samptotal,float **maxwrite,int *nctr,dataptr dz);
+static int    read_a_large_buf(dataptr dz);
+static int    read_a_normal_buf_with_wraparound(dataptr dz);
+static int    baktrak_granula(long samptotal,int absiicnt_per_chan,float **iiptr,dataptr dz);
+static int    reset_granula(int resetskip,dataptr dz);
+static int    make_grain(float *b,float **iiptr,float aamp,int gsize_per_chan,double *transpos,dataptr dz);
+static int    make_stereo_grain(float *b,float **iiptr,float aamp,int gsize_per_chan,double *transpos,dataptr dz);
+static int    write_grain(float **maxwrite,float **Fptr, float **FFptr,int gsize_per_chan,int *nctr,dataptr dz);
+static int    write_stereo_grain(double rpos,float **maxwrite,float **Fptr,float **FFptr,
+				int gsize_per_chan,int *nctr,dataptr dz);
+static double dehole(double pos);
+static int    write_samps_granula(long k,int *nctr,dataptr dz);
+static void   do_splices(int gsize_per_chan,int bspl,int espl,dataptr dz);
+static void   do_btab_splice(dataptr dz);
+static void   do_bsplice(int gsize_per_chan,dataptr dz,int bspl);
+static void   do_etab_splice(int gsize_per_chan,dataptr dz);
+static void   do_esplice(int gsize_per_chan,dataptr dz,int espl);
+static void   do_stereo_splices(int gsize_per_chan,int bspl,int espl,dataptr dz);
+static void   do_stereo_btab_splice(dataptr dz);
+static void   do_stereo_bsplice(int gsize_per_chan,dataptr dz,int bspl);
+static void   do_stereo_etab_splice(int gsize_per_chan,dataptr dz);
+static void   do_stereo_esplice(int gsize_per_chan,dataptr dz,int espl);
+static float  interp_gval_with_amp(float *s,double flcnt_frac,int chans,float ampp);
+static float  interp_gval(float *s,double flcnt_frac,int chans);
+static int    set_instep(int ostep_per_chan,dataptr dz);
+static int    set_outstep(int gsize_per_chan,dataptr dz);
+static int    set_range(int absiicnt,dataptr dz);
+static long   do_scatter(int ostep_per_chan,dataptr dz);
+static int    set_ivalue(int flag,int paramno,int hparamno,int rangeno,dataptr dz);
+static double set_dvalue(int flag,int paramno,int hparamno,int rangeno,dataptr dz);
+static int    renormalise(int nctr,dataptr dz);
+
+static int  read_samps_sausage(int firsttime,dataptr dz);
+static int  read_a_specific_large_buf(int k,dataptr dz);
+static int  read_a_specific_normal_buf_with_wraparound(int k,dataptr dz);
+static int  baktrak_sausage(int thissnd,long samptotal,int absiicnt_per_chan,float **iiptr,dataptr dz);
+static int  reset_sausage(int thissnd,int resetskip,dataptr dz);
+static int  get_next_insnd(dataptr dz);
+static void perm_sausage(int cnt,dataptr dz);
+static void insert(int n,int t,int cnt_less_one,dataptr dz);
+static void prefix(int n,int cnt_less_one,dataptr dz);
+static void shuflup(int k,int cnt_less_one,dataptr dz);
+
+static int grab_an_appropriate_block_of_sausage_memory(long *this_bloksize,long standard_block,int bufdivisor,dataptr dz);
+
+#ifdef MULTICHAN
+
+static int make_multichan_grain(float *b,float **iiptr,float aamp,int gsize_per_chan,double *transpos,dataptr dz);
+static void	do_multichan_splices(int gsize_per_chan,int bspl,int espl,dataptr dz);
+static void do_multichan_btab_splice(dataptr dz);
+static void do_multichan_bsplice(int gsize_per_chan,dataptr dz,int bspl);
+static void do_multichan_etab_splice(int gsize_per_chan,dataptr dz);
+static void do_multichan_esplice(int gsize_per_chan,dataptr dz,int espl);
+static int write_multichan_grain(double rpos,int chan, int chanb,float **maxwrite,float **Fptr,float **FFptr,int gsize_per_chan,int *nctr,dataptr dz);
+
+#endif
+
+/********************************* GRANULA_PROCESS *************************************/
+
+int granula_process(dataptr dz)
+{
+	int    exit_status;
+	int    firsttime = TRUE, thissnd = 0;
+	int    nctr = 0;	 /* normalisation vals counter */
+	long   absicnt_per_chan = 0, absocnt_per_chan = 0;
+	float  *iptr;
+	float   *Fptr = dz->fptr[GRS_LBUF];
+ 	long   vals_to_write, total_ssampsread;
+	double sr = (double)dz->infile->srate;
+	double inverse_sr = 1.0/sr;
+	float   *maxwrite = dz->fptr[GRS_LBUF];	/* pointer to last sample created */
+//TW AGREED DELETIONS
+
+	if(sloom)
+		dz->total_samps_read = 0;
+	dz->itemcnt = 0;
+	switch(dz->process) {
+	case(SAUSAGE):
+		if((exit_status = read_samps_sausage(firsttime,dz))<0)
+			return(exit_status);
+		iptr = dz->sampbuf[SAUS_BUF(thissnd)];
+		break;
+	case(BRASSAGE):
+		if((exit_status = read_samps_granula(firsttime,dz))<0)
+			return(exit_status);
+		iptr = dz->sampbuf[GRS_BUF];
+		break;
+	}
+	total_ssampsread = dz->ssampsread;	
+	display_virtual_time(0L,dz);
+	do {
+		if((exit_status = granulate(&thissnd,&absicnt_per_chan,&absocnt_per_chan,&iptr,&Fptr,
+									inverse_sr,&total_ssampsread,&maxwrite,&nctr,dz))<0)
+			return(exit_status);
+	} while(exit_status==CONTINUE);
+
+	vals_to_write = maxwrite - dz->fptr[GRS_LBUF];
+	while(vals_to_write > dz->iparam[GRS_LONGS_BUFLEN]) {					   
+// TW REVISED July 2004
+//		if((exit_status = write_samps_granula(dz->buflen,&nctr,dz))<0)
+		if((exit_status = write_samps_granula(dz->iparam[GRS_LONGS_BUFLEN],&nctr,dz))<0)
+			return(exit_status);
+		memmove((char *)dz->fptr[GRS_LBUF],(char *)dz->fptr[GRS_LBUFEND],
+			dz->iparam[GRS_LBUF_SMPXS] * sizeof(float));
+		memset((char *)dz->fptr[GRS_LBUFMID],0,dz->iparam[GRS_LONGS_BUFLEN] * sizeof(float));
+		vals_to_write -= dz->iparam[GRS_LONGS_BUFLEN];
+	}
+	if(vals_to_write > 0) {
+		if((exit_status = write_samps_granula(vals_to_write,&nctr,dz))<0)
+			return(exit_status);
+	}
+	if(dz->total_samps_written <= 0) {
+		sprintf(errstr,"SOURCE POSSIBLY TOO SHORT FOR THIS OPTION: Try 'Full Monty'\n");
+		return(GOAL_FAILED);
+	}
+	display_virtual_time(0,dz);
+#ifdef MULTICHAN
+	dz->infile->channels = dz->iparam[GRS_OUTCHANS];	// setup ONLY NOW for headwrite
+#endif
+	return renormalise(nctr,dz);
+}
+
+/******************************* READ_SAMPS_GRANULA *******************************/
+
+int read_samps_granula(int firsttime,dataptr dz)
+{
+	int exit_status;
+	if(firsttime) {
+		if((exit_status = read_a_large_buf(dz))<0)
+			return(exit_status);
+	} else {
+		if((exit_status = read_a_normal_buf_with_wraparound(dz))<0)
+			return(exit_status);
+	}
+	if(firsttime)
+		dz->iparam[SAMPS_IN_INBUF] = dz->ssampsread;
+	else
+		dz->iparam[SAMPS_IN_INBUF] = dz->ssampsread + dz->iparam[GRS_BUF_SMPXS];
+
+	return(FINISHED);
+}
+
+/*  INPUT BUFFER :-		
+ *
+ *	|-----------BUFLEN-----------|
+ *
+ *	buf      ibuf		   bufend
+ *	|_________|__________________|buf_smpxs|
+ *					 			/
+ *	|buf_smpxs|			   <<-COPY_________/
+ *
+ *		  	  |-----------BUFLEN-----------|
+ */
+
+/***************************** RENORMALISE ****************************
+ *
+ * (1)	Find smallest normalising factor S (creating gretest level reduction).
+ * (2)	For each normalising factor N, find value which will bring it
+ *	down to S. That is S/N. Reinsert these values in the normalising
+ *	factor array.
+ *	REnormalising with these factors, will ensure whole file is normalised
+ *	using same factor (S), which is also the smallest factor required.
+ * (3)	Seek to start of outfile.
+ * (4)	Set infile pointer to same as outfile pointer, so that read_samps()
+ *	now reads from OUTFILE.
+ * (5)	Reset samps_read counter.
+ * (6)	Size of buffers we read depends on whether we output a stereo
+ *	file or a mono file.
+ * (7) 	Reset normalisation-factor array pointer (m).
+ *	While we still have a complete buffer to read..
+ * (8)  Read samps into output buffer (as, if output is stereo, this
+ *	may be larger than ibuf, and will accomodate the data).
+ * (9)	Renormalise all values.
+ * (10)	Increment pointer to normalisation factors.
+ * (11)	Seek to start of current buffer, in file.
+ * (12)	Overwrite data in file.
+ * (13)	Re-seek to end of current buffer, in file.
+ * (14)	Calcualte how many samps left over at end, and if any...
+ * (16)	Read last (short) buffer.
+ * (17)	Set buffer size to actual number of samps left.
+ * (18)	Renormalise.
+ * (19)	Seek to start of ACTUAL buffer in file.
+ * (20)	Write the real number of samps left in buffer.
+ * (21) Check the arithmetic.
+ * (22) Restore pointer to original infile, so finish() works correctly.
+ */
+  
+int renormalise(int nctr,dataptr dz)
+{
+	int exit_status;
+	long n, m = 0;
+	long total_samps_read = 0;
+	long samp_total = dz->total_samps_written, samps_remaining, last_total_samps_read;
+	double min_norm  = dz->parray[GRS_NORMFACT][0];	/* 1 */
+	float  *s = NULL;
+	double nf;
+	long   cnt;
+
+    /* RWD Nov 2 2010: hack to avoid crash! */
+    SFPROPS inprops;
+    int inchans = 0;
+    if(snd_headread(dz->ifd[0],&inprops)){
+        inchans = inprops.chans;
+    }
+    else {
+        sprintf(errstr, "WARNING: Can't read infile properties for normalization.\n");
+		return SYSTEM_ERROR;    
+    }
+    
+//TW NEW MECHANISM writes renormalised vals from original file created (tempfile) into true outfile		
+	if(sndcloseEx(dz->ifd[0]) < 0) {
+		sprintf(errstr, "WARNING: Can't close input soundfile\n");
+		return(SYSTEM_ERROR);
+	}
+	if(sndcloseEx(dz->ofd) < 0) {
+		sprintf(errstr, "WARNING: Can't close output soundfile\n");
+		return(SYSTEM_ERROR);
+	}
+	if((dz->ifd[0] = sndopenEx(dz->outfilename,0,CDP_OPEN_RDWR)) < 0) {	   /*RWD Nov 2003 need RDWR to enable sndunlink to work */
+		sprintf(errstr,"Failure to reopen file %s for renormalisation.\n",dz->outfilename);
+		return(SYSTEM_ERROR);
+	}
+	sndseekEx(dz->ifd[0],0,0);
+//	if(!sloom)
+//		dz->wordstor[0][strlen(dz->wordstor[0]) -9] = ENDOFSTR;
+	if((exit_status = create_sized_outfile(dz->wordstor[0],dz))<0) {
+		sprintf(errstr,"Failure to create file %s for renormalisation.\n",dz->wordstor[0]);
+		return(exit_status);
+	}
+	if((exit_status = reset_peak_finder(dz))<0)
+		return(exit_status);
+	switch(dz->process) {
+	case(BRASSAGE):	s = dz->sampbuf[GRS_OBUF];	break;
+	case(SAUSAGE):	s = dz->sampbuf[SAUS_OBUF];	break;
+	}
+	dz->total_samps_written = 0;
+	for(m=1;m<nctr;m++) {
+		if((dz->parray[GRS_NORMFACT])[m] < min_norm)
+			min_norm  = (dz->parray[GRS_NORMFACT])[m];
+	}
+
+	if(min_norm < 1.0) {
+		sprintf(errstr,"Renormalising by %lf\n",min_norm);
+		print_outmessage_flush(errstr);
+		for(m=0;m<nctr;m++)								/* 2 */
+			(dz->parray[GRS_NORMFACT])[m] = min_norm/(dz->parray[GRS_NORMFACT])[m];
+	}
+//TW new mechanism: lines not needed
+	dz->total_samps_read = 0;						/* 5 */
+	display_virtual_time(0L,dz);					/* works on dz->total_samps_read here, so param irrelevant */
+/* RWD nov 2010 hack, part 2: do this multipLy only if infile is mono */
+    if(inchans ==1)
+        dz->buflen *= dz->iparam[GRS_OUTCHANS];			/* 6 */												
+	m = 0;											/* 7 */
+	cnt = dz->buflen;
+	while(dz->total_samps_read + dz->buflen < samp_total) {
+		if((exit_status = read_samps(s,dz))<0) {
+			close_and_delete_tempfile(dz->outfilename,dz);
+			return(exit_status);
+		}											/* 8 */
+		total_samps_read += dz->ssampsread;
+		if(min_norm < 1.0) {
+			nf  = (dz->parray[GRS_NORMFACT])[m];
+			for(n=0;n<cnt;n++)							/* 9 */
+				s[n] = /*round*/ (float)((double)s[n] * nf);
+			m++;										/* 10 */
+		}
+		if((exit_status = write_samps(s,dz->buflen,dz))<0) {
+			close_and_delete_tempfile(dz->outfilename,dz);
+			return(exit_status);					/* 12 */
+		}
+	}												/* 14 */
+	if((samps_remaining = samp_total - dz->total_samps_read)>0) {
+		last_total_samps_read =  dz->total_samps_read;
+		if((exit_status = read_samps(s,dz))<0) {
+			close_and_delete_tempfile(dz->outfilename,dz);
+			return(exit_status);					/* 16 */
+		}
+		dz->buflen = samps_remaining;	/* 17 */
+		if(min_norm < 1.0) {
+			nf  = (dz->parray[GRS_NORMFACT])[m];
+			for(n=0;n<dz->buflen;n++)					/* 18 */
+				s[n] = /*round*/(float) ((double)s[n] * nf);
+		}
+		if(samps_remaining > 0) {
+			if((exit_status = write_samps(s,samps_remaining,dz))<0) {
+				close_and_delete_tempfile(dz->outfilename,dz);
+				return(exit_status);					/* 20 */
+			}
+		}
+	}
+	if(dz->total_samps_written != samp_total) {		/* 21 */
+		sprintf(errstr,"ccounting problem: Renormalise()\n");
+		close_and_delete_tempfile(dz->outfilename,dz);
+		return(PROGRAM_ERROR);
+	}
+	close_and_delete_tempfile(dz->outfilename,dz);
+	return(FINISHED);
+}
+
+/*************************** GRANULATE *********************************
+ * iptr     = advancing base-pointer in input buffer.
+ * iiptr    = true read-pointer in input buffer.
+ * absicnt_per_chan  = advancing-base-counter in input stream, counting TOTAL samps.
+ * absiicnt_per_chan = true counter in input stream, counting TOTAL samps to write pos.
+ * Fptr     = advancing base-pointer in output buffer.
+ * FFptr    = true write pointer in output buffer.
+ * absocnt_per_chan  = advancing-base-counter in output stream, measuring OUTsize.
+ */
+
+/* rwd: some major changes here to clear bugs */
+/* tw:  some more major changes here to clear implementation errors */
+
+//TW removed redundant 'sr' parameter
+int granulate(int *thissnd,long *aipc,long *aopc,float **iiiiptr,float **LLLLptr,
+		double inv_sr,long *samptotal,float **maxwrite,int *nctr,dataptr dz)
+{
+	int exit_status;
+	long  absicnt_per_chan = *aipc, absocnt_per_chan = *aopc;
+	float *iiptr, *iptr = *iiiiptr, *endbufptr = NULL, *startbufptr = NULL, *thisbuf = NULL;
+	float  *FFptr, *Fptr = *LLLLptr;
+	long  isauspos, iisauspos;
+	float   aamp = -1;
+	int   bspl = 0, espl = 0, lastsnd;
+	int   firsttime = FALSE;
+	int   gsize_per_chan, ostep_per_chan, istep_per_chan, absiicnt_per_chan, rang_per_chan;
+	long  smpscat_per_chan;
+	int   resetskip = 0;
+	double  time = (double)absicnt_per_chan * inv_sr;
+	double	transpos = 1.0, position;
+	long saved_total_samps_read = 0;
+#ifdef MULTICHAN
+	int chana, chanb;
+#endif
+	if((exit_status = read_values_from_all_existing_brktables(time,dz))<0)
+		return(exit_status);
+
+	gsize_per_chan = set_ivalue(dz->iparray[GRS_FLAGS][G_GRAINSIZE_FLAG],GRS_GRAINSIZE,GRS_HGRAINSIZE,GRS_GRANGE,dz);
+
+	if(absicnt_per_chan + gsize_per_chan >= dz->iparam[ORIG_SMPSIZE])
+		return(FINISHED);
+
+	ostep_per_chan = set_outstep(gsize_per_chan,dz);
+
+	if(dz->iparam[GRS_OUTLEN]>0 && (absocnt_per_chan>=dz->iparam[GRS_OUTLEN]))
+		return(FINISHED); 	/* IF outfile LENGTH SPECIFIED HAS BEEN MADE: EXIT */
+
+	FFptr = Fptr;
+	if(dz->iparray[GRS_FLAGS][G_SCATTER_FLAG])	{ /* If grains scattered, scatter FFptr */
+		smpscat_per_chan = do_scatter(ostep_per_chan,dz);	
+		FFptr += (smpscat_per_chan * dz->iparam[GRS_OUTCHANS]);	
+	}
+	if(FFptr < dz->fptr[GRS_LBUF]) {
+		sprintf(errstr,"Array overrun 1: granula()\n");
+		return(PROGRAM_ERROR); /* FFptr can be outside the Lbuffer because Fptr is outside it */
+	}
+	if(FFptr >= dz->fptr[GRS_LTAILEND]) {
+		if((exit_status = write_samps_granula(dz->iparam[GRS_LONGS_BUFLEN],nctr,dz))<0)
+			return(exit_status);
+/* IF CURRENT POINTER AT END OF LBUF WRITE SAMPS, WRAP AROUND POINTERS */
+		memmove((char *)dz->fptr[GRS_LBUF],(char *)dz->fptr[GRS_LBUFEND],
+			dz->iparam[GRS_LBUF_SMPXS] * sizeof(float));
+		memset((char *)dz->fptr[GRS_LBUFMID],0,dz->iparam[GRS_LONGS_BUFLEN] * sizeof(float));
+		FFptr    -= dz->iparam[GRS_LONGS_BUFLEN];	
+		if((Fptr -= dz->iparam[GRS_LONGS_BUFLEN])  < dz->fptr[GRS_LBUF]) {
+			sprintf(errstr,"Array overrun 2: granula()\n");
+			return(PROGRAM_ERROR);
+		}
+		*maxwrite -= dz->iparam[GRS_LONGS_BUFLEN];
+	}
+
+	istep_per_chan    = set_instep(ostep_per_chan,dz);	
+	if(istep_per_chan==0 && dz->iparam[GRS_OUTLEN]==0) {
+		sprintf(errstr,"velocity or instep has become so small that file will be infinitely long!!\n"
+					   "Try slightly increasing your very small values.\n");
+		return(GOAL_FAILED);
+	}
+	iiptr    = iptr;
+
+	if(dz->process==SAUSAGE) {
+		lastsnd   = *thissnd;
+		isauspos  = iptr  - dz->sampbuf[SAUS_BUF(lastsnd)];
+		iisauspos = iiptr - dz->sampbuf[SAUS_BUF(lastsnd)];
+		*thissnd  = get_next_insnd(dz);
+		iiptr     = dz->sampbuf[SAUS_BUF(*thissnd)] + iisauspos;
+		iptr      = dz->sampbuf[SAUS_BUF(*thissnd)] + isauspos;
+	}
+
+	absiicnt_per_chan = absicnt_per_chan;
+	if(dz->iparray[GRS_FLAGS][G_RANGE_FLAG]) {
+		rang_per_chan      = set_range(absiicnt_per_chan,dz);		/* RESET iiptr etc WITHIN SEARCHRANGE */	
+		absiicnt_per_chan -= rang_per_chan;
+		iiptr             -= rang_per_chan * dz->iparam[GRS_INCHANS];
+	}
+	switch(dz->process) {
+	case(BRASSAGE):	
+		endbufptr   = dz->sbufptr[GRS_BUF];		
+		startbufptr = dz->sampbuf[GRS_BUF];		
+		break;		
+	case(SAUSAGE):	
+		endbufptr   = dz->sbufptr[SAUS_BUF(*thissnd)];	
+		startbufptr = dz->sampbuf[SAUS_BUF(*thissnd)];		
+		break;		
+	}
+	if(iiptr >= endbufptr) {
+		while(iiptr >= endbufptr) {
+			switch(dz->process) {
+			case(BRASSAGE):
+				if((read_samps_granula(firsttime,dz))<0)					/* IF iiptr OFF END OF IBUF */
+					return(exit_status);
+				break;
+			case(SAUSAGE):
+				if((read_samps_sausage(firsttime,dz))<0)					/* IF iiptr OFF END OF IBUF */
+					return(exit_status);
+				break;
+			}
+			*samptotal += dz->ssampsread;
+			if(dz->ssampsread<=0)
+				return(FINISHED);
+					/* READ SAMPS, WRAP BACK POINTER */
+			iiptr -= dz->buflen; 	
+			iptr  -= dz->buflen;
+		}
+	} else if(iiptr < startbufptr) {								/* IF RANGE TAKES US BAK OUT OF THIS BUF, */
+
+		if(sloom)
+			saved_total_samps_read = dz->total_samps_read;	/* saved so display_virtual_time() works during baktrak!! */
+		if((resetskip = *samptotal - dz->iparam[SAMPS_IN_INBUF])<0) {	/* SET RESETSKIP TO START OF CURRENT BUFFER */
+			sprintf(errstr,"Error in baktraking: granula()\n");
+			return(PROGRAM_ERROR);
+		}
+		switch(dz->process) {
+		case(BRASSAGE):
+			if((exit_status = baktrak_granula(*samptotal,absiicnt_per_chan,&iiptr,dz))<0)
+				return(exit_status);									/* SEEK BACKWDS, & RESET iiptr In NEW BUF */
+			break;
+		case(SAUSAGE):
+			if((exit_status = baktrak_sausage(*thissnd,*samptotal,absiicnt_per_chan,&iiptr,dz))<0)
+				return(exit_status);									/* SEEK BACKWDS, & RESET iiptr In NEW BUF */
+			break;
+		}
+		if(sloom)
+			dz->total_samps_read = saved_total_samps_read;		/* restore so its not changed by the baktraking!! */
+	}
+	if(dz->iparray[GRS_FLAGS][G_AMP_FLAG])
+		/* RWD was set_ivalue*/
+		aamp = (float) set_dvalue(dz->iparray[GRS_FLAGS][G_AMP_FLAG],GRS_AMP,GRS_HAMP,GRS_ARANGE,dz);
+									/* GET SPLICE VALUES */
+	bspl = set_ivalue(dz->iparray[GRS_FLAGS][G_BSPLICE_FLAG],GRS_BSPLICE,GRS_HBSPLICE,GRS_BRANGE,dz);
+	espl = set_ivalue(dz->iparray[GRS_FLAGS][G_ESPLICE_FLAG],GRS_ESPLICE,GRS_HESPLICE,GRS_ERANGE,dz);
+	switch(dz->process) {
+	case(BRASSAGE):	thisbuf = dz->sampbuf[GRS_BUF];					break;
+	case(SAUSAGE):	thisbuf = dz->sampbuf[SAUS_BUF(*thissnd)];		break;
+	}
+
+#ifndef MULTICHAN
+
+	switch(dz->iparam[GRS_INCHANS]) {
+	case(1):
+		if(!make_grain(thisbuf,&iiptr,aamp,gsize_per_chan,&transpos,dz))	
+			return(FINISHED);										/* COPYGRAIN TO GRAINBUF,INCLUDING ANY PSHIFT */
+		do_splices(gsize_per_chan,bspl,espl,dz);					/* DO SPLICES IN GRAINBUF */
+		break;
+	case(2):
+		if(!make_stereo_grain(thisbuf,&iiptr,aamp,gsize_per_chan,&transpos,dz))	
+			return(FINISHED);										/* COPYGRAIN TO GRAINBUF,INCLUDING ANY PSHIFT */
+		do_stereo_splices(gsize_per_chan,bspl,espl,dz);				/* DO SPLICES IN GRAINBUF */
+		break;
+	}
+#else
+
+	if(!make_multichan_grain(thisbuf,&iiptr,aamp,gsize_per_chan,&transpos,dz))	
+		return(FINISHED);											/* COPYGRAIN TO GRAINBUF,INCLUDING ANY PSHIFT */
+		do_multichan_splices(gsize_per_chan,bspl,espl,dz);			/* DO SPLICES IN GRAINBUF */
+
+#endif
+
+	if(dz->iparray[GRS_FLAGS][G_SPACE_FLAG]) {		/* IF SPATIAL INFO, GET IT,WRITE STEREO GRAIN */
+		position = set_dvalue(dz->iparray[GRS_FLAGS][G_SPACE_FLAG],GRS_SPACE,GRS_HSPACE,GRS_SPRANGE,dz);
+#ifndef MULTICHAN
+		if((exit_status = write_stereo_grain(position,maxwrite,&Fptr,&FFptr,gsize_per_chan,nctr,dz))<0)
+			return(exit_status);
+#else
+		if(dz->out_chans > 2) {
+			chana = (int)floor(position);
+			position  -= (double)chana;	//	position is relative position between 2 adjacent out-chans
+			chanb = chana + 1;			//	chanb is adjacent to chana
+			if(chana > dz->out_chans)	//	chana beyond last lspkr wraps around to 1st lspkr
+				chana = 1;		
+			else if(chana < 1)			//	chana below 1st loudspeaker wraps around to last-lspkr
+				chana = dz->out_chans;
+			if((exit_status = write_multichan_grain(position,chana,chanb,maxwrite,&Fptr,&FFptr,gsize_per_chan,nctr,dz))<0)
+				return(exit_status);
+		} else {
+			if((exit_status = write_stereo_grain(position,maxwrite,&Fptr,&FFptr,gsize_per_chan,nctr,dz))<0)
+				return(exit_status);
+		}
+#endif
+	} else {			/* WRITE GRAIN */
+		if((exit_status = write_grain(maxwrite,&Fptr,&FFptr,gsize_per_chan,nctr,dz))<0)
+			return(exit_status);
+	}
+	if(sloom)
+		saved_total_samps_read = dz->total_samps_read;	/* saved so not disturbed by restoring of baktrakd-from buffer */
+
+	switch(dz->process) {
+	case(BRASSAGE): 											/* IF BAKTRAKD : RESTORE ORIGINAL BUFFER */
+		if(resetskip && (exit_status = reset_granula(resetskip,dz))<0)	
+			return(exit_status);
+		break;
+	case(SAUSAGE):
+		if(resetskip && (exit_status = reset_sausage(*thissnd,resetskip,dz))<0)	
+			return(exit_status);
+		break;
+	}
+	if(sloom)
+		dz->total_samps_read = saved_total_samps_read;
+#ifndef MULTICHAN
+	iptr    += istep_per_chan;		/* MOVE FORWARD IN INFILE */
+	if(dz->iparam[GRS_INCHANS]==STEREO)
+		iptr    += istep_per_chan;			/* move further if using STEREO INPUT DATA */
+#else
+	iptr += (istep_per_chan * dz->iparam[GRS_INCHANS]);		/* MOVE FORWARD IN postmixdown input-buffer, which is either MONO or multichannel */
+#endif
+	absicnt_per_chan += istep_per_chan;		/* rwd: moved here from top of input section */
+
+#ifndef MULTICHAN
+	Fptr    += ostep_per_chan;				/* Fptr may still be outside (bottom of) Lbuf */
+	if(dz->iparray[GRS_FLAGS][G_SPACE_FLAG] || dz->iparam[GRS_INCHANS]==STEREO)
+		Fptr += ostep_per_chan;	/* Advance by stereo step, for STEREO OUTPUT */
+#else
+	Fptr += ostep_per_chan * dz->iparam[GRS_OUTCHANS];	/* Move forward in output buffer, which can be mono, spatialised-stereo or multichannel */
+#endif
+		
+			/*      so we don't lose first grain */
+	absocnt_per_chan += ostep_per_chan;		
+
+	*aipc = absicnt_per_chan;	/* RETURN VALUES OF RETAINED VARIABLES */
+	*aopc = absocnt_per_chan;
+	*iiiiptr = iptr;
+	*LLLLptr = Fptr;
+	return(CONTINUE);
+}
+
+/*************************** BAKTRAK_GRANULA ******************************
+ *
+ *     <------------ baktrak(b) ---------------->
+ *
+ *     <--(b-x)-->
+ *		  		  <------------ x -------------->
+ *		 		 |-------- current bufer --------|
+ *
+ *     |-------- new buffer --------|
+ *      <------------x------------->
+ *				
+ */
+
+#ifndef MULTICHAN
+
+int baktrak_granula(long samptotal,int absiicnt_per_chan,float **iiptr,dataptr dz)
+{
+	int  exit_status;
+	long bktrk, new_position;
+	unsigned long reset_size = dz->buflen + dz->iparam[GRS_BUF_SMPXS];
+
+	bktrk = samptotal - (absiicnt_per_chan * dz->iparam[GRS_INCHANS]);
+//TW I agree, this is FINE!!, and, with sndseekEx, algo is more efficient
+//	whenever the search-range is relatively small (and equally efficient otherwise)
+	*iiptr      = dz->sampbuf[GRS_BUF];
+
+	if((new_position = samptotal - bktrk)<0) {
+		fprintf(stdout,"WARNING: Non-fatal program error:\nRange arithmetic problem - 2, in baktraking.\n");
+		fflush(stdout);
+		new_position = 0;
+		*iiptr = dz->sampbuf[GRS_BUF];
+	}
+ 	if(dz->iparam[GRS_CHAN_TO_XTRACT])   /* IF we've converted from STEREO file */
+		new_position *= 2;
+	if(sndseekEx(dz->ifd[0],new_position,0)<0) {
+		sprintf(errstr,"sndseekEx error: baktrak_granula()\n");
+		return(SYSTEM_ERROR);
+	}
+	memset((char *)dz->sampbuf[GRS_BUF],0,reset_size * sizeof(float));
+    if(dz->iparam[GRS_CHAN_TO_XTRACT]) {
+ 		reset_size *= 2;
+    	memset((char *)dz->sampbuf[GRS_SBUF],0,reset_size * sizeof(float));
+	}
+	if((exit_status = read_a_large_buf(dz))<0)
+		return(exit_status);
+	dz->iparam[SAMPS_IN_INBUF] = dz->ssampsread;
+	return(FINISHED);
+}
+
+#else
+
+int baktrak_granula(long samptotal,int absiicnt_per_chan,float **iiptr,dataptr dz)
+{
+	int  exit_status,  chans = dz->infile->channels;
+	long bktrk, new_position;
+	unsigned long reset_size = dz->buflen + dz->iparam[GRS_BUF_SMPXS];
+
+	bktrk = samptotal - (absiicnt_per_chan * dz->iparam[GRS_INCHANS]);
+//TW I agree, this is FINE!!, and, with sndseekEx, algo is more efficient
+//	whenever the search-range is relatively small (and equally efficient otherwise)
+	*iiptr      = dz->sampbuf[GRS_BUF];
+
+	if((new_position = samptotal - bktrk)<0) {
+		fprintf(stdout,"WARNING: Non-fatal program error:\nRange arithmetic problem - 2, in baktraking.\n");
+		fflush(stdout);
+		new_position = 0;
+		*iiptr = dz->sampbuf[GRS_BUF];
+	}
+ 	if(dz->iparam[GRS_CHAN_TO_XTRACT])   /* IF we've converted from STEREO file */
+		new_position *= chans;
+	if(sndseekEx(dz->ifd[0],new_position,0)<0) {
+		sprintf(errstr,"sndseekEx error: baktrak_granula()\n");
+		return(SYSTEM_ERROR);
+	}
+	memset((char *)dz->sampbuf[GRS_BUF],0,reset_size * sizeof(float));
+    if(dz->iparam[GRS_CHAN_TO_XTRACT]) {
+  		reset_size *= chans;
+    	memset((char *)dz->sampbuf[GRS_SBUF],0,reset_size * sizeof(float));
+	}
+	if((exit_status = read_a_large_buf(dz))<0)
+		return(exit_status);
+	dz->iparam[SAMPS_IN_INBUF] = dz->ssampsread;
+	return(FINISHED);
+}
+
+#endif
+
+/*************************** READ_A_LARGE_BUF ******************************/
+
+#ifndef MULTICHAN
+
+int read_a_large_buf(dataptr dz)
+{
+	int exit_status;
+	long n, m, k;
+	dz->buflen += dz->iparam[GRS_BUF_SMPXS];
+	if(dz->iparam[GRS_CHAN_TO_XTRACT]) {
+		dz->buflen *= 2;
+		if((exit_status = read_samps(dz->sampbuf[GRS_SBUF],dz))<0)
+			return(exit_status);
+		dz->buflen /= 2;
+		dz->ssampsread /= 2;
+		switch(dz->iparam[GRS_CHAN_TO_XTRACT]) {
+		case(1):
+			for(n=0,m=0;n<dz->ssampsread;n++,m+=2)
+			(dz->sampbuf[GRS_BUF])[n] = (dz->sampbuf[GRS_SBUF])[m];
+			break;
+		case(2):
+			for(n=0,m=1;n<dz->ssampsread;n++,m+=2)
+				(dz->sampbuf[GRS_BUF])[n] = (dz->sampbuf[GRS_SBUF])[m];
+			break;
+		case(BOTH_CHANNELS):
+			for(n=0,m=0,k=1;n<dz->ssampsread;n++,m+=2,k+=2)
+				(dz->sampbuf[GRS_BUF])[n] = (float)(((dz->sampbuf[GRS_SBUF])[m] + (dz->sampbuf[GRS_SBUF])[k]) * 0.5f);
+			break;
+		}
+	} else {
+		if((exit_status = read_samps(dz->sampbuf[GRS_BUF],dz))<0)
+			return(exit_status);
+	}
+	dz->buflen -= dz->iparam[GRS_BUF_SMPXS];
+	return(FINISHED);
+}
+
+#else
+
+int read_a_large_buf(dataptr dz)
+{
+	int exit_status;
+	long n, m, ibufcnt;
+	int chans = dz->infile->channels;
+	double sum;
+	if(dz->iparam[GRS_CHAN_TO_XTRACT]) {
+		dz->buflen += dz->iparam[GRS_BUF_SMPXS];
+		dz->buflen *= chans;
+		if((exit_status = read_samps(dz->sampbuf[GRS_SBUF],dz))<0)
+			return(exit_status);
+		dz->buflen /= chans;
+		dz->buflen -= dz->iparam[GRS_BUF_SMPXS];
+		dz->ssampsread /= chans;
+		switch(dz->iparam[GRS_CHAN_TO_XTRACT]) {
+		case(ALL_CHANNELS):
+			ibufcnt = 0;
+			for(n=0;n<dz->ssampsread;n++) {
+				sum = 0.0;
+				for(m=0;m<chans;m++)
+					sum += dz->sampbuf[GRS_SBUF][ibufcnt++];
+				dz->sampbuf[GRS_BUF][n] = (float)(sum/(double)chans);
+			}
+			break;
+		default:
+			for(n=0,m=dz->iparam[GRS_CHAN_TO_XTRACT];n<dz->ssampsread;n++,m+=chans)
+				dz->sampbuf[GRS_BUF][n] = dz->sampbuf[GRS_SBUF][m];
+			break;
+		}
+	} else {
+		dz->buflen += dz->iparam[GRS_BUF_SMPXS];
+		if((exit_status = read_samps(dz->sampbuf[GRS_BUF],dz))<0)
+			return(exit_status);
+		dz->buflen -= dz->iparam[GRS_BUF_SMPXS];
+	}
+	return(FINISHED);
+}
+
+#endif
+
+/*************************** READ_A_NORMAL_BUF_WITH_WRAPAROUND ******************************/
+
+#ifndef MULTICHAN
+
+int read_a_normal_buf_with_wraparound(dataptr dz)
+{
+	int exit_status;
+	long n,m,k;
+	memmove((char *)dz->sampbuf[GRS_BUF],(char *)(dz->sbufptr[GRS_BUF]),
+		dz->iparam[GRS_BUF_SMPXS] * sizeof(float));
+	if(dz->iparam[GRS_CHAN_TO_XTRACT]) {
+		dz->buflen *= 2;
+		if((exit_status = read_samps(dz->sampbuf[GRS_SBUF],dz))<0)
+			return(exit_status);
+		dz->buflen /= 2;
+		dz->ssampsread  /= 2;
+		switch(dz->iparam[GRS_CHAN_TO_XTRACT]) {
+		case(1):
+			for(n=0,m=0;n<dz->ssampsread;n++,m+=2)
+				(dz->sampbuf[GRS_IBUF])[n] = (dz->sampbuf[GRS_SBUF])[m];
+			break;
+		case(2):
+			for(n=0,m=1;n<dz->ssampsread;n++,m+=2)
+				(dz->sampbuf[GRS_IBUF])[n] = (dz->sampbuf[GRS_SBUF])[m];
+			break;
+		case(BOTH_CHANNELS):
+			for(n=0,m=0,k=1;n<dz->ssampsread;n++,m+=2,k+=2)
+				(dz->sampbuf[GRS_IBUF])[n] = (float)(((dz->sampbuf[GRS_SBUF])[m] + (dz->sampbuf[GRS_SBUF])[k]) * 0.5f);
+			break;
+		}
+	} else {
+		if((exit_status = read_samps(dz->sampbuf[GRS_IBUF],dz))<0)
+			return(exit_status);
+	}
+	return(FINISHED);
+}
+
+#else
+
+int read_a_normal_buf_with_wraparound(dataptr dz)
+{
+	int exit_status;
+	long n,m,ibufcnt;
+	double sum;
+	int chans = dz->infile->channels;
+	memmove((char *)dz->sampbuf[GRS_BUF],(char *)(dz->sbufptr[GRS_BUF]),
+		dz->iparam[GRS_BUF_SMPXS] * sizeof(float));
+	if(dz->iparam[GRS_CHAN_TO_XTRACT]) {
+		dz->buflen *= chans;
+		if((exit_status = read_samps(dz->sampbuf[GRS_SBUF],dz))<0)
+			return(exit_status);
+		dz->buflen /= chans;
+		dz->ssampsread  /= chans;
+		switch(dz->iparam[GRS_CHAN_TO_XTRACT]) {
+		case(ALL_CHANNELS):
+			ibufcnt = 0;
+			for(n=0;n<dz->ssampsread;n++) {
+				sum = 0.0;
+				for(m=0;m<chans;m++)
+					sum += dz->sampbuf[GRS_SBUF][ibufcnt++];
+				dz->sampbuf[GRS_IBUF][n] = (float)(sum/(double)chans);
+			}
+			break;
+		default:
+			for(n=0,m=dz->iparam[GRS_CHAN_TO_XTRACT];n<dz->ssampsread;n++,m+=chans)
+				dz->sampbuf[GRS_IBUF][n] = dz->sampbuf[GRS_SBUF][m];
+			break;
+		}
+	} else {
+		if((exit_status = read_samps(dz->sampbuf[GRS_IBUF],dz))<0)
+			return(exit_status);
+	}
+	return(FINISHED);
+}
+
+#endif
+
+/****************************** RESET_GRANULA *******************************/
+
+#ifndef MULTICHAN
+
+int reset_granula(int resetskip,dataptr dz)
+{
+	unsigned long reset_size = dz->buflen + dz->iparam[GRS_BUF_SMPXS];
+
+	memset((char *)dz->sampbuf[GRS_BUF],0,reset_size * sizeof(float));
+	if(dz->iparam[GRS_CHAN_TO_XTRACT]) {
+		reset_size *= 2;
+    	memset((char *)dz->sampbuf[GRS_SBUF],0,reset_size * sizeof(float));
+	}
+	if(dz->iparam[GRS_CHAN_TO_XTRACT]) /* If we've converted from a multichannel file */
+		resetskip *= 2;
+	if(sndseekEx(dz->ifd[0],resetskip,0)<0) {
+		sprintf(errstr,"sndseek error: reset_granula()\n");
+		return(SYSTEM_ERROR);
+	}
+	return read_a_large_buf(dz);
+}
+
+#else
+
+int reset_granula(int resetskip,dataptr dz)
+{
+	unsigned long reset_size = dz->buflen + dz->iparam[GRS_BUF_SMPXS];
+
+	memset((char *)dz->sampbuf[GRS_BUF],0,reset_size * sizeof(float));
+	if(dz->iparam[GRS_CHAN_TO_XTRACT]) {
+		reset_size *= dz->infile->channels;
+    	memset((char *)dz->sampbuf[GRS_SBUF],0,reset_size * sizeof(float));
+	}
+	if(dz->iparam[GRS_CHAN_TO_XTRACT]) /* If we've converted from a multichannel file */
+		resetskip *= dz->infile->channels;
+	if(sndseekEx(dz->ifd[0],resetskip,0)<0) {
+		sprintf(errstr,"sndseek error: reset_granula()\n");
+		return(SYSTEM_ERROR);
+	}
+	return read_a_large_buf(dz);
+}
+
+#endif
+
+/************************** DO_SPLICES *****************************/
+
+void do_splices(int gsize_per_chan,int bspl,int espl,dataptr dz)
+{
+	if(dz->iparam[GRS_IS_BTAB] && (dz->iparam[GRS_BSPLICE] < gsize_per_chan/2))
+		do_btab_splice(dz);
+	else
+		do_bsplice(gsize_per_chan,dz,bspl);
+	if(dz->iparam[GRS_IS_ETAB] && (dz->iparam[GRS_ESPLICE] < gsize_per_chan/2))
+		do_etab_splice(gsize_per_chan,dz);
+	else
+		do_esplice(gsize_per_chan,dz,espl);
+}
+
+/************************** DO_BTAB_SPLICE ****************************/
+
+void do_btab_splice(dataptr dz)
+{
+	long n, k = dz->iparam[GRS_BSPLICE];
+	double *d;
+	float *gbufptr = dz->extrabuf[GRS_GBUF];   
+	if(k==0)
+		return;
+	d = dz->parray[GRS_BSPLICETAB];
+	for(n=0;n<k;n++) {
+		*gbufptr = (float)/*round*/(*gbufptr * *d); 
+		gbufptr++;
+		d++;
+	}
+}
+
+/************************** DO_BSPLICE ****************************
+ *
+ * rwd: changed to avoid f/p division, added exponential option
+ */
+void do_bsplice(int gsize_per_chan,dataptr dz,int bspl)
+{
+	double dif,val,lastval,length,newsum,lastsum,twodif;
+	long n, k = min(bspl,gsize_per_chan);
+	float *gbufptr = dz->extrabuf[GRS_GBUF];
+	if(k==0)
+		return;
+	val = 0.0;
+	length = (double)k;
+	if(!dz->vflag[GRS_EXPON]){
+		dif = 1.0/length;
+		lastval = dif;
+		*gbufptr++ = (float)val;
+		*gbufptr = (float)/*round*/(*gbufptr * lastval);
+		gbufptr++;   
+		for(n=2;n<k;n++) {
+			val = lastval + dif;
+			lastval = val;
+			*gbufptr = (float) /*round*/(*gbufptr * val);
+			gbufptr++;
+		}
+	} else {			/* fast quasi-exponential */
+		dif = 1.0/(length*length);
+		twodif = dif * 2.0;
+		lastsum = 0.0;
+		lastval = dif;
+		*gbufptr++ = (float)val;
+		*gbufptr = (float) /*round*/(*gbufptr * lastval);	
+		gbufptr++;
+		for(n=2;n<k;n++) {
+ 			newsum = lastsum + twodif;
+ 			val = lastval + newsum + dif;
+			*gbufptr = (float) /*round*/(*gbufptr * val);
+			gbufptr++;
+			lastval = val;
+			lastsum = newsum;
+		}
+	}
+}
+
+/************************** DO_ETAB_SPLICE ****************************/
+
+void do_etab_splice(int gsize_per_chan,dataptr dz)
+{
+	long n, k = (long)dz->iparam[GRS_ESPLICE];
+	double *d;
+	float *gbufptr = dz->extrabuf[GRS_GBUF] + gsize_per_chan - k;   
+	if(k==0)
+		return;
+	d = dz->parray[GRS_ESPLICETAB];
+	for(n=0;n<k;n++) {
+		*gbufptr = (float) /*round*/(*gbufptr * *d); 
+		gbufptr++;
+		d++;
+	}
+}
+
+/************************** DO_ESPLICE ****************************/
+/* rwd: changed to avoid f/p division, added exponential option */
+
+void do_esplice(int gsize_per_chan,dataptr dz,int espl)
+{
+	double dif,val,lastval,length,newsum,lastsum,twodif;
+	long n, k = min(espl,gsize_per_chan);
+	float *gbufptr = dz->extrabuf[GRS_GBUF] + gsize_per_chan;
+	if(k==0)
+		return;
+	val = 0.0;
+	length = (double) k;	
+	if(!dz->vflag[GRS_EXPON]) {
+		dif = 1.0/length;
+		lastsum = dif;
+		*--gbufptr = (float)val;
+		gbufptr--;
+		*gbufptr = (float) /*round*/(*gbufptr * lastsum);   
+		for(n=k-3;n>=0;n--) {
+			val = lastsum + dif;
+			lastsum = val;
+			gbufptr--;
+			*gbufptr = (float) /*round*/(*gbufptr * val);
+		}
+	} else {			/* fast quasi-exponential */ 
+		dif = 1.0/(length * length);
+		twodif = dif * 2.0;
+		lastsum = 0.0;
+		lastval = dif;
+		*--gbufptr = (float)val;
+		gbufptr--;
+		*gbufptr = (float) /*round*/(*gbufptr * lastval); 
+		for(n=k-3;n>=0;n--) {
+			newsum =lastsum + twodif;
+			val = lastval + newsum + dif;
+			gbufptr--;
+			*gbufptr = (float) /*round*/ (*gbufptr * val);
+			lastval = val;
+			lastsum = newsum;
+		}
+	}
+}
+
+/***************************** MAKE_GRAIN ***************************
+ * iicnt = RELATIVE read-pointer in input buffer.
+ */
+
+int make_grain(float *b,float **iiptr,float aamp,int gsize_per_chan,double *transpos,dataptr dz)
+{  						/* rwd: added interpolation option */
+	long n,real_gsize = gsize_per_chan;
+	double flcnt;
+	long iicnt;
+	double flcnt_frac;
+	float *s = *iiptr, *gbufptr = dz->extrabuf[GRS_GBUF];
+
+	if(aamp>=0) {
+		if(!dz->iparray[GRS_FLAGS][G_PITCH_FLAG]) {
+			if(real_gsize >= (long)dz->iparam[SAMPS_IN_INBUF])	  /* JUNE 1996 */
+				return(0);
+			for(n=0;n<real_gsize;n++)  /* COPY GRAIN TO GRAINBUF & RE-LEVEL ETC */
+				*gbufptr++ = (float)(*s++ * aamp);
+		} else {
+			iicnt = s - b;
+			*transpos = set_dvalue(dz->iparray[GRS_FLAGS][G_PITCH_FLAG],GRS_PITCH,GRS_HPITCH,GRS_PRANGE,dz);
+			*transpos = pow(2.0,*transpos);
+			if((int)(real_gsize * (*transpos))+1+iicnt >= dz->iparam[SAMPS_IN_INBUF])	  /* JUNE 1996 */
+				return(0);
+			flcnt = (double)iicnt;
+			if(!dz->vflag[GRS_NO_INTERP]){
+				flcnt_frac = flcnt - (double)iicnt;
+				for(n=0;n<real_gsize;n++) {
+					*gbufptr++ = interp_gval_with_amp(s,flcnt_frac,dz->iparam[GRS_INCHANS],aamp);
+					flcnt += *transpos;  
+					iicnt = (long)flcnt;	    	    
+					s = b + iicnt;
+					flcnt_frac = flcnt - (double) iicnt;	    	    
+				}
+			} else {  			/* do truncate as originally */
+				for(n=0;n<real_gsize;n++){
+					*gbufptr++ = (float)(*s * aamp);
+					flcnt += *transpos;
+					iicnt = round(flcnt);
+					s     = b + iicnt;
+				}
+			}	
+		}
+	} else {		/* NO CHANGE IN AMPLITUDE */
+		if(!dz->iparray[GRS_FLAGS][G_PITCH_FLAG]) {
+			if(real_gsize >= dz->iparam[SAMPS_IN_INBUF])	  /* JUNE 1996 */
+				return(0);
+			for(n=0;n<real_gsize;n++)
+				*gbufptr++ = *s++;
+		} else {
+			iicnt = s - b;
+			*transpos = set_dvalue(dz->iparray[GRS_FLAGS][G_PITCH_FLAG],GRS_PITCH,GRS_HPITCH,GRS_PRANGE,dz);
+			*transpos = pow(2.0,*transpos);
+			if((int)(real_gsize * (*transpos))+1+iicnt >= dz->iparam[SAMPS_IN_INBUF])	  /* JUNE 1996 */
+				return(0);
+			flcnt = (double)iicnt;
+			if(dz->vflag[GRS_NO_INTERP]){	  /* do truncate as originally */
+				for(n=0;n<gsize_per_chan;n++){
+					*gbufptr++ = *s;
+					flcnt += *transpos;
+					iicnt = round(flcnt);
+					s = b + iicnt;
+				}
+			} else {  			
+				flcnt_frac = flcnt - (double)iicnt;
+				for(n=0;n<real_gsize;n++) {
+					*gbufptr++ = interp_gval(s,flcnt_frac,dz->iparam[GRS_INCHANS]);
+					flcnt += *transpos;  
+					iicnt = (long)flcnt;	    	    
+					s = b + iicnt;
+					flcnt_frac = flcnt - (double)iicnt;	    	    
+				}
+			}	
+		}
+	}
+	*iiptr = s;
+	return(1);
+}
+
+/***************************** MAKE_STEREO_GRAIN ***************************
+ * iicnt = RELATIVE read-pointer in input buffer (starts at 0).
+ */
+
+int make_stereo_grain(float *b,float **iiptr,float aamp,int gsize_per_chan,double *transpos,dataptr dz)
+{
+	long n;
+	double flcnt;
+	long iicnt, real_gsize = gsize_per_chan * 2;
+	double flcnt_frac;
+	float *s = *iiptr, *gbufptr = dz->extrabuf[GRS_GBUF];
+	if(aamp>=0) {
+		if(!dz->iparray[GRS_FLAGS][G_PITCH_FLAG]) {
+			if(real_gsize >= dz->iparam[SAMPS_IN_INBUF])	  /* JUNE 1996 */
+				return(0);
+			for(n=0;n<real_gsize;n++)   /* COPY GRAIN TO GRAINBUF & RE-LEVEL ETC */
+				*gbufptr++ = (*s++ * aamp);
+		} else {			
+			iicnt = (s - b)/2;
+			*transpos = set_dvalue(dz->iparray[GRS_FLAGS][G_PITCH_FLAG],GRS_PITCH,GRS_HPITCH,GRS_PRANGE,dz);
+			*transpos = pow(2.0,*transpos);
+			if((((int)(gsize_per_chan * *transpos)+1) + iicnt) * 2 >= dz->iparam[SAMPS_IN_INBUF])	  /* JUNE 1996 */
+				return(0);
+			flcnt = (double)iicnt;
+			if(dz->vflag[GRS_NO_INTERP]){  /* do truncate as originally */
+				for(n=0;n<gsize_per_chan;n++){
+					*gbufptr++ = (*s * aamp);
+					s++;
+					*gbufptr++ = (*s * aamp);
+					flcnt += *transpos;
+					iicnt = round(flcnt);
+					s = b + (iicnt * 2);
+				}
+			} else {  			
+				flcnt_frac = flcnt - (double)iicnt;
+				for(n=0;n<gsize_per_chan;n++) {
+					*gbufptr++ = interp_gval_with_amp(s,flcnt_frac,dz->iparam[GRS_INCHANS],aamp);
+					s++;
+					*gbufptr++ = interp_gval_with_amp(s,flcnt_frac,dz->iparam[GRS_INCHANS],aamp);
+					flcnt += *transpos;  
+					iicnt = (long)flcnt;
+					s = b + (iicnt * 2);
+					flcnt_frac = flcnt - (double) iicnt;	    	    
+				}
+			}					   
+		}
+	} else {		/* NO CHANGE IN AMPLITUDE */
+		if(!dz->iparray[GRS_FLAGS][G_PITCH_FLAG]) {
+			if(real_gsize >= dz->iparam[SAMPS_IN_INBUF])	  /* JUNE 1996 */
+				return(0);
+			for(n=0;n<real_gsize;n++)
+				*gbufptr++ = *s++;
+		} else {
+			iicnt = (s - b)/2;
+			*transpos = set_dvalue(dz->iparray[GRS_FLAGS][G_PITCH_FLAG],GRS_PITCH,GRS_HPITCH,GRS_PRANGE,dz);
+			*transpos = pow(2.0,*transpos);
+			if((((int)(gsize_per_chan * *transpos)+1) + iicnt) * 2 >= dz->iparam[SAMPS_IN_INBUF])	  /* JUNE 1996 */
+				return(0);
+			flcnt = (double)iicnt;
+			if(!dz->vflag[GRS_NO_INTERP]){
+ 				flcnt_frac = flcnt - (double)iicnt;
+				for(n=0;n<gsize_per_chan;n++) {
+					*gbufptr++ = interp_gval(s,flcnt_frac,dz->iparam[GRS_INCHANS]);
+					s++;
+					*gbufptr++ = interp_gval(s,flcnt_frac,dz->iparam[GRS_INCHANS]);
+					flcnt += *transpos;  
+					iicnt = (long)flcnt;	    	    
+					s = b + (iicnt * 2);
+					flcnt_frac = flcnt - (double)iicnt;	    	    
+				}
+			} else {  			/* do truncate as originally */
+				for(n=0;n<gsize_per_chan;n++){
+					*gbufptr++ = *s++;
+					*gbufptr++ = *s;
+					flcnt += *transpos;
+					iicnt = round(flcnt);
+					s = b + (iicnt * 2);
+				}	
+			}
+		}
+	}
+	*iiptr = s;
+	return(1);
+}
+
+/***************************** MAKE_MULTICHAN_GRAIN ***************************
+ * iicnt = RELATIVE read-pointer in input buffer (starts at 0).
+ */
+
+int make_multichan_grain(float *b,float **iiptr,float aamp,int gsize_per_chan,double *transpos,dataptr dz)
+{
+	long n, k;
+	int chans = dz->iparam[GRS_INCHANS];		// GRS_INCHANS = no of chans in input grain, i.e. mono if its been mixed down to mono
+	double flcnt;								//	but = dz->infile->channels, if not
+	long iicnt, real_gsize = gsize_per_chan * chans;
+	double flcnt_frac;
+	float *s = *iiptr, *gbufptr = dz->extrabuf[GRS_GBUF];
+	if(aamp>=0) {
+		if(!dz->iparray[GRS_FLAGS][G_PITCH_FLAG]) {
+			if(real_gsize >= dz->iparam[SAMPS_IN_INBUF])	  /* JUNE 1996 */
+				return(0);
+			for(n=0;n<real_gsize;n++)   /* COPY GRAIN TO GRAINBUF & RE-LEVEL ETC */
+				*gbufptr++ = (*s++ * aamp);
+		} else {			
+			iicnt = (s - b)/chans;
+			*transpos = set_dvalue(dz->iparray[GRS_FLAGS][G_PITCH_FLAG],GRS_PITCH,GRS_HPITCH,GRS_PRANGE,dz);
+			*transpos = pow(2.0,*transpos);
+			if((((int)(gsize_per_chan * *transpos)+1) + iicnt) * chans >= dz->iparam[SAMPS_IN_INBUF])	  /* JUNE 1996 */
+				return(0);
+			flcnt = (double)iicnt;
+			if(dz->vflag[GRS_NO_INTERP]){  /* do truncate as originally */
+				for(n=0;n<gsize_per_chan;n++){
+					for(k = 0; k < chans;k++) {
+						*gbufptr++ = (*s * aamp);
+						s++;
+					}
+					flcnt += *transpos;
+					iicnt = round(flcnt);
+					s = b + (iicnt * chans);
+				}
+			} else {  			
+				flcnt_frac = flcnt - (double)iicnt;
+				for(n=0;n<gsize_per_chan;n++) {
+					for(k = 0; k < chans;k++) {
+						*gbufptr++ = interp_gval_with_amp(s,flcnt_frac,dz->iparam[GRS_INCHANS],aamp);
+						s++;
+					}
+					flcnt += *transpos;  
+					iicnt = (long)flcnt;
+					s = b + (iicnt * chans);
+					flcnt_frac = flcnt - (double) iicnt;	    	    
+				}
+			}					   
+		}
+	} else {		/* NO CHANGE IN AMPLITUDE */
+		if(!dz->iparray[GRS_FLAGS][G_PITCH_FLAG]) {
+			if(real_gsize >= dz->iparam[SAMPS_IN_INBUF])	  /* JUNE 1996 */
+				return(0);
+			for(n=0;n<real_gsize;n++)
+				*gbufptr++ = *s++;
+		} else {
+			iicnt = (s - b)/chans;
+			*transpos = set_dvalue(dz->iparray[GRS_FLAGS][G_PITCH_FLAG],GRS_PITCH,GRS_HPITCH,GRS_PRANGE,dz);
+			*transpos = pow(2.0,*transpos);
+			if((((int)(gsize_per_chan * *transpos)+1) + iicnt) * chans >= dz->iparam[SAMPS_IN_INBUF])	  /* JUNE 1996 */
+				return(0);
+			flcnt = (double)iicnt;
+			if(!dz->vflag[GRS_NO_INTERP]){
+ 				flcnt_frac = flcnt - (double)iicnt;
+				for(n=0;n<gsize_per_chan;n++) {
+					for(k=0;k < chans;k++) {
+						*gbufptr++ = interp_gval(s,flcnt_frac,dz->iparam[GRS_INCHANS]);
+						s++;
+					}
+					flcnt += *transpos;  
+					iicnt = (long)flcnt;	    	    
+					s = b + (iicnt * chans);
+					flcnt_frac = flcnt - (double)iicnt;	    	    
+				}
+			} else {  			/* do truncate as originally */
+				for(n=0;n<gsize_per_chan;n++){
+					for(k=0;k < chans;k++)
+						*gbufptr++ = *s++;
+					flcnt += *transpos;
+					iicnt = round(flcnt);
+					s = b + (iicnt * chans);
+				}	
+			}
+		}
+	}
+	*iiptr = s;
+	return(1);
+}
+
+/************************* WRITE_GRAIN ****************************/
+
+int write_grain(float **maxwrite,float **Fptr, float **FFptr,int gsize_per_chan,int *nctr,dataptr dz)
+{
+	int exit_status;
+	long n, to_doo, exess;
+	float *writend;
+	long real_gsize = gsize_per_chan * dz->iparam[GRS_INCHANS];
+	float *fptr = *Fptr, *ffptr = *FFptr;
+	float *gbufptr = dz->extrabuf[GRS_GBUF];
+	if((writend = (ffptr + real_gsize)) > *maxwrite)
+		*maxwrite = writend;
+	if(ffptr + real_gsize > dz->fptr[GRS_LTAILEND]) {
+		to_doo = dz->fptr[GRS_LTAILEND] - ffptr;
+		if((exess  = real_gsize - to_doo) >= dz->buflen) {
+ 			sprintf(errstr,"Array overflow:write_grain().\n");
+			return(PROGRAM_ERROR);
+		}
+		for(n = 0; n < to_doo; n++)
+			*ffptr++ += *gbufptr++;
+		if((exit_status = write_samps_granula(dz->buflen,nctr,dz))<0)
+			return(exit_status);
+		memmove((char *)dz->fptr[GRS_LBUF],(char *)dz->fptr[GRS_LBUFEND],
+			(size_t)dz->iparam[GRS_LBUF_SMPXS] * sizeof(float));
+		memset((char *)dz->fptr[GRS_LBUFMID],0,dz->iparam[GRS_LONGS_BUFLEN] * sizeof(float));
+		ffptr -= dz->iparam[GRS_LONGS_BUFLEN];	
+		fptr  -= dz->iparam[GRS_LONGS_BUFLEN];
+		*maxwrite -= dz->iparam[GRS_LONGS_BUFLEN];	/* APRIL 1996 */
+		for(n = 0; n < exess; n++)
+			*ffptr++ += *gbufptr++;
+		*Fptr  = fptr;
+		*FFptr = ffptr;
+		return(FINISHED);
+	}
+	for(n=0;n<real_gsize;n++)
+		*ffptr++ += *gbufptr++;
+	*Fptr  = fptr;
+	*FFptr = ffptr;
+	return(FINISHED);
+}
+
+/************************* WRITE_STEREO_GRAIN ****************************/
+
+int write_stereo_grain(double rpos,float **maxwrite,float **Fptr,float **FFptr,int gsize_per_chan,int *nctr,dataptr dz)
+{
+	int exit_status;
+	long   n, to_doo, exess;
+	long   /**writend,*/ real_gsize = gsize_per_chan * STEREO;
+	double lpos;
+	double adjust = dehole(rpos);
+	float  *writend, *fptr = *Fptr, *ffptr = *FFptr;
+	float  *gbufptr = dz->extrabuf[GRS_GBUF];
+	lpos  = (1.0 - rpos) * adjust;
+	rpos *= adjust;
+	if((writend = (ffptr + real_gsize)) > *maxwrite)
+		*maxwrite = writend;
+	if(ffptr + real_gsize >= dz->fptr[GRS_LTAILEND]) {
+		to_doo = dz->fptr[GRS_LTAILEND] - ffptr;
+		if((exess  = real_gsize - to_doo) >= dz->iparam[GRS_LONGS_BUFLEN]) {
+ 			sprintf(errstr,"Array overflow: write_stereo_grain()\n");
+			return(PROGRAM_ERROR);
+		}
+		to_doo /= 2;
+		for(n = 0; n < to_doo; n++) {
+			*ffptr++ += (float) (*gbufptr * lpos);
+			*ffptr++ += (float) (*gbufptr++ * rpos);
+		}
+		if((exit_status = write_samps_granula(dz->iparam[GRS_LONGS_BUFLEN],nctr,dz))<0)
+			return(exit_status);
+		memmove((char *)dz->fptr[GRS_LBUF],(char *)dz->fptr[GRS_LBUFEND],
+			(size_t)dz->iparam[GRS_LBUF_SMPXS] * sizeof(float));
+		memset((char *)dz->fptr[GRS_LBUFMID],0,dz->iparam[GRS_LONGS_BUFLEN] * sizeof(float));
+		ffptr -= dz->iparam[GRS_LONGS_BUFLEN];
+		fptr  -= dz->iparam[GRS_LONGS_BUFLEN];
+		*maxwrite -= dz->buflen; /* APR 1996 */
+		exess /= 2;
+		for(n = 0; n < exess; n++) {
+			*ffptr++ += /*round*/(float)(*gbufptr * lpos);
+			*ffptr++ += /*round*/(float)(*gbufptr++ * rpos);
+		}
+		*Fptr  = fptr;
+		*FFptr = ffptr;
+		return(FINISHED);
+	}
+	for(n=0;n<gsize_per_chan;n++) {
+		*ffptr++ += /*round*/(float)(*gbufptr   * lpos); /*rwd: was *gbuf */
+		*ffptr++ += /*round*/(float)(*gbufptr++ * rpos);
+	}
+	*Fptr  = fptr;
+	*FFptr = ffptr;
+	return(FINISHED);
+}
+
+/****************************** DEHOLE ************************/
+
+#define NONLIN  0.5
+#define DEVIATE 0.25
+
+double dehole(double pos)
+{
+	double comp = 1.0 - (fabs((pos * 2.0) - 1.0));	/* 1 */
+	comp = pow(comp,NONLIN);						/* 2 */
+	comp *= DEVIATE;								/* 3 */
+	comp += (1.0 - DEVIATE);						/* 4 */
+	return(comp);
+}
+
+
+/**************************** DO_SCATTER *****************************
+ *  scatter forward by fraction of randpart of 1 event separation.
+ *
+ *		  Possible scatter  |      	|-------------->|     
+ *		    Range selected  |		|------>      	|	
+ *	Random choice within range  |		|--->      	|	
+ */
+
+long do_scatter(int ostep_per_chan,dataptr dz)
+{
+	double scat  = dz->param[GRS_SCATTER] * drand48();
+	long   smpscat_per_chan = round((double)ostep_per_chan * scat);
+	return(smpscat_per_chan);
+}				
+
+/******************************** WRITE_SAMPS_GRANULA ****************************
+ *
+ * Normalise each buffer before writing to obuf, then to file.
+ * Save the normalisation factor in array normfact[].
+ */
+
+int write_samps_granula(long k,int *nctr,dataptr dz)
+{
+	int exit_status;
+	/*long*/double val = 0.0 /*0L, max_long = 0L*/;
+	long n;
+	double thisnorm = 1.0, max_double = 0.0;
+	float *s = NULL;
+	float  *l = dz->fptr[GRS_LBUF];
+	switch(dz->process) {
+	case(BRASSAGE):	s = dz->sampbuf[GRS_OBUF];	break;
+	case(SAUSAGE):	s = dz->sampbuf[SAUS_OBUF];	break;
+	}
+	for(n=0;n<k;n++) {
+		if((val = fabs(l[n])) > max_double)
+			max_double = val;
+	}
+	if(/*max_long*/max_double > F_MAXSAMP) {
+		thisnorm = (double)F_MAXSAMP/max_double;
+		for(n=0;n<k;n++)
+			s[n] =  /*round*/(float) ((double)(l[n]) * thisnorm);
+	} else {
+		for(n=0;n<k;n++)
+			s[n] =  l[n];
+	}
+	if((exit_status = write_samps(s,k,dz))<0)
+		return(exit_status);
+	(dz->parray[GRS_NORMFACT])[(*nctr)++] = thisnorm;
+	if(*nctr >= dz->iparam[GRS_ARRAYSIZE]) {
+		dz->iparam[GRS_ARRAYSIZE] += BIGARRAY;
+		if((dz->parray[GRS_NORMFACT] = 
+		(double *)realloc((char *)(dz->parray[GRS_NORMFACT]),dz->iparam[GRS_ARRAYSIZE]*sizeof(double)))==NULL) {
+			sprintf(errstr,"INSUFFICIENT MEMORY to reallocate normalisation array.\n");
+			return(MEMORY_ERROR);
+		}
+	}
+	return(FINISHED);
+}
+
+#ifndef MULTICHAN
+
+/************************** DO_STEREO_SPLICES *****************************/
+
+void do_stereo_splices(int gsize_per_chan,int bspl,int espl,dataptr dz)
+{
+	if(dz->iparam[GRS_IS_BTAB] && (dz->iparam[GRS_BSPLICE] < gsize_per_chan/2))
+		do_stereo_btab_splice(dz);
+	else
+		do_stereo_bsplice(gsize_per_chan,dz,bspl);
+	if(dz->iparam[GRS_IS_ETAB] && (dz->iparam[GRS_ESPLICE] < gsize_per_chan/2))
+		do_stereo_etab_splice(gsize_per_chan,dz);
+	else
+		do_stereo_esplice(gsize_per_chan,dz,espl);
+}
+
+/************************** DO_STEREO_BTAB_SPLICE ****************************/
+
+void do_stereo_btab_splice(dataptr dz)
+{
+	long n, k = dz->iparam[GRS_BSPLICE];
+	double *d;
+	float *gbufptr = dz->extrabuf[GRS_GBUF];   
+	if(k==0)
+		return;
+	d = dz->parray[GRS_BSPLICETAB];
+	for(n=0;n<k;n++) {
+		*gbufptr = (float)/*round*/(*gbufptr * *d); 
+		gbufptr++;
+		*gbufptr = (float)/*round*/(*gbufptr * *d); 
+		gbufptr++;
+		d++;
+	}
+}
+
+/************************** DO_STEREO_BSPLICE ****************************
+ *
+ * rwd: changed to avoid f/p division, added exponential option
+ */
+void do_stereo_bsplice(int gsize_per_chan,dataptr dz,int bspl)
+{
+	double dif,val,lastval,length,newsum,lastsum,twodif;
+	long n, k = min(bspl,gsize_per_chan);
+	float *gbufptr = dz->extrabuf[GRS_GBUF];
+	if(k==0)
+		return;
+	val = 0.0;
+	length = (double)k;
+	if(!dz->vflag[GRS_EXPON]){
+		dif = 1.0/length;
+		lastval = dif;
+		*gbufptr++ = (float)val;
+		*gbufptr++ = (float)val;
+		*gbufptr = (float)/*round*/(*gbufptr * lastval);
+		gbufptr++;   
+		*gbufptr = (float) /*round*/(*gbufptr * lastval);
+		gbufptr++;   
+		for(n=2;n<k;n++) {
+			val = lastval + dif;
+			lastval = val;
+			*gbufptr = (float) /*round*/(*gbufptr * val);
+			gbufptr++;
+			*gbufptr = (float) /*round*/(*gbufptr * val);
+			gbufptr++;
+		}
+	}  else {			/* fast quasi-exponential */
+		dif = 1.0/(length*length);
+		twodif = dif * 2.0;
+		lastsum = 0.0;
+		lastval = dif;
+		*gbufptr++ = (float)val;/* mca - round or truncate? */
+		*gbufptr++ = (float)val;/* mca - round or truncate? */
+		*gbufptr = (float) /*round*/(*gbufptr * lastval);	 /*** fixed MAY 1998 ***/
+		gbufptr++;
+		*gbufptr = (float) /*round*/(*gbufptr * lastval);	 /*** fixed MAY 1998 ***/
+		gbufptr++;
+		for(n=2;n<k;n++) {
+ 			newsum = lastsum + twodif;
+ 			val = lastval + newsum + dif;
+			*gbufptr = (float) /*round*/(*gbufptr * val);
+			gbufptr++;
+			*gbufptr = (float) /*round*/(*gbufptr * val);
+			gbufptr++;
+			lastval = val;
+			lastsum = newsum;
+		}
+	}
+}
+
+/************************** DO_STEREO_ETAB_SPLICE ****************************/
+
+void do_stereo_etab_splice(int gsize_per_chan,dataptr dz)
+{
+	long n, k = dz->iparam[GRS_ESPLICE];
+	double *d;
+	float *gbufptr = dz->extrabuf[GRS_GBUF] + ((gsize_per_chan - k) * 2);   
+	if(k==0)
+		return;
+	d = dz->parray[GRS_ESPLICETAB];
+	for(n=0;n<k;n++) {
+		*gbufptr = (float) /*round*/(*gbufptr * *d); 
+		gbufptr++;
+		*gbufptr = (float) /*round*/(*gbufptr * *d); 
+		gbufptr++;
+		d++;
+	}
+}
+
+/************************** DO_STEREO_ESPLICE ****************************/
+/* rwd: changed to avoid f/p division, added exponential option */
+
+void do_stereo_esplice(int gsize_per_chan,dataptr dz,int espl)
+{
+	double dif,val,lastval,length,newsum,lastsum,twodif;
+	long n, k = min(espl,gsize_per_chan);
+	long real_gsize = gsize_per_chan * 2;
+	float *gbufptr = dz->extrabuf[GRS_GBUF] + real_gsize;
+	if(k==0)
+		return;
+	val = 0.0;
+	length = (double) k;
+	if(!dz->vflag[GRS_EXPON]) {
+		dif = 1.0/length;
+		lastsum = dif;
+		gbufptr--;
+		*gbufptr = (float)val;
+		gbufptr--;
+		*gbufptr = (float)val;
+		gbufptr--;
+		*gbufptr = (float) /*round*/(*gbufptr * lastsum);   
+		gbufptr--;
+		*gbufptr = (float) /*round*/(*gbufptr * lastsum);   
+		for(n=k-3;n>=0;n--) {
+			val = lastsum + dif;
+			lastsum = val;
+			gbufptr--;
+			*gbufptr = (float) /*round*/(*gbufptr * val);
+			gbufptr--;
+			*gbufptr = (float) /*round*/(*gbufptr * val);
+		}
+	} else {			/* fast quasi-exponential */ 
+		dif = 1.0/(length * length);
+		twodif = dif * 2.0;
+		lastsum = 0.0;
+		lastval = dif;
+		gbufptr--;
+		*gbufptr = (float)val;
+		gbufptr--;
+		*gbufptr = (float)val;
+		gbufptr--;
+		*gbufptr = (float) /*round*/(*gbufptr * lastval);
+		gbufptr--;
+		*gbufptr = (float)/*round*/(*gbufptr * lastval);
+		for(n=k-3;n>=0;n--) {
+			newsum =lastsum + twodif;
+			val = lastval + newsum + dif;
+			gbufptr--;
+			*gbufptr = (float)/*round*/(*gbufptr * val);
+			gbufptr--;
+			*gbufptr = (float)/*round*/(*gbufptr * val);
+			lastval = val;
+			lastsum = newsum;
+		}
+	}
+}
+
+#else
+
+/************************** DO_MULTICHAN_SPLICES *****************************/
+
+void do_multichan_splices(int gsize_per_chan,int bspl,int espl,dataptr dz)
+{
+	if(dz->iparam[GRS_IS_BTAB] && (dz->iparam[GRS_BSPLICE] < gsize_per_chan/2))
+		do_multichan_btab_splice(dz);
+	else
+		do_multichan_bsplice(gsize_per_chan,dz,bspl);
+	if(dz->iparam[GRS_IS_ETAB] && (dz->iparam[GRS_ESPLICE] < gsize_per_chan/2))
+		do_multichan_etab_splice(gsize_per_chan,dz);
+	else
+		do_multichan_esplice(gsize_per_chan,dz,espl);
+}
+
+/************************** DO_MULTICHAN_BTAB_SPLICE ****************************/
+
+void do_multichan_btab_splice(dataptr dz)
+{
+	long n, j, k = dz->iparam[GRS_BSPLICE];
+	double *d;
+	float *gbufptr = dz->extrabuf[GRS_GBUF];   
+	
+	if(k==0)
+		return;
+	d = dz->parray[GRS_BSPLICETAB];
+	for(n=0;n<k;n++) {
+		for(j=0;j<dz->iparam[GRS_INCHANS];j++) {
+			*gbufptr = (float)/*round*/(*gbufptr * *d); 
+			gbufptr++;
+		}
+		d++;
+	}
+}
+
+/************************** DO_MULTICHAN_BSPLICE ****************************
+ *
+ * rwd: changed to avoid f/p division, added exponential option
+ */
+void do_multichan_bsplice(int gsize_per_chan,dataptr dz,int bspl)
+{
+	double dif,val,lastval,length,newsum,lastsum,twodif;
+	long n, j, k = min(bspl,gsize_per_chan);
+	float *gbufptr = dz->extrabuf[GRS_GBUF];
+	int chans = dz->iparam[GRS_INCHANS];
+	if(k==0)
+		return;
+	val = 0.0;
+	length = (double)k;
+	if(!dz->vflag[GRS_EXPON]){
+		dif = 1.0/length;
+		lastval = dif;
+		for(j= 0; j<chans;j++)
+			*gbufptr++ = (float)val;
+		for(j= 0; j<chans;j++) {
+			*gbufptr = (float)/*round*/(*gbufptr * lastval);
+			gbufptr++;   
+		}
+		for(n=2;n<k;n++) {
+			val = lastval + dif;
+			lastval = val;
+			for(j= 0; j<chans;j++) {
+				*gbufptr = (float) /*round*/(*gbufptr * val);
+				gbufptr++;
+			}
+		}
+	}  else {			/* fast quasi-exponential */
+		dif = 1.0/(length*length);
+		twodif = dif * 2.0;
+		lastsum = 0.0;
+		lastval = dif;
+		for(j=0;j<chans;j++)
+			*gbufptr++ = (float)val;/* mca - round or truncate? */
+		for(j=0;j<chans;j++) {
+			*gbufptr = (float) /*round*/(*gbufptr * lastval);	 /*** fixed MAY 1998 ***/
+			gbufptr++;
+		}
+		for(n=2;n<k;n++) {
+ 			newsum = lastsum + twodif;
+ 			val = lastval + newsum + dif;
+			for(j=0;j<chans;j++) {
+				*gbufptr = (float) /*round*/(*gbufptr * val);
+				gbufptr++;
+			}
+			lastval = val;
+			lastsum = newsum;
+		}
+	}
+}
+
+/************************** DO_MULTICHAN_ETAB_SPLICE ****************************/
+
+void do_multichan_etab_splice(int gsize_per_chan,dataptr dz)
+{
+	long n, j, k = dz->iparam[GRS_ESPLICE];
+	double *d;
+	int chans = dz->iparam[GRS_INCHANS];
+	float *gbufptr = dz->extrabuf[GRS_GBUF] + ((gsize_per_chan - k) * chans);   
+	if(k==0)
+		return;
+	d = dz->parray[GRS_ESPLICETAB];
+	for(n=0;n<k;n++) {
+		for(j=0;j<chans;j++) {
+			*gbufptr = (float) /*round*/(*gbufptr * *d); 
+			gbufptr++;
+		}
+		d++;
+	}
+}
+
+/************************** DO_MULTICHAN_ESPLICE ****************************/
+/* rwd: changed to avoid f/p division, added exponential option */
+
+void do_multichan_esplice(int gsize_per_chan,dataptr dz,int espl)
+{
+	double dif,val,lastval,length,newsum,lastsum,twodif;
+	long n, j, k = min(espl,gsize_per_chan);
+	int chans = dz->iparam[GRS_INCHANS];
+	long real_gsize = gsize_per_chan * chans;
+	float *gbufptr = dz->extrabuf[GRS_GBUF] + real_gsize;
+	if(k==0)
+		return;
+	val = 0.0;
+	length = (double) k;
+	if(!dz->vflag[GRS_EXPON]) {
+		dif = 1.0/length;
+		lastsum = dif;
+		for(j=0;j<chans;j++) {
+			gbufptr--;
+			*gbufptr = (float)val;
+		}
+		for(j=0;j<chans;j++) {
+			gbufptr--;
+			*gbufptr = (float) /*round*/(*gbufptr * lastsum);   
+		}
+		for(n=k-3;n>=0;n--) {
+			val = lastsum + dif;
+			lastsum = val;
+			for(j=0;j<chans;j++) {
+				gbufptr--;
+				*gbufptr = (float) /*round*/(*gbufptr * val);
+			}
+		}
+	} else {			/* fast quasi-exponential */ 
+		dif = 1.0/(length * length);
+		twodif = dif * 2.0;
+		lastsum = 0.0;
+		lastval = dif;
+		for(j=0;j<chans;j++) {
+			gbufptr--;
+			*gbufptr = (float)val;
+		}
+		for(j=0;j<chans;j++) {
+			gbufptr--;
+			*gbufptr = (float) /*round*/(*gbufptr * lastval);
+		}
+		for(n=k-3;n>=0;n--) {
+			newsum =lastsum + twodif;
+			val = lastval + newsum + dif;
+			for(j=0;j<chans;j++) {
+				gbufptr--;
+				*gbufptr = (float)/*round*/(*gbufptr * val);
+			}
+			lastval = val;
+			lastsum = newsum;
+		}
+	}
+}
+
+#endif
+
+/************************** INTERP_GVAL_WITH_AMP ****************************/
+
+float interp_gval_with_amp(float *s,double flcnt_frac,int chans,float ampp)
+{
+	/*long*/float tthis = /*(long)*/ *s * ampp;
+	/*long*/float next = /*(long)*/ *(s+chans) * ampp;
+	//long val  = this + round((double)(next-this) * flcnt_frac);
+	//return(short)((val+TWO_POW_14) >> 15);
+	return (float) (tthis + ((next-tthis) * flcnt_frac));
+}
+
+/************************** INTERP_GVAL ****************************/
+
+float interp_gval(float *s,double flcnt_frac,int chans)
+{
+	float tthis = *s;
+	float next = *(s+chans);
+	float val  = (float)(tthis + /*round*/((double)(next-tthis) * flcnt_frac));
+	return(val);
+}
+	
+/*************************** SET_RANGE ******************************/
+
+int set_range(int absiicnt,dataptr dz)
+{
+	long val;
+	val = min(dz->iparam[GRS_SRCHRANGE],absiicnt);
+	val = round((double)val * drand48());
+	return(val);
+}
+
+/*************************** SET_OUTSTEP ******************************/
+
+int set_outstep(int gsize_per_chan,dataptr dz)		
+{							
+	double dens;
+	int val = 0;
+	/* TW 4 :2002 */
+	switch(dz->process){
+	case(BRASSAGE):
+		switch(dz->mode) {
+		case(GRS_BRASSAGE):
+		case(GRS_FULL_MONTY):
+		case(GRS_REVERB):
+		case(GRS_GRANULATE):
+			dens = set_dvalue(dz->iparray[GRS_FLAGS][G_DENSITY_FLAG],GRS_DENSITY,GRS_HDENSITY,GRS_DRANGE,dz);
+			val  = round((double)gsize_per_chan/(double)dens);
+			break;
+		default:
+			val  = round((double)gsize_per_chan/(double)GRS_DEFAULT_DENSITY);
+		}
+		break;
+
+	case(SAUSAGE):
+		dens = set_dvalue(dz->iparray[GRS_FLAGS][G_DENSITY_FLAG],GRS_DENSITY,GRS_HDENSITY,GRS_DRANGE,dz);
+		val  = round((double)gsize_per_chan/(double)dens);
+		break;
+	}
+	return(val);
+}
+
+/*************************** SET_INSTEP ******************************/
+
+int set_instep(int ostep_per_chan,dataptr dz)	
+{												/* rwd: added range error traps */
+	double velocity;
+	int istep_per_chan = 0;
+	switch(dz->process) {		 /* TW 4:2002 */
+    case(BRASSAGE):
+		switch(dz->mode) {
+		case(GRS_BRASSAGE):
+		case(GRS_FULL_MONTY):
+		case(GRS_TIMESTRETCH):
+			velocity = set_dvalue(dz->iparray[GRS_FLAGS][G_VELOCITY_FLAG],GRS_VELOCITY,GRS_HVELOCITY,GRS_VRANGE,dz);
+			istep_per_chan =  round(velocity * (double)ostep_per_chan);
+			break;
+		default:
+			istep_per_chan =  ostep_per_chan;	/* default velocity is 1.0 */
+			break;
+		}
+		break;
+	case(SAUSAGE):
+		velocity = set_dvalue(dz->iparray[GRS_FLAGS][G_VELOCITY_FLAG],GRS_VELOCITY,GRS_HVELOCITY,GRS_VRANGE,dz);
+		istep_per_chan =  round(velocity * (double)ostep_per_chan);
+		break;
+	}
+	return(istep_per_chan);
+}
+
+/*************************** SET_IVALUE ******************************/
+
+int set_ivalue(int flag,int paramno,int hparamno,int rangeno,dataptr dz)
+{
+	int val = 0;
+	switch(flag) {
+	case(NOT_SET):
+	case(FIXED):
+	case(VARIABLE):
+		val = dz->iparam[paramno];
+		break;
+	case(RANGE_VLO):
+	case(RANGE_VHI):
+	case(RANGE_VHILO):
+		dz->iparam[rangeno] = dz->iparam[hparamno] - dz->iparam[paramno];
+		/* fall thro */
+	case(RANGED):
+		val = round((drand48() * dz->iparam[rangeno]) + (double)dz->iparam[paramno]);
+		break;
+	}    
+	return(val);
+}
+
+/*************************** SET_DVALUE ******************************/
+
+double set_dvalue(int flag,int paramno,int hparamno,int rangeno,dataptr dz)
+{
+	double val = 0;
+	switch(flag) {
+	case(NOT_SET):
+	case(FIXED):
+	case(VARIABLE):
+		val = dz->param[paramno];
+		break;
+	case(RANGE_VLO):
+	case(RANGE_VHI):
+	case(RANGE_VHILO):
+		dz->param[rangeno] = dz->param[hparamno] - dz->param[paramno];
+		/* fall thro */
+	case(RANGED):
+		val = (drand48() * dz->param[rangeno]) + dz->param[paramno];
+		break;
+	}    
+	return(val);
+}
+
+/******************************* READ_SAMPS_SAUSAGE *******************************/
+
+int read_samps_sausage(int firsttime,dataptr dz)
+{
+	int exit_status, n;
+	int samps_read = INT_MAX;	/* i.e. larger than possible */
+	for(n=0;n<dz->infilecnt;n++) {
+		if(firsttime) {
+			if((exit_status = read_a_specific_large_buf(n,dz))<0)
+				return(exit_status);
+			samps_read = min(samps_read,dz->ssampsread);
+		} else {
+			if((exit_status = read_a_specific_normal_buf_with_wraparound(n,dz))<0)
+				return(exit_status);
+			samps_read = min(samps_read,dz->ssampsread);
+		}
+	}
+	if(samps_read==INT_MAX) {           // RWD 06-2019 was LONG_MAX
+		sprintf(errstr,"Problem reading sound buffers.\n");
+		return(PROGRAM_ERROR);
+	}
+	if(firsttime)
+		dz->iparam[SAMPS_IN_INBUF] = dz->ssampsread;
+	else
+		dz->iparam[SAMPS_IN_INBUF] = dz->ssampsread + dz->iparam[GRS_BUF_SMPXS];
+	return(FINISHED);
+}
+
+/*************************** READ_A_SPECIFIC_LARGE_BUF ******************************/
+
+#ifndef MULTICHAN
+
+int read_a_specific_large_buf(int j,dataptr dz)
+{
+	long bigbufsize = dz->buflen;	   /* RWD odd one, this... */
+	long n, m, k, samps_read;
+	int bufno = SAUS_BUF(j);
+	bigbufsize += dz->iparam[GRS_BUF_SMPXS];
+	if(dz->iparam[GRS_CHAN_TO_XTRACT]) {
+		bigbufsize *= 2;
+		if((samps_read = fgetfbufEx(dz->sampbuf[SAUS_SBUF],bigbufsize,dz->ifd[j],0))<0) {
+			sprintf(errstr,"Failed to read samps from file %d.\n",j+1);
+			return(SYSTEM_ERROR);
+		}
+		dz->ssampsread = samps_read;
+		bigbufsize /= 2;			   /* RWD still in samps...buflen + smpxs */
+		dz->ssampsread /= 2;
+		switch(dz->iparam[GRS_CHAN_TO_XTRACT]) {
+		case(1):
+			for(n=0,m=0;n<dz->ssampsread;n++,m+=2)
+				(dz->sampbuf[bufno])[n] = (dz->sampbuf[SAUS_SBUF])[m];
+			break;
+		case(2):
+			for(n=0,m=1;n<dz->ssampsread;n++,m+=2)
+				(dz->sampbuf[bufno])[n] = (dz->sampbuf[SAUS_SBUF])[m];
+			break;
+		case(BOTH_CHANNELS):
+			for(n=0,m=0,k=1;n<dz->ssampsread;n++,m+=2,k+=2)
+				(dz->sampbuf[bufno])[n] = (float)(((dz->sampbuf[SAUS_SBUF])[m] + (dz->sampbuf[SAUS_SBUF])[k])* 0.5f);
+			break;
+		}
+	} else {
+		if((samps_read = fgetfbufEx(dz->sampbuf[bufno],bigbufsize,dz->ifd[j],0))<0) {
+			sprintf(errstr,"Failed to read samps from file %d.\n",j+1);
+			return(SYSTEM_ERROR);
+		}
+		dz->ssampsread = samps_read;
+	}
+	/* dz->bigbufsize -= dz->iparam[GRS_BUF_XS]; */ /* leaves dz->buflen unchanged, which is fine */
+	return(FINISHED);
+}
+
+#else
+
+int read_a_specific_large_buf(int j,dataptr dz)
+{
+	long bigbufsize = dz->buflen;	   /* RWD odd one, this... */
+	long n, m, samps_read, ibufcnt;
+	int bufno = SAUS_BUF(j), chans = dz->infile->channels;
+	double sum;
+	bigbufsize += dz->iparam[GRS_BUF_SMPXS];
+	if(dz->iparam[GRS_CHAN_TO_XTRACT]) {
+		bigbufsize *= chans;
+		if((samps_read = fgetfbufEx(dz->sampbuf[SAUS_SBUF],bigbufsize,dz->ifd[j],0))<0) {
+			sprintf(errstr,"Failed to read samps from file %d.\n",j+1);
+			return(SYSTEM_ERROR);
+		}
+		dz->ssampsread = samps_read;
+		bigbufsize /= chans;			   /* RWD still in samps...buflen + smpxs */
+		dz->ssampsread /= chans;
+		switch(dz->iparam[GRS_CHAN_TO_XTRACT]) {
+		case(ALL_CHANNELS):
+			ibufcnt = 0;
+			for(n=0;n<dz->ssampsread;n++) {
+				sum = 0.0;
+				for(m=0;m<chans;m++)
+					sum += dz->sampbuf[GRS_SBUF][ibufcnt++];
+				dz->sampbuf[bufno][n] = (float)(sum/(double)chans);
+			}
+			break;
+		default:
+			for(n=0,m=dz->iparam[GRS_CHAN_TO_XTRACT];n<dz->ssampsread;n++,m+=chans)
+				dz->sampbuf[bufno][n] = dz->sampbuf[GRS_SBUF][m];
+			break;
+		}
+	} else {
+		if((samps_read = fgetfbufEx(dz->sampbuf[bufno],bigbufsize,dz->ifd[j],0))<0) {
+			sprintf(errstr,"Failed to read samps from file %d.\n",j+1);
+			return(SYSTEM_ERROR);
+		}
+		dz->ssampsread = samps_read;
+	}
+	return(FINISHED);
+}
+
+#endif
+
+/*************************** READ_A_SPECIFIC_NORMAL_BUF_WITH_WRAPAROUND ******************************/
+
+#ifndef MULTICHAN
+
+int read_a_specific_normal_buf_with_wraparound(int j,dataptr dz)
+{
+	long bigbufsize = dz->buflen;
+	long n,m,k,samps_read;
+	int bufno  = SAUS_BUF(j);
+	int ibufno = SAUS_IBUF(j);
+	memmove((char *)dz->sampbuf[bufno],(char *)(dz->sbufptr[bufno]),
+		dz->iparam[GRS_BUF_SMPXS] * sizeof(float));
+	if(dz->iparam[GRS_CHAN_TO_XTRACT]) {
+		bigbufsize *= 2;
+		if((samps_read = fgetfbufEx(dz->sampbuf[SAUS_SBUF],bigbufsize,dz->ifd[j],0))<0) {
+			sprintf(errstr,"Failed to read from file %d.\n",j+1);
+			return(SYSTEM_ERROR);
+		}
+		dz->ssampsread = samps_read;
+		bigbufsize /= 2;
+		dz->ssampsread /= 2;
+		switch(dz->iparam[GRS_CHAN_TO_XTRACT]) {
+		case(1):
+			for(n=0,m=0;n<dz->ssampsread;n++,m+=2)
+				(dz->sampbuf[ibufno])[n] = (dz->sampbuf[GRS_SBUF])[m];
+			break;
+		case(2):
+			for(n=0,m=1;n<dz->ssampsread;n++,m+=2)
+				(dz->sampbuf[ibufno])[n] = (dz->sampbuf[GRS_SBUF])[m];
+			break;
+		case(BOTH_CHANNELS):
+			for(n=0,m=0,k=1;n<dz->ssampsread;n++,m+=2,k+=2)
+				(dz->sampbuf[ibufno])[n] = (float)(((dz->sampbuf[GRS_SBUF])[m] + (dz->sampbuf[GRS_SBUF])[k])* 0.5f);
+			break;
+		}
+	} else {
+		if((samps_read = fgetfbufEx(dz->sampbuf[ibufno],bigbufsize,dz->ifd[j],0))<0) {
+			sprintf(errstr,"Failed to read from file %d.\n",j+1);
+			return(SYSTEM_ERROR);
+		}
+		dz->ssampsread = samps_read;
+	}
+	return(FINISHED);
+}
+
+#else
+
+int read_a_specific_normal_buf_with_wraparound(int j,dataptr dz)
+{
+	long bigbufsize = dz->buflen;
+	long n,m,samps_read, ibufcnt;
+	double sum;
+	int bufno  = SAUS_BUF(j);
+	int ibufno = SAUS_IBUF(j), chans = dz->infile->channels;
+	memmove((char *)dz->sampbuf[bufno],(char *)(dz->sbufptr[bufno]),dz->iparam[GRS_BUF_SMPXS] * sizeof(float));
+	if(dz->iparam[GRS_CHAN_TO_XTRACT]) {
+		bigbufsize *= chans;
+		if((samps_read = fgetfbufEx(dz->sampbuf[SAUS_SBUF],bigbufsize,dz->ifd[j],0))<0) {
+			sprintf(errstr,"Failed to read from file %d.\n",j+1);
+			return(SYSTEM_ERROR);
+		}
+		dz->ssampsread = samps_read;
+		bigbufsize /= chans;
+		dz->ssampsread /= chans;
+		switch(dz->iparam[GRS_CHAN_TO_XTRACT]) {
+		case(ALL_CHANNELS):
+			ibufcnt = 0;
+			for(n=0;n<dz->ssampsread;n++) {
+				sum = 0.0;
+				for(m=0;m<chans;m++)
+					sum += dz->sampbuf[GRS_SBUF][ibufcnt++];
+				dz->sampbuf[ibufno][n] = (float)(sum/(double)chans);
+			}
+			break;
+		default:
+			for(n=0,m=dz->iparam[GRS_CHAN_TO_XTRACT];n<dz->ssampsread;n++,m+=chans)
+				dz->sampbuf[ibufno][n] = dz->sampbuf[GRS_SBUF][m];
+			break;
+		}
+	} else {
+		if((samps_read = fgetfbufEx(dz->sampbuf[ibufno],bigbufsize,dz->ifd[j],0))<0) {
+			sprintf(errstr,"Failed to read from file %d.\n",j+1);
+			return(SYSTEM_ERROR);
+		}
+		dz->ssampsread = samps_read;
+	}
+	return(FINISHED);
+}
+
+#endif
+
+/*************************** BAKTRAK_SAUSAGE ******************************
+ *
+ *     <------------ baktrak(b) ---------------->
+ *
+ *     <--(b-x)-->
+ *		  		  <------------ x -------------->
+ *		 		 |-------- current bufer --------|
+ *
+ *     |-------- new buffer --------|
+ *      <------------x------------->
+ *				
+ */
+
+#ifndef MULTICHAN
+
+int baktrak_sausage(int thissnd,long samptotal,int absiicnt_per_chan,float **iiptr,dataptr dz)
+{
+	int  exit_status;
+	long bktrk, new_position;
+	unsigned long reset_size = dz->buflen + dz->iparam[GRS_BUF_SMPXS];
+//TW I agree, this is FINE!!, and, with sndseekEx, algo is more efficient
+//	whenever the search-range is relatively small (and equally efficient otherwise)
+	bktrk = samptotal - (absiicnt_per_chan * dz->iparam[GRS_INCHANS]);
+	*iiptr      = dz->sampbuf[SAUS_BUF(thissnd)];
+
+	if((new_position = samptotal - bktrk)<0) {
+		fprintf(stdout,"WARNING: Non-fatal program error:\nRange arithmetic problem - 2, in baktraking.\n");
+		fflush(stdout);
+		new_position = 0;
+		*iiptr = dz->sampbuf[SAUS_BUF(thissnd)];
+	}
+    if(dz->iparam[GRS_CHAN_TO_XTRACT])   /* IF we've converted from STEREO file */
+		new_position *= 2;
+	if(sndseekEx(dz->ifd[thissnd],new_position,0)<0) {
+		sprintf(errstr,"sndseek error: baktrak_sausage()\n");
+		return(SYSTEM_ERROR);
+	}
+	memset((char *)dz->sampbuf[SAUS_BUF(thissnd)],0,reset_size * sizeof(float));
+    if(dz->iparam[GRS_CHAN_TO_XTRACT]) {
+		reset_size *= 2;
+    	memset((char *)dz->sampbuf[SAUS_SBUF],0,reset_size * sizeof(float));
+	}
+	if((exit_status = read_a_specific_large_buf(thissnd,dz))<0)
+		return(exit_status);
+	dz->iparam[SAMPS_IN_INBUF] = dz->ssampsread;
+	return(FINISHED);
+}
+
+#else
+
+int baktrak_sausage(int thissnd,long samptotal,int absiicnt_per_chan,float **iiptr,dataptr dz)
+{
+	int  exit_status,  chans = dz->infile->channels;
+	long bktrk, new_position;
+	unsigned long reset_size = dz->buflen + dz->iparam[GRS_BUF_SMPXS];
+	bktrk = samptotal - (absiicnt_per_chan * dz->iparam[GRS_INCHANS]);
+	*iiptr      = dz->sampbuf[SAUS_BUF(thissnd)];
+
+	if((new_position = samptotal - bktrk)<0) {
+		fprintf(stdout,"WARNING: Non-fatal program error:\nRange arithmetic problem - 2, in baktraking.\n");
+		fflush(stdout);
+		new_position = 0;
+		*iiptr = dz->sampbuf[SAUS_BUF(thissnd)];
+	}
+    if(dz->iparam[GRS_CHAN_TO_XTRACT])   /* IF we've converted from MULTICHAN file */
+		new_position *= chans;
+	if(sndseekEx(dz->ifd[thissnd],new_position,0)<0) {
+		sprintf(errstr,"sndseek error: baktrak_sausage()\n");
+		return(SYSTEM_ERROR);
+	}
+	memset((char *)dz->sampbuf[SAUS_BUF(thissnd)],0,reset_size * sizeof(float));
+    if(dz->iparam[GRS_CHAN_TO_XTRACT]) {
+		reset_size *= chans;
+    	memset((char *)dz->sampbuf[SAUS_SBUF],0,reset_size * sizeof(float));
+	}
+	if((exit_status = read_a_specific_large_buf(thissnd,dz))<0)
+		return(exit_status);
+	dz->iparam[SAMPS_IN_INBUF] = dz->ssampsread;
+	return(FINISHED);
+}
+
+#endif
+
+/****************************** RESET_SAUSAGE *******************************/
+
+#ifndef MULTICHAN
+
+int reset_sausage(int thissnd,int resetskip,dataptr dz)
+{
+	int exit_status;
+	unsigned long reset_size = dz->buflen + dz->iparam[GRS_BUF_SMPXS];
+
+	memset((char *)dz->sampbuf[SAUS_BUF(thissnd)],0,reset_size * sizeof(float));
+	if(dz->iparam[GRS_CHAN_TO_XTRACT]) {
+		reset_size *= 2;
+    	memset((char *)dz->sampbuf[SAUS_SBUF],0,reset_size * sizeof(float));
+	}
+	if(dz->iparam[GRS_CHAN_TO_XTRACT]) /* If we've converted from a stereo file */
+		resetskip *= 2;
+	if(sndseekEx(dz->ifd[thissnd],resetskip,0)<0) {
+		sprintf(errstr,"sndseek error: reset_sausage()\n");
+		return(SYSTEM_ERROR);
+	}
+	if((exit_status = read_a_specific_large_buf(thissnd,dz))<0)
+		return(exit_status);
+	dz->iparam[SAMPS_IN_INBUF] = dz->ssampsread;  
+	return(FINISHED);
+}
+
+#else
+
+int reset_sausage(int thissnd,int resetskip,dataptr dz)
+{
+	int exit_status, chans = dz->infile->channels;
+	unsigned long reset_size = dz->buflen + dz->iparam[GRS_BUF_SMPXS];
+
+	memset((char *)dz->sampbuf[SAUS_BUF(thissnd)],0,reset_size * sizeof(float));
+	if(dz->iparam[GRS_CHAN_TO_XTRACT]) {
+		reset_size *= chans;
+    	memset((char *)dz->sampbuf[SAUS_SBUF],0,reset_size * sizeof(float));
+	}
+	if(dz->iparam[GRS_CHAN_TO_XTRACT]) /* If we've converted from a stereo file */
+		resetskip *= chans;
+	if(sndseekEx(dz->ifd[thissnd],resetskip,0)<0) {
+		sprintf(errstr,"sndseek error: reset_sausage()\n");
+		return(SYSTEM_ERROR);
+	}
+	if((exit_status = read_a_specific_large_buf(thissnd,dz))<0)
+		return(exit_status);
+	dz->iparam[SAMPS_IN_INBUF] = dz->ssampsread;  
+	return(FINISHED);
+}
+
+#endif
+
+/****************************** GET_NEXT_INSND *******************************/
+
+int get_next_insnd(dataptr dz)
+{
+	if(dz->itemcnt <= 0) {
+		perm_sausage(dz->infilecnt,dz);
+		dz->itemcnt = dz->infilecnt;
+	}
+	dz->itemcnt--;
+	return(dz->iparray[SAUS_PERM][dz->itemcnt]);
+}
+
+/****************************** PERM_SAUSAGE *******************************/
+
+void perm_sausage(int cnt,dataptr dz)
+{
+	int n, t;
+	for(n=0;n<cnt;n++) {
+		t = (int)(drand48() * (double)(n+1));	 /* TRUNCATE */
+		if(t==n)
+			prefix(n,cnt-1,dz);
+		else
+			insert(n,t,cnt-1,dz);
+	}
+}
+
+/****************************** INSERT ****************************/
+
+void insert(int n,int t,int cnt_less_one,dataptr dz)
+{   
+	shuflup(t+1,cnt_less_one,dz);
+	dz->iparray[SAUS_PERM][t+1] = n;
+}
+
+/****************************** PREFIX ****************************/
+
+void prefix(int n,int cnt_less_one,dataptr dz)
+{   
+	shuflup(0,cnt_less_one,dz);
+	dz->iparray[SAUS_PERM][0] = n;
+}
+
+/****************************** SHUFLUP ****************************/
+
+void shuflup(int k,int cnt_less_one,dataptr dz)
+{   
+	int n;
+	for(n = cnt_less_one; n > k; n--)
+		dz->iparray[SAUS_PERM][n] = dz->iparray[SAUS_PERM][n-1];
+}
+
+/****************************** SAUSAGE_PREPROCESS ****************************/
+
+int sausage_preprocess(dataptr dz)
+{
+	if((dz->iparray[SAUS_PERM] = (int *)malloc(dz->infilecnt * sizeof(int)))==NULL) {
+		sprintf(errstr,"INSUFFICIENT MEMORY for permutation array for sausage.\n");
+		return(MEMORY_ERROR);
+	}
+	dz->iparray[SAUS_PERM][0] = dz->infilecnt + 1;	/* impossible value to initialise perm */
+
+	return create_sized_outfile(dz->outfilename,dz);
+
+
+
+	/*return(FINISHED);*/
+}
+
+/*************************** CREATE_SAUSAGE_BUFFERS **************************/
+
+#ifndef MULTICHAN
+
+int create_sausage_buffers(dataptr dz)
+{	
+	long standard_block = (long)Malloc(-1);
+	long this_bloksize;
+	int   exit_status, n;
+	int   convert_to_stereo = FALSE, overall_size, bufdivisor = 0;
+	float *tailend;
+	long  stereo_buflen = 0, stereo_bufxs = 0, outbuflen;
+//TW All buffers are in floats, so this not needed
+//	int   lfactor = sizeof(long)/sizeof(float), n;
+	if(dz->iparray[GRS_FLAGS][G_SPACE_FLAG])
+		convert_to_stereo = TRUE;							
+	if((dz->extrabuf[GRS_GBUF] = (float *)malloc(dz->iparam[GRS_GLBUF_SMPXS] * sizeof(float)))==NULL) {
+		sprintf(errstr,"INSUFFICIENT MEMORY to create grain buffer.\n");	 /* GRAIN BUFFER */
+		return(MEMORY_ERROR);
+	}
+				/* CALCULATE NUMBER OF BUFFER CHUNKS REQUIRED : bufdivisor */
+
+	if(dz->iparam[GRS_CHANNELS]>0)
+		bufdivisor += 2;							/* 2 for stereo-infile, before reducing to mono */
+//TW All buffers are in floats
+//	bufdivisor += dz->infilecnt + 1 + lfactor;		/* infilecnt IN mono, 1 OUT,   1 long OUT  */
+	bufdivisor += dz->infilecnt + 2;				/* infilecnt IN mono, 1 OUT,   1 LBUF OUT  */
+	if(convert_to_stereo)
+//TW All buffers are in floats
+//		bufdivisor += 1 + lfactor;					/*                    2nd OUT, 2nd long OUT */
+		bufdivisor += 2;							/*                    2nd OUT, 2nd LBUF OUT */
+
+
+	
+	this_bloksize = standard_block;
+	for(;;) {
+		if((exit_status = grab_an_appropriate_block_of_sausage_memory(&this_bloksize,standard_block,bufdivisor,dz))<0)
+			return(exit_status);
+
+					/* CALCULATE AND ALLOCATE TOTAL MEMORY REQUIRED : overall_size */
+	
+		overall_size = (dz->buflen * bufdivisor) + (dz->iparam[GRS_BUF_SMPXS] * dz->infilecnt) + dz->iparam[GRS_LBUF_SMPXS];
+		if(dz->iparam[GRS_CHANNELS])				
+			overall_size += 2 * dz->iparam[GRS_BUF_SMPXS];					/* IF stereo, also allow for bufxs in stereo inbuf */
+
+//TW	if(overall_size<0) 
+		if(overall_size * sizeof(float)<0) {
+			sprintf(errstr,"INSUFFICIENT MEMORY for sound buffers.\n");	/* arithmetic overflow */
+			return(MEMORY_ERROR);
+		}
+		if((dz->bigbuf=(float *)malloc(overall_size * sizeof(float)))==NULL) {
+			sprintf(errstr,"INSUFFICIENT MEMORY to create sound buffers.\n");
+			return(MEMORY_ERROR);
+		}
+					/* SET SIZE OF inbuf, outbuf, AND Lbuf (FOR CALCS) */
+		outbuflen   = dz->buflen;
+		if(convert_to_stereo)								/* For stereo out, outbuflen is double length of inbuf */
+			outbuflen *= 2;
+		if(dz->iparam[GRS_CHANNELS]) {
+			stereo_buflen = dz->buflen * 2;
+			stereo_bufxs  = dz->iparam[GRS_BUF_SMPXS] * 2;
+		}										 
+		dz->iparam[GRS_LONGS_BUFLEN] = outbuflen;			/* Longs buffer is same size as obuf */
+		if(dz->iparam[GRS_LBUF_SMPXS] > dz->iparam[GRS_LONGS_BUFLEN])
+			continue;
+		break;
+	}
+				/* DIVIDE UP ALLOCATED MEMORY IN SPECIALISED BUFFERS */	
+																	
+	if(dz->iparam[GRS_CHANNELS]) {				 					/* sbuf : extra stereo input buffer, if required */						 
+		dz->sampbuf[SAUS_SBUF]   = dz->bigbuf;									 
+		dz->sampbuf[SAUS_BUF(0)] = dz->sampbuf[SAUS_SBUF] + stereo_buflen + stereo_bufxs;			 
+	} else												 
+		dz->sampbuf[SAUS_BUF(0)] = dz->bigbuf;						
+	dz->sbufptr[SAUS_BUF(0)]  = dz->sampbuf[SAUS_BUF(0)] + dz->buflen;	
+	dz->sampbuf[SAUS_IBUF(0)] = dz->sampbuf[SAUS_BUF(0)] + dz->iparam[GRS_BUF_SMPXS]; 
+	tailend     		      = dz->sbufptr[SAUS_BUF(0)] + dz->iparam[GRS_BUF_SMPXS];  
+	for(n=1;n<dz->infilecnt;n++) {
+		dz->sampbuf[SAUS_BUF(n)]  = tailend;								   /* Lbuf: buffer for calculations */
+		dz->sbufptr[SAUS_BUF(n)]  = dz->sampbuf[SAUS_BUF(n)] + dz->buflen;	
+		dz->sampbuf[SAUS_IBUF(n)] = dz->sampbuf[SAUS_BUF(n)] + dz->iparam[GRS_BUF_SMPXS]; 
+		tailend     		      = dz->sbufptr[SAUS_BUF(n)] + dz->iparam[GRS_BUF_SMPXS]; 
+	}
+	dz->fptr[GRS_LBUF]     = tailend;								   
+	dz->fptr[GRS_LBUFEND]  = dz->fptr[GRS_LBUF] + dz->iparam[GRS_LONGS_BUFLEN];
+	dz->fptr[GRS_LTAILEND] = dz->fptr[GRS_LBUFEND] + dz->iparam[GRS_LBUF_SMPXS];
+	dz->fptr[GRS_LBUFMID]  = dz->fptr[GRS_LBUF]    + dz->iparam[GRS_LBUF_SMPXS];
+	dz->sampbuf[SAUS_OBUF]  = /*(short *)*/(dz->fptr[GRS_LTAILEND]);		 		    
+
+								/* INITIALISE BUFFERS */
+
+	memset((char *)dz->bigbuf,0,overall_size * sizeof(float));
+	return(FINISHED);
+}
+
+#else
+
+int create_sausage_buffers(dataptr dz)
+{
+	long standard_block = (long)Malloc(-1);
+	long this_bloksize;
+	int   exit_status, n, chans = dz->infile->channels;
+	int   overall_size, bufdivisor = 0;
+	float *tailend;
+	long  multichan_buflen = 0, multichan_bufxs = 0, outbuflen;
+	if((dz->extrabuf[GRS_GBUF] = (float *)malloc(dz->iparam[GRS_GLBUF_SMPXS] * sizeof(float)))==NULL) {
+		sprintf(errstr,"INSUFFICIENT MEMORY to create grain buffer.\n");	 /* GRAIN BUFFER */
+		return(MEMORY_ERROR);
+	}
+				/* CALCULATE NUMBER OF BUFFER CHUNKS REQUIRED : bufdivisor */
+
+	if(dz->iparam[GRS_CHANNELS]>0)
+		bufdivisor += chans;							/* chans for multichan-infile, before reducing to mono */
+	bufdivisor += dz->infilecnt;						/* infilecnt IN mono, 1 OUT,   1 LBUF OUT  */
+	for(n=0;n<dz->outfile->channels;n++)
+		bufdivisor += 1 + sizeof(long)/sizeof(float);	/* 1 float and 1 long buf for each input channel */
+	this_bloksize = standard_block;
+	for(;;) {
+		if((exit_status = grab_an_appropriate_block_of_sausage_memory(&this_bloksize,standard_block,bufdivisor,dz))<0)
+			return(exit_status);
+
+					/* CALCULATE AND ALLOCATE TOTAL MEMORY REQUIRED : overall_size */
+	
+		overall_size = (dz->buflen * bufdivisor) + (dz->iparam[GRS_BUF_SMPXS] * dz->infilecnt) + dz->iparam[GRS_LBUF_SMPXS];
+		if(dz->iparam[GRS_CHANNELS])				
+			overall_size += chans * dz->iparam[GRS_BUF_SMPXS];					/* IF multichan, also allow for bufxs in multichan inbuf */
+
+		if(overall_size * sizeof(float)<0) {
+			sprintf(errstr,"INSUFFICIENT MEMORY for sound buffers.\n");	/* arithmetic overflow */
+			return(MEMORY_ERROR);
+		}
+		if((dz->bigbuf=(float *)malloc(overall_size * sizeof(float)))==NULL) {
+			sprintf(errstr,"INSUFFICIENT MEMORY to create sound buffers.\n");
+			return(MEMORY_ERROR);
+		}
+					/* SET SIZE OF inbuf, outbuf, AND Lbuf (FOR CALCS) */
+		outbuflen = dz->buflen;
+
+		outbuflen *= dz->out_chans;
+		if(dz->iparam[GRS_CHANNELS]) {
+			multichan_buflen = dz->buflen * chans;
+			multichan_bufxs  = dz->iparam[GRS_BUF_SMPXS] * chans;
+		}										 
+		dz->iparam[GRS_LONGS_BUFLEN] = outbuflen;			/* Longs buffer is same size as obuf */
+		if(dz->iparam[GRS_LBUF_SMPXS] > dz->iparam[GRS_LONGS_BUFLEN])
+			continue;
+		break;
+	}
+				/* DIVIDE UP ALLOCATED MEMORY IN SPECIALISED BUFFERS */	
+																	
+	if(dz->iparam[GRS_CHANNELS]) {				 					/* sbuf : extra stereo input buffer, if required */						 
+		dz->sampbuf[SAUS_SBUF]   = dz->bigbuf;									 
+		dz->sampbuf[SAUS_BUF(0)] = dz->sampbuf[SAUS_SBUF] + multichan_buflen + multichan_bufxs;			 
+	} else												 
+		dz->sampbuf[SAUS_BUF(0)] = dz->bigbuf;						
+	dz->sbufptr[SAUS_BUF(0)]  = dz->sampbuf[SAUS_BUF(0)] + dz->buflen;	
+	dz->sampbuf[SAUS_IBUF(0)] = dz->sampbuf[SAUS_BUF(0)] + dz->iparam[GRS_BUF_SMPXS]; 
+	tailend     		      = dz->sbufptr[SAUS_BUF(0)] + dz->iparam[GRS_BUF_SMPXS];  
+	for(n=1;n<dz->infilecnt;n++) {
+		dz->sampbuf[SAUS_BUF(n)]  = tailend;								   /* Lbuf: buffer for calculations */
+		dz->sbufptr[SAUS_BUF(n)]  = dz->sampbuf[SAUS_BUF(n)] + dz->buflen;	
+		dz->sampbuf[SAUS_IBUF(n)] = dz->sampbuf[SAUS_BUF(n)] + dz->iparam[GRS_BUF_SMPXS]; 
+		tailend     		      = dz->sbufptr[SAUS_BUF(n)] + dz->iparam[GRS_BUF_SMPXS]; 
+	}
+	dz->fptr[GRS_LBUF]     = tailend;								   
+	dz->fptr[GRS_LBUFEND]  = dz->fptr[GRS_LBUF] + dz->iparam[GRS_LONGS_BUFLEN];
+	dz->fptr[GRS_LTAILEND] = dz->fptr[GRS_LBUFEND] + dz->iparam[GRS_LBUF_SMPXS];
+	dz->fptr[GRS_LBUFMID]  = dz->fptr[GRS_LBUF]    + dz->iparam[GRS_LBUF_SMPXS];
+	dz->sampbuf[SAUS_OBUF]  = /*(short *)*/(dz->fptr[GRS_LTAILEND]);		 		    
+
+								/* INITIALISE BUFFERS */
+
+	memset((char *)dz->bigbuf,0,overall_size * sizeof(float));
+	return(FINISHED);
+}
+
+#endif
+
+/*  INPUT BUFFERS :-		
+ *
+ *	|-----------BUFLEN-----------|
+ *
+ *	buf      ibuf		   bufend    tailend
+ *	|_________|__________________|buf_smpxs|  ..... (obuf->)
+ *					             /
+ *	|buf_smpxs|	          <<-COPY_________/
+ *
+ *		      |-----------BUFLEN-----------|
+ *
+ *
+ *
+ *  OUTPUT LONGS BUFFER:-
+ *
+ *	Lbuf	   Lbufmid	  Lbufend
+ *	|____________|_______________|_Lbuf_smpxs_|
+ *				                 /
+ *	|_Lbuf_smpxs_|         <<-COPY___________/	
+ *
+ */
+
+/*************************** GRAB_AN_APPROPRIATE_BLOCK_OF_SAUSAGE_MEMORY **************************/
+
+#ifndef MULTICHAN
+
+int grab_an_appropriate_block_of_sausage_memory(long *this_bloksize,long standard_block,int bufdivisor,dataptr dz)
+{
+	/*int  sector_blok;*/
+	do {
+//TW	if((dz->buflen = *this_bloksize)< 0) {	/* arithmetic overflow */
+		if((dz->buflen = *this_bloksize) * sizeof(float) < 0) {	/* arithmetic overflow */
+			sprintf(errstr,"INSUFFICIENT MEMORY for sound buffers.\n");
+			return(MEMORY_ERROR);
+		}
+		*this_bloksize += standard_block;
+				/* CALCULATE SIZE OF BUFFER REQUIRED : dz->bigbufsize */
+
+		dz->buflen -= (dz->infilecnt * dz->iparam[GRS_BUF_SMPXS]) + dz->iparam[GRS_LBUF_SMPXS];	
+															/* Allow for overflow areas */
+		if(dz->iparam[GRS_CHANNELS])				
+			dz->buflen -= 2 * dz->iparam[GRS_BUF_SMPXS];	/* Allow for overflow space in additional stereo inbuf */
+		dz->buflen /= bufdivisor;						/* get unit buffersize */
+	/*	sector_blok = SECSIZE;	*/							/* Read and write buf sizes must be multiples of SECSIZE */
+		if(dz->iparam[GRS_CHANNELS])						/* If reading stereo: 2* SECSIZE reduces to single mono SECSIZE */
+	/*		sector_blok *= 2;		*/						/* So dz->bigbufsize must be a multiple of (2 * SECSIZE) */
+			dz->buflen = (dz->buflen / STEREO) * STEREO;	   /*RWD: */
+	
+	/*	dz->buflen = (dz->bigbufsize/sector_blok) * sector_blok;*/
+	} while(dz->buflen <= 0);
+	return(FINISHED);
+}
+
+#else
+
+int grab_an_appropriate_block_of_sausage_memory(long *this_bloksize,long standard_block,int bufdivisor,dataptr dz)
+{
+	do {
+		if((dz->buflen = *this_bloksize) * sizeof(float) < 0) {	/* arithmetic overflow */
+			sprintf(errstr,"INSUFFICIENT MEMORY for sound buffers.\n");
+			return(MEMORY_ERROR);
+		}
+		*this_bloksize += standard_block;
+		dz->buflen -= (dz->infilecnt * dz->iparam[GRS_BUF_SMPXS]) + dz->iparam[GRS_LBUF_SMPXS];	
+															/* Allow for overflow areas */
+		if(dz->iparam[GRS_CHANNELS])				
+			dz->buflen -= dz->infile->channels * dz->iparam[GRS_BUF_SMPXS];	/* Allow for overflow space in additional multichan inbuf */
+		dz->buflen /= bufdivisor;							/* get unit buffersize */
+		if(dz->iparam[GRS_CHANNELS])						/* If reading multichano: chans * SECSIZE reduces to single mono SECSIZE */
+			dz->buflen = (dz->buflen / dz->infile->channels) * dz->infile->channels;
+	} while(dz->buflen <= 0);
+	return(FINISHED);
+}
+
+#endif
+
+
+#ifdef MULTICHAN
+
+/************************* WRITE_MULTICHAN_GRAIN ****************************/
+
+int write_multichan_grain(double rpos,int chana,int chanb,float **maxwrite,float **Fptr,float **FFptr,int gsize_per_chan,int *nctr,dataptr dz)
+{
+	int exit_status;
+	long   n, to_doo, exess;
+	long   real_gsize = gsize_per_chan * dz->out_chans;
+	double lpos;
+	double adjust = dehole(rpos);
+	float  *writend, *fptr = *Fptr, *ffptr = *FFptr;
+	float  *gbufptr = dz->extrabuf[GRS_GBUF];
+	lpos  = (1.0 - rpos) * adjust;
+	rpos *= adjust;
+	chana--;
+	chanb--;
+	if((writend = (ffptr + real_gsize)) > *maxwrite)
+		*maxwrite = writend;
+	if(ffptr + real_gsize >= dz->fptr[GRS_LTAILEND]) {
+		to_doo = dz->fptr[GRS_LTAILEND] - ffptr;
+		if((exess  = real_gsize - to_doo) >= dz->iparam[GRS_LONGS_BUFLEN]) {
+ 			sprintf(errstr,"Array overflow: write_stereo_grain()\n");
+			return(PROGRAM_ERROR);
+		}
+		to_doo /= dz->out_chans;
+		for(n = 0; n < to_doo; n++) {
+			*(ffptr + chana) += (float) (*gbufptr * lpos);
+			*(ffptr + chanb) += (float) (*gbufptr * rpos);
+			gbufptr++;
+			ffptr += dz->out_chans;
+		}
+		if((exit_status = write_samps_granula(dz->iparam[GRS_LONGS_BUFLEN],nctr,dz))<0)
+			return(exit_status);
+		memmove((char *)dz->fptr[GRS_LBUF],(char *)dz->fptr[GRS_LBUFEND],
+			(size_t)dz->iparam[GRS_LBUF_SMPXS] * sizeof(float));
+		memset((char *)dz->fptr[GRS_LBUFMID],0,dz->iparam[GRS_LONGS_BUFLEN] * sizeof(float));
+		ffptr -= dz->iparam[GRS_LONGS_BUFLEN];
+		fptr  -= dz->iparam[GRS_LONGS_BUFLEN];
+		*maxwrite -= dz->buflen; /* APR 1996 */
+		exess /= dz->out_chans;
+		for(n = 0; n < exess; n++) {
+			*(ffptr + chana) += (float) (*gbufptr * lpos);
+			*(ffptr + chanb) += (float) (*gbufptr * rpos);
+			gbufptr++;
+			ffptr += dz->out_chans;
+		}
+		*Fptr  = fptr;
+		*FFptr = ffptr;
+		return(FINISHED);
+	}
+	for(n=0;n<gsize_per_chan;n++) {
+		*(ffptr + chana) += (float) (*gbufptr * lpos);
+		*(ffptr + chanb) += (float) (*gbufptr * rpos);
+		gbufptr++;
+		ffptr += dz->out_chans;
+	}
+	*Fptr  = fptr;
+	*FFptr = ffptr;
+	return(FINISHED);
+}
+
+#endif

+ 242 - 0
dev/modify/main.c

@@ -0,0 +1,242 @@
+/*
+ * Copyright (c) 1983-2013 Trevor Wishart and Composers Desktop Project Ltd
+ * http://www.trevorwishart.co.uk
+ * http://www.composersdesktop.com
+ *
+ This file is part of the CDP System.
+
+    The CDP System is free software; you can redistribute it
+    and/or modify it under the terms of the GNU Lesser General Public
+    License as published by the Free Software Foundation; either
+    version 2.1 of the License, or (at your option) any later version.
+
+    The CDP System is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public
+    License along with the CDP System; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+    02111-1307 USA
+ *
+ */
+
+
+
+/* floatsam version : no changes */
+#include <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <structures.h>
+#include <tkglobals.h>
+#include <modify.h>
+#include <filetype.h>
+#include <processno.h>
+#include <modeno.h>
+#include <formants.h>
+#include <cdpmain.h>
+#include <special.h>
+#include <logic.h>
+#include <globcon.h>
+#include <cdpmain.h>
+#include <string.h>
+
+#include <sfsys.h>
+
+
+char errstr[2400];
+
+/*extern*/ int	sloom = 0;
+/*extern*/ int sloombatch = 0;	/*TW may 2001 */
+/*extern*/ int anal_infiles = 0;
+/*extern*/ int is_converted_to_stereo = -1;
+//const char* cdp_version = "9.0.0";
+/* Added midrise bitreduce mode 2013 */
+const char* cdp_version = "7.1.0";
+
+
+/**************************************** MAIN *********************************************/
+
+int main(int argc,char *argv[])
+{
+	int exit_status;
+	dataptr dz = NULL;
+	/*char *special_data_string = NULL;*/
+	char **cmdline;
+	int  cmdlinecnt;
+	aplptr ap;
+	int *valid = NULL;
+	int is_launched = FALSE;
+	int  validcnt;
+
+	if(argc==2 && (strcmp(argv[1],"--version") == 0)) {
+		fprintf(stdout,"%s\n",cdp_version);
+		fflush(stdout);
+		return 0;
+	}
+						/* CHECK FOR SOUNDLOOM */
+/* TW May 2001 */
+	if((sloom = sound_loom_in_use(&argc,&argv)) > 1) {
+		sloom = 0;
+		sloombatch = 1;
+	}
+
+	if(!sloom) {
+		if((exit_status = allocate_and_initialise_validity_flags(&valid,&validcnt))<0) {
+			print_messages_and_close_sndfiles(exit_status,is_launched,dz);
+			return(FAILED);
+		}
+	}
+
+	if(sflinit("cdp")){
+		sfperror("cdp: initialisation\n");
+		return(FAILED);
+	}
+
+						  /* SET UP THE PRINCIPLE DATASTRUCTURE */
+	if((exit_status = establish_datastructure(&dz))<0) {
+		print_messages_and_close_sndfiles(exit_status,is_launched,dz);
+		return(FAILED);
+	}
+				  
+	if(!sloom) {
+							  /* INITIAL CHECK OF CMDLINE DATA */
+		if((exit_status = make_initial_cmdline_check(&argc,&argv))<0) {
+			print_messages_and_close_sndfiles(exit_status,is_launched,dz);
+			return(FAILED);
+		}
+		cmdline    = argv;	/* GET PRE_DATA, ALLOCATE THE APPLICATION, CHECK FOR EXTRA INFILES */
+		cmdlinecnt = argc;
+		if((exit_status = get_process_and_mode_from_cmdline(&cmdlinecnt,&cmdline,dz))<0) {
+			print_messages_and_close_sndfiles(exit_status,is_launched,dz);
+			return(FAILED);
+		}		
+		if((exit_status = setup_particular_application(dz))<0) {
+			print_messages_and_close_sndfiles(exit_status,is_launched,dz);
+			return(FAILED);
+		}
+		if((exit_status = count_and_allocate_for_infiles(cmdlinecnt,cmdline,dz))<0) {
+			print_messages_and_close_sndfiles(exit_status,is_launched,dz);
+			return(FAILED);
+		}
+	} else {
+		if((exit_status = parse_tk_data(argc,argv,&cmdline,&cmdlinecnt,dz))<0) {  	/* includes setup_particular_application()      */
+			exit_status = print_messages_and_close_sndfiles(exit_status,is_launched,dz);/* and cmdlinelength check = sees extra-infiles */
+			return(exit_status);		 
+		}
+	}
+	ap = dz->application;
+
+/*********************************************************************************************************************
+	   cmdline[0]				 		  2 vals					   		  ACTIVE		 
+TK 		(infile) (more-infiles) (outfile) (flag val) (formantsqksrch) (special) params  options   variant-params  flags
+CMDLINE	(infile) (more-infiles) (outfile) (formants) (formantsqksrch) (special) params  POSSIBLY  POSSIBLY	  	POSSIBLY
+								 		  1 val
+*********************************************************************************************************************/
+
+	if(dz->process!=SIN_TAB) {
+		if((exit_status = parse_infile_and_hone_type(cmdline[0],valid,dz))<0) {
+			print_messages_and_close_sndfiles(exit_status,is_launched,dz);
+			return(FAILED);
+		}
+	}
+
+	if((exit_status = setup_param_ranges_and_defaults(dz))<0) {
+		print_messages_and_close_sndfiles(exit_status,is_launched,dz);
+		return(FAILED);
+	}
+
+					/* OPEN FIRST INFILE AND STORE DATA, AND INFORMATION, APPROPRIATELY */
+
+	if(dz->input_data_type!=NO_FILE_AT_ALL) {
+		if((exit_status = open_first_infile(cmdline[0],dz))<0) {	
+			print_messages_and_close_sndfiles(exit_status,is_launched,dz);	
+			return(FAILED);
+		}
+ 		cmdlinecnt--;
+		cmdline++;
+	
+	}
+
+/*********************************************************************************************************************
+		cmdline[0]				   2 vals				   			   ACTIVE		 
+TK 		(more-infiles) (outfile) (flag val) (formantsqksrch) (special) params  options   variant-params  flags
+CMDLINE	(more-infiles) (outfile) (formants) (formantsqksrch) (special) params  POSSIBLY  POSSIBLY		  POSSIBLY
+								   1 val
+*********************************************************************************************************************/
+
+	if((exit_status = handle_extra_infiles(&cmdline,&cmdlinecnt,dz))<0) {
+		print_messages_and_close_sndfiles(exit_status,is_launched,dz);		
+		return(FAILED);
+	}
+
+/*********************************************************************************************************************
+		cmdline[0]	  2					   			    ACTIVE		 
+TK 		(outfile) (flag val) (formantsqksrch) (special) params  options   variant-params  flags
+CMDLINE	(outfile) (formants) (formantsqksrch) (special) params  POSSIBLY  POSSIBLY		   POSSIBLY
+					  1
+*********************************************************************************************************************/
+
+	if((exit_status = handle_outfile(&cmdlinecnt,&cmdline,is_launched,dz))<0) {
+		print_messages_and_close_sndfiles(exit_status,is_launched,dz);
+		return(FAILED);
+	}
+	
+/****************************************************************************************
+		cmdline[0]	  		   			       ACTIVE		 
+TK 		(flag val) (formantsqksrch) (special) params  options   variant-params  flags
+CMDLINE	(formants) (formantsqksrch) (special) params  POSSIBLY  POSSIBLY		POSSIBLY
+*****************************************************************************************/
+
+	if((exit_status = handle_formants(&cmdlinecnt,&cmdline,dz))<0) {
+		print_messages_and_close_sndfiles(exit_status,is_launched,dz);
+		return(FAILED);
+	}
+	if((exit_status = handle_formant_quiksearch(&cmdlinecnt,&cmdline,dz))<0) {
+		print_messages_and_close_sndfiles(exit_status,is_launched,dz);
+		return(FAILED);
+	}
+	if((exit_status = handle_special_data(&cmdlinecnt,&cmdline,dz))<0) {
+		print_messages_and_close_sndfiles(exit_status,is_launched,dz);
+		return(FAILED);
+	}
+ 
+/****************************************************************************************
+		cmdline[0]	  		   			    
+TK 		active_params  	options   		variant-params  flags
+CMDLINE	active_params  	POSSIBLY  		POSSIBLY		POSSIBLY
+*****************************************************************************************/
+
+	if((exit_status = read_parameters_and_flags(&cmdline,&cmdlinecnt,dz))<0) {
+		print_messages_and_close_sndfiles(exit_status,is_launched,dz);
+		return(FAILED);
+	}
+	if((exit_status = check_param_validity_and_consistency(dz))<0) {
+		print_messages_and_close_sndfiles(exit_status,is_launched,dz);
+		return(FAILED);
+	}
+
+ 	is_launched = TRUE;
+
+	if((exit_status = allocate_large_buffers(dz))<0){
+		print_messages_and_close_sndfiles(exit_status,is_launched,dz);
+		return(FAILED);
+	}
+	if((exit_status = param_preprocess(dz))<0){
+		print_messages_and_close_sndfiles(exit_status,is_launched,dz);
+		return(FAILED);
+	}
+	if((exit_status = groucho_process_file(dz))<0) {
+		print_messages_and_close_sndfiles(exit_status,is_launched,dz);
+		return(FAILED);
+	}
+	if((exit_status = complete_output(dz))<0) {
+		print_messages_and_close_sndfiles(exit_status,is_launched,dz);
+		return(FAILED);
+	}
+	exit_status = print_messages_and_close_sndfiles(FINISHED,is_launched,dz);
+	free(dz);
+	return(SUCCEEDED);
+}
+

+ 1223 - 0
dev/modify/pan.c

@@ -0,0 +1,1223 @@
+/*
+ * Copyright (c) 1983-2013 Trevor Wishart and Composers Desktop Project Ltd
+ * http://www.trevorwishart.co.uk
+ * http://www.composersdesktop.com
+ *
+ This file is part of the CDP System.
+
+    The CDP System is free software; you can redistribute it
+    and/or modify it under the terms of the GNU Lesser General Public
+    License as published by the Free Software Foundation; either
+    version 2.1 of the License, or (at your option) any later version.
+
+    The CDP System is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public
+    License along with the CDP System; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+    02111-1307 USA
+ *
+ */
+
+
+
+/* floatsam version */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>				/*RWD Nov 2003 */
+#include <structures.h>
+#include <tkglobals.h>
+#include <globcon.h>
+#include <modify.h>
+#include <cdpmain.h>
+#include <modeno.h>
+#include <arrays.h>
+#include <filetype.h>
+#include <sfsys.h>
+//TW UPDATE
+#include <osbind.h>
+
+#if defined unix || defined __GNUC__
+#define round(x) lround((x))
+#endif
+
+//TW UPDATES
+#define SMALLARRAY	20
+#define	ONE_dB		1.22018
+
+#define BSIZE		(128)
+#define ROOT2		(1.4142136)
+#define SIGNAL_TO_LEFT  (0)
+#define SIGNAL_TO_RIGHT (1)
+
+#define	NARROW_IT	(1)
+#define	MONO_IT		(0)
+#define	MIRROR_IT	(-1)
+
+static long newpar(int *brkindex,double *par,double *parincr,long *total_sams,dataptr dz);
+static void pancalc(double position,double *leftgain,double *rightgain);
+static void do_mirror(float *buffer,dataptr dz);
+static void do_narrow(double narrow,double one_less_narrow,dataptr dz);
+static void do_mono(dataptr dz);
+
+static int more_space(int size_step,long *arraysize,double **brk);
+static int get_sinval(double *f0,double *a0,double time,double *phase,double phase_quantum,double **p,dataptr dz);
+
+//TW UPDATE: NEW FUNCTIONS
+static int insert_point_in_envelope(int *last_postk,double basetime,int thisenv,int *cnt,
+		double *last_posttime,double *last_postlevel,int *last_insertk,double *last_inserttime,double *last_insertlevel,
+		double envtime,double envlevel,dataptr dz);
+
+/* SHUDDER */
+static int apply_brkpnt_envelope(dataptr dz);
+static int  init_brkpnts
+	(long *sampno,double *starttime,double *gain,double **endbrk,double **nextbrk,
+	 double *nextgain,double *gain_step,double *gain_incr,long *nextbrk_sampno,int paramno,int brksize,dataptr dz);
+static int  advance_brkpnts
+	(double starttime,double *gain,double *endbrk,double **nextbrk,double *nextgain,
+	 double *gain_step,double *gain_incr,long *nextbrk_sampno,dataptr dz);
+static int  simple_envel_processing
+	(long *samps_left_to_process,double starttime,double *endbrk,double **nextbrk,double *nextgain,
+	 long *sampno,double *gain,double *gain_step,double *gain_incr,long *nextbrk_sampno,int chan,float *maxobuf,dataptr dz);
+static int  do_mono_envelope
+	(long samp_cnt,double starttime,double *endbrk,double **nextbrk,double *nextgain,
+	 long *sampno,double *gain,double *gain_step,double *gain_incr,long *nextbrk_sampno,float *maxobuf,dataptr dz);
+static int  read_ssamps(long samps_to_read,long *samps_left_to_process,int chan,dataptr dz);
+static int  do_simple_read(long *samps_left_to_process,long buflen,int chan,dataptr dz);
+static int other_read_samps(long samps_to_read,int fileid,int bufno,dataptr dz);
+static void unlink_temp_files(int type,int ofd0, int ofd1,dataptr dz);
+
+/************************************ MODSPACE_PCONSISTENCY *******************************/
+
+int modspace_pconsistency(dataptr dz) 
+{
+	switch(dz->mode) {
+	case(MOD_PAN):
+		if(dz->infile->channels!=MONO) {
+			sprintf(errstr,"ERROR: PAN only works with MONO input files.\n");
+			return(DATA_ERROR);
+		}
+		break;
+	case(MOD_MIRROR):
+		if(dz->infile->channels!=STEREO) {
+			sprintf(errstr,"ERROR: MIRROR only works with STEREO input files.\n");
+			return(DATA_ERROR);
+		}
+		break;
+	case(MOD_MIRRORPAN):
+		if(dz->infile->filetype!=UNRANGED_BRKFILE) {
+			sprintf(errstr,"ERROR: MIRROR PAN only works with PAN textdata files.\n");
+			return(DATA_ERROR);
+		}
+		if(dz->brksize[dz->extrabrkno] < 2) {
+			sprintf(errstr,"ERROR: MIRROR PAN table too short [%d pairs < 2].\n",dz->brksize[dz->extrabrkno]);
+			return(DATA_ERROR);
+		}
+		break;
+	case(MOD_NARROW):
+		if(dz->infile->channels!=STEREO) {
+			sprintf(errstr,"ERROR: NARROW only works with STEREO input files.\n");
+			return(DATA_ERROR);
+		}
+		break;
+	}
+	return(FINISHED);
+}
+
+/************************************ MODSPACE_PREPROCESS *******************************/
+
+int modspace_preprocess(dataptr dz)
+{
+	int exit_status;
+	if(dz->mode == MOD_PAN && dz->brksize[PAN_PAN]) {
+		if((exit_status = force_value_at_zero_time(PAN_PAN,dz))<0)
+			return(exit_status);
+	}
+
+	if(dz->mode==MOD_PAN){
+		/* create stereo outfile here! */
+		/* RWD 4:2002  now we can open outfile with corect params! */
+		dz->infile->channels = STEREO;	/* ARRGH! */
+		if((exit_status = create_sized_outfile(dz->outfilename,dz))<0)
+			return(exit_status);
+	}
+
+
+	return(FINISHED);
+}
+
+/************************************ DOPAN *******************************/
+
+int dopan(dataptr dz)
+{
+	int exit_status;
+	int 	i;
+	int		brkindex = 1;
+	long	block = 0, sams = 0, total_sams = 0;
+	float  *inbuf = dz->sampbuf[0], *bufptr;
+	double	leftgain,rightgain;
+	double	lcoef = 0.0, rcoef = 0.0;			
+	double	par = 0.0, parincr = 0.0;
+/*	double	fdist = 1.0;*/		/* fdist is for listener distance: not used yet */
+
+	if(!dz->brksize[PAN_PAN]) {
+		pancalc(dz->param[PAN_PAN],&leftgain,&rightgain);
+		lcoef = leftgain  * dz->param[PAN_PRESCALE];
+		rcoef = rightgain * dz->param[PAN_PRESCALE];
+	}
+	display_virtual_time(0L,dz);
+	dz->infile->channels = STEREO;	/* affects output only */
+	do {
+		if((exit_status = read_samps(inbuf,dz))<0) {
+			sprintf(errstr,"Failed to read data from sndfile.\n");
+			return(DATA_ERROR);
+		}
+		bufptr = dz->sampbuf[1];	/* reset output buffer pointer */
+
+		for (i = 0 ; i < dz->ssampsread; i++ ) {
+			if(dz->brksize[PAN_PAN]) {
+				if(sams-- <= 0)
+					sams = newpar(&brkindex,&par,&parincr,&total_sams,dz);
+				if(block-- <= 0) {
+					pancalc(par,&leftgain,&rightgain);
+					lcoef = leftgain  * dz->param[PAN_PRESCALE];
+					rcoef = rightgain * dz->param[PAN_PRESCALE];
+					block += BSIZE;
+					par += parincr;
+	    		}
+			}
+			*bufptr++ = (float) /*round*/(lcoef * inbuf[i]);
+			*bufptr++ = (float) /*round*/(rcoef * inbuf[i]);
+		}
+		if(dz->ssampsread > 0) {
+			if((exit_status = write_samps(dz->sampbuf[1],dz->ssampsread * STEREO,dz))<0)
+				return(exit_status);
+		}
+	} while(dz->samps_left > 0);
+	return(FINISHED);
+}
+
+/************************************ MIRRORING *******************************/
+
+int mirroring(dataptr dz)
+{  
+	int exit_status;
+	float *inbuf = dz->sampbuf[0];
+	do {
+		if((exit_status = read_samps(inbuf,dz))<0) {
+			sprintf(errstr,"Failed to read data from sndfile.\n");
+			return(DATA_ERROR);
+		}
+		do_mirror(inbuf,dz);
+		if(dz->ssampsread > 0) {
+			if((exit_status = write_exact_samps(dz->sampbuf[0],dz->ssampsread,dz))<0)
+				return(exit_status);
+		}
+	} while(dz->samps_left > 0);
+	return(FINISHED);
+}
+
+/******************************** MIRROR_PANFILE ********************************/
+
+void mirror_panfile(dataptr dz)
+{
+	int    panbrk = dz->extrabrkno;
+	long   n;
+	double *panbrktab  = dz->brk[panbrk];
+	long   panbrksize = dz->brksize[panbrk];
+	double *p = panbrktab + 1;
+	for(n=0;n<panbrksize;n++) {
+		*p = -(*p);
+		p += 2;
+	}		
+	p = panbrktab;
+	for(n=0;n<panbrksize;n++) {
+		fprintf(dz->fp,"%lf\t%lf\n",*p,*(p+1));
+		p += 2;
+	}
+	return;
+}
+
+/***************************** NARROW_SOUND ***************************/
+
+int narrow_sound(dataptr dz)
+{   
+	int exit_status;
+	int narrowing = NARROW_IT;
+	double narrow = dz->param[NARROW], one_less_narrow;
+	float *buffer = dz->sampbuf[0];
+	display_virtual_time(0L,dz);
+	if(flteq(narrow,1.0)) {
+		sprintf(errstr, "WARNING: Narrowing of 1.0 has no effect on input file.\n");
+		return(DATA_ERROR);
+   	}
+	if(flteq(narrow,-1.0)) 		narrowing = MIRROR_IT;
+   	else if(flteq(narrow,0.0))	narrowing = MONO_IT;
+   	narrow = dz->param[NARROW] + 1.0;
+   	narrow /= 2.0;
+   	one_less_narrow = narrow;
+   	narrow  = 1.0 - narrow;	
+	while(dz->samps_left != 0) {
+		if((exit_status = read_samps(buffer,dz))<0) {
+			sprintf(errstr,"Failed to read data from sndfile.\n");
+			return(PROGRAM_ERROR);
+		}
+		switch(narrowing) {
+		case(NARROW_IT):	do_narrow(narrow,one_less_narrow,dz);	break;
+		case(MIRROR_IT):	do_mirror(buffer,dz);					break;
+		case(MONO_IT):		do_mono(dz);							break;
+		}
+		if(dz->ssampsread > 0) {
+			if((exit_status= write_exact_samps(buffer,dz->ssampsread,dz))<0)
+				return(exit_status);
+		}
+    }
+	return(FINISHED);
+}
+
+/************************************ NEWPAR *******************************/
+
+long newpar(int *brkindex,double *par,double *parincr,long *total_sams,dataptr dz)
+{
+	double diff, steps, nextval;
+	double *thisbrk = dz->brk[PAN_PAN];
+	long here;
+	long sams;
+	if(*brkindex < dz->brksize[PAN_PAN]) {
+		here  = (*brkindex) * 2;
+		sams  = round(thisbrk[here] * dz->infile->srate) - *total_sams;
+		*par  = thisbrk[here-1];
+		nextval = thisbrk[++here];
+		diff  = nextval - (*par);
+		steps = (double)sams/(double)BSIZE;	
+		*parincr = diff/steps;
+		(*brkindex)++;
+	} else {
+		*parincr = 0.0;
+		sams = dz->insams[0] - *total_sams;
+	}
+	*total_sams += sams;
+	return(sams);	
+}
+
+/************************************ PANCALC *******************************/
+
+void pancalc(double position,double *leftgain,double *rightgain)
+{
+	int dirflag;
+	double temp;
+	double relpos;
+	double reldist, invsquare;
+
+	if(position < 0.0)
+		dirflag = SIGNAL_TO_LEFT;		/* signal on left */
+	else
+		dirflag = SIGNAL_TO_RIGHT;
+
+	if(position < 0) 
+		relpos = -position;
+	else 
+		relpos = position;
+	if(relpos <= 1.0){		/* between the speakers */
+		temp = 1.0 + (relpos * relpos);
+		reldist = ROOT2 / sqrt(temp);
+		temp = (position + 1.0) / 2.0;
+		*rightgain = temp * reldist;
+		*leftgain = (1.0 - temp ) * reldist;
+	} else {				/* outside the speakers */
+		temp = (relpos * relpos) + 1.0;
+		reldist  = sqrt(temp) / ROOT2;   /* relative distance to source */
+		invsquare = 1.0 / (reldist * reldist);
+		if(dirflag == SIGNAL_TO_LEFT){
+			*leftgain = invsquare;
+			*rightgain = 0.0;
+		} else {   /* SIGNAL_TO_RIGHT */
+			*rightgain = invsquare;
+			*leftgain = 0;
+		}
+	}
+}
+
+/************************************ DO_MIRROR *******************************/
+
+void do_mirror(float *buffer,dataptr dz)
+{
+	register long i;
+	float store;
+	for(i = 0; i < dz->ssampsread; i += 2) {
+		store       = buffer[i];
+		buffer[i]   = buffer[i+1];
+		buffer[i+1] = store;
+	}
+}
+
+/******************************* DO_NARROW *************************/
+
+void do_narrow(double narrow,double one_less_narrow,dataptr dz)
+{
+	register long i;
+	double new_l, new_r, add_to_l, add_to_r;
+	float *buffer = dz->sampbuf[0];
+	for(i = 0; i < dz->ssampsread; i+=2)  {
+//TW CHANGED (casts removed)
+		add_to_r    = buffer[i]   * narrow;
+		add_to_l    = buffer[i+1] * narrow;
+		new_l       = buffer[i]   * one_less_narrow;
+		new_r       = buffer[i+1] * one_less_narrow;
+		new_l      += add_to_l;
+		new_r      += add_to_r;
+		buffer[i]   = (float) /*round*/(new_l);
+		buffer[i+1] = (float) /*round*/(new_r);
+    }
+}
+
+/******************************* DO_MONO *************************/
+
+void do_mono(dataptr dz)
+{   
+	register long  i, j;
+	register double temp;
+	float *buffer =dz->sampbuf[0];
+	for(i = 0; i < dz->ssampsread; i+=2)  {
+		j = i+1;
+		temp      = (buffer[i] + buffer[j]) /*/2.0*/ * 0.5;
+		buffer[i] = (float)/*round*/(temp);
+		buffer[j] = (float)/*round*/(temp);
+	}
+}
+
+/****************************** GENERATE_SINTABLE *******************************/
+
+int generate_sintable(dataptr dz)
+{
+	int exit_status;
+	double *p, f0, a0, phase_quantum, time, phase;
+	long arraysize = BIGARRAY, cnt;
+
+	if((dz->parray[SIN_TABLE] = (double *)malloc(arraysize * sizeof(double)))==NULL) {
+		sprintf(errstr,"Out of memory for breakpoint table.\n");
+		return(MEMORY_ERROR);
+	}
+	p = dz->parray[SIN_TABLE];
+	phase = (dz->param[SIN_PHASE]/360.0) * TWOPI;
+//TW UPDATE
+//	*p++ = 0.0;
+//	*p++ = phase;
+//	cnt = 2;
+	time = 0.0;
+	if(dz->brksize[SIN_FRQ]) {
+		if((exit_status = read_value_from_brktable(time,SIN_FRQ,dz))<0)
+			return(exit_status);
+	}
+//TW UPDATE
+	dz->param[SIN_FRQ] = 1.0/dz->param[SIN_FRQ];
+
+	if(dz->brksize[SIN_AMP]) {
+		if((exit_status = read_value_from_brktable(time,SIN_AMP,dz))<0)
+			return(exit_status);
+	}		
+	f0 = dz->param[SIN_FRQ];
+	a0 = dz->param[SIN_AMP];
+
+	phase_quantum = dz->param[SIN_QUANT] * TWOPI;
+//TW UPDATES
+	if((exit_status = get_sinval(&f0,&a0,time,&phase,phase_quantum,&p,dz))<0)
+		return exit_status;
+	cnt = 2;
+
+	for(time = dz->param[SIN_QUANT]; time <= dz->param[SIN_DUR]; time += dz->param[SIN_QUANT]) {
+		if((cnt += 2) > arraysize) {
+			if((exit_status = more_space(BIGARRAY,&arraysize,&(dz->parray[SIN_TABLE])))<0)
+				return(exit_status);
+			p = dz->parray[SIN_TABLE] + cnt - 2;
+		}
+		if((exit_status = get_sinval(&f0,&a0,time,&phase,phase_quantum,&p,dz))<0)
+			return exit_status;
+	}		
+	if(!flteq(*(p-2),dz->param[SIN_DUR])) {
+		if((cnt += 2) > arraysize) {
+			arraysize = cnt;
+			if((exit_status = more_space(2,&arraysize,&(dz->parray[SIN_TABLE])))<0)
+				return(exit_status);
+			p = dz->parray[SIN_TABLE] + cnt - 2;
+		}
+		if((exit_status = get_sinval(&f0,&a0,dz->param[SIN_DUR],&phase,phase_quantum,&p,dz))<0)
+			return exit_status;
+	} else {
+		*(p-2) = dz->param[SIN_DUR];
+	}
+	if(cnt < arraysize) {
+		if((dz->parray[SIN_TABLE] = (double *)realloc((char *)(dz->parray[SIN_TABLE]),cnt * sizeof(double)))==NULL) {
+			sprintf(errstr,"Memory error on shrinking breaktable to size.\n");
+			return(MEMORY_ERROR);
+		}
+	}
+	cnt /= 2;
+	if((exit_status = write_brkfile(dz->fp,cnt,SIN_TABLE,dz))<0)
+		return(exit_status);
+	return(FINISHED);
+}
+
+/****************************** GET_SINVAL *******************************/
+
+int get_sinval(double *f0,double *a0,double time,double *phase,double phase_quantum,double **p,dataptr dz)
+{
+	int exit_status;
+	double frq, amp, val;
+	if(dz->brksize[SIN_FRQ]) {
+		if((exit_status = read_value_from_brktable(time,SIN_FRQ,dz))<0)
+			return(exit_status);
+//TW UPDATE
+		dz->param[SIN_FRQ] = 1.0/dz->param[SIN_FRQ];
+
+		frq = (dz->param[SIN_FRQ] + *f0) /*/2.0 */ * 0.5;
+	} else {
+		frq = *f0;
+	}
+	if(dz->brksize[SIN_AMP]) {
+		if((exit_status = read_value_from_brktable(time,SIN_AMP,dz))<0)
+			return(exit_status);
+		amp = (dz->param[SIN_AMP] + *a0) /* /2.0*/ * 0.5;
+	} else {
+		amp = *a0;
+	}
+//TW UPDATE (moved line)
+	val = sin(*phase) * amp;
+	*phase += frq * phase_quantum;
+	*phase = fmod(*phase,TWOPI);
+	**p = time;
+	(*p)++;
+	**p = val;
+	(*p)++;
+	*f0 = dz->param[SIN_FRQ];
+	*a0 = dz->param[SIN_AMP];
+	return(FINISHED);
+}
+
+/****************************** MORE_SPACE *******************************/
+
+int more_space(int size_step,long *arraysize,double **brk)
+{
+	*arraysize += size_step;
+	if((*brk = (double *)realloc((char *)(*brk),(*arraysize) * sizeof(double)))==NULL) {
+		sprintf(errstr,"Out of memory for breakpoint table.\n");
+		return(MEMORY_ERROR);
+	}
+	return(FINISHED);
+}
+
+//TW NEW FUNCTIONS (updated for flotsams)
+/************************************ SCALEDPAN_PREPROCESS *******************************/
+
+int scaledpan_preprocess(dataptr dz)
+{
+	int exit_status, n, len;
+	double endtime, scaling;
+	double *thisbrk;
+	if((len = (dz->brksize[PAN_PAN] * 2)) <= 0) {
+		fprintf(stdout,"WARNING: Scaled pan is no different to ordinary panning, if you do not use a brkpoint file.\n");
+		fflush(stdout);
+		return(FINISHED);
+	}
+	if((exit_status = force_value_at_zero_time(PAN_PAN,dz))<0)
+		return(exit_status);
+	thisbrk = dz->brk[PAN_PAN];
+	endtime = thisbrk[len - 2];
+	scaling = dz->duration/endtime;
+	for(n=0;n<len;n+=2)
+		thisbrk[n] *= scaling;
+	/* create stereo outfile here! */
+	dz->infile->channels = STEREO;	/* ARRGH! */
+	return create_sized_outfile(dz->outfilename,dz);
+}
+
+/************************************* DO_SHUDDER ***********************************/
+
+int do_shudder(dataptr dz)
+{
+	int left, exit_status;
+	long cnt = 0, cnt2 = 0, timecnt, n, m, j, levelcnt;
+	int cnt0, cnt1;
+	long arraysz[2] = {SMALLARRAY,SMALLARRAY};
+	double time, nexttime, lasttime, pos, leftgain, rightgain, depth, maxlevel, width, lastrealtime = -1.0;
+	double envtime, envlevel, lgain, rgain, scat, realtime, levell, levelr, one_minus_depth, safety = 1.0/ROOT2;
+	double last_posttime[2], last_postlevel[2], last_inserttime[2], last_insertlevel[2], basetime[2];
+	int last_insertk[2], last_postk[2];
+
+	double ee[] = {-7,-5, -3, -1, 1,  3,  5,  7};
+	double ff[] = {0, 0.2,0.8,1.0,0.8,0.2,0.1,0};
+
+	dz->tempsize = dz->insams[0] * 2;
+	initrand48();
+	for(n=0;n<8;n++)
+		ee[n] *= 1.0/14.0;
+
+	if((dz->parray[SHUD_TIMES] = (double *)malloc(arraysz[0] * sizeof(double)))==NULL) {
+		sprintf(errstr,"Out of Memory While calculating Shudder Times\n");
+		return(MEMORY_ERROR);
+	}
+	if((dz->parray[SHUD_LEVEL] = (double *)malloc(arraysz[1] * sizeof(double)))==NULL) {
+		sprintf(errstr,"Out of Memory While calculating Shudder Levels\n");
+		return(MEMORY_ERROR);
+	}
+	if((dz->parray[SHUD_WIDTH] = (double *)malloc(arraysz[0] * sizeof(double)))==NULL) {
+		sprintf(errstr,"Out of Memory While calculating Shudder Widths\n");
+		return(MEMORY_ERROR);
+	}
+	if((dz->parray[SHUD_DEPTH] = (double *)malloc(arraysz[0] * sizeof(double)))==NULL) {
+		sprintf(errstr,"Out of Memory While calculating Shudder Widths\n");
+		return(MEMORY_ERROR);
+	}
+	if((drand48() * 2.0) - 1.0 <= 0.0)
+		left = 1;
+	else
+		left = -1;
+								/* Get TIME, and WIDTH of initial shudder */
+	time = dz->param[SHUD_STARTTIME];
+	if((exit_status = read_values_from_all_existing_brktables(time,dz))<0)
+		return(exit_status);
+	width = ((dz->param[SHUD_MAXWIDTH] - dz->param[SHUD_MINWIDTH]) * drand48()) + dz->param[SHUD_MINWIDTH];
+	dz->parray[SHUD_WIDTH][cnt] = width;
+	time = max(time,width/2.0);
+	dz->parray[SHUD_TIMES][cnt] = time;
+
+				/* From STEREO-POSITION and DEPTH, calculate L and R levels */
+	
+	pos = dz->param[SHUD_SPREAD] * drand48() * left;
+	pancalc(pos,&leftgain,&rightgain);
+	
+	depth = ((dz->param[SHUD_MAXDEPTH] - dz->param[SHUD_MINDEPTH]) * drand48()) + dz->param[SHUD_MINDEPTH];
+					/* SHUDDER is added to existing level */
+					/*... and will be automatically scaled by existing level when imposed on sound */
+	dz->parray[SHUD_DEPTH][cnt] = 1.0 - depth;
+	lgain = depth * leftgain;
+	rgain = depth * rightgain;
+	maxlevel = max(lgain,rgain);
+	dz->parray[SHUD_LEVEL][cnt2++] = lgain;
+	dz->parray[SHUD_LEVEL][cnt2++] = rgain;
+	left = -left;
+	cnt++;
+				/* get, time , width and L & R level for all shudders */
+	while(time < dz->duration) {
+		lasttime = time;
+		time = time + (1/dz->param[SHUD_FRQ]);	/* use frq from previous time, to calculate where next time is */
+		if((exit_status = read_values_from_all_existing_brktables(time,dz))<0)
+			return(exit_status);
+		nexttime = time + (1/dz->param[SHUD_FRQ]);
+		scat = ((drand48() * 2.0) - 1.0) * dz->param[SHUD_SCAT];
+		if(scat >= 0)
+			realtime = ((nexttime - time) * scat) + time;
+		else
+			realtime = time - ((time - lasttime) * scat);
+		width = ((dz->param[SHUD_MAXWIDTH] - dz->param[SHUD_MINWIDTH]) * drand48()) + dz->param[SHUD_MINWIDTH];
+		if((realtime <= (width/2.0) + FLTERR) || (realtime <= lastrealtime))
+			continue;
+		lastrealtime = realtime;
+		dz->parray[SHUD_TIMES][cnt] = realtime;
+		pos = dz->param[SHUD_SPREAD] * drand48() * left; 
+		left = -left;
+		pancalc(pos,&leftgain,&rightgain);
+		depth = ((dz->param[SHUD_MAXDEPTH] - dz->param[SHUD_MINDEPTH]) * drand48()) + dz->param[SHUD_MINDEPTH];
+		dz->parray[SHUD_DEPTH][cnt] = 1.0 - depth;
+		lgain = depth * leftgain;
+		rgain = depth * rightgain;
+		maxlevel = max(maxlevel,lgain);
+		maxlevel = max(maxlevel,rgain);
+		dz->parray[SHUD_LEVEL][cnt2++] = lgain;
+		dz->parray[SHUD_LEVEL][cnt2++] = rgain;
+		dz->parray[SHUD_WIDTH][cnt] = width;
+		if (++cnt >= arraysz[0]) {
+			arraysz[0] += SMALLARRAY;
+			if((dz->parray[SHUD_TIMES] = (double *)realloc((char *)dz->parray[SHUD_TIMES],arraysz[0] * sizeof(double)))==NULL) {
+				sprintf(errstr,"Out of Memory While calculating Shudder Times\n");
+				return(MEMORY_ERROR);
+			}
+			if((dz->parray[SHUD_WIDTH] = (double *)realloc((char *)dz->parray[SHUD_WIDTH],arraysz[0] * sizeof(double)))==NULL) {
+				sprintf(errstr,"Out of Memory While calculating Shudder Widths\n");
+				return(MEMORY_ERROR);
+			}
+			if((dz->parray[SHUD_DEPTH] = (double *)realloc((char *)dz->parray[SHUD_DEPTH],arraysz[0] * sizeof(double)))==NULL) {
+				sprintf(errstr,"Out of Memory While calculating Shudder Widths\n");
+				return(MEMORY_ERROR);
+			}
+		}
+		if (cnt2 >= arraysz[1]) {
+			arraysz[1] += SMALLARRAY;
+			if((dz->parray[SHUD_LEVEL] = (double *)realloc((char *)dz->parray[SHUD_LEVEL],arraysz[1] * sizeof(double)))==NULL) {
+				sprintf(errstr,"Out of Memory While calculating Shudder Levels\n");
+				return(MEMORY_ERROR);
+			}
+		}
+	}
+	if((dz->parray[SHUD_TIMES] = (double *)realloc((char *)dz->parray[SHUD_TIMES],cnt * sizeof(double)))==NULL) {
+		sprintf(errstr,"Out of Memory While calculating Shudder Times\n");
+		return(MEMORY_ERROR);
+	}
+	if((dz->parray[SHUD_WIDTH] = (double *)realloc((char *)dz->parray[SHUD_WIDTH],cnt * sizeof(double)))==NULL) {
+		sprintf(errstr,"Out of Memory While calculating Shudder Widths\n");
+		return(MEMORY_ERROR);
+	}
+	if((dz->parray[SHUD_DEPTH] = (double *)realloc((char *)dz->parray[SHUD_DEPTH],cnt * sizeof(double)))==NULL) {
+		sprintf(errstr,"Out of Memory While calculating Shudder Widths\n");
+		return(MEMORY_ERROR);
+	}
+	if((dz->parray[SHUD_LEVEL] = (double *)realloc((char *)dz->parray[SHUD_LEVEL],cnt2 * sizeof(double)))==NULL) {
+		sprintf(errstr,"Out of Memory While calculating Shudder Levels\n");
+		return(MEMORY_ERROR);
+	}
+	/* NORMALISE LEVELS */
+	for(m=0;m<cnt2;m++)
+		dz->parray[SHUD_LEVEL][m] /= maxlevel;
+
+	if((dz->parray[SHUD_ENV0] = (double *)malloc(((cnt * 16) + 4) * sizeof(double)))==NULL) {
+		sprintf(errstr,"Out of Memory While calculating Shudder Envelopes\n");
+		return(MEMORY_ERROR);
+	}
+	if((dz->parray[SHUD_ENV1] = (double *)malloc(((cnt * 16) + 4) * sizeof(double)))==NULL) {
+		sprintf(errstr,"Out of Memory While calculating Shudder Envelopes\n");
+		return(MEMORY_ERROR);
+	}
+	timecnt = 0;
+	levelcnt = 0;
+	cnt0 = 0;
+	cnt1 = 0;
+	basetime[0] = -1.0;
+	basetime[1] = -1.0;
+	arraysz[0] = SMALLARRAY;
+	arraysz[1] = SMALLARRAY;
+	while(timecnt< cnt) {
+		time  = dz->parray[SHUD_TIMES][timecnt];	
+		width = dz->parray[SHUD_WIDTH][timecnt];	
+		one_minus_depth = dz->parray[SHUD_DEPTH][timecnt];
+		levell = dz->parray[SHUD_LEVEL][levelcnt];
+		levelr = dz->parray[SHUD_LEVEL][levelcnt+1];
+		last_postk[0] = -1;
+		last_postk[1] = -1;
+		for(j=0;j<8;j++) {
+			envtime = time + (ee[j] * width);
+			envlevel = ((levell * ff[j]) + one_minus_depth) * safety;
+					/* safety compensates for centre boost given by pan-calculation */
+			insert_point_in_envelope(&(last_postk[0]),basetime[0],SHUD_ENV0,&cnt0,&(last_posttime[0]),&(last_postlevel[0]),
+				&(last_insertk[0]),&(last_inserttime[0]),&(last_insertlevel[0]),envtime,envlevel,dz);
+			envlevel = (levelr * ff[j]) + one_minus_depth;
+			insert_point_in_envelope(&(last_postk[1]),basetime[1],SHUD_ENV1,&cnt1,&(last_posttime[1]),&(last_postlevel[1]),
+				&(last_insertk[1]),&(last_inserttime[1]),&(last_insertlevel[1]),envtime,envlevel,dz);
+		
+		}
+		basetime[0] = dz->parray[SHUD_ENV0][cnt0-2];	/* last envelope time in array */
+		basetime[1] = dz->parray[SHUD_ENV1][cnt1-2];	/* last envelope time in array */
+
+		timecnt++;
+		levelcnt+=2;
+	}
+	if(dz->parray[SHUD_ENV0][0] <= FLTERR) {			/* Force points at ZERO and at DURATION+ */
+		dz->parray[SHUD_ENV0][0] = 0.0;
+		dz->parray[SHUD_ENV1][0] = 0.0;
+	} else {
+		for(n=cnt0-1;n>=0;n--)
+			dz->parray[SHUD_ENV0][n+2] = dz->parray[SHUD_ENV0][n];
+		for(n=cnt1-1;n>=0;n--)
+			dz->parray[SHUD_ENV1][n+2] = dz->parray[SHUD_ENV1][n];
+		dz->parray[SHUD_ENV0][0] = 0.0;
+		dz->parray[SHUD_ENV0][1] = dz->parray[SHUD_ENV0][3];
+		dz->parray[SHUD_ENV1][0] = 0.0;
+		dz->parray[SHUD_ENV1][1] = dz->parray[SHUD_ENV1][3];
+		cnt0 += 2;
+		cnt1 += 2;
+	}
+	if(dz->parray[SHUD_ENV0][cnt0 - 2] < dz->duration - FLTERR) {
+		dz->parray[SHUD_ENV0][cnt0] = dz->duration + FLTERR;
+		dz->parray[SHUD_ENV0][cnt0 + 1] = dz->parray[SHUD_ENV0][cnt0 - 1];
+		dz->parray[SHUD_ENV1][cnt1] = dz->duration + FLTERR;
+		dz->parray[SHUD_ENV1][cnt1 + 1] = dz->parray[SHUD_ENV1][cnt1 - 1];
+		cnt0 += 2;
+		cnt1 += 2;
+	}
+	if((dz->parray[SHUD_ENV0] = (double *)realloc((char *)dz->parray[SHUD_ENV0],cnt0 * sizeof(double)))==NULL) {
+		sprintf(errstr,"Out of Memory While calculating Shudder Envelopes\n");
+		return(MEMORY_ERROR);
+	}
+	if((dz->parray[SHUD_ENV1] = (double *)realloc((char *)dz->parray[SHUD_ENV1],cnt1 * sizeof(double)))==NULL) {
+		sprintf(errstr,"Out of Memory While calculating Shudder Envelopes\n");
+		return(MEMORY_ERROR);
+	}
+	dz->itemcnt = cnt0;			/* used to store counts */
+	dz->extrabrkno = cnt1;		/* used to store counts */
+	if((exit_status = apply_brkpnt_envelope(dz))<0)
+		return(exit_status);
+	return(FINISHED);
+}
+
+/************************************* INSERT_POINT_IN_ENVELOPE ***********************************/
+
+int insert_point_in_envelope(int *last_postk,double basetime,int thisenv,int *cnt,
+		double *last_posttime,double *last_postlevel,int *last_insertk,double *last_inserttime,double *last_insertlevel,
+		double envtime,double envlevel,dataptr dz)
+{
+	int k, j, last_pk;
+	double pretime, posttime, prelevel, postlevel, timestep, frac, levelhere, last_ptime, last_plevel;
+
+	if(envtime <= basetime) {
+		k = *cnt - 2;
+		while (dz->parray[thisenv][k] > envtime)
+			k -= 2;
+		pretime   = dz->parray[thisenv][k];
+		prelevel  = dz->parray[thisenv][k+1];
+		k += 2;
+		posttime  = dz->parray[thisenv][k];
+		postlevel = dz->parray[thisenv][k+1];
+		timestep = posttime - pretime;
+		frac      = (envtime - pretime)/timestep;
+		levelhere = ((postlevel - prelevel) * frac) + prelevel;
+		if(envlevel > levelhere) {
+			for(j = *cnt-1;j >= k; j--)				/* SHUFFLUP DATA ABOVE */
+				dz->parray[thisenv][j+2] = dz->parray[thisenv][j];
+			dz->parray[thisenv][k]   = envtime;	/* INSERT NEW POINT */
+			dz->parray[thisenv][k+1] = envlevel;
+			*cnt += 2;
+			if(*last_postk >= 0) {					/* IF POINTS HAVE ALREADY BEEN INSERTED */
+				timestep = dz->parray[thisenv][k] - dz->parray[thisenv][*last_insertk];
+				last_pk     = *last_postk;
+				last_ptime  = *last_posttime;		/* CHECK POINTS INTERVENING BETWEEN THIS AND LAST INSERT */
+				last_plevel = *last_postlevel;
+				while(envtime > last_ptime) {
+					frac = (last_ptime - *last_inserttime)/timestep;
+					levelhere = ((envlevel - *last_insertlevel) * frac) + *last_insertlevel;
+					if(levelhere > last_plevel)
+						dz->parray[thisenv][last_pk+1] = levelhere;
+					last_pk += 2;
+					last_ptime  = dz->parray[thisenv][last_pk];
+					last_plevel = dz->parray[thisenv][last_pk+1];
+				}
+			}
+			*last_insertk = k;						/* REMEMBER TIMES AND LEVELS OF LAST INSERT, AND POST-INSERT */
+			*last_inserttime  = dz->parray[thisenv][k];
+			*last_insertlevel = dz->parray[thisenv][k+1];
+			k +=2;
+			*last_postk = k;							
+			*last_posttime  = dz->parray[thisenv][k];
+			*last_postlevel = dz->parray[thisenv][k+1];
+		} else {
+			*last_postk = -1;
+		}
+	} else {
+		dz->parray[thisenv][(*cnt)++]   = envtime;
+		dz->parray[thisenv][(*cnt)++]   = envlevel;
+		*last_postk = -1;
+	}
+	return(FINISHED);
+}
+
+/******************************* APPLY_BRKPNT_ENVELOPE *******************************/
+
+int apply_brkpnt_envelope(dataptr dz)
+{
+	int exit_status, ofd0, ofd1;
+	long startsamp = 0, samps_left_to_process = dz->insams[0], sampout_cnt;
+	long sampno, nextbrk_sampno;
+	double starttime, gain, nextgain, gain_step, gain_incr, multiplier0 = 0.0, multiplier1 = 0.0;
+	double *endbrk, *nextbrk; 
+	long total_samps_to_read, n, j, k,samps_to_read_here;
+	int chan;
+	float maxobuf0, maxobuf1;
+	char *outfilename;
+
+	if(sloom) {
+		if((outfilename = (char *)malloc((strlen(dz->wordstor[0])+1) * sizeof(char)))==NULL) {
+			sprintf(errstr,"INSUFFICIENT MEMORY for outfilename.\n");
+			return(MEMORY_ERROR);
+		}				
+	} else {
+		if((outfilename = (char *)malloc((strlen(dz->outfilename)+1) * sizeof(char)))==NULL) {
+			sprintf(errstr,"INSUFFICIENT MEMORY for outfilename.\n");
+			return(MEMORY_ERROR);
+		}				
+	}
+										/* ENVELOPE CHANNEL 1 */
+	chan = 0;
+	maxobuf0 = 0.0f;
+	if((exit_status = do_simple_read(&samps_left_to_process,dz->buflen,chan,dz))<0)
+		return(exit_status);								/* setup simple buffering option */
+	if((exit_status = init_brkpnts
+	(&sampno,&starttime,&gain,&endbrk,&nextbrk,&nextgain,&gain_step,&gain_incr,&nextbrk_sampno,SHUD_ENV0,dz->itemcnt,dz))<0)
+		return(exit_status);
+	if((exit_status = simple_envel_processing(&samps_left_to_process,starttime,endbrk,&nextbrk,&nextgain,
+		&sampno,&gain,&gain_step,&gain_incr,&nextbrk_sampno,chan,&maxobuf0,dz))<0)
+		return(exit_status);
+										/* STORE CHANNEL 1 OUTFILE */
+	ofd0 = dz->ofd;
+										/* CREATE CHANNEL 2 OUTFILE */
+	if(sloom) {
+		strcpy(outfilename,dz->wordstor[0]);
+		insert_new_number_at_filename_end(outfilename,2,1);
+	} else {
+		strcpy(outfilename,dz->outfilename);
+		insert_new_number_at_filename_end(outfilename,2,1);
+	}
+	sampout_cnt = dz->total_samps_written;
+
+	if((exit_status = create_sized_outfile(outfilename,dz))<0) {
+		dz->ofd = ofd0;
+		return(SYSTEM_ERROR);
+	}
+	dz->total_samps_written = sampout_cnt;
+										/* RESET INFILE TO START */
+	sndseekEx(dz->ifd[0],0,0);
+	startsamp = 0;
+	samps_left_to_process = dz->insams[0];
+
+										  /* ENVELOPE CHANNEL 2 */
+	chan = 1;
+	maxobuf1 = 0.0f;
+	if((exit_status = do_simple_read(&samps_left_to_process,dz->buflen,chan,dz))<0)
+		return(exit_status);								/* setup simple buffering option */
+	if((exit_status = init_brkpnts
+	(&sampno,&starttime,&gain,&endbrk,&nextbrk,&nextgain,&gain_step,&gain_incr,&nextbrk_sampno,SHUD_ENV1,dz->extrabrkno,dz))<0)
+		return(exit_status);
+	if((exit_status = simple_envel_processing(&samps_left_to_process,starttime,endbrk,&nextbrk,&nextgain,
+		&sampno,&gain,&gain_step,&gain_incr,&nextbrk_sampno,chan,&maxobuf1,dz))<0)
+		return(exit_status);
+										/* STORE CHANNEL 2 OUTFILE */
+	ofd1 = dz->ofd;
+										 /* CREATE STEREO OUTFILE */
+	strcpy(outfilename,dz->wordstor[0]);
+	if(sloom)
+		insert_new_number_at_filename_end(outfilename,0,1);
+	else
+		outfilename[strlen(outfilename) -9] = ENDOFSTR;
+
+	sampout_cnt = dz->total_samps_written;
+	if((exit_status = create_sized_outfile(outfilename,dz))<0) {
+		unlink_temp_files(1,ofd0,ofd1,dz);
+		return(SYSTEM_ERROR);
+	}
+	if((exit_status = reset_peak_finder(dz))<0)
+		return(exit_status);
+	dz->total_samps_written = sampout_cnt;
+									/* RESET BOTH CHANNEL-FILES TO START */
+	sndseekEx(ofd0,0,0);
+	sndseekEx(ofd1,0,0);
+	total_samps_to_read = dz->insams[0]/2;
+
+								/* MERGE SEPARATE CHANNELS BACK INTO STEREO */
+	if(dz->vflag[SHUD_BALANCE]) {
+		if(((maxobuf0 > maxobuf1) && (maxobuf0/maxobuf1 < ONE_dB)) 
+		|| (maxobuf1/maxobuf0 < ONE_dB))
+			dz->vflag[0] = 0;
+		else if(maxobuf0 > maxobuf1) {
+			multiplier1 = maxobuf0/maxobuf1;
+		} else {
+			multiplier1 = -1.0;
+			multiplier0 = maxobuf1/maxobuf0;
+		}
+	}
+	while(total_samps_to_read > 0) {
+		samps_to_read_here = min(total_samps_to_read,dz->buflen);
+		if((exit_status = other_read_samps(samps_to_read_here,ofd0,0,dz))<0) {
+			unlink_temp_files(2,ofd0,ofd1,dz);
+			return(exit_status);
+		}
+		if((exit_status = other_read_samps(samps_to_read_here,ofd1,1,dz))<0) {
+			unlink_temp_files(2,ofd0,ofd1,dz);
+			return(exit_status);
+		}
+		if(dz->vflag[SHUD_BALANCE]) {
+			if(multiplier1 > 0.0) {
+				for(n=0,j=0,k=1;n<dz->ssampsread;n++,j+=2,k+=2) {
+					dz->sampbuf[2][j] = dz->sampbuf[0][n];
+					dz->sampbuf[2][k] = (float)(dz->sampbuf[1][n] * multiplier1);
+				}
+			} else {
+				for(n=0,j=0,k=1;n<dz->ssampsread;n++,j+=2,k+=2) {
+					dz->sampbuf[2][j] = (float)(dz->sampbuf[0][n] * multiplier0);
+					dz->sampbuf[2][k] = dz->sampbuf[1][n];
+				}
+			}
+		} else {
+			for(n=0,j=0,k=1;n<dz->ssampsread;n++,j+=2,k+=2) {
+				dz->sampbuf[2][j] = dz->sampbuf[0][n];
+				dz->sampbuf[2][k] = dz->sampbuf[1][n];
+			}
+		}
+		if(dz->ssampsread > 0) {
+			if((exit_status = write_samps(dz->sampbuf[2],dz->ssampsread * 2,dz))<0) {
+				unlink_temp_files(2,ofd0,ofd1,dz);
+				return(exit_status);
+			}
+		}
+		total_samps_to_read -= dz->ssampsread;
+	}
+										/* DELETE TEMPORARY OUTFILES */
+	unlink_temp_files(2,ofd0,ofd1,dz);
+	return FINISHED;
+}
+
+/**************************** INIT_BRKPNTS ********************************/
+
+int init_brkpnts(long *sampno,double *starttime,double *gain,double **endbrk,double **nextbrk,
+double *nextgain,double *gain_step,double *gain_incr,long *nextbrk_sampno,int paramno,int brksize,dataptr dz)
+{
+	double nexttime, time_from_start;
+	*endbrk    = dz->parray[paramno] + ((brksize-1) * 2);
+	*sampno    = 0;
+	*starttime = dz->parray[paramno][0];
+	*gain      = dz->parray[paramno][1];
+	*nextbrk   = dz->parray[paramno] + 2;
+	nexttime   = **nextbrk;
+	*nextgain  = *((*nextbrk) + 1);
+	*gain_step = *nextgain - *gain;
+	time_from_start = nexttime - *starttime;
+	if((*nextbrk_sampno  = (long)round(time_from_start * (double)dz->infile->srate))<0) {
+		sprintf(errstr,"Impossible brkpoint time: (%.2lf secs)\n",time_from_start);
+		return(PROGRAM_ERROR);
+	}
+	*gain_incr = (*gain_step)/(double)(*nextbrk_sampno);
+	return(FINISHED);
+}
+
+/**************************** ADVANCE_BRKPNTS ******************************/
+
+int advance_brkpnts(double starttime,double *gain,double *endbrk,double **nextbrk,
+double *nextgain,double *gain_step,double *gain_incr,long *nextbrk_sampno,dataptr dz)
+{
+	double  nexttime, time_from_start;
+	long   lastbrk_sampno, sampdist;
+	if(*nextbrk!=endbrk) {
+		*nextbrk   += 2;
+		*gain      = *nextgain;
+		nexttime   = **nextbrk;
+		*nextgain  = *((*nextbrk) + 1);
+		*gain_step = *nextgain - *gain;
+		lastbrk_sampno = *nextbrk_sampno;
+		time_from_start = nexttime - starttime;
+		if((*nextbrk_sampno  = (long)round(time_from_start * dz->infile->srate))<0) {
+			sprintf(errstr,"Impossible brkpoint time: (%.2lf secs)\n",time_from_start);
+			return(PROGRAM_ERROR);
+		}
+		sampdist   = *nextbrk_sampno - lastbrk_sampno;
+		*gain_incr = (*gain_step)/(double)sampdist;
+	}
+	return(FINISHED);
+}
+
+/*********************** SIMPLE_ENVEL_PROCESSING *********************************/
+
+int simple_envel_processing
+(long *samps_left_to_process,double starttime,double *endbrk,double **nextbrk,double *nextgain,
+long *sampno,double *gain,double *gain_step,double *gain_incr,long *nextbrk_sampno,int chan,float *maxobuf,dataptr dz)
+{
+	int exit_status;
+	while(*samps_left_to_process > 0) {
+		if((exit_status = do_mono_envelope
+		(dz->buflen,starttime,endbrk,nextbrk,nextgain,sampno,gain,gain_step,gain_incr,nextbrk_sampno,maxobuf,dz))<0)
+			return(exit_status);
+		if((exit_status = write_samps(dz->sampbuf[1],dz->buflen,dz))<0)
+			return(exit_status);
+		if((exit_status = do_simple_read(samps_left_to_process,dz->buflen,chan,dz))<0)
+			return(exit_status);
+	}
+	if((exit_status = do_mono_envelope
+	(dz->ssampsread,starttime,endbrk,nextbrk,nextgain,sampno,gain,gain_step,gain_incr,nextbrk_sampno,maxobuf,dz))<0)
+		return(exit_status);
+	if(dz->ssampsread > 0)
+		return write_samps(dz->sampbuf[1],dz->ssampsread,dz);
+	return FINISHED;
+}
+
+/************************* DO_MONO_ENVELOPE *********************************/
+
+int do_mono_envelope
+(long sampcnt,double starttime,double *endbrk,double **nextbrk,double *nextgain,
+long *sampno,double *gain,double *gain_step,double *gain_incr,long *nextbrk_sampno,float *maxobuf,dataptr dz)
+{
+	int    exit_status;
+	long   n;
+	long   endsampno, this_endsamp, this_sampcnt;
+	float  *ibuf = dz->sampbuf[0];
+	float  *obuf = dz->sampbuf[1];
+	float  *obufend = obuf + dz->buflen;
+	int    quit = FALSE, change;
+	double this_gain      = *gain;
+	double this_gain_incr = *gain_incr;
+	double this_gain_step = *gain_step;
+	endsampno = *sampno + sampcnt;				/* 1 */
+	if(sampcnt > dz->buflen) {
+		sprintf(errstr,"Buffering anomaly: do_mono_envelope()\n");
+		return(PROGRAM_ERROR);
+	}
+	while(quit==FALSE) {						
+		if(*nextbrk_sampno <= endsampno) {		/* 2 */
+			change = TRUE;
+			this_endsamp = *nextbrk_sampno;		/* 3 */
+			if(*nextbrk_sampno==endsampno)		
+				quit = TRUE;					/* 4 */
+		} else {
+			change = FALSE;						/* 5 */
+			this_endsamp = endsampno;
+			quit = TRUE;
+		}
+		this_sampcnt = this_endsamp - *sampno;	/* 6 */
+		if(obuf + this_sampcnt > obufend) {
+			sprintf(errstr,"array overrun: do_mono_envelope()\n");
+			return(PROGRAM_ERROR);
+		}
+		if(flteq(this_gain,1.0) && flteq(this_gain_step,0.0)) {
+			obuf += this_sampcnt;				
+			ibuf += this_sampcnt;				/* no modification of sound */
+		}
+		else {
+			
+			for(n=0;n<this_sampcnt;n++) {		/* 7 */
+				this_gain += this_gain_incr;
+				*obuf = (float)(*ibuf * this_gain);
+				*maxobuf = max(*maxobuf,*obuf);
+				obuf++;
+				ibuf++;
+			}
+		}
+		*sampno += this_sampcnt;				/* 8 */
+		if(change) {							/* 9 */
+			if((exit_status = advance_brkpnts
+			(starttime,gain,endbrk,nextbrk,nextgain,gain_step,gain_incr,nextbrk_sampno,dz))<0)
+				return(exit_status);
+			this_gain = *gain;
+			this_gain_incr = *gain_incr;
+			this_gain_step = *gain_step;
+		}
+	}
+	*gain = this_gain;							/* 10 */
+	return(FINISHED);
+}
+
+/************************* READ_SSAMPS ******************************/
+
+int read_ssamps(long samps_to_read,long *samps_left_to_process,int chan,dataptr dz)
+{
+	long n, m;
+	if((dz->ssampsread = fgetfbufEx(dz->sampbuf[2],samps_to_read,dz->ifd[0],0))<0) {
+		sprintf(errstr,"Can't read samps from input soundfile: read_ssamps()\n");
+		return(SYSTEM_ERROR);
+	}
+	if(dz->ssampsread!=samps_to_read) {
+		sprintf(errstr,"Error in buffering arithmetic: read_ssamps()\n");
+		return(PROGRAM_ERROR);
+	}
+	*samps_left_to_process -= dz->ssampsread;
+	dz->ssampsread /= 2;
+	for(n=0,m=chan;n<dz->ssampsread;n++,m+=2)
+		dz->sampbuf[0][n] = dz->sampbuf[2][m];
+	return(FINISHED);
+}
+
+/******************************** DO_SIMPLE_READ **********************************/
+
+int do_simple_read(long *samps_left_to_process,long buflen,int chan,dataptr dz)
+{
+	int exit_status;
+	if(*samps_left_to_process < buflen * 2)
+		exit_status = read_ssamps(*samps_left_to_process,samps_left_to_process,chan,dz);
+	else
+		exit_status = read_ssamps(buflen * 2,samps_left_to_process,chan,dz);
+	return(exit_status);
+}
+
+/**************************** OTHER_READ_SAMPS *****************************/
+
+int other_read_samps(long samps_to_read,int fileid,int bufno,dataptr dz)
+{
+	if((dz->ssampsread = fgetfbufEx(dz->sampbuf[bufno],samps_to_read,fileid,0)) < 0) {
+		sprintf(errstr,"Can't read samps from input soundfile: other_read_samps()\n");
+		return(SYSTEM_ERROR);
+	}
+	if(dz->ssampsread < samps_to_read) {
+		sprintf(errstr,"Error in buffering arithmetic: other_read_samps()\n");
+		return(PROGRAM_ERROR);
+	}
+	return(FINISHED);
+}
+							  
+/**************************** UNLINK_TEMP_FILES *****************************/
+
+void unlink_temp_files(int type,int ofd0, int ofd1,dataptr dz)
+{
+	switch(type) {
+	case(1):
+		if(sndunlink(ofd1) < 0)
+			fprintf(stdout, "ERROR: Can't set temporary output soundfile for deletion.\n");
+		if(sndcloseEx(ofd1) < 0)
+			fprintf(stdout, "WARNING: Can't close temporary output soundfile.\n");
+		else
+			ofd1 = -1;
+		dz->ofd = ofd0;		/* closed at finish() */
+		break;
+	case(2):
+		if(sndunlink(ofd0) < 0)
+			fprintf(stdout, "ERROR: Can't set 1st temporary output soundfile for deletion.\n");
+		if(sndcloseEx(ofd0) < 0)
+			fprintf(stdout, "WARNING: Can't close 1st temporary output soundfile.\n");
+		else
+			ofd0 = -1;
+		if(sndunlink(ofd1) < 0)
+			fprintf(stdout, "ERROR: Can't set 2nd temporary output soundfile for deletion.\n");
+		if(sndcloseEx(ofd1) < 0)
+			fprintf(stdout, "WARNING: Can't close 2nd temporary output soundfile.\n");
+		else
+			ofd1 = -1;
+		break;
+	}
+}
+
+/************************************ FINDPAN *******************************/
+
+int findpan(dataptr dz)
+{  
+	int exit_status;
+	long n, m, k, samppos, secpos;
+	double panpos;
+	float *inbuf = dz->sampbuf[0];
+	float maxL = 0.0, maxR = 0.0;
+	if(dz->param[PAN_PAN] > 0.0) {		/* Assesses One Sector at given time */
+		samppos =  round(dz->param[PAN_PAN] * dz->infile->srate) * dz->infile->channels;
+		secpos = samppos;
+		if (secpos >= dz->insams[0]) {
+			if((secpos -= F_SECSIZE) < 0)
+				secpos = 0;
+		}
+		secpos = (secpos/F_SECSIZE) * F_SECSIZE;
+		sndseekEx(dz->ifd[0],secpos,0);
+		if((exit_status = read_samps(inbuf,dz))<0) {
+			sprintf(errstr,"Failed to read data from sndfile.\n");
+			return(DATA_ERROR);
+		}
+		k = min(dz->ssampsread,F_SECSIZE);
+		for(n=0,m=1;n<k;n+=2,m+=2) {
+			maxL = (float)max(fabs(inbuf[n]),maxL);
+			maxR = (float)max(fabs(inbuf[m]),maxR);
+		}
+	} else {							/* Assesses whole file */
+		do {
+			if((exit_status = read_samps(inbuf,dz))<0) {
+				sprintf(errstr,"Failed to read data from sndfile.\n");
+				return(DATA_ERROR);
+			}
+			for(n=0,m=1;n<dz->ssampsread;n+=2,m+=2) {
+				maxL = (float)max(fabs(inbuf[n]),maxL);
+				maxR = (float)max(fabs(inbuf[m]),maxR);
+			}
+		} while(dz->samps_left > 0);
+	}
+	if(maxL < SMP_FLTERR && maxR < SMP_FLTERR)
+		fprintf(stdout,"INFO: levels are ZERO\n");
+	else {				
+		panpos = maxR/(maxR + maxL);
+		panpos = (panpos * 2.0) - 1.0;
+		fprintf(stdout,"INFO: levels LEFT %.3lf RIGHT %.3lf : Panning position is %.2lf\n",maxL,maxR,panpos);
+	}
+	fflush(stdout);
+	return(FINISHED);
+}
+
+

+ 2019 - 0
dev/modify/radical.c

@@ -0,0 +1,2019 @@
+/*
+ * Copyright (c) 1983-2013 Trevor Wishart and Composers Desktop Project Ltd
+ * http://www.trevorwishart.co.uk
+ * http://www.composersdesktop.com
+ *
+ This file is part of the CDP System.
+
+    The CDP System is free software; you can redistribute it
+    and/or modify it under the terms of the GNU Lesser General Public
+    License as published by the Free Software Foundation; either
+    version 2.1 of the License, or (at your option) any later version.
+
+    The CDP System is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public
+    License along with the CDP System; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+    02111-1307 USA
+ *
+ */
+
+
+
+/* floatsam version */
+#include <stdio.h>
+#include <stdlib.h>
+#include <memory.h>
+#include <string.h>
+#include <structures.h>
+#include <tkglobals.h>
+#include <globcon.h>
+#include <arrays.h>
+#include <cdpmain.h>
+#include <modify.h>
+#include <modeno.h>
+
+//TW UPDATES
+#include <arrays.h>
+#include <flags.h>
+#include <sfsys.h>
+#include <osbind.h>
+
+#if defined unix || defined __GNUC__
+#define round(x) lround((x))
+#endif
+
+#ifndef HUGE
+#define HUGE 3.40282347e+38F
+#endif
+
+//extern int snd_makepath(char path[],const char *sfname);
+extern char *get_other_filename_x(char *filename,char c);
+
+#define SCRUB_FORWARDS  (TRUE)
+#define SCRUB_BACKWARDS (FALSE)
+#define SCRUB_SAFE (.66)
+
+static void reverse_the_buffer(float *ibuf,int chans,long ssampsread);
+static int  do_lowbit(float *maxsamp,float *postmaxsamp,dataptr dz);
+static int do_lowbit2(dataptr dz);
+
+static int  shred(int current_buf,int work_len,dataptr dz);
+static int  get_basis_lengths(int *worklen,dataptr dz);
+static void normal_scat(dataptr dz);
+static void heavy_scat(dataptr dz);
+static void permute_chunks(dataptr dz);
+static void insert(int n,int t,dataptr dz);
+static void prefix(int n,dataptr dz);
+static void shuflup(int k,dataptr dz);
+static void do_startsplice(float *i,float *j,dataptr dz);
+static void do_endsplice(float *i,float *j,dataptr dz);
+static void do_bufend_splices(int current_buf,dataptr dz);
+static void ptr_sort(int end,dataptr dz);
+static int  check_for_too_small_buf(dataptr dz);
+
+static int 	  create_sintable(dataptr dz);
+static double get_skew(void);
+static void   get_speed(double *lospeed,double *speedrang,dataptr dz);
+static void   get_end(int *direction,int *here,dataptr dz);
+static int	  gen_readtab(double skew,double lospeed,double speedrange,int scrublen_in_src,dataptr dz);
+static int 	  scrub(int *hhere,int *tthere,int direction,int effective_tablen,dataptr dz);
+static int 	  read_samps_for_scrub(int bufno,dataptr dz);
+
+static double read_rmod_tab(double dtabindex,dataptr dz);
+
+//TW UPDATES (converted to flotsams)
+static int get_obuf_sampoffset(int n,dataptr dz);
+static int transpos_and_add_to_obuf(int n,int *obufpos,double *inbufpos,float *lastival,int chans,dataptr dz);
+
+/******************************* CREATE_REVERSING_BUFFERS *******************************/
+
+int create_reversing_buffers(dataptr dz)
+{
+//TW BIG SIMPLIFICATION as buffer sector-alignment abolished
+	size_t bigbufsize;
+	bigbufsize = (size_t) Malloc(-1);
+	dz->buflen = (int)(bigbufsize / sizeof(float));
+	dz->buflen = (dz->buflen / dz->infile->channels) * dz->infile->channels;
+
+	dz->iparam[REV_BUFCNT] = dz->insams[0]/dz->buflen;
+	if(dz->iparam[REV_BUFCNT] > 0)
+		dz->iparam[REV_RSAMPS] 	  = dz->insams[0] - (dz->iparam[REV_BUFCNT] * dz->buflen);
+	if((dz->bigbuf = (float *)malloc(dz->buflen * sizeof(float)))==NULL) {
+		sprintf(errstr,"INSUFFICIENT MEMORY for sound buffers.\n");
+		return(MEMORY_ERROR);
+	}
+	dz->sampbuf[0] = dz->bigbuf; 
+	return FINISHED;
+}
+
+/******************************* DO_REVERSING *******************************/
+
+int do_reversing(dataptr dz)
+{
+//TW BIG SIMPLIFICATION as buffer sector-alignment abolished
+	int exit_status;
+	float *buf = dz->sampbuf[0];
+	int chans  = dz->infile->channels;
+	int nbuffs = dz->iparam[REV_BUFCNT];
+	int thisbufsamps;
+
+	if(nbuffs <=0) {
+		if((exit_status = read_samps(buf,dz)) < 0) {
+			sprintf(errstr,"Failed (1) to read input file.\n");
+			return(PROGRAM_ERROR);
+		}
+		if(dz->ssampsread != dz->insams[0]) {
+			sprintf(errstr,"Bad accounting.\n");
+			return(PROGRAM_ERROR);
+		}
+		reverse_the_buffer(buf,chans,dz->ssampsread);
+		if(dz->ssampsread > 0) {
+			if((exit_status = write_samps(buf,dz->ssampsread,dz)) < 0) {
+				sprintf(errstr,"Failed (1) to write to output file.");
+				return(PROGRAM_ERROR);
+			}
+		}
+	} else {
+		thisbufsamps = dz->insams[0] - dz->iparam[REV_RSAMPS];
+		if((sndseekEx(dz->ifd[0], thisbufsamps, 0)) < 0) {
+			sprintf(errstr,"Reverse: failed to seek to point in file\n");
+			return(SYSTEM_ERROR);
+		}
+		if((thisbufsamps -= dz->buflen)<0) {	/* ready for next iteration */
+			sprintf(errstr,"Bad accounting 1.\n");
+			return(PROGRAM_ERROR);
+		}
+
+		if((exit_status = read_samps(buf,dz)) < 0) {
+			sprintf(errstr,"Failed (1a) to read input file\n");
+			return(PROGRAM_ERROR);
+		}
+		if(dz->ssampsread != dz->iparam[REV_RSAMPS]) {
+			sprintf(errstr,"Bad accounting 2.\n");
+			return(PROGRAM_ERROR);
+		}
+
+		reverse_the_buffer(buf,chans,dz->ssampsread);
+
+		if(dz->ssampsread > 0) {
+			if((write_samps(buf, dz->ssampsread,dz)) < 0) {	/* writes (truncated number of) whole sector */
+				sprintf(errstr,"Failed (1a) to write to output file");
+				return(SYSTEM_ERROR);
+			}
+		}
+		while(nbuffs>0) {
+			if((sndseekEx(dz->ifd[0], thisbufsamps, 0)) < 0) {
+				sprintf(errstr,"Reverse: failed to seek to point in file.\n");
+				return(SYSTEM_ERROR);
+			}
+			if((exit_status = read_samps(buf,dz)) < 0) {
+				sprintf(errstr,"Failed (1b) to read input file\n");
+				return(PROGRAM_ERROR);
+			}
+			if(dz->ssampsread != dz->buflen) {
+				sprintf(errstr,"Bad accounting 3.\n");
+				return(PROGRAM_ERROR);
+			}
+			nbuffs--;
+			if(nbuffs>0 && (thisbufsamps -= dz->buflen)<0) {	/* ready for next iteration */
+				sprintf(errstr,"Bad accounting 4.\n");
+				return(PROGRAM_ERROR);
+			}
+			reverse_the_buffer(buf,chans,dz->ssampsread);
+
+			if(dz->ssampsread > 0) {
+				if((exit_status = write_exact_samps(buf,dz->ssampsread,dz)) < 0) {	
+					sprintf(errstr,"Failed (1b) to write to output file");
+					return(PROGRAM_ERROR);
+				}
+			}
+		}
+	}
+	return(FINISHED);
+}
+			
+/******************************* REVERSE_THE_BUFFER *******************************/
+
+void reverse_the_buffer(float *ibuf,int chans,long ssampsread)
+{	
+	int half_ssampsread = ((ssampsread/chans)/2) * chans;
+	int n, m, k;
+	float temp;
+	for(n = 0,m = ssampsread-chans;n< half_ssampsread;n+=chans,m-=chans) {
+		for(k=0;k<chans;k++) {
+			temp      = ibuf[n+k];
+			ibuf[n+k] = ibuf[m+k];
+			ibuf[m+k] = temp;
+		}
+	}
+}
+
+/***************************** LOBIT_PCONSISTENCY *************************/
+
+int lobit_pconsistency(dataptr dz)
+{
+	int garf = 1;
+	int m;
+	SFPROPS props = {0};
+	if(!snd_headread(dz->ifd[0],&props)) {
+		fprintf(stdout,"Failure to read sample size\n");
+		fflush(stdout);
+		return(DATA_ERROR);
+	}
+	
+//TW ADDED
+	dz->iparam[LOBIT_BRES_SHIFT] = 0;
+
+	if(dz->iparam[LOBIT_BRES]!=MAX_BIT_DIV) {
+    	dz->iparam[LOBIT_BRES] = MAX_BIT_DIV - dz->iparam[LOBIT_BRES];
+//TW DISCOVERED ERROR
+//	    garf = 1;
+	    garf = 2;
+	    for(m=1;m<dz->iparam[LOBIT_BRES];m++)
+			garf *= 2;
+    	dz->iparam[LOBIT_BRES] = garf;
+//TW SIMPLIFIED, removed shift arithmetic
+	}
+//TW ADDED non-16-bit cases
+
+	switch(props.samptype) {
+	case(0):	/* SHORT8 */			
+	case(7):	/* INT_MASKED */
+		sprintf(errstr,"Process does not work with 8-bit files.\n");
+		return(DATA_ERROR);
+	case(1):	/* SHORT16 */	break;
+	case(2):	/* FLOAT32 */
+	case(3):	/* INT_32 */	dz->iparam[LOBIT_BRES] *= (256 * 256);	break;
+	case(4):	/* INT2424 */	
+	case(5):	/* INT2432 */	dz->iparam[LOBIT_BRES] *= 256;			break;
+	case(6):	/* INT2024 */	dz->iparam[LOBIT_BRES] *= 16;			break;
+	default:
+		sprintf(errstr,"Unknown sample type.\n");
+		return(DATA_ERROR);
+	}
+//TW SIMPLIFIED, removed shift arithmetic for the time averaging
+	return(FINISHED);
+}
+
+/****************************** LOBIT_PROCESS *************************/
+
+int lobit_process(dataptr dz)
+{   
+	int exit_status;
+	float *buffer = dz->sampbuf[0];
+	float maxsamp = 0.0, postmaxsamp = 0.0;
+	display_virtual_time(0L,dz);
+	if(dz->mode == MOD_LOBIT)
+		dz->buflen = (dz->buflen / (dz->iparam[LOBIT_TSCAN] * dz->infile->channels)) * dz->iparam[LOBIT_TSCAN] * dz->infile->channels;
+	while(dz->samps_left != 0) {
+		if((exit_status = read_samps(buffer,dz))<0)
+			return(exit_status);
+		switch(dz->mode) {
+		case(MOD_LOBIT):
+			if((exit_status = do_lowbit(&maxsamp,&postmaxsamp,dz))<0)
+				return(exit_status);
+			break;
+		case(MOD_LOBIT2):
+			if((exit_status = do_lowbit2(dz))<0)
+				return(exit_status);
+			break;
+		}
+		if(dz->ssampsread > 0) {
+			if((exit_status = write_exact_samps(buffer,dz->ssampsread,dz))<0)
+				return(exit_status);
+		}
+    }
+	return(FINISHED);
+}
+
+/**************************** DO_LOWBIT ***************************/
+
+int do_lowbit(float *maxsamp,float *postmaxsamp,dataptr dz)
+{   
+	register int i, j;
+	double x, maxsampval;
+	int k, todo_samples;
+	int n;
+//TW MODIFIED FOR floats and non-16-bit sndfile formats
+	float *buffer = dz->sampbuf[0];
+	int tscan     = dz->iparam[LOBIT_TSCAN];
+	int bres      = dz->iparam[LOBIT_BRES];
+	int chans	  = dz->infile->channels;
+	SFPROPS props = {0};
+	
+	if(!snd_headread(dz->ifd[0],&props)) {
+		fprintf(stdout,"Failure to read sample size\n");
+		fflush(stdout);
+		return(DATA_ERROR);
+	}
+	switch(props.samptype) {
+	case(1):	/* SHORT16 */	maxsampval = MAXSAMP;		break;
+	case(2):	/* FLOAT32 */
+	case(3):	/* INT_32 */	maxsampval = 2147483647.0;	break;
+	case(4):	/* INT2424 */	
+	case(5):	/* INT2432 */	maxsampval = 8388607.0;		break;
+	case(6):	/* INT2024 */	maxsampval = 524287.0;		break;
+	/*RWD April 2004: need a default case; may add new formats one day! */
+		/* OR: make one of the above cases the default... */
+	default:
+		fprintf(stdout,"Unsupported sample type\n");
+		fflush(stdout);
+		return(DATA_ERROR);
+	/* other cases rejected earlier */
+	}
+	if(tscan!=1) {
+        if((todo_samples = (dz->ssampsread/(tscan * chans)) * tscan * chans) != dz->ssampsread) {
+		    for(i = todo_samples;i<dz->ssampsread;i++)
+		        buffer[i] = 0.0f;
+	    	dz->ssampsread = todo_samples;
+		}
+    }
+//TW MODIFIED to include non-16-bit cases, & files that are not mono
+	for(i = 0; i < dz->ssampsread; i += (tscan * chans))  {
+		for(n=0;n < chans; n++) {
+			x = 0.0;
+			k = i + n + (tscan * chans);
+			for(j = i+n;j < k; j+= chans) {
+				*maxsamp = (float) max(*maxsamp,fabs(buffer[j]));
+				x += buffer[j];
+			}
+			x /= tscan;					/* Take a time average */
+			x *= maxsampval;			/* convert to 'integer' range */
+			x /= bres;
+			x  = (double)round(x);		/* do a rounding mod bres */
+			x *= bres;
+			x /= maxsampval;
+			x = min(x,1.0);
+			x = max(x,-1.0);
+			k = min(k,dz->ssampsread);
+			for(j = i+n;j < k; j+= chans) {
+				buffer[j] = (float)x;	/* reconvert to float range */
+				*postmaxsamp = (float) max(*postmaxsamp,fabs(buffer[j]));
+			}
+		}
+	}
+	return(FINISHED);
+}
+
+/**************************** DO_LOWBIT2 ***************************/
+
+int do_lowbit2(dataptr dz)
+{   
+	int n;
+//TW MODIFIED FOR floats and non-16-bit sndfile formats
+	float *buffer = dz->sampbuf[0];
+	double samp;
+	int srcbits = 16;	// We assume src is quasi-16bit
+	int nbits   = dz->iparam[LOBIT_BRES];
+	int rescalebits = srcbits - nbits;
+	double rescalefac = pow(2.0,rescalebits);
+	for(n = 0; n < dz->ssampsread; n++) {
+		samp = buffer[n] * 32767.0;		//	prescale to 16-bit range
+		if(samp <= -32767.0)	
+			samp = -32767.0;	//	keep within range
+		// do mid-rise quantisation
+		samp /= rescalefac;
+		samp = round(samp+0.5) - 0.5;	//	round to a multiple of 0.5
+		samp *= rescalefac;
+		// rescale back to float 0-1 representation 
+		buffer[n] = (float)(samp/32768.0);
+	}
+	return FINISHED;
+}
+
+/***************************** SHRED_PCONSISTENCY *************************/
+
+int shred_pconsistency(dataptr dz)
+{
+	int chans = dz->infile->channels;
+	double duration = (double)(dz->insams[0]/chans)/(double)dz->infile->srate;
+    initrand48();
+	dz->iparam[SHR_CHCNT] = round(duration/dz->param[SHRED_CHLEN]);
+	if(dz->param[SHRED_SCAT] > (double)dz->iparam[SHR_CHCNT]) {
+		sprintf(errstr,"Scatter value cannot be greater than infileduration/chunklength.\n");
+		return(DATA_ERROR);
+	}    
+	if(dz->param[SHRED_SCAT] > 1.0)
+		dz->iparam[SHRED_SCAT] = round(dz->param[SHRED_SCAT]);
+	else
+		dz->iparam[SHRED_SCAT] = 0;		
+	/* setup splice params */
+	dz->iparam[SHRED_SPLEN]     = SHRED_SPLICELEN  * chans;
+    if((dz->lparray[SHR_CHUNKPTR] = (int *)malloc(dz->iparam[SHR_CHCNT] * sizeof(long)))==NULL
+    || (dz->lparray[SHR_CHUNKLEN] = (int *)malloc(dz->iparam[SHR_CHCNT] * sizeof(long)))==NULL
+    || (dz->iparray[SHR_PERM]     = (int  *)malloc(dz->iparam[SHR_CHCNT] * sizeof(int)))==NULL) {
+		sprintf(errstr,"INSUFFICIENT MEMORY for shredding arrays.\n");
+		return(MEMORY_ERROR);
+	}
+    dz->lparray[SHR_CHUNKPTR][0] = 0;	/* first chunk is at start of buffer */
+	return(FINISHED);
+}
+
+/***************************** SHRED_PREPROCESS *************************/
+
+int shred_preprocess(dataptr dz)
+{
+	int sectorcnt;
+	sectorcnt = dz->insams[0]/dz->buflen;
+	if(sectorcnt * dz->buflen < dz->insams[0])
+		sectorcnt++;
+	if(sectorcnt > 1)
+		fprintf(stdout,"INFO: File will be shredded in %d distinct sectors.\n",sectorcnt);
+	fflush(stdout);
+	return(FINISHED);
+}
+
+/***************************CREATE_SHRED_BUFFERS **************************/
+//TW replaced by global
+//#define SHRED_SECSIZE (256)
+/* RWD sigh..... */
+int create_shred_buffers(dataptr dz)
+{
+	int exit_status;
+	int bigfilesize, file_size_in_frames;
+	double bufs_per_file, lchunkcnt; 
+	size_t basic_bufchunk, bufchunk = (size_t)Malloc(-1);
+	int framesize = F_SECSIZE * dz->infile->channels;
+	bigfilesize = dz->insams[0];
+	if((dz->bigbuf = (float *)malloc((bigfilesize * dz->bufcnt) * sizeof(float)))==NULL) {
+		bufchunk /= sizeof(float);
+		basic_bufchunk = bufchunk;
+		for(;;) {
+			if((dz->buflen = (int) bufchunk) < 0) {
+				sprintf(errstr,"INSUFFICIENT MEMORY to allocate sound buffer.\n");
+				return(MEMORY_ERROR);
+			}
+			dz->buflen  = (dz->buflen/(framesize * dz->bufcnt)) * framesize * dz->bufcnt;
+			dz->buflen /= dz->bufcnt;
+		/* NEW --> */
+			if(dz->buflen <= 0)
+				dz->buflen  = framesize;
+		/* <-- NEW */
+			file_size_in_frames = dz->insams[0]/framesize;
+			if(framesize * file_size_in_frames < dz->insams[0])
+				file_size_in_frames++;
+			bigfilesize = file_size_in_frames * framesize;
+			if(bigfilesize <= dz->buflen)
+				dz->buflen  = bigfilesize;
+			if((dz->bigbuf = (float *)malloc((dz->buflen * dz->bufcnt) * sizeof(float)))==NULL) {
+				sprintf(errstr,"INSUFFICIENT MEMORY to allocate sound buffer.\n");
+				return(MEMORY_ERROR);
+			}
+			if((exit_status = check_for_too_small_buf(dz))>=0)
+				break;
+			bufchunk += basic_bufchunk;
+		}
+		dz->sampbuf[0] = dz->bigbuf;
+		dz->sampbuf[1] = dz->sampbuf[0] + dz->buflen;
+		if(bigfilesize == dz->buflen) {
+			dz->iparam[SHR_LAST_BUFLEN] = dz->insams[0];	/* i.e. buflen = true filelen */
+			dz->iparam[SHR_LAST_CHCNT]  = dz->iparam[SHR_CHCNT];
+			dz->iparam[SHR_LAST_SCAT]   = dz->iparam[SHRED_SCAT];
+		} else {
+			bufs_per_file = (double)dz->insams[0]/(double)dz->buflen;
+			lchunkcnt     = (double)dz->iparam[SHR_CHCNT]/bufs_per_file;
+			dz->iparam[SHR_CHCNT]       = round(lchunkcnt);
+			dz->iparam[SHRED_SCAT]      = min(dz->iparam[SHRED_SCAT],dz->iparam[SHR_CHCNT]);
+			dz->iparam[SHR_LAST_BUFLEN] = (dz->insams[0]%dz->buflen);
+			dz->iparam[SHR_LAST_CHCNT]  = round(lchunkcnt*((double)dz->iparam[SHR_LAST_BUFLEN]/(double)dz->buflen));
+			dz->iparam[SHR_LAST_SCAT]   = min(dz->iparam[SHRED_SCAT],dz->iparam[SHR_LAST_CHCNT]);
+		}
+		if(dz->iparam[SHR_LAST_CHCNT] < 2) {
+			fprintf(stdout, "WARNING: FINAL BUFFER WON'T BE SHREDDED (Too short for chunklen set).\n");
+			fprintf(stdout, "WARNING: It will shred if you\n");
+			fprintf(stdout, "WARNING: a) shorten infile by (>) chunklen, OR\n");
+			fprintf(stdout, "WARNING: b) alter chunklen until last buffer has >1 chunk in it.\n");
+			fflush(stdout);
+		}
+	} else {
+		dz->buflen = bigfilesize;
+		dz->sampbuf[0] = dz->bigbuf;
+		dz->sampbuf[1] = dz->sampbuf[0] + dz->buflen;
+		dz->iparam[SHR_LAST_BUFLEN] = dz->insams[0];	/* i.e. buflen = true filelen */
+		dz->iparam[SHR_LAST_CHCNT]  = dz->iparam[SHR_CHCNT];
+		dz->iparam[SHR_LAST_SCAT]   = dz->iparam[SHRED_SCAT];
+		if(dz->iparam[SHR_LAST_CHCNT] < 2) {
+			fprintf(stdout, "WARNING: FINAL BUFFER WON'T BE SHREDDED (Too short for chunklen set).\n");
+			fprintf(stdout, "WARNING: It will shred if you\n");
+			fprintf(stdout, "WARNING: a) shorten infile by (>) chunklen, OR\n");
+			fprintf(stdout, "WARNING: b) alter chunklen until last buffer has >1 chunk in it.\n");
+			fflush(stdout);
+		}
+	}
+	memset((char *) (dz->sampbuf[0]),0,(dz->buflen * dz->bufcnt) * sizeof(float));
+	return(FINISHED);
+}
+
+/************************* SHRED_PROCESS ***************************/
+
+int shred_process(dataptr dz)
+{
+	int exit_status;
+	int n, cnt = 0, checker = 0, work_len;
+	int current_buf;
+	if(sloom && dz->iparam[SHRED_SCAT]) {
+		fprintf(stdout,"WARNING: There is a finite possibility program will not terminate.\n");
+		fprintf(stdout,"WARNING: If in doubt, press STOP\n");
+		fflush(stdout);
+	}
+	do {
+		if(!sloom && !sloombatch)
+			fprintf(stdout,"\nBUFFER %d ",cnt++);
+		else {
+			fprintf(stdout,"INFO: BUFFER %d\n",cnt++);
+			fflush(stdout);
+		}
+		if((exit_status = read_samps(dz->sampbuf[0],dz))<0)
+			return(exit_status);
+		current_buf = 0;
+		if(dz->samps_left <= 0 ) {
+			dz->buflen = dz->iparam[SHR_LAST_BUFLEN];
+			dz->iparam[SHRED_SCAT] = dz->iparam[SHR_LAST_SCAT];
+			dz->iparam[SHR_CHCNT]  = dz->iparam[SHR_LAST_CHCNT];
+		}
+		if((dz->iparam[SHR_CHCNT_LESS_ONE] = dz->iparam[SHR_CHCNT] - 1)<=0) {
+			if(cnt==1) {
+				sprintf(errstr,"SOUNDFILE TOO SMALL to shred.\n");
+				return(DATA_ERROR);
+			} else {
+				n = dz->buflen;
+				dz->buflen = dz->ssampsread;
+				do_bufend_splices(current_buf,dz);
+				if((exit_status = write_exact_samps(dz->sampbuf[current_buf],dz->buflen,dz))<0)
+					return(exit_status);
+				dz->buflen = n;
+			}
+		} else {
+			if((exit_status = get_basis_lengths(&work_len,dz))<0)
+				return(exit_status);
+			if(!sloom && !sloombatch)
+				checker = 0;
+			else
+				display_virtual_time(0L,dz);
+			for(n=0;n<dz->iparam[SHRED_CNT];n++) {
+				if((exit_status = shred(current_buf,work_len,dz))<0)
+					return(exit_status);
+				current_buf = !current_buf;	
+
+				if(!sloom && !sloombatch) {
+					if(n==checker) {
+						printf("*");
+						checker += 16;
+					}
+				} else
+					display_virtual_time((long)n,dz);
+			}
+			do_bufend_splices(current_buf,dz);
+			if((exit_status = write_exact_samps(dz->sampbuf[current_buf],dz->buflen,dz))<0)
+				return(exit_status);
+		}
+	} while(dz->samps_left > 0);
+	return(FINISHED);
+}
+
+/******************************* SHRED **************************
+ *
+ * (1)	If the random-scattering of chunk boundaries is <= 1.0, scatter
+ *	each chunk boundary separately (normal_scat).
+ *	Else, scatter chunk boundaries over groups of chunklens (heavy_scat).
+ * (2)	Calculate the lengths of the chunks, from difference of their positions.
+ * (2A)	NB the length of the is the difference between its start and
+ *	THE END OF THE work_len (NOT  the ned of the buffer). Chunklens are
+ *	measured from start of startsplice to START of endsplice (see
+ *	diagram).
+ * (3)	Generate a permutation (permm[]) of the chunk numbers.
+ *
+ * (4)	The chunk that is to be FIRST in the permuted set does not need
+ *	to be spliced at its beginning (as there's nothing prior to it,
+ *	to splice into) but only at its end.
+ * (a)	The address from which we copy is position in current buffer
+ *	where chunk associated with 0 (chunk[permm[0]) is.
+ * (b)	The address to copy TO is start of the OTHER  buffer (buf[!this]).
+ * (c) 	The unit_len of the chunk we're copying is chunklen[permm[0]].
+ * (d)	Copy all of this.
+ * (f)	Copy SPLICELEN extra (full_len is SPLICELEN bigger that unit_len..
+ *	.. see diagram), making an endsplice on it as we do.
+ *
+ * (5)	For the rest of the chunks APART FROM THE LAST....
+ * (a)	as 4(a): n associated with perm[n]..
+ * (b)  advance in new buffer by chunklen of PREVIOUSLY written chunk..
+ *	This 'length' is length to START of its endsplice, which is where
+ *	new chunk is spliced in.
+ * (c)  as 4(c)
+ * (d)  Do a startsplice as we copy from old_address to new_address.
+ * (e)	Copy from END of this startsplice, a segment of length chnklen
+ *	(length of the total copied chunk) MINUS length of that startsplice
+ *	(SPLICELEN).
+ * (f)	as 4(f).
+ *
+ * (6)	For the last chunk, we don't need an endsplice (nothing to splice to)
+ * (a-d)as 5(a-d).
+ * (e)	Copy from end of STARTSPLICE to end of ENDSPLICE ... i.e.
+ *	a whole chunklen, because full_len - SPLICELEN = chunklen.
+ *
+ *         ___full_len___
+ *        |              |
+ *         _chunklen__   |
+ *        | S         |
+ *        | T         |E
+ *        | R ________|N
+ *        | T/|       \D
+ *        | / |        \
+ *	  |/  |         \|
+ *            |          |
+ *            |_chunklen_|
+ *        |
+ *        |___full_len___|
+ *
+ * (7)	Set memory in old buffer to 0 (because we ADD into it, with splices).
+ */
+
+int shred(int current_buf,int work_len,dataptr dz)
+{   
+	int n;
+	float *old_addr, *new_addr;
+	int chnk_len;
+	char *destination = NULL;
+	int *chunkptr = dz->lparray[SHR_CHUNKPTR];
+	int *chunklen = dz->lparray[SHR_CHUNKLEN];
+	int  *permm    = dz->iparray[SHR_PERM];
+
+	if(!dz->iparam[SHRED_SCAT])	
+		normal_scat(dz);											/* 1 */
+	else	
+		heavy_scat(dz);
+	for(n=0;n<dz->iparam[SHR_CHCNT_LESS_ONE];n++)					/* 2 */
+		chunklen[n] = chunkptr[n+1] - chunkptr[n];
+	chunklen[n] = work_len - chunkptr[n];							/* 2A */
+	permute_chunks(dz);												/* 3 */
+		/* NEW FIRST-SEGMENT IN BUFFER */							/* 4 */
+	old_addr = dz->sampbuf[current_buf]  + chunkptr[permm[0]];		/* a */
+	new_addr = dz->sampbuf[!current_buf];							/* b */
+	chnk_len = chunklen[permm[0]];									/* c */
+	if(dz->vflag[0]) {
+		do_startsplice(old_addr,new_addr,dz);
+		destination = (char *)(new_addr+dz->iparam[SHRED_SPLEN]);
+		memcpy(destination,
+		(char *)(old_addr+dz->iparam[SHRED_SPLEN]),(chnk_len-dz->iparam[SHRED_SPLEN]) * sizeof(float));
+	} else {
+		destination = (char *)new_addr;
+		memcpy(destination,(char *)old_addr,chnk_len*sizeof(float));
+	}
+	do_endsplice(old_addr+chnk_len, new_addr+chnk_len,dz);			/* f */
+
+		 /* MIDDLE-SEGMENTS IN BUFFER */							/* 5 */
+	for(n=1;n<dz->iparam[SHR_CHCNT_LESS_ONE];n++) {
+		old_addr  = dz->sampbuf[current_buf]  + chunkptr[permm[n]];	/* a */
+		new_addr += chnk_len;										/* b */
+		chnk_len  = chunklen[permm[n]];								/* c */
+		do_startsplice(old_addr,new_addr,dz);						/* d */
+		destination = (char *)(new_addr+dz->iparam[SHRED_SPLEN]);
+		memcpy(destination,
+		(char *)(old_addr+dz->iparam[SHRED_SPLEN]),(chnk_len-dz->iparam[SHRED_SPLEN]) * sizeof(float));
+		do_endsplice(old_addr+chnk_len,new_addr+chnk_len,dz);
+	}							/* f */
+		/* NEW END-SEGMENT IN BUFFER */								/* 6 */
+	old_addr  = dz->sampbuf[current_buf] + chunkptr[permm[n]];		/* a */
+	new_addr += chnk_len;											/* b */
+	chnk_len  = chunklen[permm[n]];									/* c */
+	do_startsplice(old_addr,new_addr,dz);							/* d */
+	if(dz->vflag[0])
+		do_endsplice(old_addr+chnk_len,new_addr+chnk_len,dz);
+	destination = (char *)(new_addr+dz->iparam[SHRED_SPLEN]);
+	memcpy(destination,(char *)(old_addr+dz->iparam[SHRED_SPLEN]),chnk_len*sizeof(float));
+
+		     /* RESET BUFFERS */
+	memset((char *)dz->sampbuf[current_buf],0,dz->buflen * sizeof(float)); /* 7 */
+	return(FINISHED);
+}
+
+/*********************** GET_BASIS_LENGTHS **********************
+ *
+ *
+ *    ______________buflen_______________
+ *   |............worklen.............   |  buflen - SPLICELEN  = worklen.
+ *   | unitlen unitlen		      	  |  |  unit_len * dz->iparam[SHR_CHCNT] = worklen.
+ *   |	      |	      | 	          |  |  
+ *   |_full_len_      |       _full_len__|  full_len = worklen + SPLICELEN.
+ *   |	      |	|     |      |	      |  |
+ *   |   _____| |_____|  ____|   _____|  |
+ *   |  /|    \ /     \ /     \ /     \  |
+ *   | / |    |X|      X       X       \ |
+ *   |/  |    / \     / \     / \       \|
+ *   |	 |    | 
+ *   |	 |    | 
+ *       rawlen
+ *
+ *
+ */
+
+int get_basis_lengths(int *work_len,dataptr dz)
+{   
+	int excess, full_len, endunit_len, endfull_len;
+	*work_len = dz->buflen - dz->iparam[SHRED_SPLEN];
+	dz->iparam[SHR_UNITLEN] = (int)round((*work_len)/dz->iparam[SHR_CHCNT]);
+	excess = dz->iparam[SHR_UNITLEN] % dz->infile->channels;
+	dz->iparam[SHR_UNITLEN] -= excess;
+	excess   = (*work_len) - (dz->iparam[SHR_UNITLEN] * dz->iparam[SHR_CHCNT]);
+	if(excess % dz->infile->channels) {
+		sprintf(errstr,"Problem in buffer accounting.\n");
+		return(PROGRAM_ERROR);
+	}
+	dz->iparam[SHR_RAWLEN]  = dz->iparam[SHR_UNITLEN] - dz->iparam[SHRED_SPLEN];
+	full_len = dz->iparam[SHR_UNITLEN] + dz->iparam[SHRED_SPLEN];
+	endunit_len = dz->iparam[SHR_UNITLEN] + excess;
+	endfull_len = full_len + excess;
+	dz->iparam[SHR_ENDRAWLEN]  = dz->iparam[SHR_RAWLEN]  + excess;
+	if(full_len < (dz->iparam[SHRED_SPLEN] * 2) || endfull_len < (dz->iparam[SHRED_SPLEN] * 2)) {
+		sprintf(errstr,"Chunksize too small for splices.\n");
+		return(DATA_ERROR);
+	}
+	if(dz->iparam[SHRED_SCAT]) {
+		dz->iparam[SHR_SCATGRPCNT] = (int)(dz->iparam[SHR_CHCNT]/dz->iparam[SHRED_SCAT]);
+		dz->iparam[SHR_ENDSCAT]    = (int)(dz->iparam[SHR_CHCNT] - (dz->iparam[SHR_SCATGRPCNT] * dz->iparam[SHRED_SCAT]));
+		dz->iparam[SHR_RANGE]      = dz->iparam[SHR_UNITLEN] * dz->iparam[SHRED_SCAT];
+		dz->iparam[SHR_ENDRANGE]   = ((dz->iparam[SHR_ENDSCAT]-1) * dz->iparam[SHR_UNITLEN]) + endunit_len;
+	}
+	return(FINISHED);
+}
+
+/************************** NORMAL_SCAT ******************************
+ *
+ * (1)	TOTLA_LEN generates the unscattered positions of the chunks.
+ *	Each is UNIT_LEN long, so they are equally spaced at UNIT_LEN
+ *	intervals.
+	We can't scatter the FIRST chunk as it MUST start at ZERO!!
+ * (2)	For all chunks except the first and last...
+ * (3)	    Scatter position of chunk over +- 1/2 of value of scatter,
+ *	    times the RAW-distance (not including splices) between chunks.
+ * (4)      Add (could be negative) this scattering to orig position.
+ * (5)	For the last chunk, do the same, scattering over RAW-len of previous
+ *	chunk, if scatter -ve, and over endraw_len of final chunk, if +ve.
+ */
+
+void normal_scat(dataptr dz)
+{   
+	double this_scatter;
+	int n, k;
+	int chunkscat, total_len = dz->iparam[SHR_UNITLEN];	/* 1 */
+	int *chunkptr = dz->lparray[SHR_CHUNKPTR];
+	for(n=1;n<dz->iparam[SHR_CHCNT_LESS_ONE];n++) {			/* 2 */
+		this_scatter  = (drand48() - 0.5) * dz->param[SHRED_SCAT];
+		chunkscat = (int)(this_scatter * (double)dz->iparam[SHR_RAWLEN]);
+		k = chunkscat % dz->infile->channels;
+		chunkscat -= k;
+		chunkptr[n] = total_len + chunkscat;
+		total_len  += dz->iparam[SHR_UNITLEN];				/* 4 */
+	}
+	this_scatter  = (drand48() - 0.5) * dz->param[SHRED_SCAT];
+	if(this_scatter<0.0) {					/* 5 */
+		chunkscat   = (int)(this_scatter * (double)dz->iparam[SHR_RAWLEN]);
+		k = chunkscat % dz->infile->channels;
+		chunkscat -= k;
+		chunkptr[n] = total_len - chunkscat;
+	} else {
+		chunkscat   = (int)(this_scatter * (double)dz->iparam[SHR_ENDRAWLEN]);
+		k = chunkscat % dz->infile->channels;
+		chunkscat -= k;
+		chunkptr[n] = total_len + chunkscat;
+	}
+}
+
+/*********************** HEAVY_SCAT ***************************
+ *
+ * (1)	Start at the chunk (this=1) AFTER the first (which can't be moved).
+ * (2) 	STARTPTR marks the start of the chunk GROUP (and will be advanced
+ *	by RANGE, which is length of chunk-group).
+ * (3)	The loop will generate a set of positions for the chunks in
+ *	a chunk-group. In the first chunkgroup the position of the
+ *	first chunk (start of file) can't be moved, so loop starts at
+ *	(first=) 1. Subsequemt loop passes start at 0.
+ * (4)	For eveery chunk-group.
+ * (5)	  Set the index of the first chunk in this group (start) to the
+ *	  current index (this).
+ * (6)	  For every member of this chunk-group.
+ * (7)	    Generate a random-position within the chunk-grp's range
+ *	    and check it is not too close ( < SPLICELEN) to the others.
+ *	      Set a checking flag (OK).
+ * (8)	      Generate a position within the range, and after the startptr.
+ * (9)		Compare it with all previously generated positions in this
+ *		chunk-grp AND with last position of previous chunk-group!!
+ * 		If it's closer than SPLICELEN, set OK = 0, drop out of
+		checking loop and generate another position instead.
+ * (10)	      If the position is OK, drop out of position generating loop..
+ * (11)	    Advance to next chunk in this group.
+ * (12)	  Once all this group is done, advance the group startpoint by RANGE.
+ * (13)	  After FIRST grp, all positions can by varied, so set the initial
+ *	  loop counter to (first=)0.
+ * (14)	If there are chunks left over (endscat!=0)..
+ *	  Follow the same procedure for chunks in end group, using the
+ *	  alternative variables, endscat and endrange.
+ */
+
+void heavy_scat(dataptr dz)
+{   
+	int	thiss = 1, that, start, n, m, OK;				/* 1 */
+	int k;
+	int startptr = 0;							/* 2 */
+	int endptr = 0;
+	int first = 1;								/* 3 */
+	int *chunkptr = dz->lparray[SHR_CHUNKPTR];
+	for(n=0;n<dz->iparam[SHR_SCATGRPCNT];n++) {				/* 4 */
+		start = thiss;							/* 5 */
+		endptr += dz->iparam[SHR_RANGE];
+		for(m=first;m<dz->iparam[SHRED_SCAT];m++) {			/* 6 */
+			do{							/* 7 */
+				OK = 1;					
+				chunkptr[thiss] = (long)(drand48()*dz->iparam[SHR_RANGE]); 	/* TRUNCATE (?)*/
+				chunkptr[thiss] += startptr; 					/* 8 */
+				k = chunkptr[thiss] % dz->infile->channels;
+				chunkptr[thiss] -= k;
+				for(that=start-1; that<thiss; that++) {
+					if(abs(chunkptr[thiss] - chunkptr[that])<dz->iparam[SHRED_SPLEN]) {
+						OK = 0;					/* 9 */
+						break;
+					}
+					if(abs(endptr - chunkptr[thiss])<dz->iparam[SHRED_SPLEN]) {
+						OK = 0;
+						break;
+					}
+				}
+			} while(!OK);							/* 10 */
+			thiss++;							/* 11 */
+		}
+		startptr += dz->iparam[SHR_RANGE];					/* 12 */
+		first = 0;								/* 13 */
+	}
+
+	endptr += dz->iparam[SHR_ENDRANGE];
+
+	if(dz->iparam[SHR_ENDSCAT]) {							/* 14 */
+		start = thiss;
+		for(m=0;m<dz->iparam[SHR_ENDSCAT];m++) {
+			do {
+				OK = 1;
+				chunkptr[thiss] = (long)(drand48() * dz->iparam[SHR_ENDRANGE]);	  /* TRUNCATE (?) */
+				chunkptr[thiss] += startptr;
+				k = chunkptr[thiss] % dz->infile->channels;
+				chunkptr[thiss] -= k;
+				for(that=start-1; that<thiss; that++) {
+					if(abs(chunkptr[thiss] - chunkptr[that])<dz->iparam[SHRED_SPLEN]) {
+						OK = 0;
+						break;
+					}
+					if(abs(endptr - chunkptr[thiss])<dz->iparam[SHRED_SPLEN]) {
+						OK = 0;
+						break;
+					}
+				}
+			} while(!OK);
+			thiss++;
+		}
+	}
+	ptr_sort(thiss,dz);
+}
+
+/*************************** PERMUTE_CHUNKS ***************************/
+
+void permute_chunks(dataptr dz)
+{   
+	int n, t;
+	for(n=0;n<dz->iparam[SHR_CHCNT];n++) {
+		t = (int)(drand48() * (double)(n+1));	 /* TRUNCATE */
+		if(t==n)
+			prefix(n,dz);
+		else
+			insert(n,t,dz);
+
+	}
+}
+
+/****************************** INSERT ****************************/
+
+void insert(int n,int t,dataptr dz)
+{   
+	shuflup(t+1,dz);
+	dz->iparray[SHR_PERM][t+1] = n;
+}
+
+/****************************** PREFIX ****************************/
+
+void prefix(int n,dataptr dz)
+{   
+	shuflup(0,dz);
+	dz->iparray[SHR_PERM][0] = n;
+}
+
+/****************************** SHUFLUP ****************************/
+
+void shuflup(int k,dataptr dz)
+{   
+	int n;
+	for(n = dz->iparam[SHR_CHCNT_LESS_ONE]; n > k; n--)
+		dz->iparray[SHR_PERM][n] = dz->iparray[SHR_PERM][n-1];
+}
+
+/************************* DO_STARTSPLICE *************************
+ *
+ * (0)	For each position in splice.
+ * (1)	Get the value from the source file & multiply it by position in splice.
+ *	We 'should' multiply it by position/SPLICELEN,
+ *	so new value is SPLICELEN too large.
+ * (2)	Add a rounding factor (if value were correct, this would be 1/2)
+ *	But everything is SPLICELEN times too big, so add SHRED_HSPLICELEN.
+ * (3)	Divide by SPLICELEN.
+ * (4)	ADD this value to existing value (this is a splice TO another chunk!!).
+ */
+
+void do_startsplice(float *i,float *j,dataptr dz)
+{   
+	double z;
+	int n;
+	for(n = 0; n <dz->iparam[SHRED_SPLEN]; n ++) {			/* 0 */
+		z     = (*i) * (double)n/dz->iparam[SHRED_SPLEN];	/* 1 */
+		i++;
+		*j = (float) /*round*/((*j) + z);						/* 4 */
+		j++;											
+	}
+}
+
+/************************* DO_ENDSPLICE *************************/
+
+void do_endsplice(float *i,float *j,dataptr dz)
+{   
+	double z;
+	int n;
+	for(n = dz->iparam[SHRED_SPLEN]-1; n>=0; n--) {
+		z     = *i++ * (double)n/dz->iparam[SHRED_SPLEN];
+		*j++ += (float) /*round*/ (z);
+	}
+}
+
+/********************* DO_BUFEND_SPLICES *************************/
+
+void do_bufend_splices(int current_buf,dataptr dz)
+{
+	double z;
+	int  n;
+	float *b = dz->sampbuf[current_buf];
+	for(n = 0; n <dz->iparam[SHRED_SPLEN]; n ++) {
+		z     = (*b) * (double)n/dz->iparam[SHRED_SPLEN];
+		*b++  = (float)z;
+	}
+	b = dz->sampbuf[current_buf] + dz->buflen - dz->iparam[SHRED_SPLEN];
+	for(n = dz->iparam[SHRED_SPLEN]-1; n>=0; n--) {
+		z     = (*b) * (double)n/dz->iparam[SHRED_SPLEN];
+		*b++  = (float) /*round*/(z);
+	}
+}
+
+/**************************** CHECK_FOR_TOO_SMALL_BUF *********************/
+
+int check_for_too_small_buf(dataptr dz)
+{
+	int chunksamps = round(dz->param[SHRED_CHLEN] * dz->infile->srate) * dz->infile->channels; 
+	if(dz->iparam[SHRED_SCAT]) {
+		if(dz->buflen <= chunksamps * dz->iparam[SHRED_SCAT]) {
+			sprintf(errstr,"Internal sound buffer too short (%lf secs) for chunksize and scatter.\n",
+	       (double)(dz->buflen/dz->infile->channels)/(double)dz->infile->srate);
+			return(GOAL_FAILED);
+		}
+	} else {
+		if(dz->buflen <= chunksamps * 2) {
+			sprintf(errstr,"Sound buffer too short for chunksize.\n");
+			return(GOAL_FAILED);
+		}
+	}
+	return(FINISHED);
+}
+
+/************************** PTR_SORT ***************************/
+
+void ptr_sort(int end,dataptr dz)
+{   
+	int i,j;
+	int a;
+	int *chunkptr = dz->lparray[SHR_CHUNKPTR];
+	for(j=1;j<end;j++) {
+		a = chunkptr[j];
+		i = j-1;
+		while(i >= 0 && chunkptr[i] > a) {
+			chunkptr[i+1]=chunkptr[i];
+			i--;
+		}
+		chunkptr[i+1] = a;
+	}
+}    
+
+/*************************** SCRUB_PCONSISTENCY **************************/
+
+int scrub_pconsistency(dataptr dz)
+{
+	if(dz->param[SCRUB_MINSPEED] > dz->param[SCRUB_MAXSPEED])
+		swap(&(dz->param[SCRUB_MINSPEED]),&dz->param[SCRUB_MAXSPEED]);
+	dz->iparam[SCRUB_TOTALDUR] = round(dz->param[SCRUB_TOTALDUR] * (double)(dz->infile->srate * dz->infile->channels));
+	return(FINISHED);
+}
+
+/*************************** SCRUB_PREPROCESS **************************/
+
+int scrub_preprocess(dataptr dz)
+{
+	int exit_status;
+	double sr = (double)dz->infile->srate;
+	int chans = dz->infile->channels;
+   initrand48();
+    if((exit_status = create_sintable(dz))<0)
+		return(exit_status);
+	dz->iparam[SCRUB_STARTRANGE] = round(dz->param[SCRUB_STARTRANGE] * sr);
+	dz->iparam[SCRUB_ESTART]     = round(dz->param[SCRUB_ESTART]     * sr);
+	dz->iparam[SCRUB_ENDRANGE]   = (dz->insams[0]/chans) - dz->iparam[SCRUB_ESTART];
+    dz->param[SCRUB_SPEEDRANGE]  = dz->param[SCRUB_MAXSPEED] - dz->param[SCRUB_MINSPEED];
+	return(FINISHED);
+}
+
+/*************************** CREATE_SINTABLE **************************/
+
+int create_sintable(dataptr dz)
+{   
+	int n;
+	/* GENERATE A WARPED SINUS TABLE, Range 0 - 1 */
+	if((dz->parray[SCRUB_SIN] = (double *)malloc((SCRUB_SINTABSIZE+1) * sizeof(double)))==NULL) {
+		sprintf(errstr,"INSUFFICIENT MEMORY to create sintable for scrubbing.\n");
+		return(MEMORY_ERROR);
+	}	
+	for(n=0;n<SCRUB_SINTABSIZE;n++) {
+		dz->parray[SCRUB_SIN][n] = sin(PI * (double)n/(double)SCRUB_SINTABSIZE);
+		dz->parray[SCRUB_SIN][n] = pow(dz->parray[SCRUB_SIN][n],SCRUB_SINWARP);
+	}
+	dz->parray[SCRUB_SIN][n] = 0.0;
+	if((dz->parray[SCRUB_READTAB] = (double *)malloc((SCRUB_SINTABSIZE+1) * sizeof(double)))==NULL) {
+		sprintf(errstr,"INSUFFICIENT MEMORY to create skewtable for scrubbing.\n");
+		return(MEMORY_ERROR);
+	}	
+	return(FINISHED);
+}
+
+/***************************CREATE_BUFFERS **************************/
+
+int create_scrub_buffers(dataptr dz)
+{
+	size_t bigbufsize;
+	long shsecsize = F_SECSIZE, sum = 0L;
+	long framesize = F_SECSIZE * dz->infile->channels;
+    bigbufsize = (size_t)Malloc(-1);
+	bigbufsize /= sizeof(float);
+    bigbufsize = (bigbufsize/(framesize*dz->bufcnt)) * framesize * dz->bufcnt;
+    bigbufsize = bigbufsize/dz->bufcnt;
+	if(bigbufsize <= 0)
+		bigbufsize  = framesize;
+    dz->buflen = (int) bigbufsize;
+    if((dz->bigbuf = (float *)malloc(  
+		   ((dz->buflen * dz->bufcnt) + (F_SECSIZE*2)) * sizeof(float))) == NULL) {
+		sprintf(errstr, "INSUFFICIENT MEMORY for sound buffers.\n");
+		return(MEMORY_ERROR);
+	}
+    dz->sampbuf[0] = dz->bigbuf;
+    dz->sampbuf[1] = dz->sampbuf[0] + dz->buflen + (shsecsize*2);	  /* inbuf has wraparound sectors */
+	dz->iparam[SCRUB_DROPOUT] = FALSE;
+    if(dz->iparam[SCRUB_TOTALDUR] <= dz->buflen + shsecsize) {
+		dz->buflen = dz->iparam[SCRUB_TOTALDUR];
+		dz->iparam[SCRUB_DROPOUT] = TRUE;
+    }
+	dz->iparam[SCRUB_BUFCNT] = 0;
+	while(sum < dz->insams[0]) {
+		dz->iparam[SCRUB_BUFCNT]++;
+		sum += dz->buflen;
+	}
+	return(FINISHED);
+}
+
+/****************************** DO_SCRUBBING *************************/
+
+int do_scrubbing(dataptr dz)
+{   
+	int exit_status;
+/*	float *ibuf = dz->sampbuf[0];*/
+	float *obuf = dz->sampbuf[1];
+	int chans = dz->infile->channels;
+	int scrublen_in_src, effective_tablen;
+	double skew, lospeed,speedrange;
+	int direction = SCRUB_BACKWARDS, here, lasthere = 0, there = 0;
+	display_virtual_time(0,dz);	/* fraction of total_dur!! */
+	get_end(&direction,&lasthere,dz);	/* setup start position */		
+	do {
+		here = lasthere;
+		get_end(&direction,&here,dz);		
+		skew = get_skew();
+		get_speed(&lospeed,&speedrange,dz);
+		scrublen_in_src = abs(here - lasthere);
+		effective_tablen = gen_readtab(skew,lospeed,speedrange,scrublen_in_src,dz);
+		if((exit_status = scrub(&lasthere,&there,!direction,effective_tablen,dz))<0)
+			return(exit_status);
+		if(exit_status == FINISHED)
+			break;
+		if(dz->vflag[0])		//	FORWARD SCRUB ONLY
+			break;
+	} while((there * chans) + dz->total_samps_written < dz->iparam[SCRUB_TOTALDUR]);
+	if(there > 0)
+		return write_samps(obuf,there * chans,dz);
+	return(FINISHED);
+}
+
+/******************************* GET_SKEW ******************************/
+
+double get_skew(void)
+{	double skew;
+	skew = (drand48() * 2.0) - 1.0;  	/* -1 to +1 */
+    skew *= SCRUB_SKEWRANGE;
+    skew += 1.0;						/* 1 +- SKEWRANGE */ 
+	return(skew);
+}
+
+/******************************* GET_SPEED ******************************
+ *
+ * Generate a speed distribution which is pitch (not frq) distributed.
+ */
+
+void get_speed(double *lospeed,double *speedrang,dataptr dz)
+{
+	double hispeed;				
+	hispeed  = drand48() * dz->param[SCRUB_SPEEDRANGE] * SCRUB_RANGE_REDUCE_FACTOR;
+	hispeed  = dz->param[SCRUB_MAXSPEED] - hispeed;
+	*lospeed  = drand48() * dz->param[SCRUB_SPEEDRANGE] * SCRUB_RANGE_REDUCE_FACTOR;				
+	*lospeed += dz->param[SCRUB_MINSPEED];
+	*speedrang = hispeed - *lospeed;
+}
+
+/******************************* GET_END ******************************/
+
+void get_end(int *direction,int *here,dataptr dz)
+{   
+	int lasthere = *here;
+	switch(*direction) {
+	case(SCRUB_FORWARDS):
+		*here = round(drand48() * dz->iparam[SCRUB_ENDRANGE]);
+		*here += dz->iparam[SCRUB_ESTART];
+		*direction = SCRUB_BACKWARDS;
+		break;
+	case(SCRUB_BACKWARDS):
+		*here = round(drand48() * dz->iparam[SCRUB_STARTRANGE]);
+		*direction = SCRUB_FORWARDS;
+		break;
+	}
+//TW COMMENT: this statement has no effect
+	dz->param[SCRUB_LENGTH] = abs(lasthere - *here);
+}
+
+/***************************** GEN_READTAB *****************************/
+
+int gen_readtab(double skew,double lospeed,double speedrange,int scrublen_in_src,dataptr dz)
+{   
+	int n, here, next, tablen = -1;
+	double step, sin_index, frac, dindex;
+	double *sintab  = dz->parray[SCRUB_SIN];
+	double *readtab = dz->parray[SCRUB_READTAB];
+	double readtab_integral = 0.0, last_readtab_integral, searchstep = 1.01;
+	/* GENERATE A SKEWED WARPED-SINUS-TABLE, Range 0 - 1, from orig WARPED-SINUS-TABLE */ 
+
+	if(flteq(skew,1.0)) {	
+		memcpy((char *)readtab,(char *)sintab,(SCRUB_SINTABSIZE + 1) * sizeof(double));
+		tablen = SCRUB_SINTABSIZE;
+	} else {
+		sin_index = 0.0;
+		step =  (double)SCRUB_SINTABSIZE * (1.0-skew);		/* initial step found using */
+		step /= (1.0 - pow(skew,(double)SCRUB_SINTABSIZE));	/* geometric series sum     */
+		readtab[0] = 0.0;
+		for(n=1;n<SCRUB_SINTABSIZE;n++) {
+			sin_index += step;
+			if((here = (int)sin_index) >= SCRUB_SINTABSIZE) {	   /* TRUNCATE */
+				tablen = n;
+				sprintf(errstr,"scrubbing table incomplete by %d items\n",SCRUB_SINTABSIZE - n);
+				print_outwarning_flush(errstr);
+				break;
+			} else {
+				frac = sin_index - (double)here;
+				next = here + 1;
+				readtab[n]  = (sintab[next] - sintab[here]) * frac;
+				readtab[n] += sintab[here];
+				step *= skew;
+			}
+		}
+		if(tablen < 0)
+			tablen = SCRUB_SINTABSIZE;
+		readtab[tablen] = readtab[tablen-1];
+	}	
+	for(n=0;n<=tablen;n++) {
+							/* range is initially 0 - 1 */
+		readtab[n] *= speedrange;		/* change scale to range of speedrange */
+		readtab[n] += lospeed;			/* shift values to be within range lospeed to hispeed */
+		readtab[n] *= OCTAVES_PER_SEMITONE;	/* convert values to octaves */
+		readtab[n]  = pow(2.0,readtab[n]);	/* convert vals to transposition ratios = increments in infile */
+		readtab_integral += readtab[n];  	/* integrate func to get total length */
+	}
+	/* If the speedvary process causes sample-read to fall off end of file */
+	/* move more quickly through the sample-read-incrs file */
+	while(readtab_integral >= (double)scrublen_in_src) {
+		last_readtab_integral = readtab_integral;
+		dz->param[SCRUB_TABINC] = readtab_integral/(double)scrublen_in_src;
+		dindex = 0.0;		
+		readtab_integral = 0.0;
+		while(dindex <= (double)tablen) {
+			here = (int)floor(dindex);
+			next = here+1;
+			frac = dindex - (double)here;
+			readtab_integral += (readtab[n] * (1.0 - frac)) + (readtab[next] * frac);
+			dindex += dz->param[SCRUB_TABINC];
+		}
+		if(last_readtab_integral == readtab_integral) {
+			/* if the search process stalls, kick restart it */
+			readtab_integral *= searchstep;
+			searchstep *= searchstep;
+		}
+	}
+	/* in effect: change area under function by expanding or contracting it along x-axis */
+	dz->param[SCRUB_TABINC] = readtab_integral/(double)scrublen_in_src;
+	return tablen;
+}
+
+/**************************** SCRUB *******************************/
+
+#define SCRUB_SPLICE (0.1)
+
+int scrub(int *hhere,int *tthere,int direction,int effective_tablen,dataptr dz)
+{   
+	int exit_status, scrub_exit_status;
+	int   index;
+	double lfrac, inval;
+	int    n, m;
+	int    chans = dz->infile->channels;
+	int   effective_buflen = dz->buflen/chans;
+	int    abshere = *hhere, there = *tthere;
+	int    here  = abshere % effective_buflen;
+	int    bufno = abshere/effective_buflen;  /* TRUNCATE */
+	int	   truehere, truethere;
+	int   cnt = 0, splicend, scrubend = 0;
+	double splincr, splval;
+	double dindex, dhere = here, frac, val;
+	float  *ibuf = dz->sampbuf[0];
+	float  *obuf = dz->sampbuf[1];
+	double *readtab = dz->parray[SCRUB_READTAB];
+
+	if((exit_status = read_samps_for_scrub(bufno,dz))<0)  /* read wraparound buffer */
+		return(exit_status);		
+   	if(there >= effective_buflen) {
+		if(dz->iparam[SCRUB_DROPOUT])
+			return(FINISHED);
+		if((exit_status = write_samps(obuf,dz->buflen,dz))<0)
+			return(exit_status);
+		there = 0;
+		truethere = there *chans;
+	}
+	for(m=0;m<chans;m++)
+		obuf[(there*chans)+m] = 0.0f;
+
+	splicend = (int)round((double)dz->infile->srate * SCRUB_SPLICE);
+	dindex = dz->param[SCRUB_TABINC];
+	while (dindex < (double)effective_tablen) {
+		dindex += dz->param[SCRUB_TABINC];
+		scrubend++;
+	}
+	scrubend -= splicend;
+	if(scrubend < splicend) {
+		scrubend += splicend;
+		splicend = scrubend/2;
+		scrubend -= splicend;
+	}
+	splincr = 1.0/(double)splicend;
+	splval = splincr;
+
+	dindex = dz->param[SCRUB_TABINC];
+	there++;
+	truethere = there *chans;
+	do {
+    	if(there >= effective_buflen) {
+			if(dz->iparam[SCRUB_DROPOUT])
+				return(FINISHED);
+			if((exit_status = write_samps(obuf,dz->buflen,dz))<0)
+				return(exit_status);
+			there = 0;
+			truethere = there *chans;
+		}
+		index = (long)dindex;		/* TRUNCATE */ /* interpolate vals in readtable */
+		frac  = dindex - (double)index;
+		val   = (readtab[index+1] - readtab[index]) * frac;
+		val  += readtab[index];
+ 		scrub_exit_status = CONTINUE;
+		if(direction==SCRUB_FORWARDS) {
+		    dhere += val;  /* use readtab val to interpolate in sndfile */
+			here = (int)dhere;						/* TRUNCATE */
+			truehere  = here * chans;
+			if(truehere >= dz->ssampsread) {
+				if(++bufno >= dz->iparam[SCRUB_BUFCNT]) {
+					fprintf(stdout,"WARNING: overreached infile.\n");
+					fflush(stdout);
+		 			scrub_exit_status = FINISHED;
+					break;
+				}
+				if((exit_status = read_samps_for_scrub(bufno,dz))<0)  /* read wraparound buffer */
+					return(exit_status);		
+				truehere -= dz->buflen;
+				here  -= effective_buflen;
+				dhere -= (double)effective_buflen;
+			}
+		} else {
+		    dhere -= val;  
+			here = (int)dhere;						/* TRUNCATE */
+			truehere  = here * chans;
+ 			if(here < 0) {
+				if(--bufno < 0) {
+					fprintf(stdout,"WARNING: fell off start of infile.\n");
+					fflush(stdout);
+					scrub_exit_status = FINISHED;
+					break;
+				}
+				if((exit_status = read_samps_for_scrub(bufno,dz))<0)  /* read wraparound buffer */
+					return(exit_status);		
+				truehere += dz->buflen;
+				here  += effective_buflen;
+				dhere += (double)effective_buflen;
+			}
+		}
+		lfrac = dhere - (double)here;
+		if (cnt > scrubend) {
+			for(m=0;m<chans;m++) {
+				inval =  ibuf[truehere+m] * (1.0 - lfrac);
+				inval += ibuf[truehere+m+chans] * lfrac;
+				obuf[truethere+m] = (float)(inval * splval);
+				splval -= splincr;
+			}
+		} else if(cnt < splicend) {
+			for(m=0;m<chans;m++) {
+				inval =  ibuf[truehere+m] * (1.0 - lfrac);
+				inval += ibuf[truehere+m+chans] * lfrac;
+				obuf[truethere+m] = (float)(inval * splval);
+				splval += splincr;
+			}
+		} else {
+			for(m=0;m<chans;m++) {
+				inval =  ibuf[truehere+m] * (1.0 - lfrac);
+				inval += ibuf[truehere+m+chans] * lfrac;
+				obuf[truethere+m] = (float) /*round*/(inval);	
+			}
+		}
+		there++;
+		truethere = there *chans;
+		cnt++;
+	} while ((dindex += dz->param[SCRUB_TABINC]) < SCRUB_SINTABSIZE);
+
+	for(n=0;n<SCRUB_SINTABSIZE;n++) {		/* create silent gap to avoid clicks */
+		if(there >= effective_buflen) {
+			if((exit_status = write_samps(obuf,dz->buflen,dz))<0)
+				return(exit_status);
+			there = 0;
+			truethere = 0;
+		}
+		for(m=0;m<chans;m++)
+			obuf[truethere+m] = 0.0f;
+		truethere += chans;
+		there++;
+    }
+    *hhere  = (bufno * effective_buflen) + here;
+	*tthere = there;
+	return(scrub_exit_status);
+}
+
+/**************************** READ_SAMPS_FOR_SCRUB *******************************/
+
+int read_samps_for_scrub(int bufno,dataptr dz)
+{
+	int exit_status;
+	float *buf = dz->sampbuf[0];
+	if(sndseekEx(dz->ifd[0],bufno * dz->buflen,0)<0) {  
+		sprintf(errstr,"sndseek() 1 failed in scrub.\n");		  /* seek to start of buffer from which to read */
+		return(SYSTEM_ERROR);
+	}
+	dz->buflen += F_SECSIZE;	  /* samps to read, with F_SECSIZE  wraparound for interpd reading last sample in buf */
+	/* zeroes buffer in case wraparound on last-samp-in-file !! */
+	memset((char *)buf,0,(dz->buflen + F_SECSIZE) * sizeof(float));	
+	/* zeros FURTHER F_SECSIZE samps in case file exactly fills the F_SECSIZE-extended buffer */
+																   /* & there's  wraparound on last-samp-in-file !! */
+	if((exit_status = read_samps(buf,dz))<0)  									  /* read wraparound buffer */
+		return(exit_status);		
+	dz->buflen -= F_SECSIZE;	 												  /* reset to unwrapped buffer size */
+	if(dz->ssampsread > dz->buflen)		/* if read beyond effective bufsize, there are samps in file beyond this */
+		dz->ssampsread = dz->buflen;	/* reset samps_read to non-wrapped samps read */
+	return(FINISHED);
+}
+
+/*************************** CROSSMOD_PCONSISTENCY **************************/
+
+int crossmod_pconsistency(dataptr dz)
+{
+	if(dz->infile->srate != dz->otherfile->srate) {
+		sprintf(errstr,"Cross modulation only works with files of same srate.\n");
+		return(DATA_ERROR);
+	}
+	if((dz->otherfile->channels > 2 && dz->infile->channels != 1) || (dz->infile->channels > 2 && dz->otherfile->channels != 1)) {
+		if(dz->infile->channels != dz->otherfile->channels) {
+			sprintf(errstr,"With multichannel files, Cross modulation ONLY works if files have same number of channels OR if one file is mono.\n");
+			return(DATA_ERROR);
+		}
+	}
+	return(FINISHED);
+}
+
+/*************************** CREATE_CROSSMOD_BUFFERS **************************/
+//TW replaced by global
+//#define FSECSIZE (256)
+
+int create_crossmod_buffers(dataptr dz)
+{
+	size_t bigbufsize;
+	int framesize;
+	int bufchunks;
+
+	bufchunks  = dz->infile->channels;
+	bufchunks += dz->otherfile->channels;
+	bufchunks += max(dz->otherfile->channels,dz->infile->channels);
+	bigbufsize = (size_t)Malloc(-1);
+	dz->buflen = (int)(bigbufsize / sizeof(float));
+
+//TW MODIFIED ....
+	framesize = F_SECSIZE * bufchunks;
+	if((dz->buflen  = (dz->buflen/framesize) * framesize)<=0)
+		dz->buflen  = framesize;
+
+	if((dz->bigbuf = (float *)malloc(dz->buflen * sizeof(float))) == NULL) {
+		sprintf(errstr,"INSUFFICIENT MEMORY to create sound buffers.\n");
+		return(PROGRAM_ERROR);
+	}
+	dz->buflen /= bufchunks;
+	dz->sampbuf[0] = dz->bigbuf;
+	dz->sampbuf[1] = dz->sampbuf[0] + (dz->buflen * dz->infile->channels);
+	dz->sampbuf[2] = dz->sampbuf[1] + (dz->buflen * dz->otherfile->channels);
+	return(FINISHED);
+}
+
+/**************************** RING_MODULATE *************************/
+
+int ring_modulate(dataptr dz)
+{
+	int exit_status;
+	double sr = (double)dz->infile->srate;
+	int chans = dz->infile->channels;
+	double thistime = 0.0;
+	double this_pitch = 0.0, next_pitch, pitchstep = 0.0, thisfrq, tabstep, tabindex = 0.0, sinval;
+	double tabconvertor = (double)RM_SINTABSIZE/sr;
+	float  *ibuf = dz->sampbuf[0];
+	int blokcnt =  0;
+	long m,k,j,r;
+	long total_stereosamp_cnt = 0;
+	if(dz->brksize[RM_FRQ]) {
+		if((exit_status = read_value_from_brktable(thistime,RM_FRQ,dz))<0)
+			return(exit_status);
+	}
+	next_pitch = log10(dz->param[RM_FRQ]);
+	while(dz->samps_left > 0)	{
+		if((exit_status = read_samps(ibuf,dz))<0)
+			return(exit_status);
+		dz->ssampsread /= chans;
+		for(m=0,k=0;m<dz->ssampsread;m++,k+=chans) {
+			if(blokcnt<=0) {
+				total_stereosamp_cnt += RING_MOD_BLOK;
+				thistime = (double)total_stereosamp_cnt/sr;	/* reading 1 block ahead */
+				if(dz->brksize[RM_FRQ]) {
+					if((exit_status = read_value_from_brktable(thistime,RM_FRQ,dz))<0)
+						return(exit_status);
+				}
+				this_pitch = next_pitch;
+				next_pitch = log10(dz->param[RM_FRQ]);		
+				pitchstep  = (next_pitch - this_pitch)/(double)RING_MOD_BLOK;
+				blokcnt = RING_MOD_BLOK;
+			}
+			blokcnt--;
+			thisfrq = pow(10.0,this_pitch);
+			tabstep = thisfrq * tabconvertor;
+			sinval = read_rmod_tab(tabindex,dz);
+			for(j=0;j<chans;j++) {			
+				r = k+j;
+				ibuf[r] = (float)/*round*/((double)ibuf[r] * sinval);
+			}
+			tabindex += tabstep;	
+			while(tabindex >= (double)RM_SINTABSIZE)
+				tabindex  -= (double)RM_SINTABSIZE;
+			this_pitch += pitchstep;
+		}
+		if(dz->ssampsread > 0) {
+			if((exit_status = write_exact_samps(ibuf,dz->ssampsread * chans,dz))<0)
+				return(exit_status);
+		}
+	}
+	return(FINISHED);
+}
+
+/**************************** CROSS_MODULATE *************************/
+
+int cross_modulate(dataptr dz)
+{
+	int exit_status;
+	/*double sr = (double)dz->infile->srate;*/
+	float  *ibuf1 = dz->sampbuf[0];
+	float  *ibuf2 = dz->sampbuf[1];
+	float  *obuf  = dz->sampbuf[2];
+	int    chans1 = dz->infile->channels;
+	int    chans2 = dz->otherfile->channels;
+	int    maxchans = max(chans1,chans2);
+	int   samps_read, samps_read1, samps_read2, samps_to_write;
+	int   m,k,j,r;
+	dz->tempsize = max(dz->insams[0],dz->insams[1]);
+	display_virtual_time(0L,dz);
+	for(;;)	{
+		if((samps_read1 = fgetfbufEx(ibuf1,dz->buflen * chans1,dz->ifd[0],0))<0) {
+			sprintf(errstr,"Failed to read sound from 1st file.\n");
+			return(SYSTEM_ERROR);
+		}
+		if((samps_read2 = fgetfbufEx(ibuf2,dz->buflen * chans2,dz->ifd[1],0))<0) {
+			sprintf(errstr,"Failed to read sound from 2nd file.\n");
+			return(SYSTEM_ERROR);
+		}
+		if((samps_read = min(samps_read1/chans1,samps_read2/chans2))<=0)
+			break;
+		samps_to_write = samps_read * maxchans;
+		dz->ssampsread = samps_read;
+		
+		for(m=0;m<dz->ssampsread;m++) {
+			switch(chans1) {
+			case(STEREO):						//	STEREO-STEREO
+				switch(chans2) {
+				case(STEREO):
+					k = m * 2;
+					for(j=0;j<STEREO;j++) {			
+						r = k+j;
+						obuf[r] = (float)(ibuf1[r] * ibuf2[r]);
+					}
+					break;										
+				case(MONO):						//	STEREO-MONO
+					k = m * 2;
+					for(j=0;j<STEREO;j++) {			
+						r = k+j;
+						obuf[r] = (float)(ibuf1[r] * ibuf2[m]);
+					}
+					break;										
+				}
+				break;
+			case(MONO):							// MONO-MULTICHANNEL
+				k = m * chans2;
+				for(j=0;j<chans2;j++) {			
+					r = k+j;
+					obuf[r] = (float)(ibuf1[m] * ibuf2[r]);
+				}
+				break;
+			default:
+				switch(chans2) {				// MULTICHANNEL-MONO
+				case(MONO):
+					k = m * chans1;
+					for(j=0;j<chans1;j++) {			
+						r = k+j;
+						obuf[r] = (float)(ibuf1[r] * ibuf2[m]);
+					}
+					break;										
+				default:						// MULTICHANNEL-MULTICHANNEL
+					obuf[m] = (float)(ibuf1[m] * ibuf2[m]);
+					break;
+				}			//	OTHER POSSIBLE CHANNEL COMBOS ARE TRAPPED EARLIER
+			}
+		}
+		if(samps_to_write==dz->buflen * maxchans) {
+			if((exit_status = write_exact_samps(obuf,samps_to_write,dz))<0)
+				return(exit_status);
+		} else if(samps_to_write > 0) {
+			if((exit_status = write_samps(obuf,samps_to_write,dz))<0)
+				return(exit_status);
+		}
+	}
+	dz->infile->channels = maxchans;
+	return(FINISHED);
+}
+
+/**************************** READ_RMOD_TAB *************************/
+
+double read_rmod_tab(double dtabindex,dataptr dz)
+{
+	double *sintab = dz->parray[RM_SINTAB];
+	int    tabindex = (int)dtabindex;	/* TRUNCATE */
+	double frac  = dtabindex - (double)tabindex;
+	double loval =  sintab[tabindex];
+	double hival = 	sintab[tabindex+1];
+	double incr  =  (hival - loval) * frac;
+	return(loval + incr);
+}
+
+/********************** CREATE_RM_SINTAB *************************/
+
+int create_rm_sintab(dataptr dz)
+{
+	int n;
+	double *sintab, sinsize = (double) RM_SINTABSIZE;
+#ifdef NOTDEF
+	double scaling = (double)MAXSHORT/(double)(MAXSHORT+2);	/* avoid clipping inverted max -ve sample */
+#endif
+	if((dz->parray[RM_SINTAB] = (double *)malloc((RM_SINTABSIZE+1) * sizeof(double)))==NULL) {
+		sprintf(errstr,"INSUFFICIENT MEMORY for sine rtable.\n");
+		return(MEMORY_ERROR);
+	}
+	sintab = dz->parray[RM_SINTAB];
+	for(n=0;n<RM_SINTABSIZE;n++)
+		sintab[n] = sin(TWOPI * (double)n/sinsize) /* * scaling*/;
+	sintab[n] = 0.0;
+	return(FINISHED);
+}
+
+//TW UPDATE: NEW FUNCTIONS BELOW (converted to flotsams)
+/********************** STACK_PREPROCESS *************************/
+
+int stack_preprocess(dataptr dz)
+{
+	int n, k;
+	double  step, sum, thisstep, mult;
+
+	if(dz->itemcnt == 0) {		   /* value NOT in file */
+		if((dz->parray[STACK_TRANS] = 
+		(double *)realloc((char *)(dz->parray[STACK_TRANS]),dz->iparam[STACK_CNT] * sizeof(double)))==NULL) {
+			sprintf(errstr,"Insufficient memory for storing stack transpositions.\n");
+			return(MEMORY_ERROR);
+		}
+		thisstep = 1.0;
+		mult = dz->parray[STACK_TRANS][0];
+		if(mult > 1.0) {
+			for(n=0;n<dz->iparam[STACK_CNT];n++) {
+				dz->parray[STACK_TRANS][n] = thisstep;
+				thisstep *= mult;
+			}
+		} else {
+			for(n=dz->iparam[STACK_CNT] - 1;n>=0;n--) {	/* pitch highest track always at top */
+				dz->parray[STACK_TRANS][n] = thisstep;
+				thisstep *= mult;
+			}
+		}
+		dz->itemcnt  = dz->iparam[STACK_CNT];
+	} else if(dz->itemcnt != dz->iparam[STACK_CNT]) {
+		fprintf(stdout,"WARNING: Count of transposition values in file (%d)\n",dz->itemcnt);
+		fprintf(stdout,"WARNING: does not correspond to number of stack components entered as parameter (%d),\n",dz->iparam[STACK_CNT]);
+		fprintf(stdout,"WARNING: Using %d as number of transpositions\n",dz->itemcnt);
+		fflush(stdout);
+		dz->iparam[STACK_CNT] = dz->itemcnt;
+	}
+	if((dz->parray[STACK_AMP] = (double *)malloc(dz->iparam[STACK_CNT] * sizeof(double)))==NULL) {
+		sprintf(errstr,"Insufficient memory for storing stack amplitudes.\n");
+		return(MEMORY_ERROR);
+	}
+	dz->param[STACK_MINTRANS] = HUGE;
+	for(n=0;n<dz->iparam[STACK_CNT];n++)
+		dz->param[STACK_MINTRANS] = min(dz->param[STACK_MINTRANS],dz->parray[STACK_TRANS][n]);
+	dz->param[STACK_DUR]  = (double)round(dz->param[STACK_DUR] * 10)/10.0;	
+	if(flteq(dz->param[STACK_DUR],1.0))
+		dz->iparam[STACK_DUR] = 0;
+	else if(flteq(dz->param[STACK_DUR],0.0)) {
+		sprintf(errstr,"You have asked to make NONE of the output!!");
+		return(USER_ERROR);
+	} else {
+		dz->param[STACK_DUR] /= dz->param[STACK_MINTRANS];
+		dz->iparam[STACK_DUR] = round(dz->param[STACK_DUR] * (dz->insams[0]/dz->infile->channels)) * dz->infile->channels;
+	}
+	/* attack distance from start, in input, in grouped-samples */
+	dz->iparam[STACK_OFFSET] = (long)round(dz->param[STACK_OFFSET] * dz->infile->srate);	
+/* attack distance from start, in output of slowest transposition, in grouped-samples */
+	if(dz->param[STACK_MINTRANS] < 1.0)
+		dz->iparam[STACK_OFFSET] = (long)round(dz->iparam[STACK_OFFSET] * (1.0/dz->param[STACK_MINTRANS]));		
+
+	k = dz->iparam[STACK_CNT] - 1;
+	if(flteq(dz->param[STACK_LEAN],1.0)) {
+		for(n=0;n<dz->iparam[STACK_CNT];n++)
+			dz->parray[STACK_AMP][n] = dz->param[STACK_GAIN]/dz->iparam[STACK_CNT];
+	} else { 
+		dz->parray[STACK_AMP][0] = dz->param[STACK_LEAN];
+		dz->parray[STACK_AMP][k] = 1.0;
+		step = dz->parray[STACK_AMP][k] - dz->parray[STACK_AMP][0];
+		step /= (double)k;
+		for(n = 1; n < k; n++)
+			dz->parray[STACK_AMP][n] = dz->parray[STACK_AMP][n-1] + step;
+		sum = 0.0;
+		for(n = 0; n < dz->iparam[STACK_CNT]; n++)
+			sum += dz->parray[STACK_AMP][n];
+		for(n = 0; n < dz->iparam[STACK_CNT]; n++) {
+			dz->parray[STACK_AMP][n] /= sum;
+			dz->parray[STACK_AMP][n] *= dz->param[STACK_GAIN];
+			if(dz->vflag[STACK_SEE]) {
+				fprintf(stdout,"INFO: stackitem[%d] level %lf\n",n,dz->parray[STACK_AMP][n]);
+			}
+		}
+		if(dz->vflag[STACK_SEE])
+			fflush(stdout);
+	}
+	return(FINISHED);
+}
+
+/********************** DO_STACK *************************/
+
+int do_stack(dataptr dz)
+{
+	int exit_status;
+//TW ADDED FOR MULTICHANNEL WORK
+	int qq;
+	float *ibuf = dz->sampbuf[0], *obuf = dz->sampbuf[1];
+	int chans = dz->infile->channels;
+	int bufsamplen = dz->buflen/chans;	/* buffer length in grouped-samples */
+	int all_transpositions_active, n, nn, lastpos, *obufpos, max_obufpos;
+	double *inbufpos, maxoutsamp;
+	int *active_transpos;
+	float *lastibufval;
+	int *obufskip, *seeklen, *origseeklen, *offset, *eof_in_ibuf;
+
+	if(dz->iparam[STACK_DUR] <= 0)
+		dz->tempsize = (int)round(dz->insams[0] * (1.0/dz->param[STACK_MINTRANS]));
+	else 
+		dz->tempsize = dz->iparam[STACK_DUR];
+
+	if((inbufpos = (double *)malloc(dz->iparam[STACK_CNT] * sizeof(double)))==NULL) {
+		sprintf(errstr,"Insufficient memory for storing input buffer pointers.\n");
+		return(MEMORY_ERROR);
+	}
+	if((obufpos = (int *)malloc(dz->iparam[STACK_CNT] * sizeof(int)))==NULL) {
+		sprintf(errstr,"Insufficient memory for storing output buffer pointers.\n");
+		return(MEMORY_ERROR);
+	}
+	if((active_transpos = (int *)malloc(dz->iparam[STACK_CNT] * sizeof(int)))==NULL) {
+		sprintf(errstr,"Insufficient memory for storing transposition flags.\n");
+		return(MEMORY_ERROR);
+	}
+	if((obufskip = (int *)malloc(dz->iparam[STACK_CNT] * sizeof(int)))==NULL) {
+		sprintf(errstr,"Insufficient memory for storing seek values.\n");
+		return(MEMORY_ERROR);
+	}
+	if((lastibufval = (float *)malloc(dz->iparam[STACK_CNT] * sizeof(float) * dz->infile->channels))==NULL) {
+		sprintf(errstr,"Insufficient memory for storing last values in input bufs values.\n");
+		return(MEMORY_ERROR);
+	}
+	if((seeklen = (int *)malloc(dz->iparam[STACK_CNT] * sizeof(int)))==NULL) {
+		sprintf(errstr,"Insufficient memory for storing seek values.\n");
+		return(MEMORY_ERROR);
+	}
+	if((origseeklen = (int *)malloc(dz->iparam[STACK_CNT] * sizeof(int)))==NULL) {
+		sprintf(errstr,"Insufficient memory for storing original seek values.\n");
+		return(MEMORY_ERROR);
+	}
+	if((offset = (int *)malloc(dz->iparam[STACK_CNT] * sizeof(int)))==NULL) {
+		sprintf(errstr,"Insufficient memory for storing offset values.\n");
+		return(MEMORY_ERROR);
+	}
+	if((eof_in_ibuf = (int *)malloc(dz->iparam[STACK_CNT] * sizeof(int)))==NULL) {
+		sprintf(errstr,"Insufficient memory for storing end-of-file markers.\n");
+		return(MEMORY_ERROR);
+	}
+
+	all_transpositions_active = 0;
+	for(n=0;n<dz->iparam[STACK_CNT];n++) {
+		all_transpositions_active |= (int) pow(2.0,n);	/* set all bitflags for active buffers */
+	 	seeklen[n] = origseeklen[n] = 0;
+		inbufpos[n] = 0.0;
+	 	obufskip[n] = get_obuf_sampoffset(n,dz);
+		eof_in_ibuf[n]  = dz->insams[0];
+		lastibufval[n]  = 0.0f;
+		active_transpos[n] = 1;
+	}
+	if(chans > 1) {
+		while(n < dz->iparam[STACK_CNT] * chans)
+			lastibufval[n++]  = 0.0f;
+	}
+	if(dz->vflag[1]) {
+
+		/* GET MAX OUTPUT LEVEL, THEN ADJUST LATER */
+		if(sloom) {
+			fprintf(stdout,"INFO: Assessing Output Level.\n");
+			fflush(stdout);
+		}
+		maxoutsamp = 0.0;
+		do {
+			memset((char *)obuf,0,dz->buflen * sizeof(float));	/* clear the output buffer */
+			max_obufpos = 0;					  	/* clear count of outsamps written */
+
+			for(n=0;n<dz->iparam[STACK_CNT];n++) {	/* For each transposition */
+
+				if(!active_transpos[n])				/* if this transposition inactive, go to next transpos */
+					continue;
+				if(obufskip[n] >= dz->buflen) {		/* if more samps to skip than space in obuf */
+					obufskip[n] -= dz->buflen;		/* decrement skip-value, ready for next outbuf, & go to next transpos */
+					continue;
+				}									/* get the current seek position for this transposition */
+				sndseekEx(dz->ifd[0],seeklen[n],0);	/* go to current buffer in infile, for this transposition */
+				obufpos[n] = obufskip[n];			/* set pointer to start in outputbuf for this write */
+
+					/* THIS LOOP READS INPUT AND WRITES OUTPUT UNTIL outbuf FULL OR inbuf OR infile EXHAUSTED */
+				do {
+					memset((char *)ibuf,0,dz->buflen * sizeof(float));	/* clear the input buffer */
+					if((exit_status = read_samps(ibuf,dz)) < 0) {
+						sprintf(errstr,"Failed to read from input file.\n");
+						return(PROGRAM_ERROR);
+					}
+
+						/* THIS LOOP WRITES OUTPUT UNTIL outbuf FULL OR inbuf OR infile EXHAUSTED */
+					do {
+						if((exit_status = transpos_and_add_to_obuf(n,&(obufpos[n]),&(inbufpos[n]),lastibufval,chans,dz)) < 0)
+							return(exit_status);
+						if(inbufpos[n] > (double)eof_in_ibuf[n]) {
+							active_transpos[n] = 0;						/* break at end of input FILE */
+							break;
+						} 															
+			 			if (inbufpos[n] > bufsamplen - 1) {				/* break at end of input BUFFER */
+
+							inbufpos[n] -= (double)bufsamplen;			/* move ibufpointer to buf start */
+							lastpos = dz->buflen - chans;				/* get last position in current buffer */
+	// MODIFY FOR MULTICHANNEL WORK
+							for(qq=0;qq<chans;qq++)
+								lastibufval[n+(dz->iparam[STACK_CNT] * qq)] = ibuf[lastpos++];
+							seeklen[n] += dz->buflen;					/* set seek position for next read, in case */					
+																		/* we (later) break out during a WRITE-end */
+																		
+							if((eof_in_ibuf[n] -= dz->buflen) <= dz->buflen)	/* if EOF is in the next buffer */
+								eof_in_ibuf[n] /= chans;				/* convert to a grouped-sample count */
+							break;										/* break from here and READ MORE INFILE */
+						}
+					} while(obufpos[n] < dz->buflen);					/* break at end of OUTPUT BUFFER */
+
+				} while(active_transpos[n] && (obufpos[n] < dz->buflen));	/* if inFILE or outBUF finished, break from loop */
+				max_obufpos = max(max_obufpos,obufpos[n]);
+				obufskip[n] = 0;									/* written outbuf we skipped into, so NO skip next time */
+				if(!active_transpos[n])								/* if FILE finished, reset flag for outer loop */
+					all_transpositions_active &= ~((int) pow(2.0,n));
+			}
+			if(max_obufpos > 0) {
+				if(dz->iparam[STACK_DUR] > 0) {
+					if(dz->total_samps_written + max_obufpos >= dz->iparam[STACK_DUR]) {
+						max_obufpos = dz->iparam[STACK_DUR] - dz->total_samps_written;
+						all_transpositions_active = 0;
+					}
+				}
+				for(nn = 0; nn < max_obufpos; nn++) {
+					if(fabs(obuf[nn]) > maxoutsamp)
+						maxoutsamp = fabs(obuf[nn]);
+				}
+			}					
+		} while(all_transpositions_active);
+		
+		
+		if(flteq(maxoutsamp,0.0)) {
+			sprintf(errstr,"NO SIGNIFICANT SIGNAL LEVEL GENERATED\n");
+			return(DATA_ERROR);
+		}
+		for(n = 0; n < dz->iparam[STACK_CNT]; n++)
+			dz->parray[STACK_AMP][n] *= (0.95/maxoutsamp);
+
+		all_transpositions_active = 0;
+		for(n=0;n<dz->iparam[STACK_CNT];n++) {
+			all_transpositions_active |= (int)pow(2.0,n);	/* set all bitflags for active buffers */
+	 		seeklen[n] = origseeklen[n] = 0;
+			inbufpos[n] = 0.0;
+	 		obufskip[n] = get_obuf_sampoffset(n,dz);
+			eof_in_ibuf[n]  = dz->insams[0];
+			lastibufval[n]  = 0.0f;
+			active_transpos[n] = 1;
+		}
+		if(chans > 1) {
+			while(n < dz->iparam[STACK_CNT] * chans)
+				lastibufval[n++]  = 0.0f;
+		}
+		if(sloom) {
+			fprintf(stdout,"INFO: Generating Output.\n");
+			fflush(stdout);
+		}
+	}
+	
+		/* THIS LOOP REPEATS UNTIL ALL INPUT TRANSPOSITION PROCESSES ARE COMPLETED */
+
+	do {
+		memset((char *)obuf,0,dz->buflen * sizeof(float));	/* clear the output buffer */
+		max_obufpos = 0;					  	/* clear count of outsamps written */
+
+		for(n=0;n<dz->iparam[STACK_CNT];n++) {	/* For each transposition */
+
+			if(!active_transpos[n])				/* if this transposition inactive, go to next transpos */
+				continue;
+			if(obufskip[n] >= dz->buflen) {		/* if more samps to skip than space in obuf */
+				obufskip[n] -= dz->buflen;		/* decrement skip-value, ready for next outbuf, & go to next transpos */
+				continue;
+			}									/* get the current seek position for this transposition */
+			sndseekEx(dz->ifd[0],seeklen[n],0);	/* go to current buffer in infile, for this transposition */
+			obufpos[n] = obufskip[n];			/* set pointer to start in outputbuf for this write */
+
+				/* THIS LOOP READS INPUT AND WRITES OUTPUT UNTIL outbuf FULL OR inbuf OR infile EXHAUSTED */
+			do {
+				memset((char *)ibuf,0,dz->buflen * sizeof(float));	/* clear the input buffer */
+				if((exit_status = read_samps(ibuf,dz)) < 0) {
+					sprintf(errstr,"Failed to read from input file.\n");
+					return(PROGRAM_ERROR);
+				}
+
+					/* THIS LOOP WRITES OUTPUT UNTIL outbuf FULL OR inbuf OR infile EXHAUSTED */
+				do {
+					if((exit_status = transpos_and_add_to_obuf(n,&(obufpos[n]),&(inbufpos[n]),lastibufval,chans,dz)) < 0)
+						return(exit_status);
+					if(inbufpos[n] > (double)eof_in_ibuf[n]) {
+						active_transpos[n] = 0;						/* break at end of input FILE */
+						break;
+					} 															
+			 		if (inbufpos[n] > bufsamplen - 1) {				/* break at end of input BUFFER */
+
+						inbufpos[n] -= (double)bufsamplen;			/* move ibufpointer to buf start */
+						lastpos = dz->buflen - chans;				/* get last position in current buffer */
+// MODIFY FOR MULTICHANNEL WORK
+						for(qq=0;qq<chans;qq++)
+							lastibufval[n+(dz->iparam[STACK_CNT] * qq)] = ibuf[lastpos++];
+						seeklen[n] += dz->buflen;					/* set seek position for next read, in case */					
+																	/* we (later) break out during a WRITE-end */
+																	
+						if((eof_in_ibuf[n] -= dz->buflen) <= dz->buflen)	/* if EOF is in the next buffer */
+							eof_in_ibuf[n] /= chans;				/* convert to a grouped-sample count */
+						break;										/* break from here and READ MORE INFILE */
+					}
+				} while(obufpos[n] < dz->buflen);					/* break at end of OUTPUT BUFFER */
+
+			} while(active_transpos[n] && (obufpos[n] < dz->buflen));	/* if inFILE or outBUF finished, break from loop */
+			max_obufpos = max(max_obufpos,obufpos[n]);
+			obufskip[n] = 0;									/* written outbuf we skipped into, so NO skip next time */
+			if(!active_transpos[n])								/* if FILE finished, reset flag for outer loop */
+				all_transpositions_active &= ~((int)pow(2.0,n));
+		}
+		if(max_obufpos > 0) {
+			if(dz->iparam[STACK_DUR] > 0) {
+				if(dz->total_samps_written + max_obufpos >= dz->iparam[STACK_DUR]) {
+					max_obufpos = dz->iparam[STACK_DUR] - dz->total_samps_written;
+					all_transpositions_active = 0;
+				}
+			}
+			if((exit_status = write_samps(obuf,max_obufpos,dz))<0)
+				return(exit_status);
+		}					
+	} while(all_transpositions_active);
+	return(FINISHED);
+}
+
+/********************** GET_OBUF_SAMPOFFSET *************************/
+
+int get_obuf_sampoffset(int n,dataptr dz)
+{
+	double speed_ratio_vs_slowest, offset_frac;
+	int skip;
+
+	speed_ratio_vs_slowest = dz->parray[STACK_TRANS][n]/dz->param[STACK_MINTRANS];
+	if(flteq(speed_ratio_vs_slowest,1.0))
+		return 0;
+	offset_frac = 1.0 - (1.0/speed_ratio_vs_slowest);
+	skip = (int)round(dz->iparam[STACK_OFFSET] * offset_frac);
+	return (skip * dz->infile->channels);
+
+}
+
+/********************** TRANSPOS_AND_ADD_TO_OBUF *************************/
+//TW new version for multichannel work !!
+int transpos_and_add_to_obuf(int n,int *obufpos,double *inbufpos,float *lastival,int chans,dataptr dz)
+{
+	float lastval, nextval, *ibuf = dz->sampbuf[0], *obuf = dz->sampbuf[1];
+	int i_bufpos, o_bufpos = *obufpos, i_bufpos_base = 0;
+	int k;
+	double step, val;
+
+	if(*inbufpos < -1.0) {
+		sprintf(errstr,"Impossible input buffer position encountered\n");
+		return(PROGRAM_ERROR);
+	}
+	if(*inbufpos < 0.0)	  				/* ibuf pointer points between lastval in last buffer and 1st in this buffer */
+		step = 1.0 + (*inbufpos);		/* interp position between these */
+	else {
+		step = fmod(*inbufpos,1.0);
+		i_bufpos_base = (int)floor(*inbufpos) * chans;
+	}
+	for(k=0;k<chans;k++) {
+		if(*inbufpos < 0.0) {	  			/* ibuf pointer points between lastval in last buffer and 1st in this buffer */
+			i_bufpos = k;					/* point to channel at start of this buffer */
+			lastval = lastival[n + (k * dz->iparam[STACK_CNT])];	/* get channel-val from end of last bufer */
+			nextval = ibuf[i_bufpos];	
+		} else {
+			i_bufpos = i_bufpos_base + k;
+			lastval = ibuf[i_bufpos];
+			nextval = ibuf[i_bufpos+chans];	
+		}												/* add interpd val to val already in outbuf */
+		val = lastval + ((nextval - lastval) * step);
+		val *= dz->parray[STACK_AMP][n];			/* scaling by amplitude scalers */
+		obuf[o_bufpos] = (float)(obuf[o_bufpos] + val);
+		o_bufpos++;
+	}
+	*obufpos = o_bufpos;							/* advance normally in outbuf */
+	*inbufpos += dz->parray[STACK_TRANS][n];		/* advance ibuf-pointer by transpos value */
+	return(FINISHED);
+}

+ 1268 - 0
dev/modify/strans.c

@@ -0,0 +1,1268 @@
+/*
+ * Copyright (c) 1983-2013 Trevor Wishart and Composers Desktop Project Ltd
+ * http://www.trevorwishart.co.uk
+ * http://www.composersdesktop.com
+ *
+ This file is part of the CDP System.
+
+    The CDP System is free software; you can redistribute it
+    and/or modify it under the terms of the GNU Lesser General Public
+    License as published by the Free Software Foundation; either
+    version 2.1 of the License, or (at your option) any later version.
+
+    The CDP System is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public
+    License along with the CDP System; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+    02111-1307 USA
+ *
+ */
+
+
+
+/* floatsam version */
+#include <stdio.h>
+#include <stdlib.h>
+#include <memory.h>
+#include <structures.h>
+#include <tkglobals.h>
+#include <globcon.h>
+#include <cdpmain.h>
+#include <modeno.h>
+#include <pnames.h>
+#include <arrays.h>
+#include <flags.h>
+#include <modify.h>
+
+#include <sfsys.h>
+
+#ifdef unix
+#define round(x) lround((x))
+#else
+#define round(x) cdp_round((x))
+#endif
+
+#define CALCLIM (0.02)
+#define MININC 	(0.002)		/* rwd - black hole avoidance */
+
+static int  create_vtrans_buffers(dataptr dz);
+static int  create_strans_buffers(dataptr dz);
+
+static int	read_wrapped_samps_mono(dataptr dz);
+static int	read_wrapped_samps_stereo(dataptr dz);
+
+static int	strans_process(dataptr dz);
+static int  vtrans_process(dataptr dz);
+static int  do_acceleration(dataptr dz);
+static int  do_vibrato(dataptr dz);
+
+static int 		vtrans_vtrans(dataptr dz);
+static int 		read_samps_for_vtrans(dataptr dz);
+static int	 	write_samps_with_intime_display(float *buffer,int samps_to_write,dataptr dz);
+static int 		convert_brkpnts(dataptr dz);
+static int 		timevents(int *obufcnt,int intime0,int intime1,double insize0,double insize1,dataptr dz);
+static double 	cntevents(int dur,double s0,double s1);
+static int 		samesize(int *obufcnt,int intime0,double insize0,double insize1,int duration,dataptr dz);
+static int 		integral_times(int *obufcnt,int intime0,int isize,int number,dataptr dz);
+static int 		putintval(int *obufcnt,int i,dataptr dz);
+static int 		unvarying_times(int *obufcnt,int intime0,double size,int number,dataptr dz);
+static int 		getetime(int *obufcnt,int t0,int t1,double s0,double s1,int number,dataptr dz);
+static double 	refinesize(double hibound,double lobound,double fnumber,int duration,double error,double insize0);
+static int 		putval(int *obufcnt,double pos,dataptr dz);
+static int 		sizeq(double f1,double f2);
+static int 		change_frame(dataptr dz);
+static int 	inv_cntevents(int dur,double s0,double s1);
+static int 		force_value_at_end_time(int paramno,dataptr dz);
+static void 	splice_end(int obufcnt,dataptr dz);
+static double 	interp_read_sintable(double *sintab,double sfindex);
+
+/************************* VTRANS_PREPROCESS *****************************/
+
+int vtrans_preprocess(dataptr dz)
+{
+	double acceltime, tabratio, *p, *pend;
+	int n;
+	switch(dz->mode) {
+	case(MOD_TRANSPOS):
+	case(MOD_TRANSPOS_SEMIT):
+	case(MOD_TRANSPOS_INFO):
+	case(MOD_TRANSPOS_SEMIT_INFO):
+	    dz->iparam[UNITSIZE] = dz->insams[0]/dz->infile->channels;
+	    dz->param[VTRANS_SR] = (double)dz->infile->srate;
+		dz->iparam[TOTAL_UNITS_READ] = 0;
+		break;
+	case(MOD_ACCEL):
+		acceltime = dz->param[ACCEL_GOALTIME] - dz->param[ACCEL_STARTTIME];		
+    	if(acceltime < MINTIME_ACCEL) {
+    		sprintf(errstr,"time for acceleration (%lf) must be greater than  %.3fsecs\n",acceltime,MINTIME_ACCEL);
+			return(DATA_ERROR);
+		}
+	    dz->param[ACCEL_ACCEL] = pow(dz->param[ACCEL_ACCEL],(1.0/(acceltime *(double)dz->infile->srate)));
+		dz->iparam[ACCEL_STARTTIME] = 	/* convert to time-in-samples */
+		round(dz->param[ACCEL_STARTTIME] * (double)dz->infile->srate) * dz->infile->channels;
+		break;
+	case(MOD_VIBRATO):
+		tabratio = (double)VIB_TABSIZE/(double)dz->infile->srate;  	/* converts frq to sintable step */
+		if(dz->brksize[VIB_FRQ]) {
+			p    = dz->brk[VIB_FRQ] + 1;
+			pend = dz->brk[VIB_FRQ] + (dz->brksize[VIB_FRQ] * 2);
+			while(p < pend) {
+				*p *= tabratio;
+				p += 2;
+			}
+		} else
+			dz->param[VIB_FRQ] *= tabratio;
+		if(dz->brksize[VIB_DEPTH]) {								   /* converts semitones to 8vas */
+			p    = dz->brk[VIB_DEPTH] + 1;
+			pend = dz->brk[VIB_DEPTH] + (dz->brksize[VIB_DEPTH] * 2);
+			while(p < pend) {
+				*p *= OCTAVES_PER_SEMITONE;
+				p += 2;
+			}
+		} else
+			dz->param[VIB_DEPTH] *= OCTAVES_PER_SEMITONE;
+		if((dz->parray[VIB_SINTAB] = (double *)malloc((VIB_TABSIZE + 1) * sizeof(double)))==NULL) {
+			sprintf(errstr,"INSUFFICIENT MEMORY for vibrato sintable.\n");
+			return(MEMORY_ERROR);
+		}
+		tabratio = TWOPI/(double)VIB_TABSIZE;			   /* converts table-step to fraction of 2PI */
+		for(n=0;n<VIB_TABSIZE;n++)
+			dz->parray[VIB_SINTAB][n] = sin((double)n * tabratio);
+		dz->parray[VIB_SINTAB][n] = 0.0;		
+		break;
+	}
+	return(FINISHED);
+}
+
+/************************* CREATE_MODSPEED_BUFFERS *****************************/
+
+int create_modspeed_buffers(dataptr dz)
+{
+	switch(dz->mode) {
+	case(MOD_TRANSPOS):
+	case(MOD_TRANSPOS_SEMIT):
+	case(MOD_TRANSPOS_INFO):
+	case(MOD_TRANSPOS_SEMIT_INFO):
+		if(dz->brksize[VTRANS_TRANS]==0)
+			return create_strans_buffers(dz);
+		return create_vtrans_buffers(dz);
+	case(MOD_ACCEL):
+	case(MOD_VIBRATO):
+		return create_strans_buffers(dz);
+	default:
+		sprintf(errstr,"Buffers not established for this MOD_SPEED mode.\n");
+		break;
+	}
+	return(PROGRAM_ERROR);
+}
+
+/************************* CREATE_STRANS_BUFFERS *****************************/
+//TW replaced by global
+//#define FSECSIZE (256)
+int create_strans_buffers(dataptr dz)
+{
+	size_t bigbufsize;
+	int framesize;
+	int guardspace = dz->infile->channels * sizeof(float); /* WRAPPED POINT(S) */
+	bigbufsize = (size_t)Malloc(-1);
+	
+	/* RWD belt'n'braces */
+	if(dz->infile->channels>STEREO) {
+		sprintf(errstr, "File has too many channels.\n");
+			return(DATA_ERROR);
+	}
+
+	if(dz->infile->channels==STEREO) {
+//TW Safety first: stick to existing secsize-convention for now
+//6 takes into account STEREO channel-count; no need to realign.
+//Will do it completely differently when go to 4+ channels
+		framesize = F_SECSIZE * sizeof(float) * 6;	
+		if((bigbufsize   = (bigbufsize/framesize) * framesize)<=0)
+			bigbufsize   = framesize;
+		dz->buflen    = (int)(bigbufsize / 3 / sizeof(float));
+		bigbufsize = dz->buflen * 3 * sizeof(float);
+		dz->iparam[VTRANS_HBUFSIZE] = dz->buflen/2;
+		if((dz->bigbuf = (float *)Malloc(bigbufsize + guardspace)) == 0) {
+			sprintf(errstr,"INSUFFICIENT MEMORY FOR SND BUFFERS.\n");
+			return(MEMORY_ERROR);
+		}
+		memset((char *)dz->bigbuf,0,bigbufsize + guardspace);
+		/*dz->bigbufsize = dz->bigbufsize/3;*/
+		dz->sampbuf[TRUE_LBUF] = dz->bigbuf;
+		dz->sampbuf[L_GRDPNT]  = dz->sampbuf[TRUE_LBUF];	/* GUARD POINT */
+		dz->sampbuf[LBUF]      = dz->bigbuf + 1;			
+		dz->sampbuf[TRUE_RBUF] = dz->sampbuf[LBUF] + dz->iparam[VTRANS_HBUFSIZE];
+		dz->sampbuf[R_GRDPNT]  = dz->sampbuf[TRUE_RBUF];
+		dz->sampbuf[RBUF] 	   = dz->sampbuf[R_GRDPNT] + 1;			
+		dz->sampbuf[INBUF] 	   = dz->sampbuf[RBUF] + dz->iparam[VTRANS_HBUFSIZE];
+		dz->sampbuf[OUTBUF]    = dz->sampbuf[INBUF] + dz->buflen;
+		dz->sampbuf[OBUFEND]   = dz->sampbuf[OUTBUF] + dz->buflen;
+	} else {		
+//TW Safety first: stick to existing secsize-convention for now
+		framesize = F_SECSIZE * sizeof(float) * 2;
+		bigbufsize  = (bigbufsize/framesize) * framesize;
+		dz->buflen      = bigbufsize/2/sizeof(float);
+		/* RWD probably unnecessary, but may be when we move to nChannels */
+		bigbufsize = dz->buflen * 2 * sizeof(float);
+		if((dz->bigbuf = (float *)malloc(bigbufsize + guardspace)) == 0) {
+			sprintf(errstr, "Can't allocate memory for sound.\n");
+			return(MEMORY_ERROR);
+		}
+		memset((char *)dz->bigbuf,0,bigbufsize + guardspace);
+		/*dz->bigbufsize /= 2;*/
+		dz->sampbuf[TRUE_LBUF] = dz->bigbuf;
+		dz->sampbuf[L_GRDPNT]  = dz->sampbuf[TRUE_LBUF];
+		dz->sampbuf[INBUF] = dz->bigbuf + 1;
+		dz->sampbuf[OUTBUF] = dz->sampbuf[INBUF] + dz->buflen;
+		dz->sampbuf[OBUFEND]   = dz->sampbuf[OUTBUF] + dz->buflen;
+	}
+	return(FINISHED);
+}
+
+/*************************** CREATE_VTRANS_BUFFERS **************************/
+
+int create_vtrans_buffers(dataptr dz)
+{
+	size_t bigbufsize;
+//TW: SAFETY FIRST for now
+	int fsecbytesize = F_SECSIZE * sizeof(float);
+	bigbufsize = (size_t)Malloc(-1);
+	bigbufsize /= dz->bufcnt;
+//TW: SAFETY FIRST for now
+	bigbufsize = (bigbufsize/fsecbytesize) * fsecbytesize;
+
+	dz->buflen = bigbufsize/sizeof(float);
+	dz->iparam[UNIT_BUFLEN] = dz->buflen/dz->infile->channels;
+	bigbufsize = dz->buflen * sizeof(float);
+
+	if((dz->bigbuf = (float *)malloc((bigbufsize * dz->bufcnt) + fsecbytesize)) == NULL) {
+		sprintf(errstr, "Can't allocate memory for sound.\n");
+		return(MEMORY_ERROR);
+	}
+	dz->sampbuf[INBUF]  = dz->bigbuf;
+	dz->sampbuf[OUTBUF] = dz->sampbuf[INBUF] + dz->buflen + F_SECSIZE;
+	return(FINISHED);
+}
+
+/************************* PROCESS_VARISPEED ******************************/
+
+int process_varispeed(dataptr dz)
+{
+	switch(dz->mode) {
+	case(MOD_ACCEL):	
+		return do_acceleration(dz);
+	case(MOD_VIBRATO):	
+		return do_vibrato(dz);
+	case(MOD_TRANSPOS):
+	case(MOD_TRANSPOS_SEMIT):
+	case(MOD_TRANSPOS_INFO):
+	case(MOD_TRANSPOS_SEMIT_INFO):
+		if(dz->brksize[VTRANS_TRANS]==0)
+			return strans_process(dz);
+		return vtrans_process(dz);
+	}
+	/* RWD 9:2001 need retval*/
+	return PROGRAM_ERROR;
+}
+
+/************************* STRANS_PROCESS ******************************/
+
+int strans_process(dataptr dz)
+{   
+	int exit_status;
+	int place;
+	double flplace = 1.0, fracsamp, step;
+//HEREH
+	double  interp;
+	float *obufptr  = dz->sampbuf[OUTBUF];
+	float *obuf     = dz->sampbuf[OUTBUF];
+	float *obufend  = dz->sampbuf[OBUFEND];
+	float *true_lbuf = dz->sampbuf[TRUE_LBUF];
+	float *true_rbuf;
+	double place_inc = dz->param[VTRANS_TRANS];
+	switch(dz->mode) {
+	case(MOD_TRANSPOS_INFO):
+		sprintf(errstr,"Output duration = %lf secs\n",dz->duration/dz->param[VTRANS_TRANS]);
+		if(!sloom) {
+			fprintf(stdout,"INFO: END\n");
+			fflush(stdout);
+		}
+		return(FINISHED);
+	case(MOD_TRANSPOS_SEMIT_INFO):
+		place_inc = pow(2.0,(place_inc * OCTAVES_PER_SEMITONE));
+		sprintf(errstr,"Output duration = %lf secs\n",dz->duration/place_inc);
+		if(!sloom) {
+			fprintf(stdout,"INFO: END\n");
+			fflush(stdout);
+		}
+		return(FINISHED);
+	case(MOD_TRANSPOS_SEMIT):
+		place_inc = pow(2.0,(place_inc * OCTAVES_PER_SEMITONE));
+		break;
+	}
+	switch(dz->infile->channels) {
+    case(MONO):
+		if((exit_status = read_wrapped_samps_mono(dz))<0)
+			return(exit_status);
+		while(dz->ssampsread > 0) {
+			while(flplace < (double)dz->ssampsread) {
+				place    = (int)flplace;
+				fracsamp = flplace - (double)place;
+				step     = true_lbuf[place+1] - true_lbuf[place];
+//				interp   = round(fracsamp * step);
+				interp   = fracsamp * step;
+				*obufptr = (float)(true_lbuf[place] + interp);
+				if(++obufptr >= obufend) {
+					if((exit_status = write_samps(obuf,dz->buflen,dz))<0)
+						return(exit_status);
+					obufptr = obuf;
+				}
+				flplace   += place_inc;
+			}
+			if((exit_status = read_wrapped_samps_mono(dz))<0)
+				return(exit_status);
+			flplace -= (double)dz->buflen;
+		}
+		break;
+	case(STEREO):
+		true_rbuf = dz->sampbuf[TRUE_RBUF];
+		if((exit_status = read_wrapped_samps_stereo(dz))<0)
+			return(exit_status);
+		while(dz->ssampsread > 0) {					/* 2 */
+			while(flplace < (double)dz->ssampsread) {
+				place      = (int)flplace;
+				fracsamp   = flplace - (double)place;
+				step       = true_lbuf[place+1] - true_lbuf[place];
+//				interp     = round(fracsamp * step);
+				interp     = fracsamp * step;
+				*obufptr++ = (float)(true_lbuf[place] + interp);
+				step       = true_rbuf[place+1] - true_rbuf[place];
+//				interp     = round(fracsamp * step);
+				interp     = fracsamp * step;
+				*obufptr++ = (float)(true_rbuf[place] + interp);
+				if(obufptr >= obufend) {
+					if((exit_status = write_samps(obuf,dz->buflen,dz))<0)
+						return(exit_status);
+					obufptr = obuf;
+				}
+				flplace += place_inc;
+			}
+			if((exit_status = read_wrapped_samps_stereo(dz))<0)
+				return(exit_status);
+			flplace -= (double)dz->iparam[VTRANS_HBUFSIZE];
+		}
+		break;
+	}
+    if(obufptr!=obuf)					/* 12 */
+		return write_samps(obuf,obufptr - obuf,dz);
+	return(FINISHED);
+}
+
+/************************** READ_WRAPPED_SAMPS_MONO *****************************/
+
+int read_wrapped_samps_mono(dataptr dz)
+{   
+	*(dz->sampbuf[L_GRDPNT]) = *(dz->sampbuf[INBUF] + dz->buflen - 1);
+    return read_samps(dz->sampbuf[INBUF], dz);
+}
+								   
+/************************* READ_WRAPPED_SAMPS_STEREO *****************************/
+
+int read_wrapped_samps_stereo(dataptr dz)
+{
+	int exit_status;
+	int n, m;
+	float *lbuf 	= dz->sampbuf[LBUF];
+	float *rbuf 	= dz->sampbuf[RBUF];
+	float *l_grdpnt = dz->sampbuf[L_GRDPNT];
+	float *r_grdpnt	= dz->sampbuf[R_GRDPNT];
+	*l_grdpnt = *(lbuf + dz->iparam[VTRANS_HBUFSIZE] - 1);
+	*r_grdpnt = *(rbuf + dz->iparam[VTRANS_HBUFSIZE] - 1);
+	if((exit_status = read_samps(dz->sampbuf[INBUF],dz))<0) 
+		return(exit_status);
+	for(n = 0, m = 0; n < dz->ssampsread; m++, n+=2) {
+		lbuf[m] = dz->sampbuf[INBUF][n];
+		rbuf[m] = dz->sampbuf[INBUF][n+1];
+	}
+	dz->ssampsread /= 2; 	/* stereo */
+	return(FINISHED);
+}
+
+/****************************** VTRANS_PROCESS *************************/
+
+int vtrans_process(dataptr dz)
+{
+	int exit_status;
+	if((exit_status = convert_brkpnts(dz))<0)
+		return(exit_status);
+	if((exit_status = change_frame(dz))<0)
+		return(exit_status);
+	if(dz->mode==MOD_TRANSPOS_INFO || dz->mode==MOD_TRANSPOS_SEMIT_INFO)
+		return(FINISHED);
+    if((exit_status = create_vtrans_buffers(dz))<0)
+		return(exit_status);
+    return vtrans_vtrans(dz);
+}
+
+/****************************** VTRANS_VTRANS *************************/
+
+int vtrans_vtrans(dataptr dz)
+{
+	int exit_status;
+	int n, m;
+	double *dbrk = dz->brk[VTRANS_TRANS];
+	int obufcnt = 0;
+	display_virtual_time(0L,dz);
+	if((exit_status = read_samps_for_vtrans(dz))<0)
+		return(exit_status);
+	for(n=1,m=2;n<dz->brksize[VTRANS_TRANS];n++,m+=2) {
+		if((exit_status = 
+			timevents(&obufcnt,(int)round(dbrk[m-2]),(int)round(dbrk[m]),dbrk[m-1],dbrk[m+1],dz))!=CONTINUE)
+	    	break;
+    }
+	if(exit_status < 0)
+		return(exit_status);
+	splice_end(obufcnt,dz);
+	return write_samps_with_intime_display(dz->sampbuf[OUTBUF],obufcnt ,dz);
+	return FINISHED;
+}
+
+/*************************** READ_SAMPS_FOR_VTRANS **************************/
+
+int read_samps_for_vtrans(dataptr dz)
+{
+//TW MUST READ EXTRA SECTOR to get wrap-around value
+	float *buffer = dz->sampbuf[INBUF];
+	int samps_read, samps_to_read = dz->buflen + F_SECSIZE;
+	dz->iparam[UNITS_RD_PRE_THISBUF] = dz->iparam[TOTAL_UNITS_READ];
+	if((samps_read = fgetfbufEx(buffer, samps_to_read,dz->ifd[0],0)) < 0) {
+		sprintf(errstr, "Can't read from input soundfile.\n");
+		return(SYSTEM_ERROR);
+	}
+	dz->samps_left -= samps_read;
+	if(samps_read == samps_to_read) {
+		if((sndseekEx(dz->ifd[0],-(int)F_SECSIZE,1))<0) { /* WE'VE READ EXTRA SECTOR,for wrap-around */
+			sprintf(errstr,"sndseekEx() failed.\n");
+			return(SYSTEM_ERROR);
+		}
+		samps_read -= F_SECSIZE;
+//TW: correcting an omission in original
+		dz->samps_left += F_SECSIZE;
+	}
+	dz->total_samps_read 		 += samps_read;
+	dz->iparam[UNITS_READ]        = samps_read/dz->infile->channels;
+	dz->iparam[TOTAL_UNITS_READ] += dz->iparam[UNITS_READ];
+	return(FINISHED);
+}
+
+/*************************** WRITE_SAMPS_WITH_INTIME_DISPLAY ***********************/
+
+int write_samps_with_intime_display(float *buf,int samps_to_write,dataptr dz)
+{   
+	int exit_status;
+	int samps_written;
+// 	if((samps_written = fputfbufEx(buf,samps_to_write,dz->ofd))<0) {
+	if(samps_to_write > 0) {
+		if((exit_status = write_samps_no_report(buf,samps_to_write,&samps_written,dz))<0) {
+			sprintf(errstr, "Can't write to output soundfile.\n");
+			return(SYSTEM_ERROR);
+		}
+		display_virtual_time(dz->total_samps_read,dz);
+	}
+	return(FINISHED);
+}
+
+/************************ CONVERT_BRKPNTS ************************/
+
+int convert_brkpnts(dataptr dz)
+{
+	int exit_status;
+	double *p, *pend;
+	if((exit_status= force_value_at_zero_time(VTRANS_TRANS,dz))<0)
+		return(exit_status);
+	if((exit_status= force_value_at_end_time(VTRANS_TRANS,dz))<0)
+		return(exit_status);
+
+	p    = dz->brk[VTRANS_TRANS];
+	pend = p + (dz->brksize[VTRANS_TRANS] * 2);
+
+	while(p < pend) {
+		*p = (double)round((*p) * dz->param[VTRANS_SR]);	 /* convert to (mono) sample frame */
+		p += 2;
+	}
+	if(dz->mode==MOD_TRANSPOS_SEMIT || dz->mode==MOD_TRANSPOS_SEMIT_INFO) {
+		p  = dz->brk[VTRANS_TRANS] + 1;		
+		while(p < pend) {
+			*p = pow(2.0,(*p) * OCTAVES_PER_SEMITONE);	/* convert to ratios */
+			p += 2;
+		}
+	}
+	return(FINISHED);
+}
+
+/************************** TIMEVENTS *******************************/
+/*
+ * 	Generates event positions from startsize and end size
+ *
+ *	Let start-time be T0 and end time be T1
+ *	Let start size be S0 and end size be S1
+ *
+ *	number of event is given by :-
+ *
+ *		N = (T1-T0) log S1
+ *		    -------    e__
+ *		    (S1-S0)     S0
+ *
+ *	In general this will be non-integral, and we should
+ *	round N to an integer, and recalculate S1 by successive 
+ *	approximation.
+ *
+ *	Then positions of events are given by
+ *	
+ *	    for X = 0 to N		 (S1-S0)
+ *					  ----- X
+ *	T = (S1T0 - S0T1)   S0(T1 - T0)  (T1-T0)
+ *	 s   -----------  + ----------  e 
+ *	      (S1 - S0)      (S1 - S0)
+ *
+ * 	If difference in eventsizes input to the main program is very small
+ *
+ * This function calculates the number of events within the time-interval,
+ * and generates the times of these events.
+ */
+
+int timevents(int *obufcnt,int intime0,int intime1,double insize0,double insize1,dataptr dz)
+{   
+	int exit_status;
+	int   number;
+	double fnum, fnumber, error, pos;
+	double lobound, hibound;
+	int duration;
+	if(flteq(insize0,0.0) || flteq(insize1,0.0)) {
+		sprintf(errstr,"Event size of zero encountered in pair %lf %lf at time %lf\n",
+		insize0,insize1,(double)intime0/dz->param[VTRANS_SR]);
+		return(DATA_ERROR);
+	}
+	duration = intime1-intime0;
+	if(duration<=0) {
+		sprintf(errstr,"Inconsistent input times [ %lf : %lf ] to timevents()\n",
+		(double)intime0/dz->param[VTRANS_SR],(double)intime1/dz->param[VTRANS_SR]);
+		return(DATA_ERROR);
+	}
+	if(sizeq(insize1,insize0))				/* 1 */
+		return(samesize(obufcnt,intime0,insize0,insize1,duration,dz));
+
+	fnum =cntevents(duration,insize0,insize1);		/* 2 */
+	number = round(fnum);
+	if(number<2) {					/* 3 */
+		pos = (double)(intime0 - dz->iparam[UNITS_RD_PRE_THISBUF]);
+		if(pos >= (double)dz->iparam[UNITS_READ]) {
+			if(dz->samps_left <= 0)
+				return(FINISHED);
+			if((exit_status = read_samps_for_vtrans(dz))<0)
+				return(exit_status);
+			pos -= (double)dz->iparam[UNIT_BUFLEN];
+		}
+		if((exit_status = putval(obufcnt,pos,dz))<0)
+			return(exit_status);
+	} else {
+		fnumber = (double)number;			/* 4 */
+		error   = fabs(fnum - fnumber);
+/* HIBOUND is a SMALLER value of SIZE to give BIGGER value of NUM-OF-SEGS */
+/* LOBOUND is a LARGER value of SIZE to give SMALLER value of NUM-OF-SEGS */
+		lobound = max(insize1,insize0);			/* 5 */
+		hibound = min(insize1,insize0);
+		if(error > FLTERR)				/* 6 */
+			insize1 = refinesize(hibound,lobound,fnumber,duration,error,insize0);
+		else
+			insize1 = (hibound+lobound)/2;
+		return(getetime(obufcnt,intime0,intime1,insize0,insize1,number,dz));
+    }							/* 7 */
+	return(CONTINUE);
+}
+
+
+/*************************** CNTEVENTS *****************************/
+
+double cntevents(int dur,double s0,double s1)
+{   
+	double f1 = (double)dur,f2;
+	if(sizeq(s1,s0))
+		return((f1*2.0)/(s1+s0));
+	f2  = s1-s0;
+	f1 /= f2;
+	f2  = s1/s0;
+	f2  = log(f2);
+	f1 *= f2;
+	return(fabs(f1));
+}
+
+/******************************* SAMESIZE(): *******************************
+ *
+ * get event positions, if eventsize approx same throughout segment.
+ *
+ *(1)	Get average size, find number of events and round to nearest int.
+ *(2)	If too many or zero events, do exception.
+ *(3)	Recalculate size, and thence event times.
+ */
+
+int samesize(int *obufcnt,int intime0,double insize0,double insize1,int duration,dataptr dz)
+{   
+	int exit_status;
+	int number, isize;
+	double size, pos;					/* 1 */
+	size     = (insize0+insize1)/2;
+	number   = round((double)duration/size);
+	if(number==0) {					/* 2 */
+		pos = (double)(intime0 - dz->iparam[UNITS_RD_PRE_THISBUF]);
+		if(pos >= (double)dz->iparam[UNITS_READ]) {
+			if(dz->samps_left <= 0)
+				return(FINISHED);
+			if((exit_status = read_samps_for_vtrans(dz))<0)
+				return(exit_status);
+			pos -= (double)dz->iparam[UNIT_BUFLEN];
+		}
+		if((exit_status = putval(obufcnt,pos,dz))<0)
+			return(exit_status);
+		return(CONTINUE);
+	}
+	size = (double)duration/(double)number;
+	if(flteq((double)(isize = (int)round(size)),size))
+		return integral_times(obufcnt,intime0,isize,number,dz);
+	return unvarying_times(obufcnt,intime0,size,number,dz);
+}
+
+/************************ INTEGRAL_TIMES ***************************
+ *
+ * GENERATE vals for equally spaced events, spaced by whole nos. of samps.
+ */
+
+int integral_times(int *obufcnt,int intime0,int isize,int number,dataptr dz)
+{
+	int exit_status;
+	int k, pos = intime0 - dz->iparam[UNITS_RD_PRE_THISBUF];
+	for(k=0;k<number;k++) {
+		if(pos >= dz->iparam[UNITS_READ]) {
+			if(dz->samps_left <= 0)
+				return(FINISHED);
+			if((exit_status = read_samps_for_vtrans(dz))<0)
+				return(exit_status);
+			pos -= dz->iparam[UNIT_BUFLEN];
+		}
+		if((exit_status = putintval(obufcnt,pos,dz))<0)
+			return(exit_status);
+		pos += isize;
+	}
+	return(CONTINUE);
+}
+
+/****************************** PUTINTVAL ******************************/
+
+int putintval(int *obufcnt,int i,dataptr dz)
+{  
+	int exit_status;
+	int n;
+	float *buffer = dz->sampbuf[INBUF];
+	float *obuf   = dz->sampbuf[OUTBUF];
+	i *= dz->infile->channels;
+	for(n=0;n<dz->infile->channels;n++) {
+		obuf[(*obufcnt)++] = buffer[i];
+		if(*obufcnt >= dz->buflen) {
+			if((exit_status = write_samps_with_intime_display(obuf,dz->buflen,dz))<0)
+				return(exit_status);
+			*obufcnt = 0;
+		}
+		i++;	
+	}
+	return(FINISHED);
+}
+
+/************************ UNVARYING_TIMES ***************************
+ *
+ * GENERATE vals for equally spaced events.
+ */
+
+int unvarying_times(int *obufcnt,int intime0,double size,int number,dataptr dz)
+{   
+	int exit_status;
+	int k; 
+	double pos = (double)(intime0 - dz->iparam[UNITS_RD_PRE_THISBUF]);
+/******* k = 0 *********/
+	for(k=0;k<number;k++) {
+/****************/
+		if(pos >= (double)dz->iparam[UNITS_READ]) {
+			if(dz->samps_left <= 0)
+				return(FINISHED);
+			if((exit_status = read_samps_for_vtrans(dz))<0)
+				return(exit_status);
+			pos -= (double)dz->iparam[UNIT_BUFLEN];
+		}
+		if((exit_status = putval(obufcnt,pos,dz))<0)
+			return(exit_status);
+		pos += size;
+	}
+    return(CONTINUE);
+}
+
+/******************************* GETETIME(): ********************************
+ *
+ * Calculate time-positions of events that vary in size between s0 and s1.
+ * NB We need to invert the time order, if s1 < s0.
+ */
+
+int getetime(int *obufcnt,int t0,int t1,double s0,double s1,int number,dataptr dz)
+{   
+	int exit_status;
+	int n;
+	double sdiff = s1-s0, tdiff = (double)(t1-t0), d1, d2, d3, pos;
+ /***** TW n=0 NOT 1 ********/
+// for(n=1;n<number;n++)   {
+	for(n=0;n<number;n++)   {
+/***** TW ********/
+		d1    = sdiff/tdiff;
+		d1   *= (double)n;
+		d1    = exp(d1);
+		d2    = s0*tdiff;
+		d2   /= sdiff;
+		d1   *= d2;
+		d2    = s1*t0;
+		d3    = s0*t1;
+		d2   -= d3;
+		d2   /= sdiff;
+		pos   = d1 + d2;
+		pos -= (double)dz->iparam[UNITS_RD_PRE_THISBUF];
+		if(pos >= (double)dz->iparam[UNITS_READ]) {
+			if(dz->samps_left <= 0)
+				return(FINISHED);
+			if((exit_status = read_samps_for_vtrans(dz))<0)
+				return(exit_status);
+			pos -= (double)dz->iparam[UNIT_BUFLEN];
+		}
+		if((exit_status = putval(obufcnt,pos,dz))<0)
+			return(exit_status);
+	}
+	return(CONTINUE);
+}
+
+/***************************** REFINESIZE(): ******************************
+ *
+ * refine size of final event to reduce error within bounds.
+ */
+
+double refinesize(double hibound,double lobound,double fnumber,int duration,double error,double insize0)
+{   
+	double size, fnum, lasterror;
+	double flterr_squared = FLTERR * FLTERR;
+	do {
+		lasterror = error;
+		size  = (hibound+lobound)/2.0;
+		fnum  = cntevents(duration,insize0,size);
+		error = fabs(fnumber-fnum);
+		if(error>FLTERR)  {
+			if(fnum<fnumber)
+				lobound = size;
+			else
+				hibound = size;
+		}
+		if(fabs(lasterror - error) < flterr_squared)
+			break;	/* In case error cannot be reduced */
+	} while(error > FLTERR);
+	return(size);
+}
+
+/****************************** PUTVAL ******************************/
+
+int putval(int *obufcnt,double pos,dataptr dz)
+{
+	int exit_status;
+	int i = (int)pos;	/* TRUNCATE */
+	double frac = pos - (double)i, diff; 
+	float val1, val2;
+	float *buffer = dz->sampbuf[INBUF];
+	float *obuf   = dz->sampbuf[OUTBUF];
+	int chans = dz->infile->channels;
+	int n;
+	i *= chans;
+	for(n=0;n<chans;n++) {
+		val1 = buffer[i];
+		val2 = buffer[i+chans];
+		diff = (double)(val2-val1);
+//TW	obuf[(*obufcnt)++] = val1 + (float)/*round*/(frac * diff);
+		obuf[(*obufcnt)++] = (float)(val1 + (frac * diff));
+		if(*obufcnt >= dz->buflen) {
+			if((exit_status = write_samps_with_intime_display(obuf,dz->buflen,dz))<0)
+				return(exit_status);
+			*obufcnt = 0;
+		}
+		i++;	
+	}
+	return(CONTINUE);
+}
+
+/**************************** SIZEQ *******************************/
+
+int sizeq(double f1,double f2)
+{   
+	double upperbnd, lowerbnd;
+	upperbnd = f2 + CALCLIM;
+	lowerbnd = f2 - CALCLIM;
+	if((f1>upperbnd) || (f1<lowerbnd))
+		return(FALSE);
+	return(TRUE);
+}
+
+/********************** CHANGE_FRAME *****************************/
+
+int change_frame(dataptr dz)
+{
+	int n, m;
+	int *newtime;
+	double *dbrk = dz->brk[VTRANS_TRANS];
+	double lasttime, lastval, thistime, thisval, intime, outtime; 
+	if((newtime = (int *)malloc(dz->brksize[VTRANS_TRANS] * 2 * sizeof(double)))==NULL) {
+		sprintf(errstr,"INSUFFICIENT MEMORY to create transformed brktable.\n");
+		return(MEMORY_ERROR);
+	}
+	newtime[0] = 0;
+	lasttime = dbrk[0];
+	lastval  = dbrk[1];
+	switch(dz->mode) {
+	case(MOD_TRANSPOS_INFO):
+	case(MOD_TRANSPOS_SEMIT_INFO):
+		for(n=1,m=2;n<dz->brksize[VTRANS_TRANS];n++,m+=2) {
+			thistime = dbrk[m]; 
+			thisval  = dbrk[m+1]; 
+			if(dz->vflag[VTRANS_OUTTIMES])
+				newtime[n] = newtime[n-1] + inv_cntevents((int)round(thistime - lasttime),lastval,thisval);
+			else
+				newtime[n] = newtime[n-1] + round(cntevents((int)round(thistime - lasttime),lastval,thisval));
+			lasttime = thistime;
+			lastval  = thisval;
+		}
+		print_outmessage_flush("TIME GIVEN\tOCCURS AT OUTTIME\n");
+		for(n=0,m=0;n<dz->brksize[VTRANS_TRANS];n++,m+=2) {
+			intime  = dbrk[m]/dz->param[VTRANS_SR];
+			outtime = (double)newtime[n]/dz->param[VTRANS_SR];
+			sprintf(errstr,"%lf\t%lf\n",intime,outtime);
+			print_outmessage_flush(errstr);
+		}
+		if(!sloom) {
+			fprintf(stdout,"INFO: END\n");
+			fflush(stdout);
+		}
+		break;
+	case(MOD_TRANSPOS):
+	case(MOD_TRANSPOS_SEMIT):
+		if(dz->vflag[VTRANS_OUTTIMES]) {	/* convert to intimes */
+			for(n=1,m=2;n<dz->brksize[VTRANS_TRANS];n++,m+=2) {
+				thistime = dbrk[m]; 
+				thisval  = dbrk[m+1]; 
+				newtime[n] = newtime[n-1] + 
+						 inv_cntevents((int)round(thistime - lasttime),lastval,thisval);
+				lasttime = thistime;
+				lastval  = thisval;
+			}
+			for(n=1,m=2;n<dz->brksize[VTRANS_TRANS];n++,m+=2)
+				dbrk[m] = (double)newtime[n];
+		}
+		break;
+	}
+	free(newtime);
+	return(FINISHED);
+}
+
+/*************************** INV_CNTEVENTS *****************************
+ *
+ *	no. of event in input (N) corresponding to output (T1-T0) given by :-
+ *
+ *		N = (T1-T0) log S1
+ *		    -------    e__
+ *		    (S1-S0)     S0
+ *
+ *      Hence, 
+ *	no. of event in output (T1-T0) corresponding to input (N) given by :-
+ *
+ *		(S1-S0)N = (T1-T0)
+ *		--------
+ *		 log S1
+ *		    e__
+ *		     S0
+ *
+ *	Except where S1==S0, when (T1-T0) = S * N
+ */
+
+int inv_cntevents(int dur,double s0,double s1)
+{   
+	double ftime;
+	int time;
+	if(sizeq(s1,s0))
+		ftime = (double)dur * s0;
+	else
+		ftime = ((double)dur * (s1-s0))/log(s1/s0);
+	time = round(ftime);
+	if(time==0)
+		time = 1;
+	return(time);
+}
+
+/*************************** FORCE_VALUE_AT_END_TIME *****************************/
+
+int force_value_at_end_time(int paramno,dataptr dz)
+{
+	double duration = (double)dz->iparam[UNITSIZE]/dz->param[VTRANS_SR];
+	double *p = dz->brk[paramno] + ((dz->brksize[paramno]-1) * 2);
+	double timegap, newgap, step, newstep, timeratio;
+	if(dz->brksize[paramno] < 2) {
+		sprintf(errstr,"Brktable too small (< 2 pairs).\n");
+		return(DATA_ERROR);
+	}
+	if(flteq(*p,duration)) {
+		*p = duration;
+		return(FINISHED);
+	} else if(*p <  duration) {
+		dz->brksize[paramno]++;
+		if((dz->brk[paramno] = realloc((char *)dz->brk[paramno],dz->brksize[paramno] * 2 * sizeof(double)))==NULL) {
+			sprintf(errstr,"INSUFFICIENT MEMORY TO GROW BRKTABLE.\n");
+			return(MEMORY_ERROR);
+		}
+		p = dz->brk[paramno] + ((dz->brksize[paramno]-1) * 2);
+		*p = duration;
+		*(p+1) = *(p-1);
+		return(FINISHED);
+	} else {  /* *p >  duration) */
+		while(p > dz->brk[paramno]) {
+			p -= 2;
+			if(flteq(*p,duration)) {
+				*p = duration;
+				dz->brksize[paramno] = (p - dz->brk[paramno] + 2)/2;
+				return(FINISHED);
+			} else if(*p < duration) {
+				timegap = *(p+2) - *p;
+				newgap = duration - *p;
+				timeratio = newgap/timegap;
+				switch(dz->mode) {
+				case(MOD_TRANSPOS_SEMIT):
+				case(MOD_TRANSPOS_SEMIT_INFO):
+					step = *(p+3) - *(p+1);
+					newstep = step * timeratio;
+					*(p+3) = *(p+1) + newstep;
+					break;
+				case(MOD_TRANSPOS):
+				case(MOD_TRANSPOS_INFO):
+					step    = LOG2(*(p+3)) - LOG2(*(p+1));
+					newstep = pow(2.0,step * timeratio);
+					*(p+3) = *(p+1) * newstep;
+					break;										
+				}
+				*(p+2) = duration;
+				dz->brksize[paramno] = (p - dz->brk[paramno] + 4)/2;
+				return(FINISHED);
+			}
+		}
+	}
+	sprintf(errstr,"Failed to place brkpnt at snd endtime.\n");
+	return(PROGRAM_ERROR);
+}
+
+/*************************** SPLICE_END *****************************/
+
+void splice_end(int obufcnt,dataptr dz)		/* A kludge to avoid clicks at end */
+{
+
+#define VTRANS_SPLICELEN (5.0)
+
+	float *buf = dz->sampbuf[OUTBUF];
+	int chans = dz->infile->channels;
+	int splicelen = round(VTRANS_SPLICELEN * MS_TO_SECS * dz->infile->srate) * dz->infile->channels;
+	int n, m, k = min(obufcnt,splicelen);
+	int startsamp = obufcnt - k;
+	double inv_k;
+	k /= chans;
+	inv_k = 1.0/(double)k;
+	for(n = k-1;n >= 0;n--) {
+		for(m=0;m<chans;m++) {
+			buf[startsamp] = (float)(buf[startsamp] * n * inv_k);
+			startsamp++;
+		}
+	}
+
+}
+	
+/******************************* DO_ACCELERATION ***************************/
+
+int do_acceleration(dataptr dz)
+{	
+	int exit_status;
+	int place;
+	double flplace, fracsamp, step;
+//	int OK = 1, interp;
+	int OK = 1;
+	double interp;
+	float *ibuf      = dz->sampbuf[INBUF];
+	float *obuf      = dz->sampbuf[OUTBUF];
+	float *true_lbuf = dz->sampbuf[TRUE_LBUF];
+	float *true_rbuf = dz->sampbuf[TRUE_RBUF];
+	float *obufend   = dz->sampbuf[OBUFEND];
+	float *obufptr  = obuf;
+	double place_inc = 1.0;
+	int   startsamp = dz->iparam[ACCEL_STARTTIME];
+	int   previous_total_ssampsread = 0;
+	double accel     = dz->param[ACCEL_ACCEL];
+	dz->total_samps_read = 0;
+	display_virtual_time(0L,dz);
+	if(dz->infile->channels==STEREO) {
+		while(dz->total_samps_read<=startsamp) {
+			previous_total_ssampsread = dz->total_samps_read;
+			if((exit_status = read_wrapped_samps_stereo(dz))<0)
+				return(exit_status);
+			if(dz->total_samps_read <= startsamp)
+				if((exit_status = write_samps_with_intime_display(ibuf,dz->ssampsread * STEREO,dz))<0)
+					return(exit_status);
+		}
+		startsamp -= previous_total_ssampsread;
+		if(startsamp > 0)
+			memcpy((char *)obuf,(char *)ibuf,startsamp * sizeof(float));
+		obufptr += startsamp;
+		startsamp /= 2;	/* STEREO divided into two buffers */
+		place = startsamp + 1;
+		flplace = place;
+		while(dz->ssampsread > place) {
+			while(place < dz->ssampsread) {
+				fracsamp   = flplace - (double)place;
+				step       = true_lbuf[place+1] - true_lbuf[place];
+//				interp     = round(fracsamp * step);
+				interp     = fracsamp * step;
+				*obufptr++ = (float)(true_lbuf[place] + interp);
+				step       = true_rbuf[place+1] - true_rbuf[place];
+//				interp     = round(fracsamp * step);
+				interp     = fracsamp * step;
+				*obufptr++ = (float)(true_rbuf[place] + interp);
+				if(obufptr >= obufend) {
+					if((exit_status = write_samps_with_intime_display(obuf,dz->buflen,dz))<0)
+						return(exit_status);
+					obufptr = obuf;
+				}
+				flplace   += place_inc;
+				place_inc *= accel;
+				if(place_inc <= MININC) {
+					fprintf(stdout, "INFO: Acceleration reached black hole! - finishing\n");
+					fflush(stdout);
+					OK = 0;
+					break;
+				}
+				place = (int)flplace;
+			}
+			if(!OK) {
+				break;
+			}
+			if(dz->samps_left > 0) {
+				flplace -= (double)dz->ssampsread;
+				place   -= dz->ssampsread;
+				if((exit_status = read_wrapped_samps_stereo(dz))<0)
+					return(exit_status);
+				if(dz->ssampsread<=0)
+					break;
+			} else
+				break;
+		}
+	} else {
+		while(dz->total_samps_read<=startsamp) {
+			previous_total_ssampsread = dz->total_samps_read;
+			if((exit_status = read_wrapped_samps_mono(dz))<0)
+				return(exit_status);
+			if(dz->total_samps_read <= startsamp) {
+				if((exit_status = write_samps_with_intime_display(ibuf,dz->ssampsread,dz))<0)
+					return(exit_status);
+			}
+		}
+		startsamp -= previous_total_ssampsread;
+		if(startsamp > 0)
+			memcpy((char *)obuf,(char *)ibuf,startsamp * sizeof(float));
+		obufptr += startsamp;
+		place = startsamp + 1;
+		flplace = place;
+		while(dz->ssampsread > place) {
+			while(place < dz->ssampsread) {
+				fracsamp   = flplace - (double)place;
+				step       = true_lbuf[place+1] - true_lbuf[place];
+//				interp     = round(fracsamp * step);
+				interp     = fracsamp * step;
+				*obufptr++ = (float)(true_lbuf[place] + interp);
+				if(obufptr >= obufend) {
+					if((exit_status = write_samps_with_intime_display(obuf,dz->buflen,dz))<0)
+						return(exit_status);
+					obufptr = obuf;
+				}
+				flplace   += place_inc;
+				place_inc *= accel;
+				if(place_inc <= MININC) {
+					fprintf(stdout, "INFO: Acceleration reached black hole! - finishing\n\n");
+					fflush(stdout);
+					OK = 0;
+					break;
+				}
+				place = (int)flplace;
+			}
+			if(!OK) {
+				break;
+			}
+			if(dz->samps_left > 0) {
+				flplace -= (double)dz->ssampsread;
+				place   -= dz->ssampsread;
+				if((exit_status = read_wrapped_samps_mono(dz))<0)
+					return(exit_status);
+				if(dz->ssampsread<=0)
+					break;
+			} else
+				break;
+		}
+	}
+	splice_end(obufptr - obuf,dz);
+	return write_samps_with_intime_display(obuf,obufptr - obuf ,dz);  
+}
+
+/******************************* DO_VIBRATO ********************************/
+
+int do_vibrato(dataptr dz)
+{		
+	int    exit_status;
+	float  *ibuf      = dz->sampbuf[INBUF];
+	float  *obuf      = dz->sampbuf[OUTBUF];
+	float  *obufend   = dz->sampbuf[OBUFEND];
+	float  *true_lbuf = dz->sampbuf[TRUE_LBUF];
+	float  *true_rbuf = NULL;
+	double *sintab = dz->parray[VIB_SINTAB];
+	int    chans    = dz->infile->channels;
+	double sr       = (double)dz->infile->srate;
+	double tabsize  = (double)VIB_TABSIZE;
+	double bloksize = (double)VIB_BLOKSIZE;
+	double inv_bloksize = 1.0/bloksize;
+	double thistime = 0.0;
+	double time_incr = bloksize/sr;	/* timestep  between param reads */
+	int    effective_buflen = dz->buflen/chans;
+	int   place   = 0;				/* integer position in sndfile   */
+	double flplace = 0.0;			/* float position in sndfile     */
+	double incr;					/* incr of position in sndfile   */
+	double sfindex = 0.0;			/* float position in sintable    */
+	double sinval;					/* current sintable value        */
+	double current_depth, lastdepth, depth_incr;
+	double current_frq,   lastfrq,   frq_incr;
+	double fracsamp;				/* fraction of samptime to interp*/
+	double step;					/* step between snd samples      */
+//	int    interp;					/* part of sampstep to use   	 */
+	double interp;					/* part of sampstep to use   	 */
+	int    blokcnt = 0;				/* distance through blokd params */
+	float  *obufptr = obuf;
+	if(dz->brksize[VIB_FRQ]) {
+		if((exit_status = read_value_from_brktable(thistime,VIB_FRQ,dz))<0)
+			return(exit_status);
+	} else
+		frq_incr = 0.0;	
+	if(dz->brksize[VIB_DEPTH]) {
+		if((exit_status = read_value_from_brktable(thistime,VIB_DEPTH,dz))<0)
+			return(exit_status);
+	} else
+		depth_incr = 0.0;	
+	current_frq   = lastfrq   = dz->param[VIB_FRQ];
+	current_depth = lastdepth = dz->param[VIB_DEPTH];
+	thistime += time_incr;						  /* now time is 1 bloklength ahead */
+
+	switch(chans) {
+	case(MONO):
+		if((exit_status = read_wrapped_samps_mono(dz))<0)
+			return(exit_status);
+		obuf[0] = ibuf[0];
+		obufptr++;
+		break;
+	case(STEREO):
+		true_rbuf = dz->sampbuf[TRUE_RBUF];
+		if((exit_status = read_wrapped_samps_stereo(dz))<0)
+			return(exit_status);
+		obuf[0] = ibuf[0];
+		obufptr++;
+		obuf[1] = ibuf[1];
+		obufptr++;
+		break;
+	}
+
+	if((exit_status = read_values_from_all_existing_brktables(thistime,dz))<0)
+		return(exit_status);						/* read value 1 bloklength ahead */
+	frq_incr   = (dz->param[VIB_FRQ]   - lastfrq)   * inv_bloksize;
+	depth_incr = (dz->param[VIB_DEPTH] - lastdepth) * inv_bloksize;
+	lastfrq   = dz->param[VIB_FRQ];
+	lastdepth = dz->param[VIB_DEPTH];
+	blokcnt = VIB_BLOKSIZE - 1;		  /* -1 as we've read 1 (stereo) sample already. */
+	thistime += time_incr;						  /* Now time is 2 bloklengths ahead */
+								/* but we won't read till another 1 blok has passed. */
+	for(;;) {
+		if(--blokcnt <= 0) {	/* look at params only every BLOKCNT (stereo)samples */
+			if((exit_status = read_values_from_all_existing_brktables(thistime,dz))<0)
+				return(exit_status); /* & read vals 1 bloklen ahead,to calc par incr */
+			frq_incr   = (dz->param[VIB_FRQ]   - lastfrq)   * inv_bloksize;
+			depth_incr = (dz->param[VIB_DEPTH] - lastdepth) * inv_bloksize;
+			lastfrq   = dz->param[VIB_FRQ];
+			lastdepth = dz->param[VIB_DEPTH];
+			blokcnt = VIB_BLOKSIZE;
+			thistime += time_incr;
+		}
+		current_depth += depth_incr;	 	  /* increment params sample by (stereo) sample */
+		current_frq   += frq_incr;
+		if((sfindex  += current_frq) >= tabsize)
+			sfindex -= tabsize;		 		 /* advance in sintable,wrapping around if ness */
+		sinval = interp_read_sintable(sintab,sfindex);		/* read sintab by interpolation */
+		incr = pow(2.0,sinval * current_depth); /* convert speed & depth from 8vas to ratio */
+		if((flplace += incr) >= (double)dz->ssampsread) {	   /* advance through src sound */
+			if(dz->samps_left <=0)							    /* if at end of src, finish */
+				break;						 /* else if at end of buffer, get more sound in */
+			switch(chans) {
+			case(MONO):
+				if((exit_status = read_wrapped_samps_mono(dz))<0)
+					return(exit_status);
+				break;
+			case(STEREO):
+				if((exit_status = read_wrapped_samps_stereo(dz))<0)
+					return(exit_status);
+				break;
+			}
+			flplace -= effective_buflen;
+		}
+		place 	   = (int)flplace; 	/* TRUNCATE */	   /* read sndfile by interpolation */
+		fracsamp   = flplace - (double)place;
+		step       = true_lbuf[place+1] - true_lbuf[place];
+//		interp     = round(fracsamp * step);
+		interp     = fracsamp * step;
+		*obufptr++ = (float)(true_lbuf[place] + interp);
+		if(chans==STEREO) {
+			step       = true_rbuf[place+1] - true_rbuf[place];
+//			interp     = round(fracsamp * step);
+			interp     = fracsamp * step;
+			*obufptr++ = (float)(true_rbuf[place] + interp);
+		}
+		if(obufptr >= obufend) {					 /* if at end of outbuf, write a buffer */
+			if((exit_status = write_samps_with_intime_display(obuf,dz->buflen,dz))<0)
+				return(exit_status);
+			obufptr = obuf;
+		}
+	}
+	if(obufptr < obufend)						 /* if samples remain in outbuf, write them */
+		return write_samps_with_intime_display(obuf,obufptr - obuf,dz);
+	return(FINISHED);
+}
+
+/******************************* INTERP_READ_SINTABLE ********************************/
+
+double interp_read_sintable(double *sintab,double sfindex)
+{
+	int    sindex0  = (int)sfindex;	/* TRUNCATE */			
+	int    sindex1  = sindex0 + 1;
+	double frac = sfindex - (double)sindex0;
+	double val0 = sintab[sindex0];
+	double val1 = sintab[sindex1];
+	double valdiff = val1 - val0;
+	double valfrac = valdiff * frac;
+	return(val0 + valfrac);
+}

+ 20 - 0
dev/morph/CMakeLists.txt

@@ -0,0 +1,20 @@
+if(APPLE)
+  set(CMAKE_C_FLAGS "-O2 -Wall -mmacosx-version-min=10.5 -Dunix")
+else()
+  if(MINGW)
+    set(CMAKE_C_FLAGS "-O2 -Wall -DWIN32")
+  else()
+    set(CMAKE_C_FLAGS "-O2 -Wall -Dlinux -Dunix")
+  endif()
+endif()
+
+link_directories(../cdp2k ../sfsys)
+
+include_directories(../../include)
+
+add_executable(morph main.c ap_morph.c morph.c)
+
+target_link_libraries(morph cdp2k sfsys ${EXTRA_LIBRARIES})
+
+my_install(morph)
+

+ 648 - 0
dev/morph/ap_morph.c

@@ -0,0 +1,648 @@
+/*
+ * Copyright (c) 1983-2013 Trevor Wishart and Composers Desktop Project Ltd
+ * http://www.trevorwishart.co.uk
+ * http://www.composersdesktop.com
+ *
+ This file is part of the CDP System.
+
+    The CDP System is free software; you can redistribute it
+    and/or modify it under the terms of the GNU Lesser General Public
+    License as published by the Free Software Foundation; either
+    version 2.1 of the License, or (at your option) any later version.
+
+    The CDP System is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public
+    License along with the CDP System; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+    02111-1307 USA
+ *
+ */
+
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <structures.h>
+#include <cdpmain.h>
+#include <tkglobals.h>
+#include <pnames.h>
+#include <morph.h>
+#include <processno.h>
+#include <modeno.h>
+#include <globcon.h>
+#include <logic.h>
+#include <filetype.h>
+#include <mixxcon.h>
+#include <speccon.h>
+#include <flags.h>
+#include <arrays.h>
+#include <formants.h>
+#include <sfsys.h>
+#include <osbind.h>
+#include <string.h>
+#include <math.h>
+#include <srates.h>
+
+/********************************************************************************************/
+/********************************** FORMERLY IN buffers.c ***********************************/
+/********************************************************************************************/
+
+int  allocate_triple_buffer_for_bridge(dataptr dz);
+
+/********************************************************************************************/
+/********************************** FORMERLY IN pconsistency.c ******************************/
+/********************************************************************************************/
+
+static int 	check_compatibility_of_bridge_params(dataptr dz);
+static int	check_consistency_of_morph_params(dataptr dz);
+
+/********************************************************************************************/
+/********************************** FORMERLY IN preprocess.c ********************************/
+/********************************************************************************************/
+
+static int  setup_internal_params_and_arrays_for_glide(dataptr dz);
+static int  setup_internal_params_for_bridge(dataptr dz);
+static int  establish_interplen_and_if_head_or_tail_to_the_interp(int *wlen,dataptr dz);
+static int  morph_preprocess(dataptr dz);
+static int  make_morph_costable(dataptr dz);
+static int	setup_internal_morph_params(dataptr dz);
+
+/***************************************************************************************/
+/****************************** FORMERLY IN aplinit.c **********************************/
+/***************************************************************************************/
+
+/***************************** ESTABLISH_BUFPTRS_AND_EXTRA_BUFFERS **************************/
+
+int establish_bufptrs_and_extra_buffers(dataptr dz)
+{
+	dz->extra_bufcnt = -1;	/* ENSURE EVERY CASE HAS A PAIR OF ENTRIES !! */
+	dz->bptrcnt = 0;
+	dz->bufcnt  = 0;
+	switch(dz->process) {
+	case(GLIDE):      		dz->extra_bufcnt =  2; dz->bptrcnt = 2; 	break;
+	case(BRIDGE):     		dz->extra_bufcnt =  0; dz->bptrcnt = 6; 	break;
+	case(MORPH):      		dz->extra_bufcnt =  0; dz->bptrcnt = 4; 	break;	
+	default:
+		sprintf(errstr,"Unknown program type [%d] in establish_bufptrs_and_extra_buffers()\n",dz->process);
+		return(PROGRAM_ERROR);
+	}
+
+	if(dz->extra_bufcnt < 0) {
+		sprintf(errstr,"bufcnts have not been set: establish_bufptrs_and_extra_buffers()\n");
+		return(PROGRAM_ERROR);
+	}
+	return establish_spec_bufptrs_and_extra_buffers(dz);
+}
+
+/***************************** SETUP_INTERNAL_ARRAYS_AND_ARRAY_POINTERS **************************/
+
+int setup_internal_arrays_and_array_pointers(dataptr dz)
+{
+	int n;		 
+	dz->ptr_cnt    = -1;		/* base constructor...process */
+	dz->array_cnt  = -1;
+	dz->iarray_cnt = -1;
+	dz->larray_cnt = -1;
+	switch(dz->process) {
+	case(GLIDE):  	dz->array_cnt =1;  dz->iarray_cnt =1;  dz->larray_cnt = 0; dz->ptr_cnt = 0; dz->fptr_cnt = 0;	break;
+	case(BRIDGE): 	dz->array_cnt = 0; dz->iarray_cnt = 0; dz->larray_cnt = 0; dz->ptr_cnt = 0; dz->fptr_cnt = 0;	break;
+	case(MORPH):  	dz->array_cnt =1;  dz->iarray_cnt = 0; dz->larray_cnt = 0; dz->ptr_cnt = 0; dz->fptr_cnt = 0;	break;
+	}
+
+/*** WARNING ***
+ANY APPLICATION DEALING WITH A NUMLIST INPUT: MUST establish AT LEAST 1 double array: i.e. dz->array_cnt = at least 1
+**** WARNING ***/
+
+
+	if(dz->array_cnt < 0 || dz->iarray_cnt < 0 || dz->larray_cnt < 0 || dz->ptr_cnt < 0 || dz->fptr_cnt < 0) {
+		sprintf(errstr,"array_cnt not set in setup_internal_arrays_and_array_pointers()\n");	   
+		return(PROGRAM_ERROR);
+	}
+
+	if(dz->array_cnt > 0) {  
+		if((dz->parray  = (double **)malloc(dz->array_cnt * sizeof(double *)))==NULL) {
+			sprintf(errstr,"INSUFFICIENT MEMORY for internal double arrays.\n");
+			return(MEMORY_ERROR);
+		}
+		for(n=0;n<dz->array_cnt;n++)
+			dz->parray[n] = NULL;
+	}
+	if(dz->iarray_cnt > 0) {
+		if((dz->iparray = (int     **)malloc(dz->iarray_cnt * sizeof(int *)))==NULL) {
+			sprintf(errstr,"INSUFFICIENT MEMORY for internal int arrays.\n");
+			return(MEMORY_ERROR);
+		}
+		for(n=0;n<dz->iarray_cnt;n++)
+			dz->iparray[n] = NULL;
+	}
+	if(dz->larray_cnt > 0) {	  
+		if((dz->lparray = (int    **)malloc(dz->larray_cnt * sizeof(int *)))==NULL) {
+			sprintf(errstr,"INSUFFICIENT MEMORY for internal long arrays.\n");
+			return(MEMORY_ERROR);
+		}
+		for(n=0;n<dz->larray_cnt;n++)
+			dz->lparray[n] = NULL;
+	}
+	if(dz->ptr_cnt > 0)   {  	  
+		if((dz->ptr    	= (double  **)malloc(dz->ptr_cnt  * sizeof(double *)))==NULL) {
+			sprintf(errstr,"INSUFFICIENT MEMORY for internal pointer arrays.\n");
+			return(MEMORY_ERROR);
+		}
+		for(n=0;n<dz->ptr_cnt;n++)
+			dz->ptr[n] = NULL;
+	}
+	if(dz->fptr_cnt > 0)   {  	  
+		if((dz->fptr = (float  **)malloc(dz->fptr_cnt * sizeof(float *)))==NULL) {
+			sprintf(errstr,"INSUFFICIENT MEMORY for internal float-pointer arrays.\n");
+			return(MEMORY_ERROR);
+		}
+		for(n=0;n<dz->fptr_cnt;n++)
+			dz->fptr[n] = NULL;
+	}
+	return(FINISHED);
+}
+
+/****************************** ASSIGN_PROCESS_LOGIC *********************************/
+
+int assign_process_logic(dataptr dz)
+{						 
+	switch(dz->process) {
+	case(GLIDE):	  	setup_process_logic(TWO_ANALFILES,		  	BIG_ANALFILE,		ANALFILE_OUT,	dz);	break;
+	case(BRIDGE):	  	setup_process_logic(TWO_ANALFILES,		  	BIG_ANALFILE,		ANALFILE_OUT,	dz);	break;
+	case(MORPH):	  	setup_process_logic(TWO_ANALFILES,		  	BIG_ANALFILE,		ANALFILE_OUT,	dz);	break;
+	default:
+		sprintf(errstr,"Unknown process: assign_process_logic()\n");
+		return(PROGRAM_ERROR);
+		break;
+	}
+	if(dz->has_otherfile) {
+		switch(dz->input_data_type) {
+		case(ALL_FILES):
+		case(TWO_SNDFILES):
+		case(SNDFILE_AND_ENVFILE):
+		case(SNDFILE_AND_BRKFILE):
+		case(SNDFILE_AND_UNRANGED_BRKFILE):
+		case(SNDFILE_AND_DB_BRKFILE):
+			break;
+		case(MANY_SNDFILES):
+			if(dz->process==INFO_TIMELIST)
+				break;
+			/* fall thro */
+		default:
+			sprintf(errstr,"Most processes accepting files with different properties\n"
+						   "can only take 2 sound infiles.\n");
+			return(PROGRAM_ERROR);
+		}
+	}
+	return(FINISHED);
+}
+
+/***************************** SET_LEGAL_INFILE_STRUCTURE **************************
+ *
+ * Allows 2nd infile to have different props to first infile.
+ */
+
+void set_legal_infile_structure(dataptr dz)
+{
+	switch(dz->process) {
+	default:
+		dz->has_otherfile = FALSE;
+		break;
+	}
+}
+
+/****************************** FORMERLY IN internal.c *********************************/
+/***************************************************************************************/
+
+/****************************** SET_LEGAL_INTERNALPARAM_STRUCTURE *********************************/
+
+int set_legal_internalparam_structure(int process,int mode,aplptr ap)
+{
+	int exit_status = FINISHED;
+	switch(process) {
+	case(GLIDE):	  	return(FINISHED);
+	case(BRIDGE):	  	exit_status = set_internalparam_data("ddddiiii",ap);			break;
+	case(MORPH):	  	exit_status = set_internalparam_data("iiiii",ap);				break;
+	default:
+		sprintf(errstr,"Unknown process in set_legal_internalparam_structure()\n");
+		return(PROGRAM_ERROR);
+	}
+	return(exit_status);		
+}
+
+/********************************************************************************************/
+/********************************** FORMERLY IN specialin.c *********************************/
+/********************************************************************************************/
+
+/********************** READ_SPECIAL_DATA ************************/
+
+int read_special_data(char *str,dataptr dz)	   
+{
+	aplptr ap = dz->application;
+
+	switch(ap->special_data) {
+	default:
+		sprintf(errstr,"Unknown special_data type: read_special_data()\n");
+		return(PROGRAM_ERROR);
+	}
+	return(FINISHED);	/* NOTREACHED */
+}
+
+/********************************************************************************************/
+/********************************** FORMERLY IN preprocess.c ********************************/
+/********************************************************************************************/
+
+/****************************** PARAM_PREPROCESS *********************************/
+
+int param_preprocess(dataptr dz)	
+{
+	switch(dz->process) {
+	case(GLIDE):		return setup_internal_params_and_arrays_for_glide(dz);
+	case(BRIDGE):		return setup_internal_params_for_bridge(dz);
+	case(MORPH):		return morph_preprocess(dz);
+	default:
+		sprintf(errstr,"PROGRAMMING PROBLEM: Unknown process in param_preprocess()\n");
+		return(PROGRAM_ERROR);
+	}
+	return(FINISHED);	/* NOTREACHED */
+}
+
+/************ SETUP_INTERNAL_PARAMS_AND_ARRAYS_FOR_GLIDE *************/
+
+int setup_internal_params_and_arrays_for_glide(dataptr dz)
+{
+	dz->wlength    = round(dz->param[GLIDE_DUR]/dz->frametime);
+	if((dz->parray[GLIDE_INF]   = (double *)malloc(dz->clength * sizeof(double)))==NULL) {
+		sprintf(errstr,"INSUFFICIENT MEMORY for glide array.\n");
+		return(MEMORY_ERROR);
+	}
+	if((dz->iparray[GLIDE_ZERO] = (int    *)malloc(dz->clength * sizeof(int)))==NULL) {
+		sprintf(errstr,"INSUFFICIENT MEMORY for glide zero array.\n");
+		return(MEMORY_ERROR);
+	}
+	return(FINISHED);
+}
+
+/************ SETUP_INTERNAL_PARAMS_FOR_BRIDGE *************/
+
+int setup_internal_params_for_bridge(dataptr dz)
+{
+	dz->param[BRG_TFAC]     = 0.0;			
+	dz->iparam[BRG_SWIN]    = 0;
+	dz->iparam[BRG_INTPEND] = round(dz->param[BRG_ETIME]/dz->frametime);
+	dz->iparam[BRG_STARTIS] = 0;
+	dz->iparam[BRG_TAILIS]  = 0;
+	return establish_interplen_and_if_head_or_tail_to_the_interp(&(dz->wlength),dz);
+}
+
+/************** ESTABLISH_INTERPLEN_AND_IF_HEAD_OR_TAIL_TO_THE_INTERP **********/
+
+int establish_interplen_and_if_head_or_tail_to_the_interp(int *wlen,dataptr dz)
+{
+	int interplen;
+	int endwindow1  = dz->insams[0]/dz->wanted;
+	int endwindow2  = dz->insams[1]/dz->wanted + round(dz->param[BRG_OFFSET]/dz->frametime);
+	int endwindow   = min(endwindow1,endwindow2);
+	if(endwindow > dz->iparam[BRG_INTPEND])  	/* If interp ends before snd end */
+		dz->iparam[BRG_TAILIS] = 3;				/* establish a tail */
+
+	if(flteq(dz->param[BRG_EA2],1.0) 			/* if intp ends in pure 2nd snd */ 
+	&& flteq(dz->param[BRG_EF2],1.0)  
+	&& dz->iparam[BRG_INTPEND] <= endwindow1) {	/* after 1st sound has ended */
+		dz->iparam[BRG_TAILIS] = 2;  			/* keep end of FILE2 */
+		if(endwindow2 > endwindow)
+			endwindow = endwindow2;
+	}
+	if(flteq(dz->param[BRG_EA2],0.0)  			/* if intp ends in pure 1st snd */
+	&& flteq(dz->param[BRG_EF2],0.0)
+	&& dz->iparam[BRG_INTPEND] <= endwindow2) {	/* after 2nd sound has ended */
+		dz->iparam[BRG_TAILIS] = 1;   			/* keep end of FILE1 */
+		if(endwindow1 > endwindow)
+			endwindow = endwindow1;
+	}
+	if(dz->param[BRG_STIME] > 0.0) {
+		dz->iparam[BRG_STARTIS] = 3;
+		dz->iparam[BRG_SWIN] = round(dz->param[BRG_STIME]/dz->frametime);
+		if(flteq(dz->param[BRG_SA2],0.0) && flteq(dz->param[BRG_SF2],0.0))
+			/* Start with snd1 before interp */
+			dz->iparam[BRG_STARTIS] = 1;
+		if(flteq(dz->param[BRG_SA2],1.0) && flteq(dz->param[BRG_SF2],1.0))
+			/* Start with snd2 before interp */
+			dz->iparam[BRG_STARTIS] = 2;
+	}
+	if((interplen = dz->iparam[BRG_INTPEND] - dz->iparam[BRG_SWIN])<0) {
+		sprintf(errstr,"Starttime beyond end of one soundfile, or beyond endtime.\n");
+		return(USER_ERROR);
+	}
+	dz->param[BRG_FSTEP] = (dz->param[BRG_EF2] 
+		- dz->param[BRG_SF2])/(double)interplen; /* FRQ INTERPOLATION STEP */
+	dz->param[BRG_ASTEP] = (dz->param[BRG_EA2] 
+		- dz->param[BRG_SA2])/(double)interplen; /* AMP INTERPOLATION STEP */
+	dz->param[BRG_TSTEP] = 2.0 * (1.0/(double)interplen);
+	*wlen = endwindow;
+	return(FINISHED);
+}
+
+/************************** MORPH_PREPROCESS ******************************/
+
+int morph_preprocess(dataptr dz)
+{
+	int exit_status;
+	if(dz->mode==MPH_COSIN)	{
+		if((exit_status = make_morph_costable(dz))<0)
+			return(exit_status);
+	}
+	return setup_internal_morph_params(dz);
+}
+
+/************************ MAKE_MORPH_COSTABLE ***********************/
+
+int make_morph_costable(dataptr dz)
+{
+	double d, d2;
+	int n;
+	d = PI/(double)MPH_COSTABSIZE;
+	if((dz->parray[MPH_COS] = (double *)malloc((MPH_COSTABSIZE + 1) * sizeof(double)))==NULL) {
+		sprintf(errstr,"INSUFFICIENT MEMORY for morph cosin table.\n");
+		return(MEMORY_ERROR);
+	}
+	for(n=0;n<MPH_COSTABSIZE;n++) {
+		d2 = cos((double)n * d);
+		d2 += 1.0;
+		d2 /= 2.0;
+		d2 = 1.0 - d2;
+		d2 = min(d2,1.0);	/* trap calc errors */
+		d2 = max(d2,0.0);
+		dz->parray[MPH_COS][n] = d2;
+	}
+	dz->parray[MPH_COS][n] = 1.0;	/* wrap-around point */
+	return(FINISHED);
+}
+
+/********************** SETUP_INTERNAL_MORPH_PARAMS **********************/
+
+int	setup_internal_morph_params(dataptr dz)
+{	
+	dz->iparam[MPH_AENDW] = round(dz->param[MPH_AEND]/dz->frametime);
+	dz->iparam[MPH_ASTTW] = round(dz->param[MPH_ASTT]/dz->frametime);
+	dz->iparam[MPH_FENDW] = round(dz->param[MPH_FEND]/dz->frametime);
+	dz->iparam[MPH_FSTTW] = round(dz->param[MPH_FSTT]/dz->frametime);
+	dz->iparam[MPH_STAGW] = round(dz->param[MPH_STAG]/dz->frametime);
+	return(FINISHED);
+}
+
+/********************************************************************************************/
+/********************************** FORMERLY IN procspec.c **********************************/
+/********************************************************************************************/
+
+/**************************** SPEC_PROCESS_FILE ****************************/
+
+int spec_process_file(dataptr dz)
+{	
+	dz->total_windows = 0;
+
+	display_virtual_time(0L,dz);
+
+	switch(dz->process) {
+	case(GLIDE):	return specglide(dz);
+	case(BRIDGE):	return specbridge(dz);
+	case(MORPH):	return specmorph(dz);
+	default:
+		sprintf(errstr,"Unknown process in procspec()\n");
+		return(PROGRAM_ERROR);
+	}
+	return(FINISHED);	/* NOTREACHED */
+}
+
+/***************************** INNER_LOOP (redundant) **************************/
+
+int inner_loop
+(int *peakscore,int *descnt,int *in_start_portion,int *least,int *pitchcnt,int windows_in_buf,dataptr dz)
+{
+	return(FINISHED);
+}
+
+/********************************************************************************************/
+/********************************** FORMERLY IN pconsistency.c ******************************/
+/********************************************************************************************/
+
+/****************************** CHECK_PARAM_VALIDITY_AND_CONSISTENCY *********************************/
+
+int check_param_validity_and_consistency(dataptr dz)
+{
+	handle_pitch_zeros(dz);
+	switch(dz->process) {
+	case(BRIDGE):	   return check_compatibility_of_bridge_params(dz);
+	case(MORPH):	   return check_consistency_of_morph_params(dz);
+	}
+	return(FINISHED);
+}
+
+/************** CHECK_COMPATIBILITY_OF_BRIDGE_PARAMS **********/
+
+int check_compatibility_of_bridge_params(dataptr dz)
+{
+	double bridge_time;
+	double infile0_dur = (dz->insams[0]/dz->wanted) * dz->frametime;
+	double infile1_dur = (dz->insams[1]/dz->wanted) * dz->frametime;
+
+	if(dz->param[BRG_OFFSET] >= infile0_dur - dz->frametime) {
+		sprintf(errstr,"Offset incompatible with 1st file duration.\n");
+		return(USER_ERROR);
+	}
+	if(!dz->vflag[IS_BRG_START])
+		dz->param[BRG_STIME] = dz->param[BRG_OFFSET];
+	if(!dz->vflag[IS_BRG_END])
+		dz->param[BRG_ETIME] = min(infile0_dur,dz->param[BRG_OFFSET] + infile1_dur);
+	bridge_time = dz->param[BRG_ETIME] - dz->param[BRG_STIME];
+
+	if(bridge_time < dz->frametime) {
+		sprintf(errstr,"Starttime and endtime incompatible.\n");
+		return(USER_ERROR);
+	}
+	if(dz->param[BRG_OFFSET] > dz->param[BRG_STIME]) {
+		sprintf(errstr,"time_offset beyond bridge starttime.\n");
+		return(USER_ERROR);
+	}
+	if(dz->param[BRG_ETIME] > dz->param[BRG_OFFSET] + infile1_dur) {
+		sprintf(errstr,"bridge endtime beyond end of 2nd file.\n");
+		return(USER_ERROR);
+	}
+	return(FINISHED);
+}
+
+/********************** CHECK_CONSISTENCY_OF_MORPH_PARAMS **********************/
+
+int check_consistency_of_morph_params(dataptr dz)
+{
+	double duration0  = (dz->insams[0]/dz->wanted) * dz->frametime;
+	double duration1 = ((dz->insams[1]/dz->wanted) * dz->frametime)
+		+ dz->param[MPH_STAG];
+	if(dz->param[MPH_ASTT] < dz->param[MPH_STAG]
+	|| dz->param[MPH_FSTT] < dz->param[MPH_STAG]) {
+		sprintf(errstr,
+			"start of amp or frq interpolation is set before entry of 2nd soundfile.\n");
+		return(DATA_ERROR);
+	}
+	if(dz->param[MPH_AEND] > duration0 || dz->param[MPH_AEND] > duration1
+	|| dz->param[MPH_FEND] > duration0 || dz->param[MPH_FEND] > duration1) {
+		sprintf(errstr,
+			"end of amp or frq interpolation is beyond end of one of soundfiles.\n");
+		return(DATA_ERROR);
+	}
+	if(dz->param[MPH_AEND] <= dz->param[MPH_ASTT]) {
+		sprintf(errstr,"amp interpolation starttime is after (or equal to) its endtime.\n");
+		return(USER_ERROR);
+	}
+	if(dz->param[MPH_FEND] <= dz->param[MPH_FSTT]) {
+		sprintf(errstr,"frq interpolation starttime is after (or equal to) its endtime.\n");
+		return(USER_ERROR);
+	}
+	return(FINISHED);
+}
+
+/********************************************************************************************/
+/********************************** FORMERLY IN buffers.c ***********************************/
+/********************************************************************************************/
+
+/**************************** ALLOCATE_LARGE_BUFFERS ******************************/
+
+int allocate_large_buffers(dataptr dz)
+{
+	switch(dz->process) {
+	case(GLIDE):	return allocate_single_buffer_plus_extra_pointer(dz);
+	case(BRIDGE):	return allocate_triple_buffer_for_bridge(dz);
+	case(MORPH):	return allocate_double_buffer(dz);
+	}
+	sprintf(errstr,"Unknown program no. in allocate_large_buffers()\n");
+	return(PROGRAM_ERROR);
+}
+
+/**************************** ALLOCATE_TRIPLE_BUFFER_FOR_BRIDGE ******************************/
+
+int allocate_triple_buffer_for_bridge(dataptr dz)
+{
+	unsigned int buffersize;
+	if(dz->bptrcnt < 5) {
+		sprintf(errstr,"Insufficient bufptrs established in allocate_triple_buffer_for_bridge()\n");
+		return(PROGRAM_ERROR);
+	}
+//TW REVISED: , as buffers no longer have to be in sector lengths
+	buffersize = dz->wanted * BUF_MULTIPLIER;
+	if((dz->bigfbuf = (float*)malloc((size_t)(buffersize * 3 * sizeof(float))))==NULL) {
+		sprintf(errstr,"INSUFFICIENT MEMORY for sound buffers.\n");
+		return(MEMORY_ERROR);
+	}
+	dz->big_fsize   = buffersize;
+//TW ADDED
+	dz->buflen   = buffersize;
+	dz->flbufptr[2]  = dz->bigfbuf + dz->big_fsize;
+	dz->flbufptr[3]  = dz->flbufptr[2] + dz->big_fsize;
+	dz->flbufptr[4]  = dz->flbufptr[3] + dz->big_fsize;	/* flbufptr[3-4] are static ptrs */
+	/* NB MOVING POINTERS NOT ESTABLISHED HERE !! */
+	return(FINISHED);
+}
+
+/********************************************************************************************/
+/********************************** FORMERLY IN cmdline.c ***********************************/
+/********************************************************************************************/
+
+int get_process_no(char *prog_identifier_from_cmdline,dataptr dz)
+{
+	if     (!strcmp(prog_identifier_from_cmdline,"glide"))     		dz->process = GLIDE;
+	else if(!strcmp(prog_identifier_from_cmdline,"bridge"))    		dz->process = BRIDGE;
+	else if(!strcmp(prog_identifier_from_cmdline,"morph"))     		dz->process = MORPH;
+	else {
+		sprintf(errstr,"Unknown program identification string '%s'\n",prog_identifier_from_cmdline);
+		return(USAGE_ONLY);
+	}
+	return(FINISHED);
+}
+
+/********************************************************************************************/
+/********************************** FORMERLY IN usage.c *************************************/
+/********************************************************************************************/
+
+/******************************** USAGE1 ********************************/
+
+int usage1(void)
+{
+	sprintf(errstr,
+	"\nMORPHING BETWEEN SPECTRAL FILES\n\n"
+	"USAGE: morph NAME (mode) infile infile2 outfile parameters: \n"
+	"\n"
+	"where NAME can be any one of\n"
+	"\n"
+	"glide     bridge     morph\n\n"
+	"Type 'morph glide' for more info on morph glide..ETC.\n");
+	return(USAGE_ONLY);
+}
+
+/******************************** USAGE2 ********************************/
+
+int usage2(char *str)
+{
+	if(!strcmp(str,"glide")) {
+		fprintf(stdout,
+		"morph glide infile infile2 outfile duration\n\n"
+		"INTERPOLATE, LINEARLY, BETWEEN 2 SINGLE ANALYSIS WINDOWS\n"
+		"              EXTRACTED WITH spec grab.\n\n"
+		"INFILE1, INFILE2  are single-window analysis files.\n"
+		"DURATION          is duration of output sound required.\n");
+	} else if(!strcmp(str,"bridge")) {
+		fprintf(stdout,
+		"morph bridge mode infile1 infile2 outfile\n"
+		"       [-aoffset] [-bsf2] [-csa2] [-def2] [-eea2] [-fstart] [-gend]\n\n"
+		"      MAKE A BRIDGING-INTERPOLATION BETWEEN TWO SOUND SPECTRA\n"
+		"BY INTERPOLATING BETWEEN 2 TIME-SPECIFIED WINDOWS IN THE 2 INFILES.\n\n"
+		"OFFSET time infile2 starts, relative to start of file1: (>=0)  default: 0.0\n"
+		"SF2    fraction of 2nd sound's frq interpolated at START.(default 0)\n"
+		"SA2    fraction of 2nd sound's amp interpolated at START.(default 0)\n"
+		"...if an OFFSET is used, when SF2 or SA2 are set NON-zero,\n"
+		"...outsound starts from point where 2nd sound enters.\n"
+		"EF2    fraction of 2nd sound's frq interpolated at END.(default 1)\n"
+		"EA2    fraction of 2nd sound's amp interpolated at END.(default 1)\n\n"
+		"...if EF2 or EA2 are set < 1.0 , outsound ends at end of first sound to end.\n"
+		"START  time in infile1, of startwindow for interp, (secs): default: 0.0\n"
+		"END    time in infile1 of endwindow of interp: default: end_of_file\n"
+		"...if START and END are not specified\n"
+		"...interp runs from OFFSET to end of 1st file to end.\n"
+		"MODES....\n"
+		"(1) output level is direct result of interpolation.\n"
+		"(2) output level follows moment to moment minimum of the 2 infile amplitudes.\n"
+		"(3) output level follows moment to moment amplitude of infile1.\n"
+		"(4) output level follows moment to moment amplitude of infile2.\n"
+		"(5) output level moves, through interp, from that of file1 to that of file2.\n"
+		"(6) output level moves, through interp, from that of file2 to that of file1.\n");
+	} else if(!strcmp(str,"morph")) {
+		fprintf(stdout,
+		"morph morph mode infile infile2 outfile as ae fs fe expa expf [-sstagger]\n\n"
+		"MORPH ONE SPECTRUM INTO ANOTHER.\n\n"
+		"as   is time(secs) when amplitude-interpolation starts.\n"
+		"ae   is time(secs) when amplitude-interpolation ends.\n"
+		"fs   is time(secs) when frequency-interpolation starts.\n"
+		"fe   is time(secs) when frequency-interpolation ends.\n"
+		"expa is exponent of amplitude interpolation.\n"
+		"expf is exponent of frequency interpolation.\n"
+		"stagger is time-delay of entry of 2nd file (defalut 0.0).\n\n"
+		"MODES..\n"
+		"(1) interpolate linearly (exp 1)\n"
+		"    or over a curve of increasing (exp >1) or decreasing (exp <1) slope.\n"
+		"(2) interpolate over a cosinusoidal spline.\n");
+	} else
+		fprintf(stdout,"Unknown option '%s'\n",str);
+	return(USAGE_ONLY);
+}
+
+/******************************** USAGE3 ********************************/
+
+int usage3(char *str1,char *str2)
+{
+	sprintf(errstr,"Insufficient parameters on command line.\n");
+	return(USAGE_ONLY);
+}
+

+ 238 - 0
dev/morph/main.c

@@ -0,0 +1,238 @@
+/*
+ * Copyright (c) 1983-2013 Trevor Wishart and Composers Desktop Project Ltd
+ * http://www.trevorwishart.co.uk
+ * http://www.composersdesktop.com
+ *
+ This file is part of the CDP System.
+
+    The CDP System is free software; you can redistribute it
+    and/or modify it under the terms of the GNU Lesser General Public
+    License as published by the Free Software Foundation; either
+    version 2.1 of the License, or (at your option) any later version.
+
+    The CDP System is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public
+    License along with the CDP System; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+    02111-1307 USA
+ *
+ */
+
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <structures.h>
+#include <tkglobals.h>
+#include <morph.h>
+#include <filetype.h>
+#include <processno.h>
+#include <modeno.h>
+#include <formants.h>
+#include <cdpmain.h>
+#include <special.h>
+#include <logic.h>
+#include <globcon.h>
+#include <cdpmain.h>
+#include <sfsys.h>
+#include <ctype.h>
+#include <string.h>
+
+char errstr[2400];
+
+/*extern*/ int	sloom = 0;
+/*extern*/ int sloombatch = 0;
+/*extern*/ int anal_infiles = 1;
+/*extern*/ int is_converted_to_stereo = -1;
+/* TW bugfix 2012 */
+const char* cdp_version = "7.1.0";
+
+/**************************************** MAIN *********************************************/
+
+int main(int argc,char *argv[])
+{
+	int exit_status;
+	dataptr dz = NULL;
+	char **cmdline;
+	int  cmdlinecnt;
+	aplptr ap;
+	int *valid = NULL;
+	int is_launched = FALSE;
+	int  validcnt;
+
+	if(argc==2 && (strcmp(argv[1],"--version") == 0)) {
+		fprintf(stdout,"%s\n",cdp_version);
+		fflush(stdout);
+		return 0;
+	}
+						/* CHECK FOR SOUNDLOOM */
+
+	if((sloom = sound_loom_in_use(&argc,&argv)) > 1) {
+		sloom = 0;
+		sloombatch = 1;
+	}
+
+	if(!sloom) {
+		if((exit_status = allocate_and_initialise_validity_flags(&valid,&validcnt))<0) {
+			print_messages_and_close_sndfiles(exit_status,is_launched,dz);
+			return(FAILED);
+		}
+	}
+
+	if(sflinit("cdp")){
+		sfperror("cdp: initialisation\n");
+		return(FAILED);
+	}
+
+						  /* SET UP THE PRINCIPLE DATASTRUCTURE */
+	if((exit_status = establish_datastructure(&dz))<0) {
+		print_messages_and_close_sndfiles(exit_status,is_launched,dz);
+		return(FAILED);
+	}
+
+
+					  
+	if(!sloom) {
+							  /* INITIAL CHECK OF CMDLINE DATA */
+		if((exit_status = make_initial_cmdline_check(&argc,&argv))<0) {
+			print_messages_and_close_sndfiles(exit_status,is_launched,dz);
+			return(FAILED);
+		}
+		cmdline    = argv;	/* GET PRE_DATA, ALLOCATE THE APPLICATION, CHECK FOR EXTRA INFILES */
+		cmdlinecnt = argc;
+		if((exit_status = get_process_and_mode_from_cmdline(&cmdlinecnt,&cmdline,dz))<0) {
+			print_messages_and_close_sndfiles(exit_status,is_launched,dz);
+			return(FAILED);
+		}		
+		if((exit_status = setup_particular_application(dz))<0) {
+			print_messages_and_close_sndfiles(exit_status,is_launched,dz);
+			return(FAILED);
+		}
+		if((exit_status = count_and_allocate_for_infiles(cmdlinecnt,cmdline,dz))<0) {
+			print_messages_and_close_sndfiles(exit_status,is_launched,dz);
+			return(FAILED);
+		}
+	} else {
+		if((exit_status = parse_tk_data(argc,argv,&cmdline,&cmdlinecnt,dz))<0) {  	/* includes setup_particular_application()      */
+			exit_status = print_messages_and_close_sndfiles(exit_status,is_launched,dz);/* and cmdlinelength check = sees extra-infiles */
+			return(exit_status);		 
+		}
+	}
+
+	ap = dz->application;
+
+/*********************************************************************************************************************
+	   cmdline[0]				 		  2 vals					   		  ACTIVE		 
+TK 		(infile) (more-infiles) (outfile) (flag val) (formantsqksrch) (special) params  options   variant-params  flags
+CMDLINE	(infile) (more-infiles) (outfile) (formants) (formantsqksrch) (special) params  POSSIBLY  POSSIBLY	  	POSSIBLY
+								 		  1 val
+*********************************************************************************************************************/
+
+	if((exit_status = parse_infile_and_hone_type(cmdline[0],valid,dz))<0) {
+		print_messages_and_close_sndfiles(exit_status,is_launched,dz);
+		return(FAILED);
+	}
+
+	if((exit_status = setup_param_ranges_and_defaults(dz))<0) {
+		print_messages_and_close_sndfiles(exit_status,is_launched,dz);
+		return(FAILED);
+	}
+
+					/* OPEN FIRST INFILE AND STORE DATA, AND INFORMATION, APPROPRIATELY */
+
+	if(dz->input_data_type!=NO_FILE_AT_ALL) {
+		if((exit_status = open_first_infile(cmdline[0],dz))<0) {	
+			print_messages_and_close_sndfiles(exit_status,is_launched,dz);	
+			return(FAILED);
+		}
+//TW UPDATE
+		cmdlinecnt--;
+		cmdline++;
+	}
+	
+/*********************************************************************************************************************
+		cmdline[0]				   2 vals				   			   ACTIVE		 
+TK 		(more-infiles) (outfile) (flag val) (formantsqksrch) (special) params  options   variant-params  flags
+CMDLINE	(more-infiles) (outfile) (formants) (formantsqksrch) (special) params  POSSIBLY  POSSIBLY		  POSSIBLY
+								   1 val
+*********************************************************************************************************************/
+
+	if((exit_status = handle_extra_infiles(&cmdline,&cmdlinecnt,dz))<0) {
+		print_messages_and_close_sndfiles(exit_status,is_launched,dz);		
+		return(FAILED);
+	}
+
+/*********************************************************************************************************************
+		cmdline[0]	  2					   			    ACTIVE		 
+TK 		(outfile) (flag val) (formantsqksrch) (special) params  options   variant-params  flags
+CMDLINE	(outfile) (formants) (formantsqksrch) (special) params  POSSIBLY  POSSIBLY		   POSSIBLY
+					  1
+*********************************************************************************************************************/
+
+	if((exit_status = handle_outfile(&cmdlinecnt,&cmdline,is_launched,dz))<0) {
+		print_messages_and_close_sndfiles(exit_status,is_launched,dz);
+		return(FAILED);
+	}
+
+/****************************************************************************************
+		cmdline[0]	  		   			       ACTIVE		 
+TK 		(flag val) (formantsqksrch) (special) params  options   variant-params  flags
+CMDLINE	(formants) (formantsqksrch) (special) params  POSSIBLY  POSSIBLY		POSSIBLY
+*****************************************************************************************/
+
+	if((exit_status = handle_formants(&cmdlinecnt,&cmdline,dz))<0) {
+		print_messages_and_close_sndfiles(exit_status,is_launched,dz);
+		return(FAILED);
+	}
+	if((exit_status = handle_formant_quiksearch(&cmdlinecnt,&cmdline,dz))<0) {
+		print_messages_and_close_sndfiles(exit_status,is_launched,dz);
+		return(FAILED);
+	}
+	if((exit_status = handle_special_data(&cmdlinecnt,&cmdline,dz))<0) {
+		print_messages_and_close_sndfiles(exit_status,is_launched,dz);
+		return(FAILED);
+	}
+ 
+/****************************************************************************************
+		cmdline[0]	  		   			    
+TK 		active_params  	options   		variant-params  flags
+CMDLINE	active_params  	POSSIBLY  		POSSIBLY		POSSIBLY
+*****************************************************************************************/
+
+	if((exit_status = read_parameters_and_flags(&cmdline,&cmdlinecnt,dz))<0) {
+		print_messages_and_close_sndfiles(exit_status,is_launched,dz);
+		return(FAILED);
+	}
+
+	if((exit_status = check_param_validity_and_consistency(dz))<0) {
+		print_messages_and_close_sndfiles(exit_status,is_launched,dz);
+		return(FAILED);
+	}
+
+ 	is_launched = TRUE;
+
+	if((exit_status = allocate_large_buffers(dz))<0){
+		print_messages_and_close_sndfiles(exit_status,is_launched,dz);
+		return(FAILED);
+	}
+	if((exit_status = param_preprocess(dz))<0){
+		print_messages_and_close_sndfiles(exit_status,is_launched,dz);
+		return(FAILED);
+	}
+	if((exit_status = spec_process_file(dz))<0) {
+		print_messages_and_close_sndfiles(exit_status,is_launched,dz);
+		return(FAILED);
+	}
+	if((exit_status = complete_output(dz))<0) {
+		print_messages_and_close_sndfiles(exit_status,is_launched,dz);
+		return(FAILED);
+	}
+	exit_status = print_messages_and_close_sndfiles(FINISHED,is_launched,dz);
+	free(dz);
+	return(SUCCEEDED);
+}
+

+ 896 - 0
dev/morph/morph.c

@@ -0,0 +1,896 @@
+/*
+ * Copyright (c) 1983-2013 Trevor Wishart and Composers Desktop Project Ltd
+ * http://www.trevorwishart.co.uk
+ * http://www.composersdesktop.com
+ *
+ This file is part of the CDP System.
+
+    The CDP System is free software; you can redistribute it
+    and/or modify it under the terms of the GNU Lesser General Public
+    License as published by the Free Software Foundation; either
+    version 2.1 of the License, or (at your option) any later version.
+
+    The CDP System is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public
+    License along with the CDP System; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+    02111-1307 USA
+ *
+ */
+
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <structures.h>
+#include <pnames.h>
+#include <tkglobals.h>
+#include <globcon.h>
+#include <modeno.h>
+#include <arrays.h>
+#include <morph.h>
+#include <cdpmain.h>
+#include <formants.h>
+#include <speccon.h>
+#include <sfsys.h>
+#include <string.h>
+#include <morph.h>
+
+#define BEFORE 	(0)
+#define	IN		(1)
+#define	AFTER	(2)
+
+#define NO_NORMALISE    (0)
+#define NORMALISE_FILE1 (1)
+#define NORMALISE_FILE2 (2)
+
+static int  read_two_individual_input_windows(dataptr dz);
+static int  establish_glide_ratios(dataptr dz);
+static int  establish_temporary_file_for_offsetting(dataptr dz);
+static int determine_process_startwindow(dataptr dz);
+static int determine_process_endwindow(dataptr dz);
+static int  read_bothfiles_for_bridge(int *windows_in_buf,dataptr dz);
+static int  do_specbridge(dataptr dz);
+static int  create_temporary_file_frontpadded_with_silence(dataptr dz);
+static int  do_interpolation(int where,dataptr dz);
+static int  set_tempfile_properties(dataptr dz);
+static int  set_normalisation_type(int *normalisation_type,int where,double *normaliser, dataptr dz);
+static int  read_specific_file_to_specific_buf(int fileno,int *windows_to_buf,
+				float **fbufptr,float *floatbuf,dataptr dz);
+static int  do_specmorph(double alen, double flen, dataptr dz);
+static void remove_temp_file(dataptr dz);
+static int  warped_cosin(double *interpratio,double exponent,dataptr dz);
+static int  time_warp(double *interpratio,double exponent);
+static int  cosin_lookup(double *interpratio,dataptr dz);
+
+/*********************** SPECGLIDE ***************************/
+
+int specglide(dataptr dz)
+{
+	int exit_status;
+	int wc;
+	int cc, vc;
+	double interp_fact;
+	if((exit_status = read_two_individual_input_windows(dz))<0)
+		return(exit_status);
+	if((exit_status = establish_glide_ratios(dz))<0)
+		return(exit_status);
+	dz->flbufptr[0] = dz->bigfbuf;
+	dz->flbufptr[1] = dz->bigfbuf + dz->big_fsize; /* bufend */
+	for(wc = 0; wc < dz->wlength; wc++) {
+		interp_fact = (double)wc/(double)(dz->wlength-1);
+		for(cc = 0, vc = 0; cc < dz->clength; cc++, vc += 2) {
+			if(dz->iparray[GLIDE_ZERO][cc]) {
+				dz->flbufptr[0][AMPP] = dz->windowbuf[1][AMPP];
+				dz->flbufptr[0][FREQ] = dz->windowbuf[1][FREQ];
+			} else {
+				dz->flbufptr[0][AMPP] = (float)(dz->windowbuf[0][AMPP] + (interp_fact * dz->windowbuf[1][AMPP]));
+				dz->flbufptr[0][FREQ] = (float)(dz->windowbuf[0][FREQ] * pow(2.0,(dz->parray[GLIDE_INF][cc] * interp_fact)));
+			}
+		}
+		if((dz->flbufptr[0] += dz->wanted) >= dz->flbufptr[1])	 {	/* move along bigfbuf */
+			if((exit_status = write_exact_samps(dz->bigfbuf,dz->big_fsize,dz))<0)
+				return(exit_status);
+			dz->flbufptr[0] = dz->bigfbuf;
+		}
+	}
+	if(dz->flbufptr[0] != dz->bigfbuf) {
+		if((exit_status = write_samps(dz->bigfbuf,dz->flbufptr[0] - dz->bigfbuf,dz))<0)
+			return(exit_status);
+	}
+	return(FINISHED);
+}
+
+/****************************** READ_TWO_INDIVIDUAL_INPUT_WINDOWS ***************************/
+
+int read_two_individual_input_windows(dataptr dz)
+{
+	int samps_read;
+	if((samps_read = fgetfbufEx(dz->bigfbuf,dz->wanted,dz->ifd[0],0)) < dz->wanted) {
+		if(samps_read < 0) {
+			sprintf(errstr,"Sound read error.\n");
+			return(SYSTEM_ERROR);
+		} else {
+			sprintf(errstr,"Failed to read a window from 1st input file.\n");
+			return(DATA_ERROR);
+		}
+	}
+	memmove((char *)dz->windowbuf[0],(char *)dz->bigfbuf,(size_t)(dz->wanted * sizeof(float)));
+
+	if((samps_read = fgetfbufEx(dz->bigfbuf,dz->wanted,dz->ifd[1],0)) < dz->wanted) {
+		if(samps_read < 0) {
+			sprintf(errstr,"Sound read error.\n");
+			return(SYSTEM_ERROR);
+		} else {
+			sprintf(errstr,"Failed to read a window from 2nd input file.\n");
+			return(DATA_ERROR);
+		}
+	}
+	memmove((char *)dz->windowbuf[1],(char *)dz->bigfbuf,(size_t)(dz->wanted * sizeof(float)));
+	return(FINISHED);
+}
+
+/****************************** ESTABLISH_GLIDE_RATIOS ***************************/
+
+int establish_glide_ratios(dataptr dz)
+{
+ 	int cc, vc;
+	for(cc = 0, vc = 0; cc < dz->clength; cc++, vc += 2) {
+		dz->iparray[GLIDE_ZERO][cc] = 0;
+		if(flteq((double)dz->windowbuf[0][FREQ],0.0) || flteq((double)dz->windowbuf[1][FREQ],0.0)) {
+			dz->iparray[GLIDE_ZERO][cc] = 1;	/* mark any zeros in frq */
+			dz->windowbuf[1][AMPP] = 0.0f;
+			dz->windowbuf[1][FREQ] = (float)((double)cc * dz->chwidth);
+		} else {
+			dz->windowbuf[1][AMPP] = (float)(dz->windowbuf[1][AMPP] - dz->windowbuf[0][AMPP]);
+			if(dz->windowbuf[0][FREQ] < 0.0)
+				dz->windowbuf[0][FREQ] = -dz->windowbuf[0][FREQ]; /*invert any -ve frqs */
+			if(dz->windowbuf[1][FREQ]<0.0)
+				dz->windowbuf[1][FREQ] = -dz->windowbuf[1][FREQ];
+			dz->parray[GLIDE_INF][cc] = log(dz->windowbuf[1][FREQ]/dz->windowbuf[0][FREQ])/LOG10_OF_2;
+		}
+	}
+	return(FINISHED);
+}
+
+/**************************** SPECBRIDGE ***************************
+ *
+ *	COMMENT FOR RWD: I know this is irrational!!
+ *
+ *  MOVING POINTERS
+ *			flbufptr[0]						flbufptr[1]						flbufptr[5]
+ *				|								|								|
+ *	|			V				   |			V				  |				V
+ *	|______________________________|______________________________|______________________________
+ *	|	 input buffer for file0	   |	 input buffer for file1   |	       output buffer		 |
+ *	|_____________ifd[0]___________|_(ifd[1] becoming) otherfile__|______________________________|
+ *	
+ *	/\	  						   /\							  /\							 /\
+ *	bigfbuf					   flbufptr[2]					   flbufptr[3]  					 flbufptr[4]
+ * FIXED POINTERS
+ *
+ *		I've tidied it up in 'distort' package, so fixed pointers are called windowbuf[]
+ *											  and moving pointers are called flbufptr[]
+ */
+
+int specbridge(dataptr dz)
+{
+	int exit_status;
+	int windows_in_buf, startwindow, endwindow, remain, wc;
+	dz->flbufptr[0] = dz->bigfbuf;   	 /* moving pointer */
+	dz->flbufptr[1] = dz->flbufptr[2]; /* moving pointer */
+	dz->flbufptr[5] = dz->flbufptr[3]; /* moving pointer */
+//TW we only needed dz->outfilesize for truncating the final outfile: which no longer happens
+	if((exit_status = establish_temporary_file_for_offsetting(dz))<0)
+		return(exit_status);
+	startwindow = determine_process_startwindow(dz);
+	endwindow   = determine_process_endwindow(dz);
+	dz->total_windows = 0;
+
+	if(startwindow >= endwindow) {
+		sprintf(errstr,"error in window arithmetic:	specbridge()\n");
+		return(PROGRAM_ERROR);
+	}
+  	while(dz->total_windows < endwindow) {
+		if((exit_status = read_bothfiles_for_bridge(&windows_in_buf,dz))<0)
+			return(exit_status);
+		if(windows_in_buf <=0)
+			break;
+ 		for(wc=0; wc<windows_in_buf; wc++) {
+			if(dz->total_windows >= startwindow) {
+				if((exit_status = do_specbridge(dz))<0)
+					return(exit_status);
+			}
+			if((exit_status = advance_one_2fileinput_window(dz))<0)
+				return(exit_status);
+			if(dz->total_windows >= endwindow)
+				break;
+		}
+	}
+	if((remain = dz->flbufptr[5]  - dz->flbufptr[3]) > 0) {
+		if((exit_status = write_samps(dz->flbufptr[3],remain,dz))<0)
+			return(exit_status);
+	}
+
+	remove_temp_file(dz);
+	return(FINISHED);
+}
+
+/*************************** ESTABLISH_TEMPORARY_FILE_FOR_OFFSETTING ***********************/
+
+int establish_temporary_file_for_offsetting(dataptr dz)
+{
+	int exit_status;
+	dz->flbufptr[5] = dz->flbufptr[3];
+ 	if((dz->insams = (int  *)realloc((char *)(dz->insams),(dz->infilecnt+1) * sizeof(int)))==NULL) {
+		sprintf(errstr,"INSUFFICIENT MEMORY to enlarge insams array.\n");
+		return(MEMORY_ERROR);
+	}
+ 	if(dz->param[BRG_OFFSET] > 0.0) {
+ 		if((exit_status = create_temporary_file_frontpadded_with_silence(dz))<0)
+			return(exit_status);
+  	} else {	/* point to original file */
+ 		dz->other_file  =  dz->ifd[1];
+		dz->insams[2]	=  dz->insams[1];
+	}	
+ 	return(FINISHED);
+}
+
+/*************************** DETERMINE_PROCESS_STARTWINDOW ***********************/
+
+int determine_process_startwindow(dataptr dz)
+{
+	int startwindow;
+	switch(dz->mode) {
+	case(BRG_NO_NORMALISE):
+	case(BRG_NORM_TO_FILE1):
+	case(BRG_NORM_FROM_1_TO_2):
+		if(dz->param[BRG_SF2] > 0.0 || dz->param[BRG_SA2] > 0.0)
+ 			startwindow = round(dz->param[BRG_OFFSET]/dz->frametime);	/* start_of_sound from infile2 */
+		else
+ 			startwindow = 0;
+		break;
+	case(BRG_NORM_TO_MIN):  
+	case(BRG_NORM_FROM_2_TO_1):
+	case(BRG_NORM_TO_FILE2):
+		startwindow = round(dz->param[BRG_OFFSET]/dz->frametime);	/* start_of_sound from infile2 */
+		break;
+	default:
+		sprintf(errstr,"Unknown case in determine_process_startwindow()\n");
+		return(PROGRAM_ERROR);
+	}
+	return(startwindow);
+}
+
+/*************************** DETERMINE_PROCESS_ENDWINDOW ***********************/
+
+int determine_process_endwindow(dataptr dz)
+{
+#define	STOP_AT_END_OF_INFILE1  		(0)
+#define	STOP_AT_END_OF_INFILE2			(1)
+#define	STOP_AT_END_OF_SHORTEST_FILE	(2)
+	int process_end;
+	int endwindow = 0;
+	switch(dz->mode) {
+	case(BRG_NO_NORMALISE):
+		if(dz->param[BRG_EF2] <= 0.0 && dz->param[BRG_EA2] <= 0.0)
+ 			process_end = STOP_AT_END_OF_INFILE1;
+		else if(dz->param[BRG_EF2] >= 1.0 && dz->param[BRG_EA2] >= 1.0)
+ 			process_end = STOP_AT_END_OF_INFILE2;
+		else
+			process_end = STOP_AT_END_OF_SHORTEST_FILE;
+		break;
+	case(BRG_NORM_TO_MIN):  
+		process_end = STOP_AT_END_OF_SHORTEST_FILE;
+		break;
+	case(BRG_NORM_TO_FILE1):
+	case(BRG_NORM_FROM_2_TO_1):
+		if(dz->param[BRG_EF2] > 0.0 || dz->param[BRG_EA2] > 0.0)
+			process_end = STOP_AT_END_OF_SHORTEST_FILE;
+		else
+			process_end = STOP_AT_END_OF_INFILE1;
+		break;
+	case(BRG_NORM_TO_FILE2):
+	case(BRG_NORM_FROM_1_TO_2):
+		if(dz->param[BRG_EF2] < 1.0 || dz->param[BRG_EA2] < 1.0)
+			process_end = STOP_AT_END_OF_SHORTEST_FILE;
+		else
+			process_end = STOP_AT_END_OF_INFILE2;
+		break;
+	default:
+		sprintf(errstr,"Unknown case in determine_process_endwindow()\n");
+		return(PROGRAM_ERROR);
+	}
+	switch(process_end) {
+	case(STOP_AT_END_OF_INFILE1):
+		endwindow = dz->insams[0]/dz->wanted;
+		break;
+	case(STOP_AT_END_OF_INFILE2):
+		endwindow = dz->insams[2]/dz->wanted;
+		break;
+	case(STOP_AT_END_OF_SHORTEST_FILE):
+		endwindow = min(dz->insams[2]/dz->wanted,dz->insams[0]/dz->wanted);
+		break;
+	}
+	return(endwindow);
+}
+
+/***************************** READ_BOTHFILES_FOR_BRIDGE ***********************/
+
+int read_bothfiles_for_bridge(int *windows_in_buf,dataptr dz)
+{
+	int samps_read;
+	int samps_read1, samps_read2;
+	if((samps_read1 = fgetfbufEx(dz->bigfbuf,dz->big_fsize,dz->ifd[0],0))<0
+	|| (samps_read2 = fgetfbufEx(dz->flbufptr[2],dz->big_fsize,dz->other_file,0))<0) {
+		sprintf(errstr,"Sound read error.\n");
+		return(SYSTEM_ERROR);
+	}
+	samps_read = max(samps_read1,samps_read2);
+	*windows_in_buf = samps_read/dz->wanted;
+	dz->flbufptr[0] = dz->bigfbuf;
+	dz->flbufptr[1] = dz->flbufptr[2];
+	return(FINISHED);
+}
+
+/***************************** DO_SPECBRIDGE *********************************/
+
+int do_specbridge(dataptr dz)
+{
+	int exit_status;
+	int where;
+
+	if(dz->total_windows < dz->iparam[BRG_SWIN])		where = BEFORE;
+	else if(dz->total_windows < dz->iparam[BRG_INTPEND])	where = IN;
+	else		            							 where = AFTER;
+	switch(where) {
+	case(BEFORE):	/***  BEFORE START OF INTERPOLATION ***/
+		switch(dz->iparam[BRG_STARTIS]) {
+		case(1):
+			memmove((char *)dz->flbufptr[5],(char *)dz->flbufptr[0],(size_t)(dz->wanted * sizeof(float)));
+			break;	/* KEEP FILE1 DATA */
+		case(2): 
+			memmove((char *)dz->flbufptr[5],(char *)dz->flbufptr[1],(size_t)(dz->wanted * sizeof(float)));	
+			break;	/* KEEP FILE2 DATA */
+		case(3): 
+			if((exit_status = do_interpolation(BEFORE,dz))<0)
+				return(exit_status);
+			break;	/* INTERP DATA */
+		case(0):
+			sprintf(errstr,"BRG_STARTIS = 0: Should be impossible!!! do_specbridge()\n");
+			return(PROGRAM_ERROR);
+		}
+		break;
+	case(IN):		/********  INTERPOLATION PROPER ********/
+		dz->param[BRG_SF2] += dz->param[BRG_FSTEP];
+		dz->param[BRG_SA2] += dz->param[BRG_ASTEP];
+		if((exit_status = do_interpolation(IN,dz))<0)
+			return(exit_status);
+		break;
+	case(AFTER):	/***  TAIL ***/
+		switch(dz->iparam[BRG_TAILIS]) {
+		case(1):																		
+			memmove((char *)dz->flbufptr[5],(char *)dz->flbufptr[0],(size_t)(dz->wanted * sizeof(float)));
+			break;	 /* KEEP FILE1 DATA */
+		case(2): 
+			memmove((char *)dz->flbufptr[5],(char *)dz->flbufptr[1],(size_t)(dz->wanted * sizeof(float))); 
+			break;	 /* KEEP FILE2 DATA */
+		case(3): 
+			if((exit_status = do_interpolation(AFTER,dz))<0)
+				return(exit_status);
+			break;	 /* KEEP INTERPOLATED DATA */
+		case(0):
+			sprintf(errstr,"tailis = 0: Should be impossible!!! do_specbridge()\n");
+			return(PROGRAM_ERROR);
+		}
+		break;
+	}
+	if((dz->flbufptr[5] += dz->wanted) >= dz->flbufptr[4]) {
+		if((exit_status = write_exact_samps(dz->flbufptr[3],dz->big_fsize,dz))<0)
+			return(exit_status);
+		dz->flbufptr[5] = dz->flbufptr[3];
+	}
+	return(FINISHED);
+}
+
+/*************************** CREATE_TEMPORARY_FILE_FRONTPADDED_WITH_SILENCE ***********************/
+
+int create_temporary_file_frontpadded_with_silence(dataptr dz)
+{
+	int exit_status;
+	int offset_windows,bufwindows, samps_read, windows_read, remain;
+// 	if((dz->other_file = sndcreat("temp",-1,SAMP_FLOAT)) < 0) {
+//		sprintf(errstr,"Can't create intermediate soundfile 'temp.wav'\n");
+//		return(GOAL_FAILED);
+//	}
+	if((dz->other_file = sndcreat_formatted("temp",-1,SAMP_FLOAT,
+			dz->infile->channels,dz->infile->srate,CDP_CREATE_NORMAL)) < 0) {
+		sprintf(errstr,"Can't create intermediate soundfile 'temp.wav'\n");
+		return(GOAL_FAILED);
+	}
+	if((exit_status = set_tempfile_properties(dz))<0)
+		return(exit_status);
+	offset_windows = round(dz->param[BRG_OFFSET]/dz->frametime);
+	bufwindows     = dz->big_fsize/dz->wanted;
+	while(offset_windows >= bufwindows) {
+		memset((char *)dz->flbufptr[3],0,(size_t)(dz->big_fsize * sizeof(float)));
+		if((exit_status = 
+		write_samps_to_elsewhere(dz->other_file,dz->flbufptr[3],dz->big_fsize,dz))<0)
+			return(exit_status);
+		offset_windows -= bufwindows;
+	}
+	if(offset_windows) {
+		memset((char *)dz->flbufptr[3],0,(size_t)(offset_windows * dz->wanted * sizeof(float)));
+		dz->flbufptr[5] = dz->flbufptr[3] + offset_windows * dz->wanted;
+	}
+	do {
+		if((samps_read = fgetfbufEx(dz->bigfbuf,dz->big_fsize,dz->ifd[1],0)) < 0) {
+			sprintf(errstr,"soundfile read failed.\n");
+			return(SYSTEM_ERROR);
+		}
+		dz->flbufptr[0] = dz->bigfbuf;
+		if(samps_read > 0) {
+			windows_read = samps_read/dz->wanted;
+			while(windows_read) {
+				if(dz->flbufptr[0] >= dz->flbufptr[2]) {	
+					sprintf(errstr,"Error in buffer arithmetic: create_temporary_file_frontpadded_with_silence()\n");
+					return(PROGRAM_ERROR);
+				}
+				memmove((char *)dz->flbufptr[5],(char *)dz->flbufptr[0],(size_t)(dz->wanted * sizeof(float)));
+				if((dz->flbufptr[5] += dz->wanted) >= dz->flbufptr[4]) {
+					if((exit_status = 
+					write_samps_to_elsewhere(dz->other_file,dz->flbufptr[3],dz->big_fsize,dz))<0)
+						return(exit_status);
+					dz->flbufptr[5] = dz->flbufptr[3];
+				}
+				dz->flbufptr[0] += dz->wanted;
+			 	windows_read--;
+			}
+		}
+	}while(samps_read > 0);
+	if((remain = dz->flbufptr[5] - dz->flbufptr[3]) > 0) {
+		if((exit_status = write_samps_to_elsewhere(dz->other_file,dz->flbufptr[3],remain,dz))<0)
+			return(exit_status);
+	}
+	dz->insams[2] = dz->total_samps_written;
+	dz->total_samps_written = 0;
+	dz->flbufptr[0] = dz->bigfbuf;
+	dz->flbufptr[5] = dz->flbufptr[3];
+	if((sndseekEx(dz->other_file,0L,0))<0) {
+		sprintf(errstr,"seek to 0 failed, in create_temporary_file_frontpadded_with_silence()\n");
+		return(SYSTEM_ERROR);
+	}
+	return(FINISHED);
+}
+
+/********************* DO_INTERPOLATION **************************/
+
+int do_interpolation(int where,dataptr dz)
+{
+	int exit_status;
+	int n = 0, normalisation_type = NO_NORMALISE;
+	double normaliser = 0.0;
+
+	if(dz->mode!= BRG_NO_NORMALISE)	   {		/* RWD need these! */
+		if((exit_status = set_normalisation_type(&normalisation_type,where,&normaliser,dz))<0)
+			return(exit_status);
+	}//RWD
+	switch(normalisation_type) {
+	case(NO_NORMALISE):
+		while(n < dz->wanted) {
+			dz->flbufptr[5][n] = (float)((dz->flbufptr[1][n]*dz->param[BRG_SA2]) + (dz->flbufptr[0][n]*(1.0 - dz->param[BRG_SA2])));
+			n++;
+		}
+		break;
+	case(NORMALISE_FILE1):
+		while(n < dz->wanted) {
+			dz->flbufptr[5][n] = (float)((dz->flbufptr[1][n]*dz->param[BRG_SA2]) + (dz->flbufptr[0][n]*(1.0 - dz->param[BRG_SA2])*normaliser));
+			n++;
+			dz->flbufptr[5][n] = (float)((dz->flbufptr[1][n]*dz->param[BRG_SF2]) + (dz->flbufptr[0][n]*(1.0 - dz->param[BRG_SF2])));
+			n++;
+		}
+		break;
+	case(NORMALISE_FILE2):
+		while(n < dz->wanted) {
+			dz->flbufptr[5][n] = (float)((dz->flbufptr[1][n]*dz->param[BRG_SA2]*normaliser) + (dz->flbufptr[0][n]*(1.0 - dz->param[BRG_SA2])));
+			n++;
+			dz->flbufptr[5][n] = (float)((dz->flbufptr[1][n]*dz->param[BRG_SF2]) + (dz->flbufptr[0][n]*(1.0 - dz->param[BRG_SF2])));
+			n++;
+		}
+		break;
+	default:
+		sprintf(errstr,"unknown case in do_interpolation()\n");
+		return(PROGRAM_ERROR);
+	}
+	return(FINISHED);
+}
+
+/***************************** SET_TEMPFILE_PROPERTIES ******************************/			
+ 
+int set_tempfile_properties(dataptr dz)
+{	
+	if(sndputprop(dz->other_file,"original sampsize", (char *)&(dz->infile->origstype), sizeof(int)) < 0){
+		sprintf(errstr,"Failure to write original sample size. set_tempfile_properties()\n");
+		return(PROGRAM_ERROR);
+	}
+	if(sndputprop(dz->other_file,"original sample rate", (char *)&(dz->infile->origrate), sizeof(int)) < 0){
+		sprintf(errstr,"Failure to write original sample rate. set_tempfile_properties()\n");
+		return(PROGRAM_ERROR);
+	}
+	if(sndputprop(dz->other_file,"arate",(char *)&(dz->infile->arate),sizeof(float)) < 0){
+		sprintf(errstr,"Failed to write analysis sample rate. set_tempfile_properties()\n");
+		return(PROGRAM_ERROR);
+	}
+	if(sndputprop(dz->other_file,"analwinlen",(char *)&(dz->infile->Mlen),sizeof(int)) < 0){
+		sprintf(errstr,"Failure to write analysis window length. set_tempfile_properties()\n");
+		return(PROGRAM_ERROR);
+	}
+	if(sndputprop(dz->other_file,"decfactor",(char *)&(dz->infile->Dfac),sizeof(int)) < 0){
+		sprintf(errstr,"Failure to write decimation factor. set_tempfile_properties()\n");
+		return(PROGRAM_ERROR);
+	}
+	if(sndputprop(dz->other_file,"sample rate", (char *)&(dz->infile->srate), sizeof(int)) < 0){
+		sprintf(errstr,"Failure to write sample rate. set_tempfile_properties()\n");
+		return(PROGRAM_ERROR);
+	}
+	if(sndputprop(dz->other_file,"channels", (char *)&(dz->infile->channels), sizeof(int)) < 0){
+		sprintf(errstr,"Failure to write channel data. set_tempfile_properties()\n");
+		return(PROGRAM_ERROR);
+	}
+//TW can't change sample type after file opened
+//	if(sndputprop(dz->other_file,"sample type", (char *)&(dz->infile->stype), sizeof(int)) < 0){
+//		sprintf(errstr,"Failure to write sample size. set_tempfile_properties()\n");
+//		return(PROGRAM_ERROR);
+//	}
+	return(FINISHED);
+}
+
+/********************* SET_NORMALISATION_TYPE **************************/
+
+int set_normalisation_type(int *normalisation_type,int where,double *normaliser, dataptr dz)
+{
+	int vc;
+	double z1, z2;
+	double sum1 = 0.0;
+	double sum2 = 0.0;
+	for(vc = 0;vc < dz->wanted; vc+=2) {
+		sum1 += dz->flbufptr[0][AMPP];
+		sum2 += dz->flbufptr[1][AMPP];
+	}
+	if(sum1 < 0.0 || sum2 < 0.0) {
+		sprintf(errstr,"Amplitude anomaly in data: cannot proceed.\n");
+		return(DATA_ERROR);
+	}
+	switch(dz->mode) {
+	case(BRG_NORM_TO_MIN):
+		if(sum1>sum2) {
+			*normalisation_type = NORMALISE_FILE1;		
+			if(flteq(sum1,0.0))
+				*normaliser = 0.0;
+			else 
+			*normaliser = sum2/sum1;
+		} else {
+			*normalisation_type = NORMALISE_FILE2;		
+			if(flteq(sum2,0.0))
+				*normaliser = 0.0;
+			else 
+				*normaliser = sum1/sum2;
+		}
+		break;
+	case(BRG_NORM_TO_FILE1):
+		*normalisation_type = NORMALISE_FILE2;			
+		if(flteq(sum2,0.0))
+			*normaliser = 0.0;
+		else 
+			*normaliser = sum1/sum2;
+		break;
+	case(BRG_NORM_TO_FILE2):
+		*normalisation_type = NORMALISE_FILE1;			
+		if(flteq(sum1,0.0))
+			*normaliser = 0.0;
+		else 
+			*normaliser = sum2/sum1;
+		break;
+	case(BRG_NORM_FROM_1_TO_2):
+		switch(where) {
+		case(BEFORE):
+			*normalisation_type = NORMALISE_FILE2;		
+			if(flteq(sum2,0.0))
+				*normaliser = 0.0;
+			else 
+				*normaliser = sum1/sum2;
+			break;
+		case(IN):
+			if(flteq(sum2,0.0))
+				*normaliser = 0.0;
+			else if(flteq(sum1,0.0))
+				*normaliser = 0.0; 
+			else {
+				z1 = sum1/sum2;
+				z2 = sum2/sum1;
+				*normaliser = z1 * pow(z2,dz->param[BRG_TFAC]);
+			}
+			if(dz->param[BRG_TFAC]<=1.0)
+				*normalisation_type = NORMALISE_FILE2;
+			else
+				*normalisation_type = NORMALISE_FILE1;
+			dz->param[BRG_TFAC] += dz->param[BRG_TSTEP];
+			break;
+		case(AFTER):
+			*normalisation_type = NORMALISE_FILE1;
+			if(flteq(sum1,0.0))
+				*normaliser = 0.0; 
+			else 
+				*normaliser = sum2/sum1;
+			break;
+		default:
+			sprintf(errstr,"Unknown case (A) in set_normalisation_type()\n");
+			return(PROGRAM_ERROR);
+		}
+		break;
+	case(BRG_NORM_FROM_2_TO_1):
+		switch(where) {
+		case(BEFORE):
+			*normalisation_type = NORMALISE_FILE1;
+			if(flteq(sum1,0.0))
+				*normaliser = 0.0;
+			else 
+				*normaliser = sum2/sum1;
+			break;
+		case(IN):
+			if(flteq(sum1,0.0))
+				*normaliser = 0.0;
+			else if(flteq(sum2,0.0))
+				*normaliser = 0.0; 
+			else {
+				z1 = sum2/sum1;
+				z2 = sum1/sum2;
+				*normaliser = z1 * pow(z2,dz->param[BRG_TFAC]);
+			}
+			if(dz->param[BRG_TFAC]<=1.0)
+				*normalisation_type = NORMALISE_FILE1;
+			else
+				*normalisation_type = NORMALISE_FILE2;
+			dz->param[BRG_TFAC] += dz->param[BRG_TSTEP];
+			break;
+		case(AFTER):
+			*normalisation_type = NORMALISE_FILE2;
+			if(flteq(sum2,0.0))
+				*normaliser = 0.0;
+			else 
+				*normaliser = sum1/sum2;
+			break;
+		default:
+			sprintf(errstr,"Unknown case (B) in set_normalisation_type()\n");
+			return(PROGRAM_ERROR);
+		}
+		break;
+	default:
+		sprintf(errstr,"Unknown case (C) in set_normalisation_type()\n");
+		return(PROGRAM_ERROR);
+	}
+	return(FINISHED);
+}
+
+/***************************** SPECMORPH ***********************/
+
+int specmorph(dataptr dz)
+{
+#define	FILE0 (0)
+#define FILE1 (1)
+
+	int		exit_status;
+	int	windows_to_buf0 = 0, windows_to_buf1 = 0, 
+			bufwsize		= dz->big_fsize/dz->wanted;
+	int	start_of_morph	= min(dz->iparam[MPH_ASTTW],dz->iparam[MPH_FSTTW]);
+	int	end_of_morph	= max(dz->iparam[MPH_AENDW],dz->iparam[MPH_FENDW]);
+	double	flen			= (double)(dz->iparam[MPH_FENDW] - dz->iparam[MPH_FSTTW]);
+	double	alen			= (double)(dz->iparam[MPH_AENDW] - dz->iparam[MPH_ASTTW]);
+	int	window_position_in_current_buf_for_file0 = 0,
+			window_position_in_outfile = 0, 
+			window_position_in_current_buf_for_file1 = -dz->iparam[MPH_STAGW];
+	int	total_windows_processed_from_file0 = 0, 
+			total_windows_processed_from_file1 = 0;
+	int		finished_file0 = 0, 
+			finished_file1 = 0;
+	int	total_windows_in_file1 = dz->insams[1]/dz->wanted;
+	
+	do {
+		if(!finished_file0) {
+			if(total_windows_processed_from_file0 >= end_of_morph)
+				finished_file0 = 1;
+			else {
+				if(window_position_in_current_buf_for_file0 == windows_to_buf0) {
+					if((exit_status = read_specific_file_to_specific_buf
+					(FILE0,&windows_to_buf0,&dz->flbufptr[0],dz->bigfbuf,dz))<0)
+						return(exit_status);
+					window_position_in_current_buf_for_file0 = 0;
+				}
+			}
+		}
+		if(window_position_in_current_buf_for_file1>=0) {
+			if(window_position_in_current_buf_for_file1 >= windows_to_buf1) {
+				if((exit_status = read_specific_file_to_specific_buf
+				(FILE1,&windows_to_buf1,&dz->flbufptr[1],dz->flbufptr[2],dz))<0)
+					return(exit_status);
+				window_position_in_current_buf_for_file1 = 0;
+			}
+			if(total_windows_processed_from_file0 >= start_of_morph) {
+				if(!finished_file0) {
+					if((exit_status = do_specmorph(alen,flen,dz))<0)
+						return(exit_status);
+				} else
+					memmove((char *)dz->flbufptr[0],(char *)dz->flbufptr[1],(size_t)(dz->wanted * sizeof(float)));	 
+			}
+			dz->flbufptr[1] += dz->wanted;
+			if(++total_windows_processed_from_file1 >= total_windows_in_file1)
+				finished_file1 = 1;
+		}
+		dz->flbufptr[0] += dz->wanted;
+		if(++window_position_in_outfile >= bufwsize) {
+			if((exit_status = write_exact_samps(dz->bigfbuf,dz->big_fsize,dz))<0)
+				return(exit_status);
+			window_position_in_outfile = 0;
+			dz->flbufptr[0] = dz->bigfbuf;
+		}
+		if(!finished_file0) {
+			total_windows_processed_from_file0++;
+			window_position_in_current_buf_for_file0++;
+		}
+		window_position_in_current_buf_for_file1++;
+		dz->total_windows++;
+	} while(!finished_file1);
+
+	if((window_position_in_outfile > 0) && (window_position_in_current_buf_for_file0 > 0)) {
+		if((exit_status = write_samps(dz->bigfbuf,window_position_in_current_buf_for_file0 * dz->wanted,dz))<0)
+		
+			return(exit_status);
+	}
+	return(FINISHED);
+}
+
+/***************************** READ_SPECIFIC_FILE_TO_SPECIFIC_BUF ***********************/
+
+int read_specific_file_to_specific_buf(int fileno,int *windows_to_buf,float **fbufptr,float *floatbuf,dataptr dz)
+{
+	int samps_read;
+	if((samps_read = fgetfbufEx(floatbuf,dz->big_fsize,dz->ifd[fileno],0))<=0) {
+		if(samps_read<0) {
+			sprintf(errstr,"Sound read error.\n");
+			return(SYSTEM_ERROR);
+		} else {
+			sprintf(errstr,"Error in buffer arithmetic in read_specific_file_to_specific_buf()\n");
+			return(PROGRAM_ERROR);
+		}
+	}
+	*windows_to_buf = samps_read/dz->wanted;
+	*fbufptr  = floatbuf;
+	return(FINISHED);
+}
+
+/*************************************** DO_SPECMORPH ******************************************/
+
+int do_specmorph(double alen, double flen, dataptr dz)
+{
+	int exit_status;
+	int vc;
+	double amp_interpratio, frq_interpratio, diff, incr;
+
+	if(dz->total_windows > dz->iparam[MPH_ASTTW]) {
+		if(dz->total_windows < dz->iparam[MPH_AENDW]) {
+			amp_interpratio = (double)(dz->total_windows - dz->iparam[MPH_ASTTW])/(double)alen;
+
+			switch(dz->mode) {
+			case(MPH_LINE):  
+				amp_interpratio = pow(amp_interpratio,dz->param[MPH_AEXP]);				
+				break;
+			case(MPH_COSIN): 
+				if((exit_status = warped_cosin(&amp_interpratio,dz->param[MPH_AEXP],dz))<0)
+					return(exit_status);
+				break;
+			default:
+				sprintf(errstr,"Unknown case in do_specmorph()\n");
+				return(PROGRAM_ERROR);
+			}
+			for(vc=0;vc < dz->wanted; vc+=2) {				
+				diff = dz->flbufptr[1][AMPP] - dz->flbufptr[0][AMPP];
+				incr = diff * amp_interpratio;
+				dz->flbufptr[0][AMPP] = (float)(dz->flbufptr[0][AMPP] + incr);
+			}
+		}
+		else {
+			for(vc=0;vc < dz->wanted; vc+=2)
+				dz->flbufptr[0][AMPP] = dz->flbufptr[1][AMPP];
+		}
+	}
+	if(dz->total_windows > dz->iparam[MPH_FSTTW]) {
+		if(dz->total_windows < dz->iparam[MPH_FENDW]) {
+			frq_interpratio = (double)(dz->total_windows - dz->iparam[MPH_FSTTW])/flen;
+
+			switch(dz->mode) {
+			case(MPH_LINE):  
+				frq_interpratio = pow(frq_interpratio,dz->param[MPH_FEXP]);				
+				break;
+			case(MPH_COSIN): 
+				if((exit_status = warped_cosin(&frq_interpratio,dz->param[MPH_FEXP],dz))<0)
+					return(exit_status);
+				break;
+			default:
+				sprintf(errstr,"Unknown case in do_specmorph()\n");
+				return(PROGRAM_ERROR);
+			}
+			for(vc=0;vc < dz->wanted; vc+=2) {
+				diff = dz->flbufptr[1][FREQ] - dz->flbufptr[0][FREQ];
+				incr = diff * frq_interpratio;
+				dz->flbufptr[0][FREQ] = (float)(dz->flbufptr[0][FREQ] + incr);
+			}
+		} else {
+			for(vc=0;vc < dz->wanted; vc+=2)
+				dz->flbufptr[0][FREQ] = dz->flbufptr[1][FREQ];
+		}
+	}
+	return(FINISHED);
+}	
+
+/*************************** DETERMINE_PROCESS_STARTWINDOW ***********************/
+
+void remove_temp_file(dataptr dz)
+{
+	if(dz->param[BRG_OFFSET] && dz->other_file >= 0) {
+		if(sndunlink(dz->other_file) < 0) {
+			fprintf(stdout, "WARNING: Can't set temporary sndfile 'temp' for deletion\n");
+		}
+		if(sndcloseEx(dz->other_file) < 0) {
+			fprintf(stdout,"WARNING: Can't close temporary sndfile 'temp'\n");
+		}
+	}
+	dz->other_file = -1;
+}
+
+/****************************** WARPED_COSIN ******************************/
+
+int warped_cosin(double *interpratio,double exponent,dataptr dz)
+{
+	int exit_status;
+	if(*interpratio < .5) {
+		if((exit_status = time_warp(interpratio,exponent))<0)
+		return(exit_status);
+	} else if(*interpratio > .5) {
+		*interpratio = 1.0 - *interpratio;
+		if((exit_status = time_warp(interpratio,exponent))<0)
+		return(exit_status);
+		*interpratio = 1.0 - *interpratio;					
+	}
+	if((exit_status = cosin_lookup(interpratio,dz))<0)
+		return(exit_status);
+	return(FINISHED);
+}
+
+/****************************** TIME_WARP ******************************/
+
+int time_warp(double *interpratio,double exponent)
+{
+	*interpratio = min(*interpratio * 2.0,1.0);
+	*interpratio = pow(*interpratio,exponent);
+	*interpratio /= 2.0;
+	return(FINISHED);
+}
+
+/****************************** COSIN_LOOKUP ******************************/
+
+int cosin_lookup(double *interpratio,dataptr dz)
+{
+	double dtabindex = *interpratio * (double)MPH_COSTABSIZE;
+	int tabindex = (int)floor(dtabindex);	/* TRUNCATE */
+	double frac  = dtabindex - (double)tabindex;
+	double thisval = dz->parray[0][tabindex++]; /* table has wraparound pnt */
+	double nextval = dz->parray[0][tabindex];
+	double diff = nextval - thisval;
+	double step = diff * frac;
+	*interpratio = thisval + step;
+	return(FINISHED);
+}