Browse Source

initial commit

richarddobson 3 years ago
parent
commit
f17dae89bf

+ 20 - 0
dev/editsf/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(sfedit main.c ap_edit.c cut.c twixt.c)
+
+target_link_libraries(sfedit cdp2k sfsys ${EXTRA_LIBRARIES})
+
+my_install(sfedit)
+

+ 1605 - 0
dev/editsf/ap_edit.c

@@ -0,0 +1,1605 @@
+/*
+ * 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
+ *
+ */
+
+
+
+/* floatsams 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 <edit.h>
+#include <processno.h>
+#include <modeno.h>
+#include <globcon.h>
+#include <logic.h>
+#include <filetype.h>
+
+#include <mixxcon.h>
+#include <flags.h>
+#include <speccon.h>
+#include <arrays.h>
+#include <special.h>
+#include <formants.h>
+#include <sfsys.h>
+#include <osbind.h>
+#include <ctype.h>
+
+#include <srates.h>
+
+#ifdef unix
+#define round(x) lround((x))
+#endif
+
+int randcuts_pconsistency(dataptr dz);
+int syllabs_pconsistency(dataptr dz);
+int get_syllab_times(char *filename,dataptr dz);
+int get_joinseq(char *filename,dataptr dz);
+int get_joindynseq(char *filename,dataptr dz);
+
+/********************************************************************************************/
+/********************************** FORMERLY IN specialin.c *********************************/
+/********************************************************************************************/
+
+static int  get_excise_times_from_file(char *filename,dataptr dz);
+static int get_many_cuts_times(char *filename,dataptr dz);
+static int preprocess_cutmany(dataptr dz);
+static int create_cutmany_sndbuf(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(EDIT_CUT):
+	case(EDIT_CUTEND):
+	case(INSERTSIL_MANY):		dz->extra_bufcnt = 0;	dz->bufcnt = 0;		break;
+
+	case(MANY_ZCUTS):
+	case(EDIT_ZCUT):			dz->extra_bufcnt = 0;	dz->bufcnt = 2;		break;
+
+	case(EDIT_EXCISE):			
+	case(EDIT_EXCISEMANY):		dz->extra_bufcnt = 0;	dz->bufcnt = 4;		break;
+
+	case(EDIT_INSERT):
+	case(EDIT_INSERT2):
+	case(EDIT_INSERTSIL):		dz->extra_bufcnt = 0;	dz->bufcnt = 3;		break;
+	case(JOIN_SEQDYN):
+	case(JOIN_SEQ):				dz->extra_bufcnt = 0;	dz->bufcnt = 5;		break;
+	case(EDIT_JOIN):			dz->extra_bufcnt = 0;	dz->bufcnt = 4;		break;
+	case(RANDCUTS):				dz->extra_bufcnt = 0;	dz->bufcnt = 2;		break;
+	case(RANDCHUNKS):			dz->extra_bufcnt = 0;	dz->bufcnt = 0;		break;
+	case(TWIXT):				dz->extra_bufcnt = 0;	dz->bufcnt = 2;		break;
+	case(SPHINX):				dz->extra_bufcnt = 0;	dz->bufcnt = 2;		break;
+	case(SYLLABS):
+	case(EDIT_CUTMANY):			dz->extra_bufcnt = 0;	dz->bufcnt = 1;		break;
+	case(NOISE_SUPRESS):		dz->extra_bufcnt = 0;	dz->bufcnt = 1;		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_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(EDIT_CUT):		   dz->array_cnt=0; dz->iarray_cnt=0; dz->larray_cnt=0; dz->ptr_cnt= 0; dz->fptr_cnt = 0; break;
+	case(EDIT_CUTEND):	   dz->array_cnt=0; dz->iarray_cnt=0; dz->larray_cnt=0; dz->ptr_cnt= 0; dz->fptr_cnt = 0; break;
+	case(MANY_ZCUTS):	   dz->array_cnt=0; dz->iarray_cnt=0; dz->larray_cnt=1; dz->ptr_cnt= 0; dz->fptr_cnt = 0; break;
+	case(EDIT_ZCUT):	   dz->array_cnt=0; dz->iarray_cnt=0; dz->larray_cnt=0; dz->ptr_cnt= 0; dz->fptr_cnt = 0; break;
+	case(EDIT_EXCISE):	   dz->array_cnt=0; dz->iarray_cnt=0; dz->larray_cnt=4; dz->ptr_cnt= 0; dz->fptr_cnt = 0; break;
+	case(EDIT_EXCISEMANY): dz->array_cnt=0; dz->iarray_cnt=0; dz->larray_cnt=4; dz->ptr_cnt= 0; dz->fptr_cnt = 0; break;
+	case(EDIT_INSERT2):
+	case(EDIT_INSERT):	   dz->array_cnt=0; dz->iarray_cnt=0; dz->larray_cnt=0; dz->ptr_cnt= 0; dz->fptr_cnt = 0; break;
+	case(EDIT_INSERTSIL):  dz->array_cnt=0; dz->iarray_cnt=0; dz->larray_cnt=0; dz->ptr_cnt= 0; dz->fptr_cnt = 0; break;
+	case(INSERTSIL_MANY):  dz->array_cnt=0; dz->iarray_cnt=0; dz->larray_cnt=4; dz->ptr_cnt= 0; dz->fptr_cnt = 0; break;
+	case(JOIN_SEQDYN):	   dz->array_cnt=3; dz->iarray_cnt=1; dz->larray_cnt=0; dz->ptr_cnt= 0; dz->fptr_cnt = 0; break;
+	case(JOIN_SEQ):		   dz->array_cnt=2; dz->iarray_cnt=1; dz->larray_cnt=0; dz->ptr_cnt= 0; dz->fptr_cnt = 0; break;
+	case(EDIT_JOIN):  	   dz->array_cnt=2; dz->iarray_cnt=0; dz->larray_cnt=0; dz->ptr_cnt= 0; dz->fptr_cnt = 0; break;
+	case(RANDCUTS):  	   dz->array_cnt=0; dz->iarray_cnt=0; dz->larray_cnt=1; dz->ptr_cnt= 0; dz->fptr_cnt = 0; break;
+	case(RANDCHUNKS):  	   dz->array_cnt=0; dz->iarray_cnt=0; dz->larray_cnt=0; dz->ptr_cnt= 0; dz->fptr_cnt = 0; break;
+	case(TWIXT):  	   	   dz->array_cnt=1; dz->iarray_cnt=2; dz->larray_cnt=0; dz->ptr_cnt= 0; dz->fptr_cnt = 0; break;
+	case(SPHINX):  	   	   dz->array_cnt=1; dz->iarray_cnt=2; dz->larray_cnt=0; dz->ptr_cnt= 0; dz->fptr_cnt = 0; break;
+	case(NOISE_SUPRESS):  dz->array_cnt=0; dz->iarray_cnt=0; dz->larray_cnt=1; dz->ptr_cnt= 0; dz->fptr_cnt = 0; break;
+	case(SYLLABS):
+	case(EDIT_CUTMANY):	   dz->array_cnt=0; dz->iarray_cnt=0; dz->larray_cnt=1; 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(EDIT_CUT):			setup_process_logic(SNDFILES_ONLY,		UNEQUAL_SNDFILE,	SNDFILE_OUT,	dz);	break;
+	case(EDIT_CUTEND):		setup_process_logic(SNDFILES_ONLY,		UNEQUAL_SNDFILE,	SNDFILE_OUT,	dz);	break;
+	case(MANY_ZCUTS):
+	case(EDIT_ZCUT):		setup_process_logic(SNDFILES_ONLY,		UNEQUAL_SNDFILE,	SNDFILE_OUT,	dz);	break;
+	case(EDIT_EXCISE):		setup_process_logic(SNDFILES_ONLY,		UNEQUAL_SNDFILE,	SNDFILE_OUT,	dz);	break;
+	case(EDIT_EXCISEMANY):	setup_process_logic(SNDFILES_ONLY,		UNEQUAL_SNDFILE,	SNDFILE_OUT,	dz);	break;
+	case(EDIT_INSERT2):
+	case(EDIT_INSERT):		setup_process_logic(TWO_SNDFILES,		UNEQUAL_SNDFILE,	SNDFILE_OUT,	dz);	break;
+	case(EDIT_INSERTSIL):	setup_process_logic(SNDFILES_ONLY,		UNEQUAL_SNDFILE,	SNDFILE_OUT,	dz);	break;
+	case(INSERTSIL_MANY):	setup_process_logic(SNDFILES_ONLY,		EQUAL_SNDFILE,		SNDFILE_OUT,	dz);	break;
+	case(JOIN_SEQDYN):
+	case(JOIN_SEQ):
+	case(EDIT_JOIN):		setup_process_logic(MANY_SNDFILES,		UNEQUAL_SNDFILE,	SNDFILE_OUT,	dz);	break;
+	case(RANDCUTS):			setup_process_logic(SNDFILES_ONLY,		OTHER_PROCESS,		NO_OUTPUTFILE,	dz);	break;
+	case(RANDCHUNKS):		setup_process_logic(SNDFILES_ONLY,		OTHER_PROCESS,		NO_OUTPUTFILE,	dz);	break;
+	case(TWIXT):			setup_process_logic(MANY_SNDFILES,		UNEQUAL_SNDFILE,	SNDFILE_OUT,	dz);	break;
+	case(SPHINX):			setup_process_logic(MANY_SNDFILES,		UNEQUAL_SNDFILE,	SNDFILE_OUT,	dz);	break;
+	case(NOISE_SUPRESS):	setup_process_logic(SNDFILES_ONLY,		UNEQUAL_SNDFILE,	SNDFILE_OUT,	dz);	break;
+	case(SYLLABS):
+	case(EDIT_CUTMANY):		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) {
+	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(EDIT_CUT):			exit_status = set_internalparam_data( "0iiiiiiiiiiiiiiiiiiiiiii",ap); break;
+	case(EDIT_CUTEND):	    exit_status = set_internalparam_data( "0iiiiiiiiiiiiiiiiiiiiiii",ap); break;
+	case(MANY_ZCUTS):	    exit_status=set_internalparam_data("ii00iiiiiiiiiiiiiiiiiiiiiii",ap); break;
+	case(EDIT_ZCUT):	    exit_status = set_internalparam_data("00iiiiiiiiiiiiiiiiiiiiiii",ap); break;
+	case(EDIT_EXCISE):	    exit_status = set_internalparam_data( "0iiiiiiiiiiiiiiiiiiiiiii",ap); break;
+	case(EDIT_EXCISEMANY):  exit_status = set_internalparam_data( "0iiiiiiiiiiiiiiiiiiiiiii",ap); break;
+	case(INSERTSIL_MANY):   exit_status = set_internalparam_data( "0iiiiiiiiiiiiiiiiiiiiiii",ap); break;
+	case(EDIT_INSERT2):
+	case(EDIT_INSERT):	    exit_status = set_internalparam_data(  "iiiiiiiiiiiiiiiiiiiiiii",ap); break;
+	case(EDIT_INSERTSIL):   exit_status = set_internalparam_data( "0iiiiiiiiiiiiiiiiiiiiiii",ap); break;
+	case(JOIN_SEQDYN):
+	case(JOIN_SEQ):
+	case(EDIT_JOIN):   		exit_status = set_internalparam_data( "0iiiiiiiiiiiiiiiiiiiiiii",ap); break;
+	case(RANDCUTS):   		exit_status = set_internalparam_data( "iiiiii",ap); break;
+	case(RANDCHUNKS):   	exit_status = set_internalparam_data( "0iiiiiiiiiiiiiiiiiiiiiii",ap); break;
+	case(TWIXT):
+		switch(mode) {
+		case(TRUE_EDIT):	exit_status = set_internalparam_data( "0di",ap); break;
+		default:   			exit_status = set_internalparam_data(  "di",ap); break;
+		}
+		break;
+	case(SPHINX):			exit_status = set_internalparam_data(  "di",ap); break;
+	case(NOISE_SUPRESS):	exit_status = set_internalparam_data(  "",ap); break;
+	case(SYLLABS):		/* this sets up too many internal params in this case, but doesn't matter */
+	case(EDIT_CUTMANY):		exit_status = set_internalparam_data(  "iid",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) {
+	case(EXCISE_TIMES):				return get_excise_times_from_file(str,dz);
+	case(SWITCH_TIMES):				return get_switchtime_data(str,dz);
+	case(MANY_SWITCH_TIMES):		return get_multi_switchtime_data(str,dz);
+	case(MANYCUTS):					return get_many_cuts_times(str,dz);
+	case(SYLLTIMES):				return get_syllab_times(str,dz);
+	case(JOINSEQ):					return get_joinseq(str,dz);
+	case(JOINSEQDYN):				return get_joindynseq(str,dz);
+	default:
+		sprintf(errstr,"Unknown special_data type: read_special_data()\n");
+		return(PROGRAM_ERROR);
+	}
+	return(FINISHED);	/* NOTREACHED */
+}
+
+/************************* GET_EXCISE_TIMES_FROM_FILE *************************/ 
+
+int get_excise_times_from_file(char *filename,dataptr dz)
+{
+	int is_start = 1, k = 0;
+	char *q, *p, temp[200];
+	double dummy;
+	int chans = dz->infile->channels; 
+	double sr = (double)dz->infile->srate;
+	FILE *fp;
+	if((fp = fopen(filename,"r"))==NULL) {
+		sprintf(errstr,"Cannot open textfile %s\n",filename);
+		return(DATA_ERROR);
+	}
+	dz->iparam[CUT_NO_END] = FALSE;
+	if((dz->lparray[CUT_STTSAMP] = (int *)malloc(sizeof(int)))==NULL
+	|| (dz->lparray[CUT_STTSPLI] = (int *)malloc(sizeof(int)))==NULL
+	|| (dz->lparray[CUT_ENDSAMP] = (int *)malloc(sizeof(int)))==NULL
+	|| (dz->lparray[CUT_ENDSPLI] = (int *)malloc(sizeof(int)))==NULL) {
+		sprintf(errstr,"INSUFFICIENT_MEMORY to store excise times.\n");
+		return(MEMORY_ERROR);
+	}
+	while(fgets(temp,200,fp)!=NULL) {
+		p = temp;
+		while(get_word_from_string(&p,&q)) {
+			if(dz->iparam[CUT_NO_END] == TRUE) {
+				sprintf(errstr,"End of excise %d is beyond end of file: cannot proceed.\n",k);
+				return(DATA_ERROR);
+			}
+			if(is_start) {
+				if(k > 0) {
+					if((dz->lparray[CUT_STTSAMP] = 
+					(int *)realloc((char *)(dz->lparray[CUT_STTSAMP]),(k+1) * sizeof(int)))==NULL
+					|| (dz->lparray[CUT_STTSPLI] = 
+					(int *)realloc((char *)(dz->lparray[CUT_STTSPLI]),(k+1) * sizeof(int)))==NULL
+					|| (dz->lparray[CUT_ENDSAMP] = 
+					(int *)realloc((char *)(dz->lparray[CUT_ENDSAMP]),(k+1) * sizeof(int)))==NULL
+					|| (dz->lparray[CUT_ENDSPLI] = 
+					(int *)realloc((char *)(dz->lparray[CUT_ENDSPLI]),(k+1) * sizeof(int)))==NULL) {
+						sprintf(errstr,"INSUFFICIENT_MEMORY to store more excise times.\n");
+						return(MEMORY_ERROR);
+					}
+				}
+				switch(dz->mode) {
+				case(EDIT_SAMPS):
+	   				if(sscanf(q,"%d",&(dz->lparray[CUT_STTSAMP][k]))!=1) {
+						sprintf(errstr,"Cannot read samplecnt %d\n",k+1);
+						return(DATA_ERROR);
+	   				}
+					break;
+				case(EDIT_STSAMPS):
+	   				if(sscanf(q,"%d",&(dz->lparray[CUT_STTSAMP][k]))!=1) {
+						sprintf(errstr,"Cannot read samplecnt %d\n",k+1);
+						return(DATA_ERROR);
+	   				}
+					dz->lparray[CUT_STTSAMP][k] *= chans;
+					break;
+				case(EDIT_SECS):
+	   				if(sscanf(q,"%lf",&dummy)!=1) {
+						sprintf(errstr,"Cannot read starttime %d\n",k+1);
+						return(DATA_ERROR);
+					}
+					dz->lparray[CUT_STTSAMP][k] = round(dummy * sr) * chans;
+					break;
+				}
+			    if(dz->lparray[CUT_STTSAMP][k] < 0 || dz->lparray[CUT_STTSAMP][k] >= dz->insams[0]) {
+					sprintf(errstr,"excise starttime %d is outside filelen.\n",k+1);
+					return(DATA_ERROR);
+			    }
+				if(k>0 && dz->lparray[CUT_STTSAMP][k] <= dz->lparray[CUT_ENDSAMP][k-1]) {
+					sprintf(errstr,"Start and end of excised portions %d & %d overlap.\n",k,k+1);
+					return(DATA_ERROR);
+				}							
+			} else {
+				switch(dz->mode) {
+				case(EDIT_SAMPS):
+		    		if(sscanf(q,"%d",&(dz->lparray[CUT_ENDSAMP][k]))!=1) {
+						sprintf(errstr,"Cannot read end samplecnt %d\n",k+1);
+						return(DATA_ERROR);
+		    		}
+					break;
+				case(EDIT_STSAMPS):
+		    		if(sscanf(q,"%d",&(dz->lparray[CUT_ENDSAMP][k]))!=1) {
+						sprintf(errstr,"Cannot read end samplecnt %d\n",k+1);
+						return(DATA_ERROR);
+		    		}
+					dz->lparray[CUT_ENDSAMP][k] *= chans;
+					break;
+				case(EDIT_SECS):
+		    		if(sscanf(q,"%lf",&dummy)!=1) {
+						sprintf(errstr,"Cannot read endtime %d\n",k+1);
+						return(DATA_ERROR);
+		    		}
+					dz->lparray[CUT_ENDSAMP][k] = round(dummy * sr) * chans;
+					break;
+				}
+			    if(dz->lparray[CUT_STTSAMP][k] >= dz->lparray[CUT_ENDSAMP][k]) {
+					sprintf(errstr,"starttime <= endtime for excise %d\n",k+1);
+					return(DATA_ERROR);
+		    	}
+				if(dz->lparray[CUT_ENDSAMP][k] >= dz->insams[0]) {
+					dz->iparam[CUT_NO_END] = TRUE;
+				}
+			}
+			is_start = !is_start;
+			if(is_start)
+				k++;
+		}
+	}
+	if(!is_start) {
+		sprintf(errstr,"Start and End times not paired correctly in textfile %s\n",filename);
+		return(DATA_ERROR);
+	}
+	if(k==0) {
+		sprintf(errstr,"No values found in textfile %s\n",filename);
+		return(DATA_ERROR);
+	}
+	dz->iparam[EXCISE_CNT] = k;
+	return(FINISHED);
+}
+
+/**************************** GET_SWITCHTIME_DATA ****************************/
+
+int get_switchtime_data(char *filename,dataptr dz)
+{
+	FILE *fp;
+	int n = 0, curtailed = 0;
+	int arraysize = BIGARRAY;
+	char temp[2000], *p;
+	double lasttime = 0.0, dummy;
+	double duration1 = (double)dz->insams[0]/(double)(dz->infile->channels * dz->infile->srate);
+	double duration2 = (double)dz->insams[1]/(double)(dz->infile->channels * dz->infile->srate);
+	double mindur = min(duration1,duration2);
+	if((fp = fopen(filename,"r"))==NULL) {
+		sprintf(errstr,"Cannot open file %s to read time-switch data.\n",filename);
+		return(DATA_ERROR);
+	}
+	if((dz->parray[0] = (double *)malloc(arraysize * sizeof(double)))==NULL) {
+		sprintf(errstr,"INSUFFICIENT MEMORY to store time-switch data.\n");
+		return(MEMORY_ERROR);
+	}
+
+	while(fgets(temp,2000,fp)!=NULL) {
+		p = temp;
+		if(*p == ';')
+			continue;
+		while(get_float_from_within_string(&p,&dummy)) {
+			if(n==0)
+				lasttime = dummy;
+			else if(dummy <= lasttime) {
+				sprintf(errstr,"Times %d (%lf) and %d (%lf) are not in ascending order\n",n,lasttime,n+1,dummy);
+				return(DATA_ERROR);
+			}
+			if(dummy < 0.0) {
+				sprintf(errstr,"Times %lf does not lie within the file (duration %lf).\n",dummy,dz->duration);
+				return(DATA_ERROR);
+			} else if(dummy > mindur) {
+				fprintf(stdout,"WARNING: Time %lf does not lie within both files (smallest duration %lf).\n",dummy,mindur);
+				fprintf(stdout,"WARNING: Curtailing output.\n");
+				fflush(stdout);
+				curtailed = 1;
+				break;
+			}
+			dz->parray[0][n] = dummy;
+			if(++n >= arraysize) {
+				arraysize += BIGARRAY;
+				if((dz->parray[0] = (double *)realloc((char *)dz->parray[0],arraysize*sizeof(double)))==NULL) {
+					sprintf(errstr,"INSUFFICIENT MEMORY to reallocate switch-times store.\n");
+					return(MEMORY_ERROR);
+				}
+			}
+		}
+		if(curtailed)
+			break;
+	}
+	if(n==0) {
+		sprintf(errstr,"No valid data found in switch-times data file %s\n",filename);
+		return(DATA_ERROR);
+	}
+	if(n < 2) {
+		sprintf(errstr,"Insufficient valid data (only 1 value) found in switch-times data file %s\n",filename);
+		return(DATA_ERROR);
+	}
+	if((dz->parray[0] = (double *)realloc((char *)dz->parray[0],n * sizeof(double)))==NULL) {
+		sprintf(errstr,"INSUFFICIENT MEMORY to reallocate switch-times store.\n");
+		return(MEMORY_ERROR);
+	}
+	if(dz->mode == RAND_REORDER) {
+		if((dz->iparray[0] = (int *)malloc((n-1) * sizeof(int)))==NULL) {
+			sprintf(errstr,"INSUFFICIENT MEMORY to allocate switch-times permutation store.\n");
+			return(MEMORY_ERROR);
+		}
+	}
+	dz->itemcnt = n;
+	if(fclose(fp)<0) {
+		fprintf(stdout,"WARNING: Failed to close input textfile %s.\n",filename);
+		fflush(stdout);
+	}
+	return(FINISHED);
+}
+    
+/**************************** GET_MULTI_SWITCHTIME_DATA ****************************/
+
+int get_multi_switchtime_data(char *filename,dataptr dz)
+{
+	FILE *fp;
+	int m, n = 0, curtailed = 0;
+	int arraysize = BIGARRAY;
+	char temp[2000], *p;
+	double *lasttime, *thistime, *duration, dummy;
+
+	if((fp = fopen(filename,"r"))==NULL) {
+		sprintf(errstr,"Cannot open file %s to read time-switch data.\n",filename);
+		return(DATA_ERROR);
+	}
+	if((dz->parray = (double **)realloc((char *)dz->parray,dz->infilecnt * sizeof(double *)))==NULL) {
+		sprintf(errstr,"INSUFFICIENT MEMORY to store time-switch data.\n");
+		return(MEMORY_ERROR);
+	}
+	if((duration = (double *)malloc(dz->infilecnt * sizeof(double)))==NULL) {
+		sprintf(errstr,"INSUFFICIENT MEMORY to store file durations.\n");
+		return(MEMORY_ERROR);
+	}
+	for(m=0; m<dz->infilecnt;m++) {
+		duration[m] = (double)(dz->insams[m]/dz->infile->channels)/(double)(dz->infile->srate);
+		if((dz->parray[m] = (double *)malloc(arraysize * sizeof(double)))==NULL) {
+			sprintf(errstr,"INSUFFICIENT MEMORY to store time-switch data.\n");
+			return(MEMORY_ERROR);
+		}
+	}
+	if((lasttime = (double *)malloc(dz->infilecnt * sizeof(double)))==NULL) {
+		sprintf(errstr,"INSUFFICIENT MEMORY to store time-check data.\n");
+		return(MEMORY_ERROR);
+	}
+	if((thistime = (double *)malloc(dz->infilecnt * sizeof(double)))==NULL) {
+		sprintf(errstr,"INSUFFICIENT MEMORY to store time data.\n");
+		return(MEMORY_ERROR);
+	}
+	while(fgets(temp,2000,fp)!=NULL) {
+		p = temp;
+		if(*p == ';')
+			continue;
+		m = 0;
+		if(n==0) {
+			while(get_float_from_within_string(&p,&dummy)) {
+				if(m >= dz->infilecnt) {
+					sprintf(errstr,"Too many entries found in row %d.\n",n+1);
+					return(DATA_ERROR);
+				}
+				if(dummy < 0.0 || dummy > duration[m]) {
+					sprintf(errstr,"First time %lf for file %d does not lie within the file (duration %lf).\n",dummy,m+1,duration[m]);
+					return(DATA_ERROR);
+				}
+				lasttime[m] = dummy;
+				dz->parray[m][n] = lasttime[m];
+				m++;
+			}				
+			p = temp;
+			if(m==0)	 	/* ignore blank lines */
+				continue;
+			if(m!=dz->infilecnt) {
+				sprintf(errstr,"Number of data-items per line (%d) does not tally with number of infiles (%d).\n",
+				m,dz->infilecnt);
+				return(DATA_ERROR);
+			}
+		} else {
+			while(get_float_from_within_string(&p,&dummy)) {
+				if(m >= dz->infilecnt) {
+					sprintf(errstr,"Too many entries found in row %d.\n",n+1);
+					return(DATA_ERROR);
+				}
+				thistime[m++] = dummy;
+			}
+			if(m==0)	 	/* ignore blank lines */
+				continue;
+			if(m != dz->infilecnt) {
+				sprintf(errstr,"Too few entries found in row %d.\n",n+1);
+				return(DATA_ERROR);
+			}
+			for(m = 0;m < dz->infilecnt; m++) {
+				if(thistime[m] <= lasttime[m]) {
+					sprintf(errstr,"Times %d (%lf) and %d (%lf) are not in ascending order in column %d\n",
+					n,lasttime[m],n+1,thistime[m],m+1);
+					return(DATA_ERROR);
+				}
+				if(thistime[m] < 0.0 || thistime[m] > duration[m]) {
+					fprintf(stdout,"WARNING: Time %lf for file %d does not lie within the file (duration %lf).\n",
+					thistime[m],m+1,duration[m]);
+					fprintf(stdout,"WARNING: Curtailing output.\n");
+					fflush(stdout);
+					curtailed = 1;
+					break;
+				}
+				dz->parray[m][n] = thistime[m];
+			}
+		}
+		if(curtailed)
+			break;
+		if(++n >= arraysize) {
+			arraysize += BIGARRAY;
+			for(m=0; m<dz->infilecnt;m++) {
+				if((dz->parray[m] = (double *)realloc((char *)dz->parray[m],arraysize*sizeof(double)))==NULL) {
+					sprintf(errstr,"INSUFFICIENT MEMORY to reallocate switch-times stores.\n");
+					return(MEMORY_ERROR);
+				}
+			}
+		}
+	}
+	if(n==0) {
+		sprintf(errstr,"No valid data found in switch-times data file %s\n",filename);
+		return(DATA_ERROR);
+	}
+	if(n < 2) {
+		sprintf(errstr,"Insufficient valid data (only 1 value) found in switch-times data file %s\n",filename);
+		return(DATA_ERROR);
+	}
+	for(m=0; m<dz->infilecnt;m++) {
+		if((dz->parray[m] = (double *)realloc((char *)dz->parray[m],n * sizeof(double)))==NULL) {
+			sprintf(errstr,"INSUFFICIENT MEMORY to reallocate switch-times stores.\n");
+			return(MEMORY_ERROR);
+		}
+	}
+	if(dz->mode == RAND_REORDER) {
+		if((dz->iparray[0] = (int *)malloc((n-1) * sizeof(int)))==NULL) {
+			sprintf(errstr,"INSUFFICIENT MEMORY to allocate switch-times permutation store.\n");
+			return(MEMORY_ERROR);
+		}
+	}
+	dz->itemcnt = n;
+	if(fclose(fp)<0) {
+		fprintf(stdout,"WARNING: Failed to close input textfile %s.\n",filename);
+		fflush(stdout);
+	}
+	free(thistime);
+	free(lasttime);
+	free(duration);
+	return(FINISHED);
+}
+    
+/**************************** PREPROCESS_CUTMANY ****************************/
+
+int preprocess_cutmany(dataptr dz)
+{
+	int n;
+	dz->param[CM_SPLICEINCR]   = 1.0/(double)dz->iparam[CM_SPLICESAMPS];
+
+	for(n=0; n < dz->itemcnt; n+=2) {
+		if(dz->lparray[0][n+1] - dz->lparray[0][n] <= dz->iparam[CM_SPLICE_TOTSAMPS] * 2) {
+			sprintf(errstr,"Time pair %d is not possible with soundfile and splice length being used.\n",
+			(n+2)/2);
+			return(GOAL_FAILED);
+		}
+	}
+	return(FINISHED);
+}
+
+/**************************** CREATE_CUTMANY_SNDBUF ****************************/
+
+int create_cutmany_sndbuf(dataptr dz)
+{
+	int splicespace, splicesects;
+    size_t bigbufsize;
+	int k, framesize;
+	framesize = dz->infile->channels * F_SECSIZE;
+
+	dz->iparam[CM_SPLICESAMPS] = (int)round(dz->param[CM_SPLICELEN] * MS_TO_SECS * dz->infile->srate);
+	dz->param[CM_SPLICEINCR]   = 1.0/(double)dz->iparam[CM_SPLICESAMPS];
+	dz->iparam[CM_SPLICE_TOTSAMPS] = dz->iparam[CM_SPLICESAMPS] * dz->infile->channels; 
+
+	splicespace = (dz->iparam[CM_SPLICE_TOTSAMPS] * 2);
+	splicesects = splicespace/framesize;
+	if(splicespace > splicesects * framesize)
+		splicesects++;
+	splicespace = splicesects * framesize;
+
+	bigbufsize = (size_t)Malloc(-1);
+	dz->buflen = (int)(bigbufsize/sizeof(float));
+	k = dz->buflen % framesize;					/* truncate to multiple of framesize */
+	dz->buflen -= k;
+	if(dz->buflen <= 0)
+		dz->buflen = framesize;
+	dz->buflen = max(dz->buflen,splicespace);
+	bigbufsize = dz->buflen * sizeof(float);
+	if((dz->bigbuf	= (float *)malloc((dz->buflen * sizeof(float)) + F_SECSIZE))==NULL) {  
+		sprintf(errstr,"INSUFFICIENT MEMORY for sound buffer.\n");
+		return(MEMORY_ERROR);
+	}
+	return(FINISHED);
+}
+
+/**************************** GET_MANY_CUTS_TIMES ****************************/
+
+int get_many_cuts_times(char *filename,dataptr dz)
+{
+	FILE *fp;
+	int n = 0, OK;
+	int arraysize = BIGARRAY, /* byteval */sampval = 0;
+	char temp[200], *p;
+	double  dummy;
+
+	if((fp = fopen(filename,"r"))==NULL) {
+		sprintf(errstr,"Cannot open file %s to read cut-times data.\n",filename);
+		return(DATA_ERROR);
+	}
+	if((dz->lparray[0] = (int *)malloc(arraysize * sizeof(int *)))==NULL) {
+		sprintf(errstr,"INSUFFICIENT MEMORY to store time-switch data.\n");
+		return(MEMORY_ERROR);
+	}
+	OK = 1;
+	while(fgets(temp,200,fp)!=NULL) {
+		p = temp;
+		while(isspace(*p))
+			p++;
+		if(*p == ';')
+			continue;
+		while(get_float_from_within_string(&p,&dummy)) {
+			if(dummy < 0.0) {
+				sprintf(errstr,"Cut-segment time before zero in file %s\n",filename);
+				return(DATA_ERROR);
+			}
+			switch(dz->mode) {
+			case(EDIT_SECS): 
+				sampval = (int)round(dummy * dz->infile->srate);
+				sampval *= dz->infile->channels;
+				break;
+			case(EDIT_SAMPS): 
+				sampval = (int)round(dummy);
+				break;
+			case(EDIT_STSAMPS): 
+				sampval = (int)round(dummy) * dz->infile->channels;
+				break;
+			}
+			if(ODD(n)) {
+				if(sampval <= dz->lparray[0][n-1]) {
+					sprintf(errstr,"Time pair %d in file %s is not in the correct order.\n",(n+1)/2,filename);
+					return(DATA_ERROR);
+				}
+				dz->lparray[0][n] = min(sampval,dz->insams[0]);
+			} else {
+				if(sampval >= dz->insams[0]) {
+					fprintf(stdout,"WARNING: Some cut points are beyond the end of the input file.\n");
+					fflush(stdout);
+					OK = 0;
+					break;
+				}
+				dz->lparray[0][n] = sampval;
+			}
+			if(++n >= arraysize) {
+				arraysize += BIGARRAY;
+				if((dz->lparray[0] = (int *)realloc((char *)dz->lparray[0],arraysize*sizeof(int)))==NULL) {
+					sprintf(errstr,"INSUFFICIENT MEMORY to reallocate cut-times store.\n");
+					return(MEMORY_ERROR);
+				}
+			}
+		}
+		if(!OK)
+			break;
+	}
+	if(n<=0) {
+		sprintf(errstr,"No data found in data file %s\n",filename);
+		return(DATA_ERROR);
+	}
+	if(ODD(n)) {
+		sprintf(errstr,"cut times incorrectly paired in data file %s\n",filename);
+		return(DATA_ERROR);
+	}
+	if((dz->lparray[0] = (int *)realloc((char *)dz->lparray[0],n * sizeof(int)))==NULL) {
+		sprintf(errstr,"INSUFFICIENT MEMORY to reallocate cut-times stores.\n");
+		return(MEMORY_ERROR);
+	}
+	dz->itemcnt = n;
+	if(fclose(fp)<0) {
+		fprintf(stdout,"WARNING: Failed to close input textfile %s.\n",filename);
+		fflush(stdout);
+	}
+	dz->tempsize = dz->itemcnt/2;
+	return(FINISHED);
+}
+
+/********************************************************************************************/
+/********************************** FORMERLY IN preprocess.c ********************************/
+/********************************************************************************************/
+
+
+/****************************** PARAM_PREPROCESS *********************************/
+
+int param_preprocess(dataptr dz)	
+{
+	switch(dz->process) {
+	case(EDIT_CUT):
+	case(EDIT_CUTEND):
+	case(EDIT_INSERT):
+	case(EDIT_INSERT2):
+	case(EDIT_INSERTSIL):
+		return edit_preprocess(dz);
+	case(MANY_ZCUTS):
+	case(EDIT_ZCUT):
+	case(EDIT_EXCISE):
+	case(EDIT_EXCISEMANY):
+	case(JOIN_SEQ):
+	case(JOIN_SEQDYN):
+	case(EDIT_JOIN):
+	case(INSERTSIL_MANY):
+	case(RANDCUTS):
+	case(RANDCHUNKS):
+	case(TWIXT):
+	case(SPHINX):
+		break;
+	case(EDIT_CUTMANY):
+		return preprocess_cutmany(dz);
+	case(NOISE_SUPRESS):
+		dz->iparam[NOISE_SPLEN] = (int)round(dz->param[NOISE_SPLEN] * MS_TO_SECS * (double)dz->infile->srate);
+		dz->iparam[NOISE_MINFRQ] = (int)round((double)dz->infile->srate/dz->param[NOISE_MINFRQ]);
+		dz->iparam[MIN_NOISLEN] = (int)round(dz->param[MIN_NOISLEN] * MS_TO_SECS * (double)dz->infile->srate);
+		dz->iparam[MIN_TONELEN] = (int)round(dz->param[MIN_TONELEN] * MS_TO_SECS * (double)dz->infile->srate);
+		if(dz->iparam[NOISE_SPLEN] >= dz->buflen) {
+			sprintf(errstr,"Splices are too long for the internal sound buffers.\n");
+			return(GOAL_FAILED);
+		}
+		break;
+
+	default:
+		sprintf(errstr,"PROGRAMMING PROBLEM: Unknown process in param_preprocess()\n");
+		return(PROGRAM_ERROR);
+	}
+	return(FINISHED);
+}
+
+/********************************************************************************************/
+/********************************** FORMERLY IN procgrou.c **********************************/
+/********************************************************************************************/
+
+/**************************** GROUCHO_PROCESS_FILE ****************************/
+
+int groucho_process_file(dataptr dz)   /* FUNCTIONS FOUND IN PROCESS.C */
+{	
+	switch(dz->process) {
+	case(EDIT_CUT):
+	case(EDIT_CUTEND):		
+		return do_cut(dz);
+	case(MANY_ZCUTS):		
+		return do_many_zcuts(dz);
+	case(EDIT_ZCUT):		
+		return do_zcut(dz);
+	case(EDIT_EXCISE):
+	case(EDIT_EXCISEMANY):	
+		return do_excise(dz);
+	case(EDIT_INSERT):
+	case(EDIT_INSERT2):
+	case(EDIT_INSERTSIL):	
+		return do_insert(dz);
+	case(INSERTSIL_MANY):	
+		return do_insertsil_many(dz);
+	case(EDIT_JOIN):		
+		return do_joining(dz);
+	case(JOIN_SEQ):		
+	case(JOIN_SEQDYN):		
+		return do_patterned_joining(dz);
+	case(RANDCUTS):		
+		return do_randcuts(dz);
+	case(RANDCHUNKS):		
+		return do_randchunks(dz);
+	case(TWIXT):		
+	case(SPHINX):		
+		return do_twixt(dz);
+	case(EDIT_CUTMANY):
+		return cut_many(dz);
+	case(NOISE_SUPRESS):		
+		return do_noise_suppression(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)
+{
+	handle_pitch_zeros(dz);
+	switch(dz->process) {
+	case(EDIT_CUT):
+	case(EDIT_CUTEND):
+	case(EDIT_ZCUT):
+	case(EDIT_EXCISE):
+	case(EDIT_EXCISEMANY):
+	case(EDIT_INSERT):
+	case(EDIT_INSERT2):
+	case(EDIT_INSERTSIL):
+	case(INSERTSIL_MANY):
+	case(EDIT_JOIN):
+	case(JOIN_SEQ):	
+	case(JOIN_SEQDYN):
+		return edit_pconsistency(dz);
+	case(RANDCUTS):
+		return randcuts_pconsistency(dz);
+	case(SYLLABS):
+		return syllabs_pconsistency(dz);
+	case(RANDCHUNKS):
+	case(NOISE_SUPRESS):
+	case(EDIT_CUTMANY):
+	case(MANY_ZCUTS):
+		break;
+	case(TWIXT):
+		return twixt_preprocess(dz);
+	case(SPHINX):
+		return sphinx_preprocess(dz);
+	}
+	return(FINISHED);
+}
+
+/**************************** RANDCUTS_PCONSISTENCY ****************************/
+
+int randcuts_pconsistency(dataptr dz)
+{
+	int chans = dz->infile->channels;
+	int excess, endunit_len;
+	double duration = (double)(dz->insams[0]/chans)/(double)dz->infile->srate;
+    initrand48();
+	dz->iparam[RC_CHCNT] = round(duration/dz->param[RC_CHLEN]);
+	if(dz->param[RC_SCAT] > (double)dz->iparam[RC_CHCNT]) {
+		sprintf(errstr,"Scatter value cannot be greater than infileduration/chunklength.\n");
+		return(DATA_ERROR);
+	}    
+	dz->iparam[RC_UNITLEN] = (int)round(dz->insams[0]/dz->iparam[RC_CHCNT]);
+/* 2009 MULTICHANNEL --> */
+	excess = dz->iparam[RC_UNITLEN] % chans;
+	dz->iparam[RC_UNITLEN] -= excess;
+/* <-- 2009 MULTICHANNEL */
+/* OLD
+	if(ODD(dz->iparam[RC_UNITLEN]))   
+		dz->iparam[RC_UNITLEN]--;
+*/
+	excess = dz->insams[0] - (dz->iparam[RC_UNITLEN] * dz->iparam[RC_CHCNT]);
+	endunit_len = dz->iparam[RC_UNITLEN] + excess;
+	if((dz->lparray[0] = (int *)malloc(dz->iparam[RC_CHCNT] * sizeof(int))) ==NULL) {
+		sprintf(errstr,"Insufficient space to store block sizes\n");
+		return(MEMORY_ERROR);
+	}
+	if(dz->param[RC_SCAT] > 1.0) {
+		dz->iparam[RC_SCAT] = round(dz->param[RC_SCAT]);
+		dz->iparam[RC_SCATGRPCNT] = (int)(dz->iparam[RC_CHCNT]/dz->iparam[RC_SCAT]);
+		dz->iparam[RC_ENDSCAT]    = (int)(dz->iparam[RC_CHCNT] - (dz->iparam[RC_SCATGRPCNT] * dz->iparam[RC_SCAT]));
+		dz->iparam[RC_RANGE]      = dz->iparam[RC_UNITLEN] * dz->iparam[RC_SCAT];
+		dz->iparam[RC_ENDRANGE]   = ((dz->iparam[RC_ENDSCAT]-1) * dz->iparam[RC_UNITLEN]) + endunit_len;
+	} else if(dz->param[RC_SCAT] > 0.0)
+		dz->iparam[RC_SCAT] = 0;		
+	else
+		dz->iparam[RC_SCAT] = -1;		
+	return(FINISHED);
+}
+
+/********************************************************************************************/
+/********************************** FORMERLY IN buffers.c ***********************************/
+/********************************************************************************************/
+
+/**************************** ALLOCATE_LARGE_BUFFERS ******************************/
+
+int allocate_large_buffers(dataptr dz)
+{
+	switch(dz->process) {
+	case(EDIT_CUT):
+	case(EDIT_CUTEND):
+	case(MANY_ZCUTS):
+	case(EDIT_ZCUT):
+	case(EDIT_EXCISE):
+	case(EDIT_EXCISEMANY):
+	case(EDIT_INSERT):
+	case(EDIT_INSERT2):
+	case(EDIT_INSERTSIL):
+	case(INSERTSIL_MANY):
+	case(EDIT_JOIN):
+	case(JOIN_SEQ):
+	case(JOIN_SEQDYN):
+	case(RANDCHUNKS):
+		return create_edit_buffers(dz);
+	case(RANDCUTS):
+	case(NOISE_SUPRESS):
+		return create_sndbufs(dz);
+	case(EDIT_CUTMANY):
+		return create_cutmany_sndbuf(dz);
+
+	case(TWIXT):
+	case(SPHINX):
+		return create_twixt_buffers(dz);
+	default:
+		sprintf(errstr,"Unknown program no. in allocate_large_buffers()\n");
+		return(PROGRAM_ERROR);
+	}
+	return(FINISHED);	/* NOTREACHED */
+}
+
+/********************************************************************************************/
+/********************************** FORMERLY IN cmdline.c ***********************************/
+/********************************************************************************************/
+
+int get_process_no(char *prog_identifier_from_cmdline,dataptr dz)
+{
+	if     (!strcmp(prog_identifier_from_cmdline,"cut"))			dz->process = EDIT_CUT;
+	else if(!strcmp(prog_identifier_from_cmdline,"cutend"))			dz->process = EDIT_CUTEND;
+	else if(!strcmp(prog_identifier_from_cmdline,"zcut"))			dz->process = EDIT_ZCUT;
+	else if(!strcmp(prog_identifier_from_cmdline,"zcuts"))			dz->process = MANY_ZCUTS;
+	else if(!strcmp(prog_identifier_from_cmdline,"excise"))			dz->process = EDIT_EXCISE;
+	else if(!strcmp(prog_identifier_from_cmdline,"excises"))		dz->process = EDIT_EXCISEMANY;
+	else if(!strcmp(prog_identifier_from_cmdline,"insert"))			dz->process = EDIT_INSERT;
+	else if(!strcmp(prog_identifier_from_cmdline,"replace"))		dz->process = EDIT_INSERT2;
+	else if(!strcmp(prog_identifier_from_cmdline,"insil"))			dz->process = EDIT_INSERTSIL;
+	else if(!strcmp(prog_identifier_from_cmdline,"join"))			dz->process = EDIT_JOIN;
+	else if(!strcmp(prog_identifier_from_cmdline,"masks"))			dz->process = INSERTSIL_MANY;
+	else if(!strcmp(prog_identifier_from_cmdline,"randcuts"))		dz->process = RANDCUTS;
+	else if(!strcmp(prog_identifier_from_cmdline,"randchunks"))		dz->process = RANDCHUNKS;
+	else if(!strcmp(prog_identifier_from_cmdline,"twixt"))			dz->process = TWIXT;
+	else if(!strcmp(prog_identifier_from_cmdline,"sphinx"))			dz->process = SPHINX;
+	else if(!strcmp(prog_identifier_from_cmdline,"noisecut"))		dz->process = NOISE_SUPRESS;
+	else if(!strcmp(prog_identifier_from_cmdline,"cutmany"))		dz->process = EDIT_CUTMANY;
+	else if(!strcmp(prog_identifier_from_cmdline,"syllables"))		dz->process = SYLLABS;
+	else if(!strcmp(prog_identifier_from_cmdline,"joinseq"))		dz->process = JOIN_SEQ;
+	else if(!strcmp(prog_identifier_from_cmdline,"joindyn"))		dz->process = JOIN_SEQDYN;
+	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,
+	"USAGE: sfedit NAME (mode) infile(s) outfile (parameters)\n"
+	"\n"
+	"where NAME can be any one of\n"
+	"\n"
+	"cut    cutend   zcut   zcuts   excise   excises   insert   replace\n"
+	"insil  join     masks     randcuts   randchunks    cutmany\n"
+	"noisecut   syllables   joinseq    joindyn  twixt  sphinx  noisecut\n"
+	"\n"
+	"Type 'sfedit excise'  for more info on sfedit excise option... ETC.\n");
+	return(USAGE_ONLY);
+}
+
+/******************************** USAGE2 ********************************/
+
+int usage2(char *str)
+{
+	if(!strcmp(str,"cut")) {
+	    sprintf(errstr,
+		"CUT & KEEP A SEGMENT OF A SOUND.\n\n"
+		"USAGE: sfedit cut mode infile outfile start end [-wsplice]\n\n"
+		"MODES ARE\n"
+		"1) Time in seconds.\n"
+		"2) Time as sample count (rounded to multiples of channel-cnt).\n"
+		"3) Time as grouped-sample count (e.g. 3 = 3 stereo-pairs).\n\n"
+		"START  is time in infile where segment to keep begins.\n"
+		"END    is time in infile where segment to keep ends.\n"
+		"SPLICE  splice window in milliseconds (default: %.0lf)\n",EDIT_SPLICELEN);
+	} else if(!strcmp(str,"cutmany")) {
+	    sprintf(errstr,
+		"CUT & KEEP SEVERAL SEGMENTS OF A SOUND.\n\n"
+		"USAGE: sfedit cutmany mode infile outfile cuttimes splice\n\n"
+		"MODES ARE\n"
+		"1) Time in seconds.\n"
+		"2) Time as sample count (rounded to multiples of channel-cnt).\n"
+		"3) Time as grouped-sample count (e.g. 3 = 3 stereo-pairs).\n\n"
+		"CUTTIMES is a file of time-pairs of the start and end of each segment\n"
+		"SPLICE  splice window in milliseconds\n"/*,EDIT_SPLICELEN*/);
+	} else if(!strcmp(str,"syllables")) {
+	    sprintf(errstr,
+		"CUT TEXT INTO ITS CONTIGUOUS SYLLABLES.\n\n"
+		"USAGE: sfedit syllables mode infil outfil cuttimes dovetail splice [-p]\n\n"
+		"MODES ARE\n"
+		"1) Time in seconds.\n"
+		"2) Time as sample count (rounded to multiples of channel-cnt).\n"
+		"3) Time as grouped-sample count (e.g. 3 = 3 stereo-pairs).\n\n"
+		"CUTTIMES is starttime of syllables, and end time of last syllable.\n"
+		"DOVETAIL is time in milliseconds to allow for syllable overlap.\n"
+		"SPLICE  splice window in milliseconds.\n"
+		"-p   Forces process to cut PAIRS of syllables.\n");
+	} else if(!strcmp(str,"cutend")) {
+	    sprintf(errstr,
+		"CUT & KEEP END PORTION OF A SOUND.\n\n"
+		"USAGE: sfedit cutend mode infile outfile length [-wsplice]\n\n"
+		"MODES ARE\n"
+		"1) Time in seconds.\n"
+		"2) Time as sample count (rounded to multiples of channel-cnt).\n"
+		"3) Time as grouped-sample count (e.g. 3 = 3 stereo-pairs).\n\n"
+		"LENGTH is length of sound to keep, ending at end of input sound.\n"
+		"SPLICE  splice window in milliseconds (default: %.0lf)\n",EDIT_SPLICELEN);
+	} else if(!strcmp(str,"zcut")) {
+	    sprintf(errstr,
+		"CUT & KEEP SEG OF MONO SOUND, CUTTING AT ZERO-CROSSINGS (NO SPLICES).\n\n"
+    	"USAGE: sfedit zcut mode infile outfile start end\n\n"
+		"MODES ARE\n"
+		"1) Time in seconds.\n"
+		"2) Time as sample count.\n"
+		"START  is (approx) time in infile where segment to keep begins.\n"
+		"END    is (approx) time in infile where segment to keep ends.\n");
+	} else if(!strcmp(str,"zcuts")) {
+	    sprintf(errstr,
+		"CUT & KEEP SEGS OF MONO SOUND, CUTTING AT ZERO-CROSSINGS (NO SPLICES).\n\n"
+    	"USAGE: sfedit zcuts mode infile outfile cuttimes\n\n"
+		"MODES ARE\n"
+		"1) Time in seconds.\n"
+		"2) Time as sample count.\n"
+		"CUTTIMES is a file of time-pairs of the start and end of each segment\n");
+	} else if(!strcmp(str,"excise")) {
+	    sprintf(errstr,
+		"DISCARD SPECIFIED CHUNK OF SOUND, CLOSING UP THE GAP.\n\n"
+		"USAGE: sfedit excise mode infile outfile start end [-wsplice]\n\n"
+		"MODES ARE\n"
+		"1) Time in seconds.\n"
+		"2) Time as sample count (rounded to multiples of channel-cnt).\n"
+    	"START   starttime of excision.\n"
+    	"END     endtime of excision.\n"
+		"SPLICE  splice window in milliseconds (default: %.0lf)\n",EDIT_SPLICELEN);
+	} else if(!strcmp(str,"excises")) {
+	    sprintf(errstr,
+		"DISCARD SPECIFIED CHUNKS OF A SOUND, CLOSING UP THE GAPS.\n\n"
+    	"USAGE: sfedit excises mode infile outfile excisefile [-wsplice]\n\n"
+		"MODES ARE\n"
+		"1) Time in seconds.\n"
+		"2) Time as sample count (rounded to multiples of channel-cnt).\n"
+		"3) Time as grouped-sample count (e.g. 3 = 3 stereo-pairs).\n\n"
+		"EXCISEFILE is a texfile with (paired) start & end times of chunks\n"
+		"           to be removed. These must be in increasing time order.\n"
+		"SPLICE  splice window in milliseconds (default: %.0lf)\n",EDIT_SPLICELEN);
+	} else if(!strcmp(str,"insert")) {
+		sprintf(errstr,
+		"INSERT A 2nd SOUND INTO AN EXISTING SOUND.\n\n"
+		"USAGE: sfedit insert mode infile insert outfile time [-wsplice] [-llevel] [-o]\n\n"
+		"MODES ARE\n"
+		"1) Time in seconds.\n"
+		"2) Time as sample count (rounded to multiples of channel-cnt).\n"
+		"3) Time as grouped-sample count (e.g. 3 = 3 stereo-pairs).\n\n"
+		"TIME    at which 2nd file to be inserted in 1st file.\n"
+		"SPLICE  splice window in milliseconds (default: %.0lf)\n"
+		"LEVEL   gain multiplier on inserted file. (default 1.0).\n"
+		"-o      overwrite equivalent duration of original file with inserted file.\n"
+		"        (default .. insertion pushes infile apart).\n",EDIT_SPLICELEN);
+	} else if(!strcmp(str,"replace")) {
+		sprintf(errstr,
+		"INSERT A 2nd SOUND INTO AN EXISTING SOUND, REPLACING PART OF ORIGINAL SOUND.\n\n"
+		"USAGE: sfedit replace mode infile insert outfile time endtime [-wsplice] [-llevel]\n\n"
+		"MODES ARE\n"
+		"1) Time in seconds.\n"
+		"2) Time as sample count (rounded to multiples of channel-cnt).\n"
+		"3) Time as grouped-sample count (e.g. 3 = 3 stereo-pairs).\n\n"
+		"TIME    at which 2nd file to be inserted in 1st file.\n"
+		"ENDTIME endtime of segment in original file to be replaced.\n"
+		"SPLICE  splice window in milliseconds (default: %.0lf)\n"
+		"LEVEL   gain multiplier on inserted file. (default 1.0).\n",EDIT_SPLICELEN);
+	} else if(!strcmp(str,"insil")) {
+		sprintf(errstr,
+		"INSERT SILENCE INTO AN EXISTING SOUND.\n\n"
+		"USAGE: sfedit insil mode infile outfile time duration [-wsplice] [-o] [-s]\n\n"
+		"MODES ARE\n"
+		"1) Time in seconds.\n"
+		"2) Time as sample count (rounded to multiples of channel-cnt).\n"
+		"3) Time as grouped-sample count (e.g. 3 = 3 stereo-pairs).\n\n"
+		"TIME     at which silence to be inserted in infile.\n"
+		"DURATION of inserted silence.\n"
+		"SPLICE   splice window in milliseconds (default: %.0lf)\n"
+		"-o       overwrites original file with the silence.\n"
+		"         (default .. silence pushes infile apart).\n"
+		"-s       retains any silence written over file end.\n"
+		"         (default .. rejects silence added at file end).\n",EDIT_SPLICELEN);
+	} else if(!strcmp(str,"join")) {
+    	sprintf(errstr,
+    	"JOIN FILES TOGETHER, ONE AFTER ANOTHER.\n\n"
+		"USAGE: sfedit join infile1 [infile2 infile3....] outfile [-wsplice] [-b] [-e] \n\n"
+    	"SPLICE duration of splices, in MS (default 15)\n"
+    	"-b     splices start of first file\n"
+    	"-e     splices end of last file\n");
+	} else if(!strcmp(str,"joinseq")) {
+    	sprintf(errstr,
+    	"JOIN FILES TOGETHER, ONE AFTER ANOTHER, IN A PATTERN\n\n"
+		"USAGE: sfedit join infile1 [infile2 ....] outfile pattern [-wsplice] [-mmaxlen] [-b] [-e] \n\n"
+    	"PATTERN file contains sequence of numbers = sequence of input files to use\n"
+    	"SPLICE duration of splices, in MS (default 15)\n"
+    	"MAXLEN maximum number of items in pattern to use\n"
+    	"-b     splices start of first file\n"
+    	"-e     splices end of last file\n");
+	} else if(!strcmp(str,"joindyn")) {
+    	sprintf(errstr,
+    	"JOIN FILES TOGETHER, ONE AFTER ANOTHER, IN A PATTERN, WITH LOUDNESS PATTERN\n\n"
+		"USAGE: sfedit join inf1 [inf2...] outf pattern [-wsplice] [-b] [-e] \n\n"
+    	"PATTERN  file of sequence of numbers = sequence of input files to use,\n"
+    	"         each paired with a gain value for that pattern item\n"
+    	"SPLICE duration of splices, in MS (default 15)\n"
+    	"-b     splices start of first file\n"
+    	"-e     splices end of last file\n");
+	} else if(!strcmp(str,"masks")) {
+	    sprintf(errstr,
+		"MASK SPECIFIED CHUNKS OF A SOUND, WITH SILENCE.\n\n"
+    	"USAGE: sfedit masks mode infile outfile excisefile [-wsplice]\n\n"
+		"MODES ARE\n"
+		"1) Time in seconds.\n"
+		"2) Time as sample count (rounded to multiples of channel-cnt).\n"
+		"3) Time as grouped-sample count (e.g. 3 = 3 stereo-pairs).\n\n"
+		"EXCISEFILE is a texfile with (paired) start & end times of chunks\n"
+		"           to be masked. These must be in increasing time order.\n"
+		"SPLICE  splice window in milliseconds (default: %.0lf)\n",EDIT_SPLICELEN);
+	} else if(!strcmp(str,"randcuts")) {
+	    sprintf(errstr,
+		"CUT FILE INTO PIECES WITH CUTS AT RANDOM TIMES.\n\n"
+    	"USAGE: sfedit randcuts infile average-chunklen scattering\n\n"
+		"Names of outfiles will be infilename truncated by 1 character,\n"
+		"      with a number added, starting from zero.\n"
+		"average-chunklen is average length of chunks cut.\n"
+		"scattering       is variation in length of cuts : range 0-8\n");
+	} else if(!strcmp(str,"randchunks")) {
+	    sprintf(errstr,
+		"CUT CHUNKS FROM FILE, RANDOMLY.\n\n"
+    	"USAGE:\n"
+    	"sfedit randchunks infile chunkcnt minchunk [-mmaxchunk] [-l] [-s]\n\n"
+		"Names of outfiles will be 'infilename' truncated by 1 character,\n"
+		"      with a number added, starting from zero.\n"
+		"Chunkcnt is number of chunks to cut.\n"
+		"Minchunk is minimum length of chunks.\n\n"
+		"-m    maxchunk is maximum length of chunks.\n"
+		"-l    chunks chosen are evenly distributed over file\n"
+		"      (default: random distribution)\n"
+		"-s    all chunks start at beginning of file\n");
+	} else if(!strcmp(str,"twixt")) {
+	    sprintf(errstr,
+		"SWITCH BETWEEN SEVERAL FILES, TO MAKE A NEW SOUND.\n\n"
+    	"USAGE:\n"
+    	"sfedit twixt mode infile(s) outfile switch-times splicelen (segcnt) [-wweight] [-r]\n\n"
+		"MODES ARE\n"
+		"1) In Sequence    Imagine all files are running in parallel on a multitrack.\n"
+		"                  Switch from one to another at switch-times.\n"
+		"2) Permuted       ..similarly, but time-segment order randomly permuted.\n"
+		"3) Random Choice  ..similarly, but chose any time-seg, at random, as next segment.\n\n"
+		"4) Edit only      Cut file-1 (only) to chunks defined by switch-times,\n"
+		"                  and output chunks as separate files.\n"
+		"SWITCH-TIMES is a texfile with times which divide every file into segments.\n"
+		"             Times must be in ascending order.\n"
+		"             (Include time zero if you want to use segments at start of files).\n"
+		"SPLICELEN    is duration of splices, in milliseconds\n"
+		"SEGCNT       is number of segments to use in output (only with modes 2 & 3)\n"
+		"-wWEIGHT     if flag set, file-1 occurs WEIGHT times more often than other files.\n"
+		"-r           if flag set, order of files used is randomly permuted.\n");
+	} else if(!strcmp(str,"sphinx")) {
+	    sprintf(errstr,
+		"SWITCH BETWEEN SEVERAL FILES, WITH DIFFERENT SWITCH TIMES, TO MAKE NEW SOUND.\n\n"
+    	"USAGE:\n"
+    	"sfedit sphinx mode infile(s) outfile switch-times splicelen (segcnt) [-wweight -r]\n\n"
+		"MODES ARE\n"
+		"1) In Sequence    Imagine all files are running in parallel on a multitrack.\n"
+		"                  Switch from one to another at switch-times, where\n"
+		"                  Nth switch-time in one file, corresponds to Nth in another file.\n"
+		"                  but these are not necessarily the same absolute time.\n"
+		"2) Permuted       ..similarly, but time-segment order randomly permuted.\n"
+		"3) Random Choice  ..similarly, but chose any time-seg, at random, as next segment.\n\n"
+		"SWITCH-TIMES texfile with times which divide each file into segments.\n"
+		"             There must be one column of times for each input file,\n"
+		"             and the same number of entries in each column.\n"
+		"             Times, in each column, must be in ascending order.\n"
+		"             (Include time zero if you want to use a segment at start of a file).\n"
+		"SPLICELEN    is duration of splices, in milliseconds\n"
+		"SEGCNT       is number of segments to use in output (only with modes 2 & 3)\n"
+		"-wWEIGHT     if flag set, 1st file occurs WEIGHT times more often than other files.\n"
+		"-r           if flag set, order of files used is randomly permuted.\n");
+	} else if(!strcmp(str,"noisecut")) {
+	    sprintf(errstr,
+		"SUPPRESS NOISE IN A (MONO) SOUND FILE: REPLACE BY SILENCE.\n\n"
+    	"USAGE: sfedit noisecut infile outfile splicelen noisfrq maxnoise mintone [-n]\n\n"
+		"SPLICELEN    duration of splices, in MS\n"
+		"NOISEFRQ     frequency above which signal regarded as noise (try 6000 Hz)\n"
+		"MAXNOISE     max duration of any noise segments permitted to remain (NOT replaced)\n"
+		"MINTONE      min duration of any non-noise segments to be retained.\n"
+		"-n           retain noise rather than non-noise\n");
+	} else
+		sprintf(errstr,"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);
+}
+
+/******************************** 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);
+}
+
+/******************************** SYLLABS_CONSISTENCY ********************************
+ *
+ * Converts the syllables data into EDIT_CUTMANY data
+ */
+
+int syllabs_pconsistency(dataptr dz)
+{
+	int orig_cnt = dz->itemcnt, new_cnt = dz->itemcnt, n, k;
+	int end, stt;
+	int dovesamps = round(dz->param[SYLLAB_DOVETAIL] * MS_TO_SECS * (double)dz->infile->srate);
+	dovesamps *= dz->infile->channels;
+	if(dz->vflag[SYLLAB_PAIRS]) {
+		if(dz->itemcnt < 3) {
+			sprintf(errstr,"INSUFFICIENT DATA to cut syllable pairs (need at least 3 times).\n");
+			return(MEMORY_ERROR);
+		}
+		new_cnt -= 2;
+		new_cnt *= 2;
+		if((dz->lparray[0] = (int *)realloc((char *)dz->lparray[0],(orig_cnt + new_cnt) * sizeof(int)))==NULL) {
+			sprintf(errstr,"INSUFFICIENT MEMORY to reallocate cut-times stores.\n");
+			return(MEMORY_ERROR);
+		}
+		for(n=orig_cnt-3,k = (orig_cnt + new_cnt) - 2;n>=0;n--,k-=2) {
+			end = min(dz->insams[0],dz->lparray[0][n+2] + dovesamps);
+			dz->lparray[0][k+1] = end;
+			stt = max(0,dz->lparray[0][n] - dovesamps);
+			dz->lparray[0][k] = stt;
+		}
+		for(n=0,k = orig_cnt;n < new_cnt;n++,k++)
+			dz->lparray[0][n] = dz->lparray[0][k];
+	} else {
+		new_cnt--;
+		new_cnt *= 2;
+		if((dz->lparray[0] = (int *)realloc((char *)dz->lparray[0],new_cnt * sizeof(int)))==NULL) {
+			sprintf(errstr,"INSUFFICIENT MEMORY to reallocate cut-times stores.\n");
+			return(MEMORY_ERROR);
+		}
+		for(n=orig_cnt-2,k = new_cnt - 2;n>=0;n--,k-=2) {
+			end = min(dz->insams[0],dz->lparray[0][n+1] + dovesamps);
+			dz->lparray[0][k+1] = end;
+			stt = max(0,dz->lparray[0][n] - dovesamps);
+			dz->lparray[0][k] = stt;
+		}		
+	}
+	dz->itemcnt = new_cnt;
+	dz->tempsize = dz->itemcnt/2;
+	dz->process = EDIT_CUTMANY;
+	return(FINISHED);
+}
+
+/******************************** GET_SYLLAB_TIMES ********************************/
+
+int get_syllab_times(char *filename,dataptr dz)
+{
+	FILE *fp;
+	int n = 0;
+	int arraysize = BIGARRAY, sampval = 0;
+	char temp[200], *p;
+	double  dummy;
+
+	if((fp = fopen(filename,"r"))==NULL) {
+		sprintf(errstr,"Cannot open file %s to read cut-times data.\n",filename);
+		return(DATA_ERROR);
+	}
+	if((dz->lparray[0] = (int *)malloc(arraysize * sizeof(int *)))==NULL) {
+		sprintf(errstr,"INSUFFICIENT MEMORY to store time-switch data.\n");
+		return(MEMORY_ERROR);
+	}
+		
+	while(fgets(temp,200,fp)!=NULL) {
+		p = temp;
+		while(isspace(*p))
+			p++;
+		if(*p == ';')
+			continue;
+
+		while(get_float_from_within_string(&p,&dummy)) {
+			if(dummy < 0.0) {
+				sprintf(errstr,"Cut-segment time before zero in file %s\n",filename);
+				return(DATA_ERROR);
+			}
+			switch(dz->mode) {
+			case(EDIT_SECS): 
+				sampval = (int)round(dummy * dz->infile->srate);
+				sampval *= dz->infile->channels;
+				break;
+			case(EDIT_SAMPS): 
+				sampval = (int)round(dummy);
+				break;
+			case(EDIT_STSAMPS): 
+				sampval = (int)round(dummy) * dz->infile->channels;
+				break;
+			}
+			if(n>0) {
+				dz->lparray[0][n] = min(sampval,dz->insams[0]);
+				if(sampval <= dz->lparray[0][n-1]) {
+					sprintf(errstr,"Time %d in file %s is not in the correct order.\n",(n+1)/2,filename);
+					return(DATA_ERROR);
+				}
+			} else 
+				dz->lparray[0][n] = max(sampval,0);
+			if(dz->lparray[0][n] >= dz->insams[0])
+				break;
+			if(++n >= arraysize) {
+				arraysize += BIGARRAY;
+				if((dz->lparray[0] = (int *)realloc((char *)dz->lparray[0],arraysize*sizeof(int)))==NULL) {
+					sprintf(errstr,"INSUFFICIENT MEMORY to reallocate cut-times store.\n");
+					return(MEMORY_ERROR);
+				}
+			}
+		}
+	}
+	if(n<2) {
+		sprintf(errstr,"Insufficient data found in data file %s (at least 2 times required)\n",filename);
+		return(DATA_ERROR);
+	}
+	dz->itemcnt = n;
+	if(fclose(fp)<0) {
+		fprintf(stdout,"WARNING: Failed to close input textfile %s.\n",filename);
+		fflush(stdout);
+	}
+	return(FINISHED);
+}
+
+/******************************** GET_JOINSEQ ********************************/
+
+int get_joinseq(char *filename,dataptr dz)
+{
+	FILE *fp;
+	int n = 0, k;
+	int arraysize = BIGARRAY;
+	char temp[200], *p;
+	double  dummy;
+
+	if((fp = fopen(filename,"r"))==NULL) {
+		sprintf(errstr,"Cannot open file %s to read joining seqence.\n",filename);
+		return(DATA_ERROR);
+	}
+	if((dz->iparray[0] = (int *)malloc(arraysize * sizeof(int *)))==NULL) {
+		sprintf(errstr,"INSUFFICIENT MEMORY to store joining seqence data.\n");
+		return(MEMORY_ERROR);
+	}
+		
+	while(fgets(temp,200,fp)!=NULL) {
+		p = temp;
+		while(isspace(*p))
+			p++;
+		if(*p == ';')
+			continue;
+
+		while(get_float_from_within_string(&p,&dummy)) {
+			k = round(dummy);
+			if(k < 1 || k > dz->infilecnt) {
+				sprintf(errstr,"Number '%d' in sequence data does not correspond to any input soundfile\n",k);
+				return(DATA_ERROR);
+			}
+			k--;
+			dz->iparray[0][n] = k;
+			if(++n >= arraysize) {
+				arraysize += BIGARRAY;
+				if((dz->iparray[0] = (int *)realloc((char *)dz->iparray[0],arraysize*sizeof(int)))==NULL) {
+					sprintf(errstr,"INSUFFICIENT MEMORY to reallocate joining sequence data.\n");
+					return(MEMORY_ERROR);
+				}
+			}
+		}
+	}
+	if(n<2) {
+		sprintf(errstr,"Insufficient data found in data file %s (at least 2 file numbers reuqired)\n",filename);
+		return(DATA_ERROR);
+	}
+	dz->itemcnt = n;
+	if(fclose(fp)<0) {
+		fprintf(stdout,"WARNING: Failed to close input textfile %s.\n",filename);
+		fflush(stdout);
+	}
+	return(FINISHED);
+}
+
+/******************************** GET_JOINDYNSEQ ********************************/
+
+int get_joindynseq(char *filename,dataptr dz)
+{
+	FILE *fp;
+	int n = 0, k, is_loudness;
+	int arraysize = BIGARRAY;
+	char temp[200], *p;
+	double  dummy, maxloudness;
+
+	if((fp = fopen(filename,"r"))==NULL) {
+		sprintf(errstr,"Cannot open file %s to read joining seqence.\n",filename);
+		return(DATA_ERROR);
+	}
+	if((dz->iparray[0] = (int *)malloc(arraysize * sizeof(int *)))==NULL) {
+		sprintf(errstr,"INSUFFICIENT MEMORY to store joining seqence data.\n");
+		return(MEMORY_ERROR);
+	}
+	if((dz->parray[2] = (double *)malloc(arraysize * sizeof(double *)))==NULL) {
+		sprintf(errstr,"INSUFFICIENT MEMORY to store joining seqence data.\n");
+		return(MEMORY_ERROR);
+	}
+	is_loudness = 0;
+	maxloudness = 0.0;
+	while(fgets(temp,200,fp)!=NULL) {
+		p = temp;
+		while(isspace(*p))
+			p++;
+		if(*p == ';')
+			continue;
+
+		while(get_float_from_within_string(&p,&dummy)) {
+			if(is_loudness) {
+				if(dummy < 0.0) {
+					sprintf(errstr,"Number '%lf' in loudness data is invalid (negative).\n",dummy);
+					return(DATA_ERROR);
+				} else if(dummy > maxloudness)
+					maxloudness = dummy;
+				dz->parray[2][n] = dummy;
+			} else {
+				k = round(dummy);
+				if(k < 1 || k > dz->infilecnt) {
+					sprintf(errstr,"Number '%d' in sequence data does not correspond to any input soundfile\n",k);
+					return(DATA_ERROR);
+				}
+				k--;
+				dz->iparray[0][n] = k;
+			}
+			if(is_loudness) {
+				if(++n >= arraysize) {
+					arraysize += BIGARRAY;
+					if((dz->iparray[0] = (int *)realloc((char *)dz->iparray[0],arraysize*sizeof(int)))==NULL) {
+						sprintf(errstr,"INSUFFICIENT MEMORY to reallocate joining sequence data.\n");
+						return(MEMORY_ERROR);
+					}
+					if((dz->parray[2] = (double *)realloc((char *)dz->parray[2],arraysize*sizeof(double)))==NULL) {
+						sprintf(errstr,"INSUFFICIENT MEMORY to reallocate joining sequence loudness data.\n");
+						return(MEMORY_ERROR);
+					}
+				}
+			}
+			is_loudness = !is_loudness;
+		}
+	}
+	if(is_loudness) {
+		sprintf(errstr,"Data incorrectly paired in file %s\n",filename);
+		return(DATA_ERROR);
+	}
+	if(n<2) {
+		sprintf(errstr,"Insufficient data found in data file %s (at least 2 file numbers reuqired)\n",filename);
+		return(DATA_ERROR);
+	}
+	dz->itemcnt = n;
+	for(n=0;n<dz->itemcnt;n++)		/* NORMALISE LOUDNESS VALS */
+		dz->parray[2][n] /= maxloudness;
+	if(fclose(fp)<0) {
+		fprintf(stdout,"WARNING: Failed to close input textfile %s.\n",filename);
+		fflush(stdout);
+	}
+	return(FINISHED);
+}

+ 3757 - 0
dev/editsf/cut.c

@@ -0,0 +1,3757 @@
+/*
+ * 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 <pnames.h>
+#include <flags.h>
+#include <globcon.h>
+#include <cdpmain.h>
+#include <edit.h>
+#include <modicon.h>
+#include <processno.h>
+#include <modeno.h>
+#include <logic.h>
+#include <flags.h>
+#include <arrays.h>
+
+#include <sfsys.h>
+
+#include <osbind.h>
+
+#ifdef unix
+#define round(x) lround((x))
+#endif
+
+#define	UPSLOPE		(0)
+#define DOWNSLOPE 	(1)
+
+#define	IBUF	(0)
+#define	OBUF	(1)
+#define	SAVEBUF	(1)
+#define	SPLBUF	(2)
+#define	SPLBUF2	(3)
+
+#define	BBUF		(0)
+#define	BUFEND		(1)
+#define	READBUF		(2)
+#define	SPLICEBUF	(3)
+#define	COPYBUF		(4)
+#define	ENDSPLICE_ADDR	(3)
+
+#define CUTOFF_OUTPUT (0)
+#define JUST_CONTINUE (1)
+#define WRITERESTOF_INPUT (2)
+
+static int do_alternating_splices(int *in_noise,int *splice_cnt,int *edit_position,double splincr,dataptr dz);
+
+#define movmem(from, to, bytes)         memcpy((to), (from), (bytes))
+
+static void setup_startcut_sector_offset(dataptr dz);
+static int  create_cut_buffer(dataptr dz);
+static int  create_zcut_buffer(dataptr dz);
+static int  create_excise_buffers(dataptr dz);
+static int  create_insert_buffers(dataptr dz);
+static int  establish_working_chunks(dataptr dz);
+static void dosplice(float *buf, int samples, int chans, int invert);
+static int  check_excise_splices(dataptr dz);
+static int find_zero(int end,int allsamps,dataptr dz);
+static int  do_excise_finish(int obufleft,dataptr dz);
+static void crossplice(dataptr dz);
+static int  do_excise_beginning(int *last_total_samps,int *obufleft,int k,dataptr dz);
+static int  do_excise_ending(int *last_total_samps,int *obufleft,int *ibufleft,int k,dataptr dz);
+static int  write_excise_end(int last_total_samps,int obufleft,int ibufleft,dataptr dz);
+static int  copy_excise_chunk(int *last_total_samps,int *obufleft,int *ibufleft,int k,dataptr dz);
+static int  gain_insert_buffer(float *thisbuf,int size,double gain);
+static void setup_excise_outdisplay_len(dataptr dz);
+
+static int  join_pconsistency(dataptr dz);
+static int  create_join_buffer(dataptr dz);
+static int  create_join_seq_buffer(dataptr dz);
+static int  read_join_splice_remnant(int n,int splice_remnant,int oversamps,dataptr dz);
+static void do_join_startsplice(int k,dataptr dz);
+static void do_join_initial_splice(int chans,dataptr dz);
+static void do_join_endsplice(dataptr dz);
+static void housekeep1(int samps_read,int overspill,dataptr dz);
+static void housekeep2(int samps_read,dataptr dz);
+static int  do_join_write(int n,int splice_remnant,int oversamps,dataptr dz);
+static int  reset_join_buffer_params(dataptr dz);
+
+int algo2;
+
+int do_insertsil_many(dataptr dz);
+void do_other_splice(float *buf, int splicelen, int start_in_splice, int end_in_splice, int chans, int invert);
+
+void ptr_sort(int end,dataptr dz);
+void heavy_scat(int stereo_splicelen,dataptr dz);
+void normal_scat(dataptr dz);
+int  get_lengths(int stereo_splicelen,dataptr dz);
+void do_insitu_splice(int start,int end,int splicecnt,int chans,dataptr dz);
+void do_insitu_upsplice(int rel_bufstart,dataptr dz);
+//int  create_an_outfile(int cutno, int cutlen, char *outfilename, char *outfilenumber, dataptr dz);
+int  create_an_outfile(int cutno, int cutlen, char *outfilename, dataptr dz);
+int  close_an_outfile(char *outfilename,dataptr dz);
+
+static int 	do_linear(dataptr dz,double,int,double), do_nonlinear(dataptr dz,double,int,double);
+static int	do_fromstart(dataptr dz);
+static int  cut_chunk(dataptr dz,double startcut,double endcut,int count);
+
+static void splice_obuf_start(float *obuf,dataptr dz);
+static void splice_obuf_end(float *obuf,int *splice_start,int startsamp,int endsamp,dataptr dz);
+static int  setup_insert2_overwrite_flag(dataptr dz);
+
+static int silent_end;		
+
+/******************************** EDIT_PCONSISTENCY ********************************/
+
+int edit_pconsistency(dataptr dz)
+{
+	int exit_status;
+	int chans = dz->infile->channels, k;
+	double sr = (double)dz->infile->srate;
+	int zz, zsecs;
+	algo2 = 0;
+	silent_end = 0;
+	switch(dz->process) {
+	case(EDIT_JOIN):
+	case(JOIN_SEQ):
+	case(JOIN_SEQDYN):
+		return join_pconsistency(dz);
+
+	case(EDIT_ZCUT):		 	/* check for stereo file: no splicelen data: REALLY UNNECESSARY */
+		if(chans!=MONO) {
+			sprintf(errstr,"This process only works for MONO files.\n");
+			return(DATA_ERROR);
+		}
+		break;
+	default:					/* establish splicelen constants */
+		dz->iparam[CUT_SPLEN]     = round(dz->param[CUT_SPLEN] * MS_TO_SECS * sr) * chans;
+
+		break;
+	}
+	if(dz->process!=EDIT_EXCISEMANY && dz->process!=INSERTSIL_MANY) {
+		switch(dz->mode) {		/* read cutstart info, and convert to samps: info in file for EXCISEMANY  */
+		case(EDIT_SECS):
+			dz->iparam[CUT_CUT]     = round(dz->param[CUT_CUT] * sr) * chans;
+			break;
+		case(EDIT_SAMPS):
+			dz->iparam[CUT_CUT]     = (dz->iparam[CUT_CUT]/chans) * chans;	/* align to sample-group boundary */
+			break;
+		case(EDIT_STSAMPS):
+			dz->iparam[CUT_CUT]    *= chans;	
+			break;
+		}
+	}
+	switch(dz->process) {
+	case(EDIT_CUT):				/* read cutend or cutdur info, and convert to samps */
+	case(EDIT_ZCUT):
+	case(EDIT_EXCISE):
+	case(EDIT_INSERTSIL):
+		switch(dz->mode) {
+		case(EDIT_SECS):
+			dz->iparam[CUT_END]     = round(dz->param[CUT_END] * sr) * chans;
+			break;
+		case(EDIT_SAMPS):
+			dz->iparam[CUT_END]     = (dz->iparam[CUT_END]/chans) * chans;	/* align to sample-group boundary */
+			break;
+		case(EDIT_STSAMPS):
+			dz->iparam[CUT_END]    *= chans;	
+			break;
+		}
+		break;
+	case(EDIT_INSERT2):
+		dz->iparam[CUT_END]     = round(dz->param[CUT_END] * sr) * chans;
+		if((exit_status = setup_insert2_overwrite_flag(dz))<0)
+			return(exit_status);
+		break;
+	}
+	switch(dz->process) {
+	case(EDIT_CUT):		  		/* check consistency cutstart & cutend data */
+	case(EDIT_ZCUT):
+	case(EDIT_EXCISE):
+		  if(dz->iparam[CUT_END] == dz->iparam[CUT_CUT]) {
+			sprintf(errstr,"endcut = startcut: No cutting possible.\n");
+			return(DATA_ERROR);
+		}
+		if(dz->iparam[CUT_END] < dz->iparam[CUT_CUT]) {
+			fprintf(stdout,"WARNING: end cut before startcut: reversing these times.\n");
+			fflush(stdout);
+			iiswap(&(dz->iparam[CUT_END]),&(dz->iparam[CUT_CUT]));
+		}
+	 	break;
+	}
+
+	switch(dz->process) {		/* establish cutlen: check mutual consistency of params, for process */
+	case(EDIT_INSERTSIL):
+		dz->iparam[CUT_LEN] = dz->iparam[CUT_END];
+		if(dz->iparam[CUT_SPLEN] * 2 > dz->iparam[CUT_LEN]) {
+
+			sprintf(errstr,"Inserted silence is too short for splices.\n");
+			return(GOAL_FAILED);
+		}
+		if(dz->vflag[INSERT_OVERWRITE] 
+		&& (dz->iparam[CUT_CUT] + dz->iparam[CUT_LEN] - dz->iparam[CUT_SPLEN] >= dz->insams[0])) {
+			if(dz->vflag[ACCEPT_SILENT_END]) {
+				silent_end = 1;
+				fprintf(stdout,"WARNING: Insertion will cut sound at end of file: leaving a silent section there.\n");
+				fflush(stdout);
+			} else {
+				if(sloom)
+					sprintf(errstr,"Insertion will cut off entire end of file: use EDIT : CUTOUT & KEEP\n");
+				else
+					sprintf(errstr,"Insertion will cut off entire end of file: use sfedit cut\n");
+				return(GOAL_FAILED);
+
+			}
+		}
+		if(dz->iparam[CUT_CUT] < dz->iparam[CUT_SPLEN]) {
+			sprintf(errstr,"Insert time too close to start of file (allowing for splice)\n");
+			return(GOAL_FAILED);
+		}
+		if(dz->iparam[CUT_CUT] >= dz->insams[0] - dz->iparam[CUT_SPLEN]) {
+			if(dz->vflag[INSERT_OVERWRITE] || (dz->iparam[CUT_LEN] <= dz->iparam[CUT_SPLEN])) {
+				sprintf(errstr,"Insert time beyond end of infile (allowing for splice)\n");
+				return(GOAL_FAILED);
+			} else {
+				dz->tempsize = dz->insams[0] + dz->iparam[CUT_CUT];
+				algo2 = 1;
+				return(FINISHED);
+			}
+		}
+		if(dz->vflag[INSERT_OVERWRITE])
+			dz->tempsize = dz->insams[0];
+		else
+			dz->tempsize = dz->insams[0] + dz->insams[1] - (dz->iparam[CUT_SPLEN] * 2);
+		break;
+	case(INSERTSIL_MANY):
+		dz->tempsize = dz->insams[0];
+		algo2 = 1;
+		break;
+	case(EDIT_INSERT2):
+		if(dz->iparam[CUT_END] >= dz->insams[0] - dz->iparam[CUT_SPLEN]) {
+			sprintf(errstr,"Overwrite endtime is beyond end of infile (allowing for splice)\n");
+			return(GOAL_FAILED);
+		}
+		/*fall thro */
+	case(EDIT_INSERT):
+		if(dz->iparam[CUT_CUT] < dz->iparam[CUT_SPLEN]) {
+			sprintf(errstr,"Insert time too close to start of file (allowing for splice)\n");
+			return(GOAL_FAILED);
+		}
+		if(dz->iparam[CUT_CUT] >= dz->insams[0] - dz->iparam[CUT_SPLEN]) {
+			sprintf(errstr,"Insert time beyond end of infile (allowing for splice)\n");
+			return(GOAL_FAILED);
+		}
+		if((dz->process == EDIT_INSERT) && dz->vflag[INSERT_OVERWRITE] 
+		&& (dz->iparam[CUT_CUT] + dz->insams[1] - dz->iparam[CUT_SPLEN] >= dz->insams[0])) {
+			sprintf(errstr,"Insertion will cut off whole end of first file: use cut and splice.\n");
+			return(GOAL_FAILED);
+		}
+		if(dz->iparam[CUT_SPLEN] * 2 > dz->insams[1]) {
+			sprintf(errstr,"Inserted file is too short for splices.\n");
+			return(GOAL_FAILED);
+		}
+		if((dz->process == EDIT_INSERT) && dz->vflag[INSERT_OVERWRITE])
+			dz->tempsize = dz->insams[0];
+		else
+			dz->tempsize = dz->insams[0] + dz->insams[1] - (dz->iparam[CUT_SPLEN] * 2);
+		break;
+	case(EDIT_CUT):
+	case(EDIT_EXCISE):
+		dz->iparam[CUT_LEN] = dz->iparam[CUT_END] - dz->iparam[CUT_CUT];
+		dz->tempsize = dz->iparam[CUT_LEN];		/* EDIT_CUT only : EDIT_EXCISE reset below */
+		if((dz->iparam[CUT_SPLEN] * 2) > dz->iparam[CUT_LEN]) {
+			sprintf(errstr,"Edited portion is too short for specified splicelen.\n");
+			return(GOAL_FAILED);
+		}
+		break;
+	case(EDIT_CUTEND):
+		dz->tempsize = dz->iparam[CUT_CUT];
+		dz->iparam[CUT_CUT] = dz->insams[0] - dz->iparam[CUT_CUT];		
+		if(dz->iparam[CUT_CUT] >= dz->insams[0] - (2 * dz->iparam[CUT_SPLEN])) {
+			sprintf(errstr,"Edited portion is too short for specified splicelen.\n");
+			return(GOAL_FAILED);
+		}
+		dz->iparam[CUT_END] = dz->insams[0];		
+		dz->iparam[CUT_LEN] = dz->iparam[CUT_END] - dz->iparam[CUT_CUT];
+		break;
+	case(EDIT_ZCUT):
+		if(dz->iparam[CUT_END] > dz->insams[0]) {
+			fprintf(stdout,"WARNING: Assumed end of cut [%.2lf] is end of file [%.2lf]\n",
+			dz->param[CUT_END],(double)(dz->insams[0]/chans)/sr);
+			fflush(stdout);
+			dz->iparam[CUT_END] = dz->insams[0];
+		}
+		dz->tempsize = dz->iparam[CUT_END] - dz->iparam[CUT_CUT];
+		if(dz->iparam[CUT_END]== dz->insams[0])
+			dz->iparam[CUT_GOES_TO_END] = TRUE;
+		else
+			dz->iparam[CUT_GOES_TO_END] = FALSE;
+		break;
+	}
+
+	switch(dz->process) {			/* setup extra arrays or internal variables */
+	case(EDIT_EXCISE):
+		dz->iparam[EXCISE_CNT] = 1;
+		dz->iparam[CUT_NO_END] = FALSE;
+		if((dz->lparray[CUT_STTSAMP] = (int *)malloc(sizeof(int)))==NULL
+		|| (dz->lparray[CUT_STTSPLI] = (int *)malloc(sizeof(int)))==NULL
+		|| (dz->lparray[CUT_ENDSAMP] = (int *)malloc(sizeof(int)))==NULL
+		|| (dz->lparray[CUT_ENDSPLI] = (int *)malloc(sizeof(int)))==NULL) {
+			sprintf(errstr,"INSUFFICIENT_MEMORY to store excise times.\n");
+			return(MEMORY_ERROR);
+		}
+		dz->lparray[CUT_STTSAMP][0] = dz->iparam[CUT_CUT];
+		dz->lparray[CUT_ENDSAMP][0] = dz->iparam[CUT_END];
+		/* fall thro */
+	case(INSERTSIL_MANY):
+	case(EDIT_EXCISEMANY):
+		/* It's values were read from a file by special */
+		zz = chans * 2;
+		zsecs = dz->iparam[CUT_SPLEN]/zz;
+		if(zsecs * zz != dz->iparam[CUT_SPLEN]) {
+			zsecs++;
+		}
+		dz->iparam[CUT_SPLEN] = zsecs * zz;
+		dz->iparam[CUT_HLFSPLEN] = dz->iparam[CUT_SPLEN]/2;	/* hence hlfsplen is whole no. chans */
+		if(dz->infile->channels>MONO) {
+			for(k=0;k<dz->iparam[EXCISE_CNT];k++) {			/* align to samp-grp boundaries */
+				dz->lparray[CUT_STTSAMP][k] = (dz->lparray[CUT_STTSAMP][k]/chans) * chans;
+				dz->lparray[CUT_ENDSAMP][k] = (dz->lparray[CUT_ENDSAMP][k]/chans) * chans;
+			}
+	    }
+		if((exit_status = check_excise_splices(dz))<0)
+			return(exit_status);
+		setup_excise_outdisplay_len(dz);
+		break;
+	case(EDIT_CUT):
+	case(EDIT_CUTEND):
+		setup_startcut_sector_offset(dz);
+		break;
+	}
+	return(FINISHED);
+}
+
+/******************************** EDIT_PREPROCESS ********************************/
+
+int edit_preprocess(dataptr dz)
+{
+	int shsecsize = F_SECSIZE;			  /* RWD want to eliminate this... */
+
+	switch(dz->process) {
+	case(EDIT_CUT):
+	case(EDIT_CUTEND):
+		return establish_working_chunks(dz);
+	case(EDIT_INSERT2):
+	case(EDIT_INSERT):
+	case(EDIT_INSERTSIL):
+		if(algo2)
+			break;
+		dz->iparam[CUT_BUFXS]      = (dz->iparam[CUT_CUT] - dz->iparam[CUT_SPLEN]) % F_SECSIZE;
+	 	dz->iparam[CUT_BUFREMNANT] = 
+	 	(dz->iparam[CUT_SECSREMAIN] * shsecsize) - (dz->iparam[CUT_BUFXS] + dz->iparam[CUT_SPLEN]);
+
+		break;
+	}
+ 	return(FINISHED);
+}
+
+/******************************** SETUP_SECTOR_OFFSET_PARAMS ********************************/
+
+void setup_startcut_sector_offset(dataptr dz)
+{
+	dz->iparam[CUT_BUFXS]         =  dz->iparam[CUT_CUT] % F_SECSIZE;
+ 	dz->iparam[CUT_BUFOFFSET]     = F_SECSIZE - dz->iparam[CUT_BUFXS];
+}
+
+/******************************** CREATE_EDIT_BUFFERS ********************************/
+
+int create_edit_buffers(dataptr dz)
+{
+	int exit_status;
+	switch(dz->process) {
+	case(EDIT_CUT):
+	case(EDIT_CUTEND):
+	case(RANDCHUNKS):		exit_status = create_cut_buffer(dz);		break;
+	case(MANY_ZCUTS):
+	case(EDIT_ZCUT):		exit_status = create_zcut_buffer(dz);		break;
+	case(EDIT_EXCISE):
+	case(EDIT_EXCISEMANY):	exit_status = create_excise_buffers(dz);	break;
+	case(EDIT_INSERT):
+	case(EDIT_INSERT2):
+	case(INSERTSIL_MANY):
+	case(EDIT_INSERTSIL):	exit_status = create_insert_buffers(dz);	break;
+	case(JOIN_SEQDYN):
+	case(JOIN_SEQ):			exit_status = create_join_seq_buffer(dz);	break;
+	case(EDIT_JOIN):		exit_status = create_join_buffer(dz);		break;
+	default:
+		sprintf(errstr,"Unknown process in create_edit_buffers()\n");
+		return(PROGRAM_ERROR);
+	}
+	return(exit_status);
+}
+
+/******************************** CREATE_CUT_BUFFER ********************************/
+
+int create_cut_buffer(dataptr dz)
+{
+	size_t bigbufsize;
+    int secsize, sectorsize = dz->infile->channels * F_SECSIZE;
+	bigbufsize = (size_t)Malloc(-1);
+	bigbufsize /= sizeof(float);
+	bigbufsize =  (bigbufsize / sectorsize) * sectorsize;
+	if(bigbufsize < dz->iparam[CUT_SPLEN]) {
+		bigbufsize = dz->iparam[CUT_SPLEN] + sectorsize;
+		secsize = bigbufsize / sectorsize;
+		if(secsize * sectorsize != bigbufsize)
+			secsize++;
+		bigbufsize = secsize * sectorsize;	
+	}
+	if(bigbufsize <= F_SECSIZE ){		  
+		sprintf(errstr, "INSUFFICIENT MEMORY for sound.\n");
+		return(MEMORY_ERROR);
+	}
+	dz->iparam[SMALLBUFSIZ] = bigbufsize - F_SECSIZE;
+	if((dz->bigbuf = (float *)Malloc(bigbufsize * sizeof(float))) == 0) {
+		sprintf(errstr, "INSUFFICIENT MEMORY for sound.\n");
+		return(MEMORY_ERROR);
+	}
+	dz->buflen = (int) bigbufsize;		/*RWD*/
+	return(FINISHED);
+}
+
+/******************************** CREATE_ZCUT_BUFFER ********************************/
+
+int create_zcut_buffer(dataptr dz)
+{
+	/* RWD this may still all be dodgy for n-channel work!*/
+	size_t bigbufsize;
+    int secextra = F_SECSIZE;
+//	secextra = (secextra / dz->infile->channels) * dz->infile->channels;
+	if((secextra = (secextra / dz->infile->channels) * dz->infile->channels)<=0) {
+		sprintf(errstr,"Can't handle this many channels.\n");
+		return(DATA_ERROR);
+	}
+	bigbufsize = (size_t)Malloc(-1);
+	bigbufsize /= sizeof(float);
+	bigbufsize = (bigbufsize/F_SECSIZE) * F_SECSIZE;
+		
+	if((dz->bigbuf = (float *)Malloc((bigbufsize + secextra) * sizeof(float))) == NULL) {
+		sprintf(errstr, "INSUFFICIENT MEMORY for sound.\n");
+		return(MEMORY_ERROR);
+	}
+	dz->buflen = (int) bigbufsize;
+	dz->sampbuf[OBUF] = dz->sampbuf[IBUF] = dz->bigbuf + secextra;
+	return(FINISHED);
+}
+
+/******************************** CREATE_EXCISE_BUFFERS ********************************/
+
+int create_excise_buffers(dataptr dz)
+{   
+	size_t bigbufsize, framesize;
+	int splicespace = 2 * dz->iparam[CUT_SPLEN];
+//TW : again algo depends on this SECSIZE structuring, at present
+//	framesize = dz->infile->channels;
+	framesize = dz->infile->channels * F_SECSIZE * 2;
+	bigbufsize = (size_t) Malloc(-1) / sizeof(float);
+	bigbufsize = (bigbufsize/framesize) * framesize;
+	bigbufsize /= 2;
+	if(bigbufsize<=0) {
+		sprintf(errstr, "INSUFFICIENT MEMORY for sound.\n");
+		return(MEMORY_ERROR);
+	}
+	if((dz->bigbuf = (float *) Malloc(((bigbufsize * 2) + splicespace) * sizeof(float)))==0) {
+		sprintf(errstr, "INSUFFICIENT MEMORY for sound.\n");
+		return(MEMORY_ERROR);
+	}
+	dz->buflen   = (int) bigbufsize;
+	dz->sbufptr[IBUF]    = dz->sampbuf[IBUF]    = dz->bigbuf;
+	dz->sbufptr[OBUF]    = dz->sampbuf[OBUF]    = dz->sampbuf[IBUF]  + dz->buflen;
+	dz->sbufptr[SPLBUF]  = dz->sampbuf[SPLBUF]  = dz->sampbuf[OBUF]  + dz->buflen;
+	dz->sbufptr[SPLBUF2] = dz->sampbuf[SPLBUF2] = dz->sampbuf[SPLBUF] + dz->iparam[CUT_SPLEN];
+	memset((char *)dz->sampbuf[SPLBUF],0,dz->iparam[CUT_SPLEN]* sizeof(float));
+	return FINISHED;
+}
+
+/******************************** CREATE_INSERT_BUFFERS ********************************/
+				 
+int create_insert_buffers(dataptr dz)
+{
+	size_t bigbufsize;
+	int splice_space = dz->iparam[CUT_SPLEN] + F_SECSIZE; /* Allow for splice-end not aligning to sector boundary */
+	int prelen  =  dz->iparam[CUT_CUT]  - dz->iparam[CUT_SPLEN];
+	int prelen2, splicebuf_samplen, insertsize;
+	float *cp;
+	int framesize = dz->infile->channels * F_SECSIZE * 2;
+	bigbufsize = (size_t) Malloc(-1);
+	/*RWD*/
+	dz->buflen = (bigbufsize / framesize)  * framesize;
+	if(algo2) {
+		if((dz->bigbuf = (float *)Malloc(dz->buflen * sizeof(float))) == 0) {
+			sprintf(errstr, "INSUFFICIENT MEMORY.\n");
+			return(MEMORY_ERROR);
+		} else {
+			return(FINISHED);
+		}
+	}
+	dz->iparam[SMALLBUFSIZ] = /*dz->bigbufsize - SECSIZE;*/ dz->buflen - F_SECSIZE;
+	if(dz->iparam[SMALLBUFSIZ] < splice_space) {
+		sprintf(errstr,"INSUFFICIENT MEMORY for sound.\n");
+		return(MEMORY_ERROR);
+	}
+	dz->iparam[CUT_BUFCNT] = prelen/dz->buflen;				/* no. of whole buffers in sfile, before splice */
+	dz->iparam[CUT_SECCNT] = (prelen%dz->buflen)/F_SECSIZE;	/* no. whole sectors remaining, before splice */
+	dz->iparam[CUT_SMPSREMAIN] = 
+	dz->iparam[CUT_CUT] - ((dz->iparam[CUT_BUFCNT] * dz->buflen) + (dz->iparam[CUT_SECCNT] * F_SECSIZE)); 
+																/* remainder of file */
+	dz->iparam[CUT_SECSREMAIN]   = dz->iparam[CUT_SMPSREMAIN]/F_SECSIZE;
+	if(dz->iparam[CUT_SECSREMAIN] * F_SECSIZE != dz->iparam[CUT_SMPSREMAIN])
+		dz->iparam[CUT_SECSREMAIN]++;					  			/* GROSS number of sectors in remainder of file */
+	if(dz->iparam[CUT_SECSREMAIN] * F_SECSIZE > dz->buflen)	{	 
+		sprintf(errstr,"INSUFFICIENT MEMORY for sound.\n");
+		return(MEMORY_ERROR);
+	}
+	switch(dz->process) {
+	case(EDIT_INSERT):		insertsize = dz->insams[1];			break;	
+	case(EDIT_INSERT2):		insertsize = dz->insams[1];			break;	
+	case(EDIT_INSERTSIL):	insertsize = dz->iparam[CUT_LEN];	break;	
+	default:
+		sprintf(errstr,"Unknown process in create_insert_buffers()\n");
+		return(PROGRAM_ERROR);
+	}
+	prelen2 =  insertsize - splice_space;
+	dz->iparam[CUT_BUFCNT2]     = prelen2/dz->iparam[SMALLBUFSIZ];	     /* no. whole bufs in insertfile, before splice */
+	dz->iparam[CUT_SECCNT2]     = (prelen2%dz->iparam[SMALLBUFSIZ])/F_SECSIZE; /* no. whole secs remaining, before splice */
+	dz->iparam[CUT_SMPSREMAIN] =										 /* remainder of file */
+	insertsize - ((dz->iparam[CUT_BUFCNT2] * dz->iparam[SMALLBUFSIZ]) + (dz->iparam[CUT_SECCNT2] * F_SECSIZE)); 
+	dz->iparam[CUT_SECSREMAIN2]   = dz->iparam[CUT_SMPSREMAIN]/F_SECSIZE;
+
+	if(dz->iparam[CUT_SECSREMAIN2] * F_SECSIZE != dz->iparam[CUT_SMPSREMAIN])
+		dz->iparam[CUT_SECSREMAIN2]++;					  			       /* GROSS no. of sectors in remainder of file */
+	if((dz->iparam[CUT_SECSREMAIN2] + 1) * F_SECSIZE > dz->buflen) {
+		sprintf(errstr,"Buffers too small for splice.\n");
+		return(MEMORY_ERROR);
+	}
+
+	splicebuf_samplen = (dz->iparam[CUT_SECSREMAIN] + 2) * F_SECSIZE;
+	if((cp = dz->bigbuf = (float *)malloc(sizeof(float) * (dz->buflen + (splicebuf_samplen * 2)))) == NULL) {
+		sprintf(errstr,"INSUFFICIENT MEMORY for sound.\n");
+		return(MEMORY_ERROR);
+	}
+	dz->sampbuf[0]       = dz->bigbuf;
+	dz->sampbuf[SPLBUF]  = dz->sampbuf[0] + dz->buflen;
+	dz->sampbuf[SAVEBUF] = dz->sampbuf[SPLBUF] + (splicebuf_samplen);
+	memset((char *)dz->sampbuf[SAVEBUF],0,splicebuf_samplen * sizeof(float));
+	memset((char *)dz->sampbuf[SPLBUF], 0,splicebuf_samplen * sizeof(float));
+	return(FINISHED);
+}
+
+/******************************** ESTABLISH_WORKING_CHUNKS ********************************
+ *
+ * (2)	SPLICE_SPACE: 	number of sectors definitely containing the endsplice of the cut.
+ * (3)	PRELEN: 	  	No of samps in file from end of last complete sector BEFORE cut, to a point
+ *					  	definitely before final splice starts.
+ * (4)	LOPOFF:			Counts up number of samps to read, from end of preliminary seek to BEFORE endsplice area.
+ * (5)	CUT_SECSREMAIN:	Final number of sectors to read, containing all of the final splice.
+ */
+
+int establish_working_chunks(dataptr dz)
+{
+/* OLD **/
+	int splice_space = dz->iparam[CUT_SPLEN] + F_SECSIZE; 							/* 2 */
+	int prelen = dz->iparam[CUT_LEN] + dz->iparam[CUT_BUFXS] - splice_space; 	/* 3 */
+	int lopoff = 0;																	/* 4 */
+
+	int OK = 0;
+	while (!OK) {
+	/* count number of whole BUFFERS to read */
+		dz->iparam[CUT_BUFCNT] = 0;
+		if(prelen >= dz->buflen) {	  				    /* 1st attempt to read a whole buffer, reads dz->bigbufsize */
+			dz->iparam[CUT_BUFCNT]++;
+			prelen -= dz->buflen;
+			lopoff += dz->buflen;
+			while(prelen >= dz->iparam[SMALLBUFSIZ]) {	/* subsequent attempts read a smbuffsz, allowing for wraparound */
+				dz->iparam[CUT_BUFCNT]++;
+				prelen -= dz->iparam[SMALLBUFSIZ];
+				lopoff += dz->iparam[SMALLBUFSIZ];
+			}
+		}
+		/* count number of whole SECTORS to read */
+		dz->iparam[CUT_SECCNT] = 0;
+		while(prelen >= F_SECSIZE) {
+			dz->iparam[CUT_SECCNT]++;
+			prelen -= F_SECSIZE;
+			lopoff += F_SECSIZE;
+		}																	   /* calculate final no. samples left to read */
+		dz->iparam[CUT_SMPSREMAIN] = dz->iparam[CUT_LEN] + dz->iparam[CUT_BUFXS] - lopoff;
+		dz->iparam[CUT_SECSREMAIN] = dz->iparam[CUT_SMPSREMAIN] / F_SECSIZE;
+		if(dz->iparam[CUT_SECSREMAIN] * F_SECSIZE != dz->iparam[CUT_SMPSREMAIN])					/* 5 */		
+			dz->iparam[CUT_SECSREMAIN]++;					  			  /* GROSS number of sectors in remainder of file */
+		if(dz->iparam[CUT_SECSREMAIN] * F_SECSIZE > dz->buflen)	{	   /* Possibly unnnecessary check: but being safe */
+			dz->iparam[SMALLBUFSIZ] = dz->buflen;
+			dz->buflen += F_SECSIZE;
+			if((dz->bigbuf = (float *)realloc((char *)dz->bigbuf,dz->buflen * sizeof(float)))==NULL) {
+				sprintf(errstr, "INSUFFICIENT MEMORY for endsplice.\n");
+				return(MEMORY_ERROR);
+			}
+		} else
+			OK = 1;
+	}
+	return(FINISHED);
+}
+
+/******************************** DO_CUT ********************************/
+
+int do_cut(dataptr dz)
+{
+	int   exit_status;
+	int  ref, cc, to_write = 0, seektest;
+	int   first = 1;
+	float *bufptr = dz->bigbuf;	  /* CUrrent buffer pointer */
+	int  shsecsize = F_SECSIZE, samps_read;
+	int is_startcut = TRUE;
+
+ 	if(dz->process==EDIT_CUT && dz->iparam[CUT_CUT]==0)
+		is_startcut = FALSE;
+	/* seek to start of sector before cut */
+	if((seektest = sndseekEx(dz->ifd[0], (dz->iparam[CUT_CUT] / F_SECSIZE)  * F_SECSIZE, 0)) 
+		!= (dz->iparam[CUT_CUT] / F_SECSIZE)  * F_SECSIZE) {		
+		if(seektest<0) {
+			sprintf(errstr,"sndseekEx() failed.\n");
+			return(SYSTEM_ERROR);
+		} else {
+			sprintf(errstr,"Start time after end of file.\n");
+			return(PROGRAM_ERROR);
+		}
+	}
+
+	/* ANY WHOLE BUFFERS OF CUT ARE COPIED */
+
+	ref = dz->iparam[SMALLBUFSIZ];
+	for(cc = 1; cc <= dz->iparam[CUT_BUFCNT]; cc++)	{
+		if(first) {
+			first = 0;
+			if((samps_read = fgetfbufEx(dz->bigbuf, dz->buflen,dz->ifd[0],0))!=dz->buflen) {
+				sprintf(errstr,"Bad sound read 1.\n");
+				if(samps_read<0)
+					return(SYSTEM_ERROR);
+				return(PROGRAM_ERROR);
+			}
+			bufptr += dz->iparam[CUT_BUFXS];  	/* reset input-pointer to start of cut */
+
+			if(dz->iparam[CUT_SPLEN] > 0 && is_startcut)
+				dosplice(bufptr, dz->iparam[CUT_SPLEN], dz->infile->channels, UPSLOPE);
+
+			if((exit_status = write_exact_samps(bufptr, dz->iparam[SMALLBUFSIZ],dz))<0)
+				return(exit_status);
+			bufptr += ref;	   
+			memcpy((char *)dz->bigbuf, (char *)bufptr, 
+				dz->iparam[CUT_BUFOFFSET] * sizeof(float));
+			bufptr = dz->bigbuf + dz->iparam[CUT_BUFOFFSET];
+		} else {
+			if((samps_read = fgetfbufEx(bufptr, dz->iparam[SMALLBUFSIZ],dz->ifd[0],0))!=dz->iparam[SMALLBUFSIZ]) {
+				sprintf(errstr,"Bad sound read 2.\n");
+				if(samps_read<0)
+					return(SYSTEM_ERROR);
+				return(PROGRAM_ERROR);
+			}
+			if((exit_status = write_exact_samps(dz->bigbuf, dz->iparam[SMALLBUFSIZ],dz))<0)
+				return(exit_status);
+			bufptr = dz->bigbuf + ref;
+			memcpy((char *)dz->bigbuf, (char *)bufptr, 
+				 dz->iparam[CUT_BUFOFFSET] * sizeof(float));
+			bufptr = dz->bigbuf + dz->iparam[CUT_BUFOFFSET];
+		}
+	}
+	
+	/* ANY (FURTHER) WHOLE SECTORS BEFORE ENDSPLICE, ARE COPIED */
+	
+	if(dz->iparam[CUT_SECCNT]) {
+ 		if(first) {
+			first = 0;
+			if((samps_read  = 
+			fgetfbufEx(dz->bigbuf, dz->iparam[CUT_SECCNT] * F_SECSIZE,dz->ifd[0],0))!=dz->iparam[CUT_SECCNT] * F_SECSIZE) {
+				sprintf(errstr,"Bad sound read 3.\n");
+				if(samps_read<0)
+					return(SYSTEM_ERROR);
+				return(PROGRAM_ERROR);
+			}
+			bufptr += dz->iparam[CUT_BUFXS];  	/* reset input-pointer to start of cut */
+
+			if(dz->iparam[CUT_SPLEN]>0 && is_startcut) 		
+												/* splice beginning of input */
+				dosplice(bufptr, dz->iparam[CUT_SPLEN],dz->infile->channels, UPSLOPE);
+
+			dz->iparam[CUT_SECCNT]--;
+			if(dz->iparam[CUT_SECCNT]) {
+  				if((exit_status = write_exact_samps(bufptr, dz->iparam[CUT_SECCNT] * F_SECSIZE,dz))<0)
+					return(exit_status);
+			}
+			bufptr += dz->iparam[CUT_SECCNT] * shsecsize;
+			memcpy((char *)dz->bigbuf, (char *)bufptr, 
+				 dz->iparam[CUT_BUFOFFSET] * sizeof(float));
+			bufptr = dz->bigbuf + dz->iparam[CUT_BUFOFFSET];
+		} else {
+			if((samps_read  = 
+			fgetfbufEx(bufptr,dz->iparam[CUT_SECCNT] * F_SECSIZE,dz->ifd[0],0))
+			      != dz->iparam[CUT_SECCNT] * F_SECSIZE) {
+				sprintf(errstr,"Bad sound read 4.\n");
+				if(samps_read<0)
+					return(SYSTEM_ERROR);
+				return(PROGRAM_ERROR);
+			}
+			if(dz->iparam[CUT_SECCNT]) {
+  				if((exit_status = write_exact_samps(dz->bigbuf,dz->iparam[CUT_SECCNT] * F_SECSIZE,dz))<0)
+					return(exit_status);
+			}
+			bufptr = dz->bigbuf + (dz->iparam[CUT_SECCNT] * shsecsize);
+			memcpy((char *)dz->bigbuf, (char *)bufptr, 
+				dz->iparam[CUT_BUFOFFSET] * sizeof(float));
+			bufptr = dz->bigbuf + dz->iparam[CUT_BUFOFFSET];
+		}
+	}
+
+	/* DO SECTORS CONTAINING ENDSPLICE OF CUT */
+
+	if(first) {	/* IF THERE ARE NO WHOLE BUFFERS OR SECTORS BEFORE SPLICE STARTS */
+		if((samps_read  = fgetfbufEx(dz->bigbuf, dz->iparam[CUT_SECSREMAIN] * F_SECSIZE,dz->ifd[0],0))<=0) {
+			sprintf(errstr,"Bad sound read 5.\n");
+			if(samps_read<0)
+				return(SYSTEM_ERROR);
+			return(PROGRAM_ERROR);
+		}
+		bufptr += dz->iparam[CUT_BUFXS];	  	/* reset input-pointer to start of cut */
+
+		if(dz->iparam[CUT_SPLEN] > 0) { 		/* splice beginning (& end if not CUTEND) of file */
+			if(is_startcut)
+				dosplice(bufptr, dz->iparam[CUT_SPLEN],dz->infile->channels, UPSLOPE);
+			bufptr = dz->bigbuf + dz->iparam[CUT_SMPSREMAIN] - dz->iparam[CUT_SPLEN];	
+			if(dz->process==EDIT_CUT)
+				dosplice(bufptr, dz->iparam[CUT_SPLEN],dz->infile->channels, DOWNSLOPE);
+		}
+		bufptr = dz->bigbuf + dz->iparam[CUT_BUFXS];
+		if(dz->iparam[CUT_LEN] > 0) {
+			if((exit_status = write_samps(bufptr, dz->iparam[CUT_LEN],dz))<0)
+				return(exit_status);
+		}
+
+	} else {
+		if((samps_read  = fgetfbufEx(bufptr, dz->iparam[CUT_SECSREMAIN] * F_SECSIZE,dz->ifd[0],0))<=0) {
+			sprintf(errstr,"Bad sound read 6.\n");
+			if(samps_read<0)
+				return(SYSTEM_ERROR);
+			return(PROGRAM_ERROR);
+		}
+		switch(dz->process) {
+		case(EDIT_CUT):
+			if(dz->iparam[CUT_SPLEN] > 0) {
+				bufptr += dz->iparam[CUT_SMPSREMAIN] - dz->iparam[CUT_SPLEN];
+				dosplice(bufptr, dz->iparam[CUT_SPLEN],dz->infile->channels, DOWNSLOPE);		   
+			}
+			to_write = dz->iparam[CUT_BUFOFFSET] + dz->iparam[CUT_SMPSREMAIN];
+			break;
+		case(EDIT_CUTEND):
+			to_write = dz->iparam[CUT_BUFOFFSET] + samps_read;
+			break;
+		}			
+		if(to_write > 0) {
+			if((exit_status = write_samps(dz->bigbuf,to_write,dz))<0)
+				return(exit_status);
+		}
+	}
+	return(FINISHED);
+}
+
+/******************************** DOSPLICE ********************************
+ * 
+ * INVERT is flag to invert the direction of splice
+ * 			0 = normal, 1 = inverted
+ */
+
+void dosplice(float *buf, int samples, int chans, int invert)
+{
+	double	a1 = 0.0, aincr;
+	register int i, j;
+	int sampgrps = samples/chans;
+
+	aincr = 1.0/sampgrps;
+	if(invert) {
+		aincr = -aincr;
+		a1 = 1.0 + aincr;
+	}
+	for(i = 0; i < samples; i+= chans) {
+		for(j=0;j<chans;j++) 
+			buf[i+j] = (float)((double)buf[i+j] * a1);
+		a1 += aincr;
+	}
+}
+
+/*************************** CHECK_EXCISE_SPLICES ****************************/
+
+int check_excise_splices(dataptr dz)
+{
+	int k;
+    if(dz->lparray[CUT_STTSAMP][0] <= 0) {
+		dz->iparam[CUT_NO_STT] = TRUE;
+		dz->lparray[CUT_STTSPLI][0] = 0;
+	} else {
+		dz->iparam[CUT_NO_STT] = FALSE;
+		if((dz->lparray[CUT_STTSPLI][0] = dz->lparray[CUT_STTSAMP][0] - dz->iparam[CUT_HLFSPLEN])<0) {
+			sprintf(errstr,"initial excise is too close to start of file for splice\n");
+			return(DATA_ERROR);
+		}
+		dz->lparray[CUT_STTSAMP][0]  += dz->iparam[CUT_HLFSPLEN];
+	}
+	for(k=1;k<dz->iparam[EXCISE_CNT];k++) {
+		dz->lparray[CUT_STTSPLI][k] = dz->lparray[CUT_STTSAMP][k] - dz->iparam[CUT_HLFSPLEN];
+		dz->lparray[CUT_STTSAMP][k]  += dz->iparam[CUT_HLFSPLEN];
+	}
+	for(k=0;k<dz->iparam[EXCISE_CNT];k++) {
+		dz->lparray[CUT_ENDSPLI][k] = dz->lparray[CUT_ENDSAMP][k] + dz->iparam[CUT_HLFSPLEN];
+		dz->lparray[CUT_ENDSAMP][k]  -= dz->iparam[CUT_HLFSPLEN];
+		if(dz->lparray[CUT_ENDSAMP][k] < dz->lparray[CUT_STTSAMP][k]) {
+			sprintf(errstr,"Excised segment %d too short for splices (shorten splices?)\n",k+1);
+			return(DATA_ERROR);
+		}
+		if(k && (dz->lparray[CUT_STTSPLI][k] < dz->lparray[CUT_ENDSPLI][k-1])) {
+			sprintf(errstr,"Retained segment between excise %d & %d is too short for splices.\n",k,k+1);
+			return(DATA_ERROR);
+		}						 
+	}
+	if(dz->lparray[CUT_ENDSPLI][k-1] >= dz->insams[0]) {
+		dz->iparam[CUT_NO_END] = TRUE;
+		if(dz->iparam[CUT_NO_STT]==TRUE && dz->iparam[EXCISE_CNT]==1) {
+			sprintf(errstr,"This process would remove the entire file!\n");
+			return(DATA_ERROR);
+		}
+		if(dz->lparray[CUT_ENDSAMP][k-1] <dz->insams[0])
+			fprintf(stdout,"INFO: End of final excise = END of FILE (it's closer than SPLICELEN).\n");
+			fflush(stdout);
+	}
+	return(FINISHED);
+}
+
+/**************************** DO_ZCUT ********************************/
+
+int do_zcut(dataptr dz)
+{   
+	int exit_status;
+	int start_wr = 0, end_wr, last_end_wr, samps_to_wr, secs_to_wr ,extra, samps_written;
+	int shsecsize = F_SECSIZE, last_total_samps;
+	if(dz->process != MANY_ZCUTS)
+		display_virtual_time(0L,dz);
+	do {
+		last_total_samps = dz->total_samps_read;
+		if((exit_status = read_samps(dz->sampbuf[IBUF],dz))<0)
+			return(exit_status);
+	} while(dz->total_samps_read < dz->iparam[CUT_CUT]);
+	if(dz->iparam[CUT_CUT]) {
+		start_wr = dz->iparam[CUT_CUT] - last_total_samps;
+		start_wr = find_zero(start_wr,dz->ssampsread,dz);
+	}
+	if(dz->iparam[CUT_END] <= dz->total_samps_read) {
+		end_wr = dz->iparam[CUT_END] - last_total_samps;
+		end_wr = find_zero(end_wr,dz->ssampsread,dz);
+		if(end_wr - start_wr > 0) {
+			if(dz->process == MANY_ZCUTS)
+				exit_status = write_samps_no_report((dz->sampbuf[IBUF]+start_wr),(end_wr - start_wr),&samps_written,dz);
+			else			
+				exit_status = write_samps((dz->sampbuf[IBUF]+start_wr),(end_wr - start_wr),dz);
+			if(exit_status < 0)
+				return(exit_status);
+		}
+	} else {
+		samps_to_wr = dz->buflen - start_wr;
+		secs_to_wr  = samps_to_wr/shsecsize;
+		extra	    = samps_to_wr - (secs_to_wr * shsecsize);
+		samps_to_wr = secs_to_wr * shsecsize;
+		if(samps_to_wr > 0) {
+			if(dz->process == MANY_ZCUTS)
+				exit_status = write_samps_no_report((dz->sampbuf[IBUF]+start_wr),samps_to_wr,&samps_written,dz);
+			else			
+				exit_status = write_samps((dz->sampbuf[IBUF]+start_wr),samps_to_wr,dz);
+			if(exit_status < 0)
+				return(exit_status);
+		}
+		end_wr      = dz->buflen - extra;
+		memcpy((char *)(dz->sampbuf[OBUF] - extra),(char *)(dz->sampbuf[OBUF] + end_wr),extra*sizeof(float));
+		dz->sampbuf[OBUF] -= extra;
+		for(;;) {
+			last_total_samps = dz->total_samps_read;
+			if((exit_status = read_samps(dz->sampbuf[IBUF],dz))<0)
+				return(exit_status);
+			if(dz->total_samps_read < dz->iparam[CUT_END]) {	
+				if(dz->process == MANY_ZCUTS)
+					exit_status = write_samps_no_report(dz->sampbuf[OBUF],dz->buflen,&samps_written,dz);
+				else			
+					exit_status = write_samps(dz->sampbuf[OBUF],dz->buflen,dz);
+				if(exit_status < 0)
+					return(exit_status);
+				memcpy((char *)dz->sampbuf[OBUF],(char *)(dz->sampbuf[OBUF] + end_wr),extra*sizeof(float));
+			} else {
+				last_end_wr = dz->iparam[CUT_END] - last_total_samps;
+				if(!dz->iparam[CUT_GOES_TO_END]) {
+					last_end_wr = find_zero(last_end_wr+extra,dz->ssampsread+extra,dz);
+					if(last_end_wr > 0) {
+						if(dz->process == MANY_ZCUTS)
+							exit_status = write_samps_no_report(dz->sampbuf[OBUF],last_end_wr,&samps_written,dz);
+						else			
+							exit_status = write_samps(dz->sampbuf[OBUF],last_end_wr,dz);
+						if(exit_status < 0)
+							return(exit_status);
+					}
+				} else {
+					if(last_end_wr + extra > 0) {
+						if(dz->process == MANY_ZCUTS)
+							exit_status = write_samps_no_report(dz->sampbuf[OBUF],(last_end_wr + extra),&samps_written,dz);
+						else			
+							exit_status = write_samps(dz->sampbuf[OBUF],(last_end_wr + extra),dz);
+						if(exit_status < 0)
+							return(exit_status);
+					}
+				}
+				break;
+			}
+		}
+	}
+	return(FINISHED);
+}
+
+/************************ FIND_ZERO **************************/
+
+int find_zero(int end,int allsamps,dataptr dz)
+{
+	int n = end;
+	int m = end;
+	int  phase, in_nloop = 0, in_mloop = 0;
+	if(smpflteq(dz->sampbuf[OBUF][n],0.0))
+		return(end);
+	if(dz->sampbuf[OBUF][n]>0.0)
+		phase = 1;
+	else
+		phase = -1;
+	switch(phase) {
+	case(1):
+		while(n>0) {
+			in_nloop = 1;
+			if(dz->sampbuf[OBUF][n]<0.0) {  
+				n++;  
+				break;  
+			}
+			n--;
+		}
+		if(n==0 && in_nloop)        
+			n = dz->buflen; /* FLAG NO ZERO FOUND BACKWRD */
+		while(m<allsamps) {
+			in_mloop = 1;
+			if(dz->sampbuf[OBUF][m]<0.0)  
+				break;
+			m++;
+		}
+		if(m==allsamps && in_mloop) 
+			m = dz->buflen;	/* FLAG NO ZERO FOUND FORWRD */
+		break;
+	case(-1):
+		while(n>0) {
+			in_nloop = 1;
+			if(dz->sampbuf[OBUF][n]>0.0) {  
+				n++;  
+				break;  
+			}
+			n--;
+		}
+		if(n==0 && in_nloop) 	    
+			n = dz->buflen;
+		while(m<allsamps) {
+			in_mloop = 1;
+			if(dz->sampbuf[OBUF][m]>0.0)  
+				break;
+			m++;
+		}
+		if(m==allsamps && in_mloop) 
+			m = dz->buflen;
+		break;
+	}
+	if(m==dz->buflen && n==dz->buflen)  /* NO ZERO CROSSING FOUND */
+		return(allsamps);
+	if((m-end) < (end-n))	/* ELSE RETURN CLOSEST ZERO CROSSING */
+		return(m);
+	return(n);
+}
+
+/****************************** DO_EXCISE *************************/
+
+int do_excise(dataptr dz)
+{   
+	int exit_status;
+	int k;
+	int last_total_samps;
+	int obufleft, ibufleft;
+	dz->total_samps_read = 0;
+	display_virtual_time(0L,dz);
+	last_total_samps = dz->total_samps_read;
+    if((exit_status = read_samps(dz->sampbuf[IBUF],dz))<0)
+		return(exit_status);
+	obufleft = dz->buflen;
+	ibufleft = dz->buflen;
+	if((exit_status = copy_excise_chunk(&last_total_samps,&obufleft,&ibufleft,0,dz))<0)
+		return(exit_status);
+	obufleft = dz->buflen - (dz->lparray[CUT_STTSPLI][0] - last_total_samps);
+	ibufleft = dz->buflen - (dz->lparray[CUT_STTSPLI][0] - last_total_samps);
+	exit_status = CONTINUE;
+	for(k=0;k<dz->iparam[EXCISE_CNT];k++) {
+		if(k==0) {
+			if(!dz->iparam[CUT_NO_STT])	{
+				if((exit_status = do_excise_beginning(&last_total_samps,&obufleft,0,dz))<0)
+					return(exit_status);
+			}			
+		} else {
+			if((exit_status = do_excise_beginning(&last_total_samps,&obufleft,k,dz))<0)
+				return(exit_status);
+		}
+    	if(k==dz->iparam[EXCISE_CNT]-1 && dz->iparam[CUT_NO_END])
+			exit_status = FINISHED;
+ 	  	if(exit_status==FINISHED)
+    		break;
+		if((exit_status = do_excise_ending(&last_total_samps,&obufleft,&ibufleft,k,dz))<0)
+			return(exit_status);
+	}
+  	if(exit_status==FINISHED)
+		return do_excise_finish(obufleft,dz);
+	return write_excise_end(last_total_samps,obufleft,ibufleft,dz);
+}
+
+/*************************** DO_EXCISE_FINISH ***********************/
+
+int do_excise_finish(int obufleft,dataptr dz)
+{
+	int exit_status;
+	int overflow;
+	dz->sbufptr[SPLBUF] = dz->sampbuf[SPLBUF];
+	if((overflow = dz->iparam[CUT_SPLEN] - obufleft)<=0) {
+		memcpy((char *)dz->sbufptr[OBUF],(char *)dz->sbufptr[SPLBUF],dz->iparam[CUT_SPLEN]*sizeof(float));
+	dz->sbufptr[OBUF] += dz->iparam[CUT_SPLEN];
+	if(dz->sbufptr[OBUF]-dz->sampbuf[OBUF] > 0) {
+		if((exit_status = write_samps(dz->sampbuf[OBUF],(dz->sbufptr[OBUF]-dz->sampbuf[OBUF]),dz))<0)
+			return(exit_status);
+	}
+	} else {
+		memcpy((char *)dz->sbufptr[OBUF],(char *)dz->sbufptr[SPLBUF],obufleft*sizeof(float));
+		if((exit_status = write_samps(dz->sampbuf[OBUF],dz->buflen,dz))<0)
+			return(exit_status);
+		dz->sbufptr[SPLBUF] += obufleft;
+		if(overflow > 0) {
+			if((exit_status = write_samps(dz->sbufptr[SPLBUF],overflow,dz))<0)
+				return(exit_status);
+		}
+	}
+	return(FINISHED);
+}
+
+/**************************** CROSSPLICE ******************************/
+
+void crossplice(dataptr dz)
+{   
+	double a1, aincr;
+	int chans = dz->infile->channels;
+	int    sampgrps = dz->iparam[CUT_SPLEN]/chans;
+	float  *splptr2 = dz->sampbuf[SPLBUF2]; 
+	float  *splptr  = dz->sampbuf[SPLBUF]; 
+	int i;
+	int j;
+
+	aincr = 1.0/sampgrps;
+	a1 = aincr;
+	
+	for(i = 0; i < dz->iparam[CUT_SPLEN]; i+= chans) {
+		for(j=0;j<chans;j++) {
+			*splptr2   = (float)((double)(*splptr2) * a1);
+			*splptr++ += *splptr2++;
+		}
+		a1 += aincr;
+	}
+}
+
+/*********************************** DO_EXCISE_BEGINNING *************************/
+
+int do_excise_beginning(int *last_total_samps,int *obufleft,int k,dataptr dz)
+{
+	int exit_status = CONTINUE;
+	int overflow, remnant, startsplice_in_buf, startsamp_in_buf, samps_to_copy;
+	dz->sbufptr[SPLBUF] = dz->sampbuf[SPLBUF];
+	startsplice_in_buf  = dz->lparray[CUT_STTSPLI][k] - *last_total_samps;
+	dz->sbufptr[IBUF] = dz->sampbuf[IBUF] + startsplice_in_buf;
+	*obufleft = dz->sampbuf[SPLBUF] - dz->sbufptr[OBUF];
+	startsamp_in_buf  = dz->lparray[CUT_STTSAMP][k] - *last_total_samps;
+	if((overflow = startsamp_in_buf - dz->buflen)<=0) {
+		memcpy((char *)dz->sbufptr[SPLBUF],(char *)dz->sbufptr[IBUF],
+			dz->iparam[CUT_SPLEN] * sizeof(float));
+		dz->sbufptr[IBUF] += dz->iparam[CUT_SPLEN];
+		if(dz->sbufptr[IBUF] >= dz->sampbuf[OBUF]) {
+			if(dz->samps_left<=0)
+				exit_status = FINISHED;
+			else {
+				*last_total_samps = dz->total_samps_read;
+			    if((exit_status = read_samps(dz->sampbuf[IBUF],dz))<0)
+					return(exit_status);
+				dz->sbufptr[IBUF]  = dz->sampbuf[IBUF];
+				exit_status = CONTINUE;
+			}
+		}
+	} else {
+		remnant = dz->iparam[CUT_SPLEN]-overflow;
+		memcpy((char *)dz->sbufptr[SPLBUF],(char *)dz->sbufptr[IBUF],remnant*sizeof(float));
+		dz->sbufptr[SPLBUF] += remnant;
+		while(overflow > 0) {
+			*last_total_samps = dz->total_samps_read;
+			if((exit_status = read_samps(dz->sampbuf[IBUF],dz))<0)
+				return(exit_status);
+			dz->sbufptr[IBUF] = dz->sampbuf[IBUF];
+			samps_to_copy = min(overflow,dz->buflen);
+			overflow -= samps_to_copy;
+			memcpy((char *)dz->sbufptr[SPLBUF],(char *)dz->sbufptr[IBUF],samps_to_copy*sizeof(float));
+			dz->sbufptr[IBUF] += samps_to_copy;
+			dz->sbufptr[SPLBUF] += samps_to_copy;
+			startsamp_in_buf = dz->lparray[CUT_STTSAMP][k] - *last_total_samps;
+		}
+		exit_status = CONTINUE;
+	}
+	dosplice(dz->sampbuf[SPLBUF],dz->iparam[CUT_SPLEN],dz->infile->channels,DOWNSLOPE);
+	dz->sbufptr[SPLBUF] = dz->sampbuf[SPLBUF];
+	return(exit_status);
+}
+
+
+/****************************** DO_EXCISE_ENDING ****************************/
+
+int do_excise_ending(int *last_total_samps,int *obufleft,int *ibufleft,int k,dataptr dz)
+{
+	int exit_status;
+	int overflow, remnant;
+	int endsplice_in_buf, endsamp_in_buf;
+	int samps_to_copy;
+
+	dz->sbufptr[SPLBUF2] = dz->sampbuf[SPLBUF2];
+	while(dz->total_samps_read < dz->lparray[CUT_ENDSAMP][k]) {
+		*last_total_samps = dz->total_samps_read;
+	    if((exit_status = read_samps(dz->sampbuf[IBUF],dz))<0)
+			return(exit_status);
+	}
+	endsamp_in_buf   = dz->lparray[CUT_ENDSAMP][k]   - *last_total_samps;
+	endsplice_in_buf = dz->lparray[CUT_ENDSPLI][k] - *last_total_samps;
+	dz->sbufptr[IBUF] = dz->sampbuf[IBUF] + endsamp_in_buf;
+	if((overflow = endsplice_in_buf - dz->buflen)<=0) {
+		memcpy((char *)dz->sbufptr[SPLBUF2],(char *)dz->sbufptr[IBUF],
+			dz->iparam[CUT_SPLEN] * sizeof(float));
+		dz->sbufptr[IBUF] += dz->iparam[CUT_SPLEN];
+		if(dz->sbufptr[IBUF] >= dz->sampbuf[OBUF]) {
+			if(dz->samps_left<=0)
+				return(FINISHED);
+			else {
+				*last_total_samps = dz->total_samps_read;
+			    if((exit_status = read_samps(dz->sampbuf[IBUF],dz))<0)
+					return(exit_status);
+				dz->sbufptr[IBUF]  = dz->sampbuf[IBUF];
+			}
+		}
+	} else {
+		remnant = dz->iparam[CUT_SPLEN]-overflow;
+		memcpy((char *)dz->sbufptr[SPLBUF2],(char *)dz->sbufptr[IBUF],remnant*sizeof(float));
+		dz->sbufptr[SPLBUF2] += remnant;
+		while(overflow > 0) {
+			*last_total_samps = dz->total_samps_read;
+			if((exit_status = read_samps(dz->sampbuf[IBUF],dz))<0)
+				return(exit_status);
+			dz->sbufptr[IBUF] = dz->sampbuf[IBUF];
+			samps_to_copy = min(overflow,dz->buflen);
+			overflow -= samps_to_copy;
+			memcpy((char *)dz->sbufptr[SPLBUF2],(char *)dz->sbufptr[IBUF],samps_to_copy*sizeof(float));
+			dz->sbufptr[IBUF] += overflow;
+			dz->sbufptr[SPLBUF2] += samps_to_copy;
+		}
+	}
+	crossplice(dz);
+	dz->sbufptr[SPLBUF]  = dz->sampbuf[SPLBUF]; 
+	dz->sbufptr[SPLBUF2] = dz->sampbuf[SPLBUF2]; 
+	if((overflow = dz->iparam[CUT_SPLEN] - *obufleft)<=0) {
+		memcpy((char *)dz->sbufptr[OBUF],(char *)dz->sbufptr[SPLBUF],
+			dz->iparam[CUT_SPLEN] * sizeof(float));
+		dz->sbufptr[OBUF] += dz->iparam[CUT_SPLEN];
+	} else {
+		memcpy((char *)dz->sbufptr[OBUF],(char *)dz->sbufptr[SPLBUF],(*obufleft)*sizeof(float));
+		dz->sbufptr[SPLBUF] += *obufleft;
+		while(overflow > 0) {
+			if((exit_status = write_samps(dz->sampbuf[OBUF],dz->buflen,dz))<0)
+				return(exit_status);
+			dz->sbufptr[OBUF]  = dz->sampbuf[OBUF];
+			samps_to_copy = min(overflow,dz->buflen);
+			overflow -= samps_to_copy;
+			memcpy((char *)dz->sbufptr[OBUF],(char *)dz->sbufptr[SPLBUF],samps_to_copy*sizeof(float));
+// MAY 2010
+//			dz->sbufptr[OBUF] += overflow;
+			dz->sbufptr[OBUF] += samps_to_copy;
+			dz->sbufptr[SPLBUF] += samps_to_copy;
+		}
+	}
+	*obufleft = dz->sampbuf[SPLBUF] - dz->sbufptr[OBUF];
+	*ibufleft = dz->ssampsread - (dz->sbufptr[IBUF] - dz->sampbuf[IBUF]);
+	if(k < dz->iparam[EXCISE_CNT]-1)
+		copy_excise_chunk(last_total_samps,obufleft,ibufleft,k+1,dz);
+	return(CONTINUE);
+}
+
+/************************* WRITE_EXCISE_END *****************************/
+
+int write_excise_end(int last_total_samps,int obufleft,int ibufleft,dataptr dz)
+{
+	int exit_status;
+	int finished = 0, do_it = 0;
+	while(!finished) {
+		if     (obufleft == ibufleft) do_it = 0; 
+		else if(obufleft  > ibufleft) do_it = 1;
+		else if(obufleft  < ibufleft) do_it = 2;
+		switch(do_it) {
+		case(0):	/* EQUAL SPACE IN INPUT & OUTPUT BUFFERS */
+			memcpy((char *)dz->sbufptr[OBUF],(char *)dz->sbufptr[IBUF],ibufleft * sizeof(float));
+			dz->sbufptr[OBUF] += ibufleft;
+			if(dz->sbufptr[OBUF] - dz->sampbuf[OBUF] > 0) {
+				if((exit_status = 
+				write_samps(dz->sampbuf[OBUF],(dz->sbufptr[OBUF] - dz->sampbuf[OBUF]),dz))<0)
+					return(exit_status);
+			}
+			while(dz->samps_left) {
+				last_total_samps = dz->total_samps_read;
+				if((exit_status = read_samps(dz->sampbuf[IBUF],dz))<0)
+					return(exit_status);
+				if(dz->ssampsread > 0) {
+					if((exit_status = write_samps(dz->sampbuf[IBUF],dz->ssampsread,dz))<0)
+						return(exit_status);
+				}
+			}
+			finished = 1;
+			break;
+		case(1):	/* MORE SPACE IN OUTPUT BUFFER */
+			memcpy((char *)dz->sbufptr[OBUF],(char *)dz->sbufptr[IBUF],ibufleft * sizeof(float));
+			dz->sbufptr[OBUF]  += ibufleft;
+			obufleft -= ibufleft;
+			if(dz->samps_left<=0) {
+				if(dz->sbufptr[OBUF]-dz->sampbuf[OBUF] > 0) {
+					if((exit_status = 
+					write_samps(dz->sampbuf[OBUF],(dz->sbufptr[OBUF]-dz->sampbuf[OBUF]),dz))<0)
+						return(exit_status);
+				}
+				finished = 1;
+				break;
+			}
+			last_total_samps = dz->total_samps_read;
+			if((exit_status = read_samps(dz->sampbuf[IBUF],dz))<0)
+				return(exit_status);
+			dz->sbufptr[IBUF]  = dz->sampbuf[IBUF];
+			ibufleft = dz->ssampsread;
+			break;
+		case(2):	/* MORE SPACE IN INPUT BUFFER */
+			memcpy((char *)dz->sbufptr[OBUF],(char *)dz->sbufptr[IBUF],obufleft * sizeof(float));
+			dz->sbufptr[IBUF]  += obufleft;
+			ibufleft -= obufleft;
+			if((exit_status = write_samps(dz->sampbuf[OBUF],dz->buflen,dz))<0)
+				return(exit_status);
+			dz->sbufptr[OBUF]   = dz->sampbuf[OBUF];
+			obufleft  = dz->buflen;
+			break;
+		}
+	}
+	return(FINISHED);
+}
+
+
+/************************* COPY_EXCISE_CHUNK *************************/ 
+
+int copy_excise_chunk(int *last_total_samps,int *obufleft,int *ibufleft,int k,dataptr dz)
+{
+	int exit_status;
+	int samps_to_copy = dz->lparray[CUT_STTSPLI][k] - (*last_total_samps + (dz->sbufptr[IBUF] - dz->sampbuf[IBUF]));
+	while(samps_to_copy>0) {
+		if((*obufleft > *ibufleft) && (samps_to_copy >= *ibufleft)) {
+			memcpy((char *)dz->sbufptr[OBUF],(char *)dz->sbufptr[IBUF],(*ibufleft)*sizeof(float));
+			samps_to_copy -= *ibufleft;
+			*obufleft     -= *ibufleft;
+			dz->sbufptr[OBUF]       += *ibufleft;
+			*last_total_samps = dz->total_samps_read;
+		    if((exit_status = read_samps(dz->sampbuf[IBUF],dz))<0)
+				return(exit_status);
+			dz->sbufptr[IBUF]   = dz->sampbuf[IBUF];					 
+			*ibufleft  = dz->buflen;
+		} else if((*ibufleft >= *obufleft) && (samps_to_copy >= *obufleft)) {
+ 			memcpy((char *)dz->sbufptr[OBUF],(char *)dz->sbufptr[IBUF],(*obufleft)*sizeof(float));
+			if((exit_status = write_samps(dz->sampbuf[OBUF],dz->buflen,dz))<0)
+				return(exit_status);
+			samps_to_copy -= *obufleft;
+			*ibufleft      -= *obufleft;
+			dz->sbufptr[IBUF]       += *obufleft;
+			dz->sbufptr[OBUF]   = dz->sampbuf[OBUF];
+			*obufleft  = dz->buflen;
+		} else {
+			memcpy((char *)dz->sbufptr[OBUF],(char *)dz->sbufptr[IBUF],samps_to_copy*sizeof(float));
+			dz->sbufptr[OBUF] += samps_to_copy;
+			*obufleft -= samps_to_copy;
+			dz->sbufptr[IBUF] += samps_to_copy;
+			*ibufleft -= samps_to_copy;
+			samps_to_copy = 0;
+		}
+	}
+	return(FINISHED);
+}
+
+/******************************** DO_INSERT **********************************/
+
+int do_insert(dataptr dz)
+{
+	int exit_status;
+	int seektest;
+	float	*cp;				/* current buffer pointer */
+	int	ref, ssampsread;	/* reference value for insert loop */
+	int		first = TRUE;		/* first is first read flag */
+	int	buffxs2, samps_to_read, sects_to_read, samps_read,n, m, samps_in_buf, remainder, outsize = 0;
+// TW 2010
+	int	/* secs_to_write, */ samps_to_move, seek_samps = 0, seek_sects, samps_to_write;
+	int 	c;
+	short	shsecsize = F_SECSIZE;
+
+	dz->total_samps_written = 0;	
+
+	if(algo2) {
+		while(dz->total_samps_written < dz->tempsize) {
+			memset((char *)dz->bigbuf,0,dz->buflen * sizeof(float));
+			if(dz->total_samps_read < dz->insams[0]) {
+				if((exit_status = read_samps(dz->bigbuf,dz))<0)
+					return(exit_status);
+			}
+			if((samps_to_write = min(dz->buflen,dz->tempsize - dz->total_samps_written)) > 0) {
+				if((exit_status = write_samps(dz->bigbuf,samps_to_write,dz))<0)
+					return(exit_status);
+			}
+		}
+		return(FINISHED);
+	}
+
+	ref = dz->buflen - F_SECSIZE;
+
+	/* READ FIRST PART OF INFILE, AND GET SPLICE SECTION */
+	fprintf(stdout,"INFO: Reading first file\n");
+	fflush(stdout);
+	for(c = 1; c <= dz->iparam[CUT_BUFCNT]; c++) {	   /* ANY WHOLE BUFFERS COPIED */
+		if((samps_read  = fgetfbufEx(dz->sampbuf[0], dz->buflen,dz->ifd[0],0))!=dz->buflen) {
+			sprintf(errstr,"Bad sound read 7.\n");
+			if(samps_read<0)
+				return(SYSTEM_ERROR);
+			return(PROGRAM_ERROR);
+		}
+//		if((samps_written = fputfbufEx(dz->sampbuf[0], dz->buflen,dz->ofd))!=samps_read) {
+		if((exit_status = write_samps(dz->sampbuf[0],dz->buflen,dz))< 0)
+			return(exit_status);
+	}
+
+	if(dz->iparam[CUT_SECCNT]) {	   	/* SPARE SECTORS BEFORE SPLICE */
+		samps_to_read = dz->iparam[CUT_SECCNT] * F_SECSIZE;
+		if((samps_read  = fgetfbufEx(dz->sampbuf[0],samps_to_read,dz->ifd[0],0))!=samps_to_read) {
+			sprintf(errstr,"Bad sound read 8.\n");
+			if(samps_read<0)
+				return(SYSTEM_ERROR);
+			return(PROGRAM_ERROR);
+		}
+		if(samps_read > 0) {
+			if((exit_status =  write_samps(dz->sampbuf[0],samps_read,dz)) < 0)
+				return(exit_status);
+		}
+	}
+
+	if((samps_read  = fgetfbufEx(dz->sampbuf[0], dz->iparam[CUT_SECSREMAIN] * F_SECSIZE,dz->ifd[0],0))<=0) {
+		if(samps_read<0) {
+			sprintf(errstr,"Bad sound read 9.\n");
+			return(SYSTEM_ERROR);
+		} else if(dz->iparam[CUT_SECSREMAIN] > 0) {
+			sprintf(errstr,"Bad sound read 9.\n");
+			return(PROGRAM_ERROR);
+		}
+	}
+	samps_to_move = (dz->iparam[CUT_SECSREMAIN] * F_SECSIZE) - dz->iparam[CUT_BUFXS];
+	if(samps_to_move<0) {
+		sprintf(errstr,"Arithmetic problem 1\n");
+		return(PROGRAM_ERROR);
+	}
+	if(samps_to_move) {
+		memcpy((char *)dz->sampbuf[SPLBUF],(char *)(dz->sampbuf[0] + dz->iparam[CUT_BUFXS]),
+			samps_to_move * sizeof(float));
+		if(!dz->vflag[INSERT_OVERWRITE])
+			memcpy((char *)dz->sampbuf[SAVEBUF],(char *)dz->sampbuf[SPLBUF],
+			   samps_to_move * sizeof(float));
+	}
+	if(dz->iparam[CUT_SPLEN] > 0) {
+		dosplice(dz->sampbuf[SPLBUF], dz->iparam[CUT_SPLEN], dz->infile->channels, DOWNSLOPE);
+		if(!dz->vflag[INSERT_OVERWRITE])
+			dosplice(dz->sampbuf[SAVEBUF], dz->iparam[CUT_SPLEN], dz->infile->channels, UPSLOPE);
+	}
+	cp = dz->sampbuf[0] + dz->iparam[CUT_BUFXS];
+	memset((char *)cp,0,(dz->buflen - dz->iparam[CUT_BUFXS]) * sizeof(float));
+	if((dz->process == EDIT_INSERT2) || dz->vflag[INSERT_OVERWRITE]) {
+		switch(dz->process) {
+		case(EDIT_INSERT2):
+			seek_samps = dz->iparam[CUT_END] - (2 * dz->iparam[CUT_SPLEN]);
+			break;
+		case(EDIT_INSERT):
+			seek_samps = dz->iparam[CUT_CUT] + dz->insams[1] 
+				- (2 * dz->iparam[CUT_SPLEN]);
+			break;
+		case(EDIT_INSERTSIL):
+			if(silent_end)
+				seek_samps = dz->iparam[CUT_CUT] - dz->iparam[CUT_SPLEN];
+			else
+				seek_samps = dz->iparam[CUT_CUT] 
+				     + dz->iparam[CUT_LEN] - (2 * dz->iparam[CUT_SPLEN]);
+			break;
+		}
+		seek_sects = seek_samps / F_SECSIZE;
+		if((seektest = sndseekEx(dz->ifd[0],seek_sects * F_SECSIZE,0))!=seek_sects * F_SECSIZE) {
+			if(seektest<0) {
+				sprintf(errstr,"Seek failed.\n");
+				return(SYSTEM_ERROR);
+			} else {
+				sprintf(errstr,"Seek problem 1 in insert().\n");
+				return(PROGRAM_ERROR);
+			}
+		}
+		buffxs2 = 	(seek_samps - (seek_sects * F_SECSIZE));
+
+		samps_to_read = dz->iparam[CUT_SPLEN] + buffxs2 + F_SECSIZE;
+		if(((sects_to_read = samps_to_read/F_SECSIZE) * F_SECSIZE)!= samps_to_read)
+			sects_to_read++;
+		samps_to_read = sects_to_read * F_SECSIZE;
+		if((samps_read = fgetfbufEx(dz->sampbuf[SAVEBUF],samps_to_read,dz->ifd[0],0))<=0) {
+			sprintf(errstr,"Bad sound read 10.\n");
+			if(samps_read<0)
+				return(SYSTEM_ERROR);
+			return(PROGRAM_ERROR);
+		}
+		ssampsread = samps_read;
+		if(buffxs2) {
+			for(n=0,m = buffxs2;n<ssampsread - buffxs2;n++,m++)
+				dz->sampbuf[SAVEBUF][n] = dz->sampbuf[SAVEBUF][m];
+		}
+		dz->iparam[CUT_BUFREMNANT] = ssampsread - (buffxs2 + dz->iparam[CUT_SPLEN]);
+		dosplice(dz->sampbuf[SAVEBUF], dz->iparam[CUT_SPLEN], dz->infile->channels, UPSLOPE);
+	}											
+
+	switch(dz->process) {
+	case(EDIT_INSERT):
+	case(EDIT_INSERT2):
+		fprintf(stdout,"INFO: Inserting file.\n");
+		break;
+	case(EDIT_INSERTSIL):
+		fprintf(stdout,"INFO: Inserting silence\n");
+		break;
+	}
+	fflush(stdout);
+ 	for(c = 1; c <= dz->iparam[CUT_BUFCNT2]; c++) {	   /* ANY WHOLE BUFFERS COPIED */	  
+		switch(dz->process) {
+		case(EDIT_INSERT):
+		case(EDIT_INSERT2):
+			if((samps_read  = fgetfbufEx(cp, dz->iparam[SMALLBUFSIZ],dz->ifd[1],0))!=dz->iparam[SMALLBUFSIZ]) {
+				sprintf(errstr,"Bad sound read 11.\n");
+				if(samps_read<0)
+					return(SYSTEM_ERROR);
+				return(PROGRAM_ERROR);
+			}
+			if(!flteq(dz->param[INSERT_LEVEL],1.0)) {
+			 	if((exit_status = gain_insert_buffer(cp,dz->iparam[SMALLBUFSIZ],dz->param[INSERT_LEVEL]))<0)
+					return(exit_status);
+			}
+			break;
+		case(EDIT_INSERTSIL):
+			memset((char *)cp,0, dz->iparam[SMALLBUFSIZ] * sizeof(float));
+			break;
+		}
+		if(first) {
+			first = FALSE;
+			if(dz->iparam[CUT_SPLEN] > 0) {/* splice beginning of input */
+				if(dz->process==EDIT_INSERT)
+					dosplice(cp, dz->iparam[CUT_SPLEN], dz->infile->channels, UPSLOPE);
+				for(n=0;n<dz->iparam[CUT_SPLEN];n++)
+					cp[n] += dz->sampbuf[SPLBUF][n];   /* creates cross-splice */
+			}
+		}
+		if(dz->iparam[SMALLBUFSIZ] > 0) {
+			if((exit_status = write_samps(dz->sampbuf[0],dz->iparam[SMALLBUFSIZ],dz)) < 0)
+				return(exit_status);
+		}
+		if(dz->iparam[CUT_BUFXS]) {	
+			cp = dz->sampbuf[0] + ref;
+			movmem((char *)cp, (char *)dz->sampbuf[0], dz->iparam[CUT_BUFXS] * sizeof(float));
+			cp = dz->sampbuf[0] + dz->iparam[CUT_BUFXS];
+		}
+	}
+
+	if(dz->iparam[CUT_SECCNT2]) {	   	/* SPARE SECTORS BEFORE END SPLICE */
+		switch(dz->process) {
+		case(EDIT_INSERT):
+		case(EDIT_INSERT2):
+	 		if((samps_read  = 
+	 		fgetfbufEx(cp,  dz->iparam[CUT_SECCNT2] * F_SECSIZE,dz->ifd[1],0))!=dz->iparam[CUT_SECCNT2] * F_SECSIZE) {
+				sprintf(errstr,"Bad sound read 12.\n");
+				if(samps_read<0)
+					return(SYSTEM_ERROR);
+				return(PROGRAM_ERROR);
+			}
+			if(!flteq(dz->param[INSERT_LEVEL],1.0)) {
+			 	if((exit_status = gain_insert_buffer(cp,dz->iparam[CUT_SECCNT2] * F_SECSIZE,dz->param[INSERT_LEVEL]))<0)
+					return(exit_status);
+			}
+			break;
+		case(EDIT_INSERTSIL):
+			memset((char *)cp,0,  (dz->iparam[CUT_SECCNT2] * F_SECSIZE) * sizeof(float));
+			break;
+		}
+		if(first) {
+			first = FALSE;
+			if(dz->iparam[CUT_SPLEN] > 0)  {/* splice beginning of input */
+				if(dz->process==EDIT_INSERT)
+					dosplice(cp, dz->iparam[CUT_SPLEN], dz->infile->channels, UPSLOPE);
+				for(n=0;n<dz->iparam[CUT_SPLEN];n++)
+					cp[n] += dz->sampbuf[SPLBUF][n];
+			}
+		}
+		if(dz->iparam[CUT_SECCNT2] > 0) {	
+			if((exit_status = write_samps(dz->sampbuf[0],dz->iparam[CUT_SECCNT2] * F_SECSIZE,dz)) < 0)
+				return(exit_status);
+		}
+		if(dz->iparam[CUT_BUFXS]) {	
+			cp = dz->sampbuf[0] + (dz->iparam[CUT_SECCNT2] * shsecsize);
+			movmem((char *)cp, (char *)dz->sampbuf[0], 
+				dz->iparam[CUT_BUFXS] * sizeof(float));
+			cp = dz->sampbuf[0] + dz->iparam[CUT_BUFXS];
+		}
+	}
+ 	
+	switch(dz->process) {
+	case(EDIT_INSERT):
+	case(EDIT_INSERT2):
+		if((samps_read  = 
+ 		fgetfbufEx(cp, dz->iparam[CUT_SECSREMAIN2] * F_SECSIZE,dz->ifd[1],0))<=0) {
+			sprintf(errstr,"Bad sound read 13.\n");
+			if(samps_read<0)
+				return(SYSTEM_ERROR);
+			return(PROGRAM_ERROR);
+		}
+		if(!flteq(dz->param[INSERT_LEVEL],1.0)) {
+		 	if((exit_status = gain_insert_buffer(cp,dz->iparam[CUT_SECSREMAIN2] * F_SECSIZE,dz->param[INSERT_LEVEL]))<0)
+				return(exit_status);
+		}
+		break;
+	case(EDIT_INSERTSIL):
+		memset((char *)cp,0,(dz->iparam[CUT_SECSREMAIN2] * F_SECSIZE) * sizeof(float));
+		break;
+	}
+	if(first) {	/* NO SECTORS BEFORE END SPLICE STARTS */
+
+		if(dz->iparam[CUT_SPLEN]>0) { /* splice beginning of file */
+			if(dz->process==EDIT_INSERT || dz->process==EDIT_INSERT2)
+				dosplice(cp, dz->iparam[CUT_SPLEN], dz->infile->channels, UPSLOPE);
+			for(n=0;n<dz->iparam[CUT_SPLEN];n++)
+				cp[n] += dz->sampbuf[SPLBUF][n];
+		}
+	}
+	cp = dz->sampbuf[0] + dz->iparam[CUT_BUFXS] + dz->iparam[CUT_SMPSREMAIN];
+	if(dz->iparam[CUT_SPLEN]>0) {
+		cp -= dz->iparam[CUT_SPLEN];
+		if(dz->process==EDIT_INSERT || dz->process==EDIT_INSERT2)
+			dosplice(cp, dz->iparam[CUT_SPLEN], dz->infile->channels, DOWNSLOPE);
+		if(!silent_end) {
+			for(n=0;n<dz->iparam[CUT_SPLEN];n++)
+				cp[n] += dz->sampbuf[SAVEBUF][n];
+		}
+		cp += dz->iparam[CUT_SPLEN];
+	}
+	for(n=0,m=dz->iparam[CUT_SPLEN];n<dz->iparam[CUT_BUFREMNANT];n++,m++) {
+		if(silent_end)
+//			cp[n] = (short)0;
+			cp[n] = (float)0;
+		else
+			cp[n] = dz->sampbuf[SAVEBUF][m];
+	}
+	cp += dz->iparam[CUT_BUFREMNANT];
+	samps_in_buf = cp - dz->sampbuf[0];
+	dz->iparam[CUT_SECCNT] = samps_in_buf/shsecsize;
+	dz->iparam[CUT_BUFXS]  = samps_in_buf - (dz->iparam[CUT_SECCNT] * shsecsize);
+	if(dz->iparam[CUT_SECCNT] > 0) {
+		if((exit_status = write_samps(dz->sampbuf[0],dz->iparam[CUT_SECCNT] * F_SECSIZE,dz)) < 0)
+			return(exit_status);
+	}
+	cp = dz->sampbuf[0] + (dz->iparam[CUT_SECCNT] * shsecsize);
+	movmem((char *)cp, (char *)dz->sampbuf[0], 
+		dz->iparam[CUT_BUFXS] * sizeof(float));
+	cp = dz->sampbuf[0] + dz->iparam[CUT_BUFXS];
+	remainder = dz->iparam[CUT_BUFXS];
+	
+	fprintf(stdout,"INFO: Reading remainder of infile.\n");
+	fflush(stdout);
+	while((samps_read = fgetfbufEx(cp, dz->iparam[SMALLBUFSIZ],dz->ifd[0],0)) > 0) {
+		samps_to_write = min(dz->iparam[SMALLBUFSIZ],samps_read + dz->iparam[CUT_BUFXS]);
+		remainder      = samps_read - ((dz->iparam[SMALLBUFSIZ]) - dz->iparam[CUT_BUFXS]);
+		if(silent_end)
+			memset((char *)dz->sampbuf[0],0,dz->buflen * sizeof(float));
+		if(samps_to_write > 0) {
+			if((exit_status = write_samps(dz->sampbuf[0],samps_to_write,dz)) < 0)
+				return(exit_status);
+		}
+		if(remainder > 0) {
+			cp = dz->sampbuf[0] + ref;
+ 			movmem((char *)cp, (char *)dz->sampbuf[0], remainder * sizeof(float));
+			cp = dz->sampbuf[0] + dz->iparam[CUT_BUFXS];
+		}
+	}
+	if(samps_read<0) {
+		sprintf(errstr,"Bad sound read.\n");
+		return(SYSTEM_ERROR);
+	}
+	if(remainder > 0) {
+		if((exit_status = write_samps(dz->sampbuf[0],remainder,dz))<=0)
+			return(exit_status);
+	}				  
+	
+	if (dz->process == EDIT_INSERT2)
+		outsize = dz->insams[0] + dz->insams[1] - dz->iparam[CUT_SPLEN];
+	else if(dz->vflag[INSERT_OVERWRITE])
+		outsize = dz->insams[0];
+	else {
+		switch(dz->process) {
+		case(EDIT_INSERT):
+			outsize = dz->insams[0] + dz->insams[1] - dz->iparam[CUT_SPLEN];
+			break;
+		case(EDIT_INSERTSIL):
+			outsize = dz->insams[0] + dz->iparam[CUT_LEN] 
+				- dz->iparam[CUT_SPLEN];
+			break;
+		}
+	}
+	dz->total_samps_written = outsize; /* for truncation calculations */
+   	return(FINISHED);
+}
+
+
+/******************************** GAIN_INSERT_BUFFER ********************************/ 
+
+int gain_insert_buffer(float *thisbuf,int size,double gain)
+{
+	int n;
+	double d;
+	if(gain > 1.0) {
+		for(n=0;n < size; n++) {
+			if(fabs(d = (double)thisbuf[n] * gain) > (double)F_MAXSAMP) {
+				sprintf(errstr,"gain has caused insertfile to distort.\n");
+				return(DATA_ERROR);
+			}
+			thisbuf[n] = (float) /*round*/(d);
+		}
+	} else {
+		for(n=0;n < size; n++)
+			thisbuf[n] = (float) /*round*/((double)thisbuf[n] * gain);
+	}
+	return(FINISHED);
+}
+
+/******************************** SETUP_EXCISE_OUTDISPLAY_LEN ********************************/ 
+
+void setup_excise_outdisplay_len(dataptr dz)
+{
+	int n;
+	dz->tempsize = dz->insams[0];
+	for(n=0;n<dz->iparam[EXCISE_CNT]-1;n++)
+		dz->tempsize -= dz->lparray[CUT_ENDSAMP][n] - dz->lparray[CUT_STTSAMP][n];
+	if(dz->iparam[CUT_NO_END])
+		dz->tempsize -= dz->insams[0] - dz->lparray[CUT_STTSAMP][n];
+	else
+		dz->tempsize -= dz->lparray[CUT_ENDSAMP][n] - dz->lparray[CUT_STTSAMP][n];
+	if(dz->tempsize<=0)
+		dz->tempsize = 1;	/* trap later divides by zero !! */
+}
+
+/************************** JOIN_PCONSISTENCY ***************************/
+
+int join_pconsistency(dataptr dz)
+{
+	int n, m;
+	int stsplen;
+	double *p, *q;
+	double sr = (double)dz->infile->srate;
+	int chans = dz->infile->channels;
+		 
+	stsplen = round(dz->param[CUT_SPLEN] * MS_TO_SECS * sr);
+	dz->iparam[CUT_SPLEN]     = stsplen * chans;
+
+	if((dz->parray[SPLICE_UP] = (double *)malloc(stsplen * sizeof(double)))==NULL) {
+		sprintf(errstr,"INSUFFICENT MEMORY for first splice table.\n");
+		return(MEMORY_ERROR);
+	}
+	if((dz->parray[SPLICE_DN] = (double *)malloc(stsplen * sizeof(double)))==NULL) {
+		sprintf(errstr,"INSUFFICENT MEMORY for 2nd splice table.\n");
+		return(MEMORY_ERROR);
+	}
+	p = dz->parray[SPLICE_UP];
+	q = dz->parray[SPLICE_DN];
+	for(n=0;n<stsplen;n++) {
+		*p++ = (double)n/(double)stsplen;    
+		*q++ = (double)(stsplen-n)/(double)stsplen;    
+	}
+	if(dz->insams[0] < 2 * dz->iparam[CUT_SPLEN]) {
+		sprintf(errstr,"File 1 too short for specified spliclength.\n");
+		return(DATA_ERROR);
+	}	
+	dz->tempsize = dz->insams[0];
+	switch(dz->process) {
+	case(EDIT_JOIN):
+		dz->tempsize = dz->insams[0];
+		for(n=1;n<dz->infilecnt;n++) {
+			if(dz->insams[n] < 2 * dz->iparam[CUT_SPLEN]) {
+				sprintf(errstr,"File %d too short for specified spliclength.\n",n+1);
+				return(DATA_ERROR);
+			}	
+			dz->tempsize += dz->insams[n] - dz->iparam[CUT_SPLEN];
+		}
+		break;
+	case(JOIN_SEQDYN):
+		dz->tempsize = 0;
+		for(n=0;n<dz->itemcnt;n++) {
+			m = dz->iparray[0][n];
+			if(dz->insams[m] < 2 * dz->iparam[CUT_SPLEN]) {
+				sprintf(errstr,"File %d too short for specified splicelength.\n",m+1);
+				return(DATA_ERROR);
+			}	
+			dz->tempsize += dz->insams[m] - dz->iparam[CUT_SPLEN];
+		}
+		break;
+	case(JOIN_SEQ):
+		dz->tempsize = 0;
+		for(n=0;n<dz->itemcnt;n++) {
+			if(n >= dz->iparam[MAX_LEN])
+				break;
+			m = dz->iparray[0][n];
+			if(dz->insams[m] < 2 * dz->iparam[CUT_SPLEN]) {
+				sprintf(errstr,"File %d too short for specified splicelength.\n",m+1);
+				return(DATA_ERROR);
+			}	
+			dz->tempsize += dz->insams[m] - dz->iparam[CUT_SPLEN];
+		}
+		break;
+	}
+
+	return(FINISHED);
+}
+
+/************************** CREATE_JOIN_BUFFER ***************************/
+
+int create_join_buffer(dataptr dz)
+{
+	int seccnt;
+	size_t bigbufsize;
+	int framesize = F_SECSIZE * dz->infile->channels;
+	int fl_secsize = F_SECSIZE * sizeof(float);
+	int splicelen = dz->iparam[CUT_SPLEN] * dz->infile->channels;
+
+	bigbufsize = (size_t) Malloc(-1);
+	bigbufsize = (bigbufsize/fl_secsize) * fl_secsize;
+	bigbufsize -= fl_secsize;
+
+	dz->buflen = (int)(bigbufsize/sizeof(float));
+	dz->buflen = (dz->buflen/framesize) * framesize; 
+	if(dz->buflen <= 0)
+		dz->buflen = framesize;
+	if(splicelen > dz->buflen - F_SECSIZE) {
+		dz->buflen = splicelen;
+		if(((seccnt = dz->buflen/framesize) * framesize) < dz->buflen)
+			seccnt++;
+		dz->buflen = seccnt * framesize;
+	}
+	if(dz->buflen<=0
+	|| (dz->bigbuf = (float *)malloc(sizeof(float) * (dz->buflen + F_SECSIZE 
+		   + splicelen)))==NULL) {
+		sprintf(errstr, "INSUFFICIENT MEMORY for sounds.\n");
+		return(MEMORY_ERROR);
+	}
+	dz->sampbuf[BBUF] = dz->bigbuf;
+	dz->sampbuf[BUFEND] = dz->sampbuf[BBUF] + dz->buflen;
+	dz->sampbuf[SPLICEBUF] = dz->sampbuf[BUFEND] + F_SECSIZE;
+	return(FINISHED);
+}
+
+/************************** CREATE_JOIN_SEQ_BUFFER ***************************/
+
+int create_join_seq_buffer(dataptr dz)
+{
+	int seccnt, OK = 0;
+	int last_buflen = 0;
+	int framesize = F_SECSIZE * dz->infile->channels;
+	int fl_secsize = F_SECSIZE * sizeof(float);
+	size_t bigbufsize = (size_t) Malloc(-1);
+
+	bigbufsize = (bigbufsize/fl_secsize) * fl_secsize;
+	bigbufsize -= fl_secsize;						/* Leave F_SECSIZE available for malloc */
+
+	dz->buflen = (int)(bigbufsize/sizeof(float));
+	dz->buflen = (dz->buflen/framesize) * framesize; 
+	if(dz->buflen <= 0)
+		dz->buflen = framesize;
+
+	while(!OK) {	
+		if(dz->buflen <= last_buflen) {
+			sprintf(errstr, "Too many channels to cope with.\n");
+			return(MEMORY_ERROR);
+	    }
+		if(dz->buflen<=0
+	    || (dz->bigbuf = (float *)malloc(sizeof(float) * ((dz->buflen * 2) + F_SECSIZE 
+		       + dz->iparam[CUT_SPLEN])))==NULL) {
+			sprintf(errstr, "INSUFFICIENT MEMORY for sounds.\n");
+			return(MEMORY_ERROR);
+	    }
+		last_buflen = dz->buflen;
+	 	dz->sampbuf[COPYBUF] = dz->bigbuf;
+	 	dz->bigbuf += dz->buflen;
+	 	dz->sampbuf[BBUF] = dz->bigbuf;
+	    dz->sampbuf[BUFEND] = dz->sampbuf[BBUF] + dz->buflen;
+		dz->sampbuf[SPLICEBUF] = dz->sampbuf[BUFEND] + F_SECSIZE;
+	    if(dz->iparam[CUT_SPLEN] <= dz->buflen - F_SECSIZE)	/* splice must fit in buffer */
+			OK = 1;
+		else {
+			dz->buflen = dz->iparam[CUT_SPLEN];
+			if(((seccnt = dz->buflen/framesize) * framesize) < dz->buflen)
+				seccnt++;
+			dz->buflen = seccnt * framesize;
+		}
+	}
+	return(FINISHED);
+}
+
+/*************************** DO_JOINING *****************************
+ *
+ * (A)	Sets special loop condition for zero splice length, see (B).
+ * (0)	For every input file.
+ * (1)	Set 'samps_to_get' to equal size of file MINUS number of samps
+ *	we will use in end-of0-file splice.
+ * (2)	Set the total_fsamps_read to zero..
+ * (3)	and the number of reads OF THIS FILE to zero.
+ * (4)	NORMAL CASE lmt = 0.
+ 	Read the file. Note the number of samps read. Add this to the total
+ *	number of samps read from this file.
+ *	If the TOTAL number of samps read, EXCEEDS 'samps_to_get' then we
+ *	have read some samps in the END SPLICE REGION. The number of those
+ *	samps is 'overspill'.
+ * 	  If we have not read any samps in END SPLICE REGION...
+ *	  (i.e. we cannot be at the end of the file, and hence we must have
+ *	  read a FULL BUFFER!!!).
+ * (B)	ZERO SPLICE LENGTH CASE, LMT = -1.
+ *	  In this case, an overspill of zero just tells us that the
+ *	  entire block has been read .. no special adjustments need
+ *	  to be made for splice overlaps, so we can drop out of
+ *	  the while loop when we get ZERO overspill in this case.
+ *   (5)  If this is the first read of this file, then the START-SPLICE must
+ *	  be in the buffer. So do the start-splice IN SITU.
+ *   (6)  As the END_SPLICE is not in the buffer, and the buffer is full,
+ *	  we can WRITE the whole existing buffer to the output.
+ *   (7)  Increment the count of reads OF THIS FILE.
+ * (8)  If we have left the read_loop for the current file, with readcnt
+ *	remaining at zero, the start of the current file must be in the
+ *	current buffer.
+ *	We can therefore do the start_splice IN SITU in the current buffer.
+ * (9)	Housekeep1
+ *	   (a)	finds the address of the start of end_splice
+ *	   (b) 	copies whatever part of the splice is in the buffer, into
+ *		the splice buffer.
+ * (10)	If not all of the splice is in this buffer (splice_remnant>0)...
+ *	   (a)	Reads rest of splice directly to splice buffer
+ *	   (b)	finds the size and address of any part-sector existing
+ *		just prior to the splice-area.
+ *	   (c)	Writes the whole buufer up to start of this part-sector..
+ *	   (d)	copies part_sector to start of buffer
+ *	   (e)  resets readbuf address and size of readbuffer.
+ * (11) Otherwise, reset the read-place in buffer, and the (remaining) size
+ *	of the read_buffer.
+ * (12) On leaving loop, do any splice required at end of file.
+ * (13)	Flush buffer.
+ */
+
+int do_joining(dataptr dz)
+{
+	int  exit_status;
+	int total_fsamps_read, samps_to_get, samps_read, samps_to_write;
+	int	 n, readcnt, lmt = 0;
+	int  overspill, splice_remnant;
+	dz->iparam[CUT_SMPSREMAIN] = dz->buflen;
+	dz->sampbuf[READBUF]       = dz->sampbuf[BBUF];
+	if(dz->iparam[CUT_SPLEN]==0)
+		lmt = -1;									/* A */
+	for(n=0;n<dz->infilecnt;n++) {					/* 0 */
+		fprintf(stdout,"INFO: Processing FILE %d\n",n+1);
+		fflush(stdout);
+		if((samps_to_get = dz->insams[n] - dz->iparam[CUT_SPLEN])<=0) {
+			sprintf(errstr,"File %d is too short for the given splicelength\n",n+1);
+			return(GOAL_FAILED);
+		}
+																				/* 1 */
+		total_fsamps_read = 0;													/* 2 */
+		readcnt = 0;															/* 3 */
+		for(;;) {
+			if((samps_read = fgetfbufEx(dz->sampbuf[READBUF],
+				     dz->iparam[CUT_SMPSREMAIN],dz->ifd[n],0))<0)  {
+				sprintf(errstr, "Can't read from input soundfile\n");
+				return(SYSTEM_ERROR);
+			}
+			overspill = (total_fsamps_read += samps_read) - samps_to_get;
+			if(overspill > lmt)
+				break;
+			if(dz->iparam[CUT_SPLEN]>0 && readcnt==0)							/* B */
+				do_join_startsplice(n,dz);										/* 5 */
+			if((exit_status = write_exact_samps(dz->sampbuf[BBUF],dz->buflen,dz))<0)	
+				return(exit_status);											/* 6 */
+			housekeep2(samps_read,dz);
+			readcnt++;															/* 7 */
+		}
+		if(dz->iparam[CUT_SPLEN]>0) {
+			if(readcnt==0)														/* 8 */
+				do_join_startsplice(n,dz);
+			housekeep1(samps_read,overspill,dz);								/* 9 */
+			if((splice_remnant = dz->iparam[CUT_SPLEN] - overspill)>0)	{	/* 10 */
+				if((exit_status = do_join_write(n,splice_remnant,(int)(overspill),dz))<0)
+					return(exit_status);
+			} else {
+				if((exit_status = reset_join_buffer_params(dz))<0)				/* 11 */
+					return(exit_status);
+			}
+		} else {
+			dz->sbufptr[ENDSPLICE_ADDR] = dz->sampbuf[READBUF] + samps_read;
+			if((exit_status = reset_join_buffer_params(dz))<0)
+				return(exit_status);
+		}
+		if(sndcloseEx(dz->ifd[n]) < 0) {
+		    fprintf(stdout, "WARNING: Can't close input soundfile %d\n",n+1);
+			fflush(stdout);
+		}
+		dz->ifd[n] = -1;
+	}
+	if(dz->iparam[CUT_SPLEN]>0) {
+		if(dz->vflag[SPLICE_END])												/* 12 */
+			do_join_endsplice(dz);
+		memcpy((char *)dz->sampbuf[READBUF],(char *)dz->sampbuf[SPLICEBUF],
+			dz->iparam[CUT_SPLEN] * sizeof(float));
+	}		
+	if((samps_to_write = dz->sampbuf[READBUF] + dz->iparam[CUT_SPLEN] - dz->sampbuf[BBUF])>0)
+		return write_samps(dz->sampbuf[BBUF],samps_to_write,dz);				/* 13 */
+	return FINISHED;
+}
+
+/************************ READ_JOIN_SPLICE_REMNANT ********************************
+ *
+ * Reads any EXTRA bit of the splice NOT captured in main buffer.
+ */
+
+int read_join_splice_remnant(int n,int splice_remnant,int oversamps,dataptr dz)
+{
+	int toread = splice_remnant/F_SECSIZE, samps_read;
+	if((toread * F_SECSIZE) != splice_remnant)
+		toread += 1;
+	toread *= F_SECSIZE;
+     	/* MUST ASK FOR WHOLE NO OF SECTORS : AND THIS MUST BE >= NO OF SAMPS WANTED */
+	if((samps_read = fgetfbufEx(dz->sampbuf[SPLICEBUF] + oversamps,toread,dz->ifd[n],0))<0) {
+		sprintf(errstr,"Can't read samples for splice from input soundfile.\n");
+		return(SYSTEM_ERROR);
+	}
+	if(samps_read != splice_remnant) {
+		sprintf(errstr,"Problem reading part splice-buffer.\n");
+		return(PROGRAM_ERROR);
+	}
+	return(FINISHED);
+}
+
+/********************************* DO_JOIN_STARTSPLICE ************************/
+
+void do_join_startsplice(int k,dataptr dz)
+{   
+	int n;
+	int m;
+	float *a = dz->sampbuf[READBUF];
+	float *b = dz->sampbuf[SPLICEBUF];
+	int chans = dz->infile->channels;
+	double *p = dz->parray[SPLICE_UP];
+	double *q = dz->parray[SPLICE_DN];
+    a = dz->sampbuf[READBUF];
+	if(k==0)
+		do_join_initial_splice(chans,dz);
+	else {
+		for(n=0;n<dz->iparam[CUT_SPLEN];n+=chans) {
+			for(m=0;m<chans;m++) {
+				*a= (float) /*round*/((*q * (double)(*b)) + (*p * (double)(*a)));
+				a++;
+				b++;
+			}
+			p++;
+			q++;
+		}
+	}
+}
+
+/************************** DO_JOIN_INITIAL_SPLICE ********************************/
+
+void do_join_initial_splice(int chans,dataptr dz)
+{   
+	int n;
+	int m;
+	float *a = dz->sampbuf[BBUF];
+	double *p = dz->parray[SPLICE_UP];
+	if(dz->vflag[SPLICE_START]) {
+		for(n=0;n<dz->iparam[CUT_SPLEN];n+=chans) {
+			for(m=0;m<chans;m++) {
+				*a = (float) /*round*/(*p  * (double)(*a));
+				a++;
+			}
+			p++;
+		}
+	}
+}
+
+/*********************************** DO_JOIN_ENDSPLICE **************************
+ *
+ * Put a fade on data in splice_buffer.
+ */
+
+void do_join_endsplice(dataptr dz)
+{   
+	int n;
+	int m, chans = dz->infile->channels;
+	float *b = dz->sampbuf[SPLICEBUF];
+    double *q = dz->parray[SPLICE_DN];
+    for(n=0;n<dz->iparam[CUT_SPLEN];n+=chans) {
+		for(m=0;m<chans;m++) {
+			*b = (float) /*round*/(*q  * (double)(*b));
+			b++;
+		}
+		q++;
+    }
+}
+
+/************************* HOUSEKEEP1 *******************************
+ *
+ * (1)	'body' is the number of samps of the current file, in the
+ *	current buffer, NOT COUNTING the splice portion.
+ * (2)  ENDSPLICE_ADDR, is offset from the address where we
+ * 	last read into this buffer, by 'body'.
+ * (3)	Copy whatever part of the end-splice region is in this buffer
+ *	into the splice-buffer.
+ */
+
+void housekeep1(int samps_read,int overspill,dataptr dz)
+{   
+	int body = (samps_read - overspill);										/* 1 */
+	dz->sbufptr[ENDSPLICE_ADDR] = dz->sampbuf[READBUF] + body;								/* 2 */
+	memcpy((char *)dz->sampbuf[SPLICEBUF],(char *)dz->sbufptr[ENDSPLICE_ADDR],overspill * sizeof(float));	/* 3 */
+}
+
+/************************* HOUSEKEEP2 *******************************
+ *
+ * (1)	Find end of final write into this buffer.
+ * (2)	Find size of part-sector written beyond ACTUAL (read) buffer.
+ * (3)	Copy part-sector to start of ACTUAL buffer.
+ * (4) 	Reset start of readbuf to end of this part-sector.
+ * (5) 	Set size of readbuffer to full-size (we have an extra sector for
+ *	overrun at end!!).
+ */
+
+void housekeep2(int samps_read,dataptr dz)
+{   
+	float *write_end = dz->sampbuf[READBUF] + samps_read;							/* 1 */
+    int  part_sector_size = write_end - dz->sampbuf[BUFEND];										/* 2 */
+    memcpy((char *)dz->sampbuf[BBUF],(char *)dz->sampbuf[BUFEND],part_sector_size * sizeof(float));	/* 3 */
+    dz->sampbuf[READBUF]       = dz->sampbuf[BBUF] + part_sector_size;								/* 4 */
+    dz->iparam[CUT_SMPSREMAIN] = dz->buflen;													/* 5 */
+}
+
+/******************************* DO_JOIN_WRITE **********************************
+ *
+ * (1)	Read the unread PART of the splice directly into the end of the
+ *	splice_buffer.
+ * (2)	The distance of the start of this end-splice from the start of 
+ *	the ACTUAL buffer is given by (ENDSPLICE_ADDR - buffer).
+ * (3)	This distance in SECTORS (truncated).
+ * (4)	This truncated distance in samps.
+ * (5)	The size of any part_sector preceding the splice-start.
+ * (6)	The address of this part_sector.
+ * (7)	Write the existing buffer, up as far as the last complete sector
+ *	before the splice sector begins.
+ * (8)	Copy any incomplete sector (prior to the splice) to the start
+ *	of the buffer.
+ * (9)	Set the reading-in point (readbuf) to the end of that part_sector.
+ * (10)	Set the space remaining in the buffer (dz->iparam[CUT_SAMPREMAIN]) to the
+ *	total buffersize (bear in mind that there is a guard SECSIZE
+ *	of address space at the end, to allow for the part_sectors
+ *	inserted at the start of the buffer).
+ */
+
+int do_join_write(int n,int splice_remnant,int oversamps,dataptr dz)
+{
+	int exit_status;
+	int shsecsize = F_SECSIZE;			   	
+    int samps_from_buf_start,secdist,sector_sampdist,part_sector_size;
+    float *part_sector_addr;
+	if((exit_status = read_join_splice_remnant(n,splice_remnant,oversamps,dz))<0)	
+		return(exit_status);												/* 1 */
+    samps_from_buf_start = dz->sbufptr[ENDSPLICE_ADDR] - dz->sampbuf[BBUF];	/* 2 */
+    secdist  	     	 = samps_from_buf_start/shsecsize;					/* 3 */
+    sector_sampdist	  	 = secdist * shsecsize;								/* 4 */
+    part_sector_size     = (samps_from_buf_start - sector_sampdist);		/* 5 */
+    part_sector_addr     = dz->sampbuf[BBUF] + sector_sampdist;				/* 6 */
+	if(sector_sampdist) {
+    	if((exit_status = write_samps(dz->sampbuf[BBUF],sector_sampdist,dz))<0)
+    		return(exit_status);											/* 7 */
+	}
+	if(part_sector_size && (dz->sampbuf[BBUF]!=part_sector_addr))			/* 8 */
+		memcpy((char *)dz->sampbuf[BBUF],(char *)part_sector_addr,part_sector_size * sizeof(float));		
+    dz->sampbuf[READBUF]   = dz->sampbuf[BBUF] + (part_sector_size);		/* 9 */
+// SEPT 2010
+	dz->iparam[CUT_SMPSREMAIN] = dz->buflen;							/* 10 */
+	return(FINISHED);
+}
+
+
+/*********************** RESET_JOIN_BUFFER_PARAMS ****************************
+ *
+ * (1)	Set the next read-in address to be at the START of the
+ *	current file's end-splice area. Note that the end-splice
+ *	samps have been saved to the splice-buffer. The start-splice
+ *	samps of the new file will be written over the end-splice values
+ *	and the splice then created IN SITU.
+ * (2)	Check how many complete sectors remain in the ACTUAL buffer.
+ * (3)	Convert this to a sampcount.
+ * (4)	Unless there was an exact number of sectors, add one extra sector
+ *	of samps. This ensures that the reads will write to the end of OR
+ *	beyond the end of the ACTUAL buffer, so that WRITES will be
+ *	valid. This is safe because we have allowed an extra sector
+ *	at the end of the buffer.
+ */
+
+int reset_join_buffer_params(dataptr dz)
+{   
+	int shsecsize = F_SECSIZE;
+	int bufcheck;
+    dz->sampbuf[READBUF]  = dz->sbufptr[ENDSPLICE_ADDR];						/* 1 */
+    if((bufcheck = dz->sampbuf[BUFEND] - dz->sbufptr[ENDSPLICE_ADDR])==0) {		/* 2 */
+		dz->iparam[CUT_SMPSREMAIN]  =  dz->buflen;
+		dz->sbufptr[ENDSPLICE_ADDR] = dz->sampbuf[BBUF];
+		dz->sampbuf[READBUF]        = dz->sampbuf[BBUF];
+	} else {
+		dz->iparam[CUT_SMPSREMAIN] =  bufcheck/shsecsize;
+			dz->iparam[CUT_SMPSREMAIN] *= F_SECSIZE;								/* 3 */
+		if(bufcheck != dz->iparam[CUT_SMPSREMAIN])		
+			dz->iparam[CUT_SMPSREMAIN] += F_SECSIZE;								/* 4 */
+		if(dz->iparam[CUT_SMPSREMAIN] < F_SECSIZE) {								/* 5 */
+			sprintf(errstr,"Zero buffer sectorsize: impossible!?: reset_join_buffer_params()\n");
+			return(PROGRAM_ERROR);
+		}
+	}
+	return(FINISHED);
+}
+
+
+/******************************** DO_INSERTSIL_MANY **********************************/
+
+int do_insertsil_many(dataptr dz)
+{
+	int exit_status;
+	int last_total_samps_read, endsamp, startsamp, inbuf_location;
+	int chans = dz->infile->channels;
+	int here = 0;
+	int here_in_splice = 0;
+	int in_downsplice = 0;
+	int in_upsplice = 0;
+	int in_zero = 0;
+	int splicelen = dz->iparam[CUT_SPLEN];
+	dz->total_samps_read = 0;	
+
+	while(dz->total_samps_read < dz->insams[0]) {
+		last_total_samps_read = dz->total_samps_read;
+		if((exit_status = read_samps(dz->bigbuf,dz))<0)
+			return(exit_status);
+		if (here >= dz->iparam[EXCISE_CNT]) {
+			if(dz->ssampsread > 0) {
+				if((exit_status = write_samps(dz->bigbuf,dz->ssampsread,dz))<0)
+		   			return(exit_status);											/* 7 */
+			}
+			continue;
+		}
+		if (in_downsplice) {
+			endsamp = dz->lparray[CUT_STTSAMP][here] - last_total_samps_read;
+			if(endsamp <= dz->buflen) {
+				do_other_splice(dz->bigbuf,splicelen,here_in_splice,splicelen,chans,1);
+				in_downsplice  = 0;
+				here_in_splice = 0;
+			} else {
+				do_other_splice(dz->bigbuf,splicelen,here_in_splice,here_in_splice + dz->buflen,chans,1);
+				here_in_splice += dz->buflen;
+				if(dz->ssampsread > 0) {
+		    		if((exit_status = write_samps(dz->bigbuf,dz->ssampsread,dz))<0)
+		    			return(exit_status);											/* 7 */
+				}
+				continue;
+			}
+		} else if (in_zero) {
+			endsamp = dz->lparray[CUT_ENDSAMP][here] - last_total_samps_read;
+			if(endsamp <= dz->buflen) {
+				memset((char *)dz->bigbuf,0,endsamp * sizeof(float));
+				in_zero = 0;
+			} else {
+
+				memset((char *)dz->bigbuf,0,dz->buflen * sizeof(float));
+				if(dz->ssampsread > 0) {
+					if((exit_status = write_samps(dz->bigbuf,dz->ssampsread,dz))<0)
+		    			return(exit_status);											/* 7 */
+				}
+				continue;
+			}
+		} else if (in_upsplice) {
+			endsamp = dz->lparray[CUT_ENDSPLI][here] - last_total_samps_read;
+			if(endsamp <= dz->buflen) {
+				do_other_splice(dz->bigbuf,splicelen,here_in_splice,splicelen,chans,0);
+				in_upsplice  = 0;
+				here_in_splice = 0;
+				here++;				/* To next set of values */
+			} else {
+				do_other_splice(dz->bigbuf,splicelen,here_in_splice,here_in_splice + dz->buflen,chans,0);
+				here_in_splice += dz->buflen;
+				if(dz->ssampsread > 0) {
+		    		if((exit_status = write_samps(dz->bigbuf,dz->ssampsread,dz))<0)
+		    			return(exit_status);											/* 7 */
+				}
+				continue;
+			}
+		}
+		while(here < dz->iparam[EXCISE_CNT]) {
+			if(dz->lparray[CUT_STTSPLI][here] >= dz->total_samps_read) {
+				break;
+			}
+			inbuf_location =  dz->lparray[CUT_STTSPLI][here] - last_total_samps_read;
+			if(inbuf_location >= 0 && inbuf_location < dz->ssampsread) {
+				startsamp = dz->lparray[CUT_STTSPLI][here] % dz->buflen;
+				if(dz->lparray[CUT_STTSAMP][here] < dz->total_samps_read) {
+					endsamp = dz->lparray[CUT_STTSAMP][here] % dz->buflen;
+					do_other_splice((dz->bigbuf + startsamp),splicelen,0,splicelen,chans,1);
+					here_in_splice = 0;
+					in_downsplice = 0;
+				} else {
+					endsamp = dz->buflen;
+					here_in_splice = endsamp - startsamp;
+					do_other_splice((dz->bigbuf + startsamp),splicelen,0,here_in_splice,chans,1);
+					in_downsplice = 1;
+					break;
+				}
+			}
+			inbuf_location =  dz->lparray[CUT_STTSAMP][here] - last_total_samps_read;
+			if(inbuf_location >= 0 && inbuf_location < dz->ssampsread) {
+				startsamp = dz->lparray[CUT_STTSAMP][here] % dz->buflen;
+				if(dz->lparray[CUT_ENDSAMP][here] < dz->total_samps_read) {
+					endsamp = dz->lparray[CUT_ENDSAMP][here] % dz->buflen;
+					memset((char *)(dz->bigbuf + startsamp),0,(endsamp - startsamp) * sizeof(float));
+					in_zero = 0;
+				} else {
+					endsamp = dz->buflen;
+					memset((char *)(dz->bigbuf + startsamp),0,(endsamp - startsamp) * sizeof(float));
+					in_zero = 1;
+					break;
+				}
+			}
+			inbuf_location =  dz->lparray[CUT_ENDSAMP][here] - last_total_samps_read;
+			if(inbuf_location >= 0 && inbuf_location < dz->ssampsread) {
+				startsamp = dz->lparray[CUT_ENDSAMP][here] % dz->buflen;
+				if(dz->lparray[CUT_ENDSPLI][here] < dz->total_samps_read) {
+					endsamp = dz->lparray[CUT_ENDSPLI][here] % dz->buflen;
+					do_other_splice((dz->bigbuf + startsamp),splicelen,0,splicelen,chans,0);
+					here_in_splice = 0;
+					in_upsplice = 0;
+				} else {
+					endsamp = dz->buflen;
+					here_in_splice = endsamp - startsamp;
+					do_other_splice((dz->bigbuf + startsamp),splicelen,0,here_in_splice,chans,0);
+					in_upsplice = 1;
+					break;
+				}
+			}
+			here++;
+		}
+ 		if(dz->ssampsread > 0) {
+	   		if((exit_status = write_samps(dz->bigbuf,dz->ssampsread,dz))<0)
+    			return(exit_status);											/* 7 */
+		}
+	}
+	return(FINISHED);
+}
+
+void do_other_splice(float *buf, int splicelen, int start_in_splice, int end_in_splice, int chans, int invert)
+{
+	double	a1 = 0.0, aincr;
+	register int i, j, k;
+	int sampgrps = splicelen/chans;
+	aincr = 1.0/sampgrps;
+	if(invert) {
+		aincr = -aincr;
+		a1 = 1.0 + aincr;
+	}
+	a1 += (aincr * start_in_splice);
+	for(i = 0, k = start_in_splice; k < end_in_splice; i+= chans, k += chans) {
+		for(j=0;j<chans;j++) 
+			buf[i+j] = (float)((double)buf[i+j] * a1);
+		a1 += aincr;
+	}
+}
+
+
+/**************************** DO_RANDCUTS ****************************/
+
+int do_randcuts(dataptr dz)
+{
+//	int bigbufsize;
+	int exit_status, namelen, cutendno;
+	float *obuf;
+	char *outfilename;
+	int rel_bufend, rel_bufstart, abs_bufend, abs_bufstart, /*origbufsize*/origbuflen;
+	int rel_cutend, last_cut, next_cut, cutlen;
+	int chans = dz->infile->channels;
+	int stereo_splicelen = SHRED_SPLICELEN * chans;
+	int part_splice, splice_start, samps_to_write;
+
+	if((exit_status = get_lengths(stereo_splicelen,dz))<0)
+		return(PROGRAM_ERROR);
+
+	namelen = strlen(dz->wordstor[0]);		
+	if(sloom)
+		namelen--;								/* Drop the 0 at end of name */
+//FEB 2010 TW
+	if((outfilename = (char *)malloc((namelen + 6 + 10) * sizeof(char)))==NULL) {
+		sprintf(errstr,"INSUFFICIENT MEMORY for outfilename.\n");
+		return(MEMORY_ERROR);
+	}				
+	strcpy(outfilename,dz->wordstor[0]);
+//FEB 2010 TW
+	if(!sloom)
+		insert_separator_on_sndfile_name(outfilename,2);
+	cutendno = 0;
+	obuf = dz->sampbuf[0];
+	rel_bufend = dz->buflen;	
+	abs_bufend = dz->buflen;	
+	rel_bufstart = 0;
+
+	/*origbufsize = dz->bigbufsize;	*/		/*	READ A DOUBLE BUFFER */
+	origbuflen = dz->buflen;
+	dz->buflen *= 2;
+	if((exit_status = read_samps(dz->sampbuf[0],dz)) < 0) {
+		sprintf(errstr,"Failed (1) to read input file.\n");
+		/*RWD need this here.. */
+		free(outfilename);
+
+		return(PROGRAM_ERROR);
+	}
+	dz->buflen = origbuflen;
+	
+	cutendno = 0;
+	next_cut = 0;
+ 	abs_bufstart = 0;
+	part_splice = 0;
+
+	while(cutendno < dz->iparam[RC_CHCNT]) {
+		last_cut = next_cut;
+		next_cut = dz->lparray[0][cutendno];
+		cutlen = next_cut - last_cut;
+/* FIX: MAR 2003 */
+		strcpy(outfilename,dz->wordstor[0]);
+//FEB 2010 TW
+		if(!sloom)
+			insert_separator_on_sndfile_name(outfilename,2);
+		if((exit_status = create_an_outfile(cutendno,cutlen,outfilename,dz))<0)  {
+			free(outfilename);	/*RWD should be done here */
+			return(exit_status);
+		}
+		if(cutendno > 0)
+			do_insitu_upsplice(rel_bufstart,dz);
+		while(next_cut >= abs_bufend) {	/* ?? >= OR > ?? */
+			part_splice = 0;
+			if(cutendno != dz->iparam[RC_CHCNT]-1) {
+				if((part_splice = stereo_splicelen - (next_cut - abs_bufend)) > 0) {
+					splice_start = rel_bufend - part_splice;
+					do_insitu_splice(splice_start,rel_bufend,0,chans,dz);
+				} else {
+					part_splice = 0;
+				}
+			}
+			if((exit_status = write_samps(obuf,dz->buflen,dz)) < 0)	{
+				/* RWD and here..... */
+				free(outfilename);
+				return(exit_status);
+			}
+			memcpy((char *)dz->sampbuf[0],(char *)dz->sampbuf[1],dz->buflen * sizeof(float));
+			abs_bufend += dz->buflen;
+			cutlen -= dz->buflen;
+			if((exit_status = read_samps(dz->sampbuf[1],dz)) < 0) {
+				/*RWD and here.... */
+				free(outfilename);
+				return(exit_status);
+			}
+		}
+		rel_cutend = cutlen + rel_bufstart;
+		if(cutendno != dz->iparam[RC_CHCNT]-1) {
+			if(part_splice > 0) {
+				part_splice /= dz->infile->channels;
+				do_insitu_splice(rel_bufstart,rel_cutend,part_splice,chans,dz);
+			} else {
+				do_insitu_splice(rel_cutend - stereo_splicelen,rel_cutend,0,chans,dz);
+			}
+		}
+		if((samps_to_write = rel_cutend - rel_bufstart) > 0) {
+			if((exit_status = write_samps(obuf,samps_to_write,dz)) < 0)	 {
+				/*RWD and here.... */
+				free(outfilename);
+				return(exit_status);
+			}
+		}
+		if((exit_status = close_an_outfile(outfilename,dz)) < 0) {
+			/*RWD and here.... */
+			free(outfilename);
+			return(exit_status);
+		}
+		abs_bufstart = next_cut;
+		abs_bufend   = abs_bufstart + dz->buflen;
+
+		if(rel_cutend >= dz->buflen) {
+  			memcpy((char *)dz->sampbuf[0],(char *)dz->sampbuf[1],dz->buflen * sizeof(float));
+			if((exit_status = read_samps(dz->sampbuf[1],dz)) < 0) {
+				sprintf(errstr,"Failed (2) to read input file.\n");
+				/*RWD and here.... */
+				free(outfilename);
+				return(PROGRAM_ERROR);
+			}
+			rel_cutend -= dz->buflen;
+		}
+		rel_bufstart = rel_cutend;
+		rel_bufend   = rel_bufstart + dz->buflen;
+		obuf = dz->sampbuf[0] + rel_bufstart;
+		cutendno++;
+	}
+	/*RWD and finally here! */
+	free(outfilename);
+	return(FINISHED);
+}
+
+/**************************** CLOSE_AN_OUTFILE ****************************/
+
+int close_an_outfile(char *outfilename,dataptr dz)
+{
+	int exit_status;
+	dz->process_type = UNEQUAL_SNDFILE;		/* allows header to be written  */
+	dz->outfiletype  = SNDFILE_OUT;			/* allows header to be written  */
+	if((exit_status = complete_output(dz))<0) {	/* ensures file is truncated */
+		/*free(outfilename);*/
+		return(exit_status);
+	}
+	dz->process_type = OTHER_PROCESS;		/* restore true status */
+	dz->outfiletype  = NO_OUTPUTFILE;		/* restore true 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);
+	}
+	/*free(outfilename);	*/		/*RWD: dangerous! */
+	dz->ofd = -1;
+	return(FINISHED);
+}
+
+/**************************** CREATE_AN_OUTFILE ****************************/
+
+int create_an_outfile(int cutno, int cutlen, char *outfilename, dataptr dz)
+{
+	int exit_status;
+	int orig_infilesize;
+
+	insert_new_number_at_filename_end(outfilename,cutno,1);
+	dz->process_type = EQUAL_SNDFILE;	/* allow sndfile to be created */
+	orig_infilesize = dz->insams[0];
+	
+	fprintf(stdout,"INFO: creating file	%s\n",outfilename);
+	fflush(stdout);
+	if((exit_status = create_sized_outfile(outfilename,dz))<0) {
+		sprintf(errstr, "Failed to open file %s\n",outfilename);
+		/*free(outfilename);*/
+		dz->process_type = OTHER_PROCESS;
+		dz->insams[0] = orig_infilesize;
+		dz->ofd = -1;
+		return(GOAL_FAILED);
+	}
+	dz->process_type = OTHER_PROCESS;
+	dz->insams[0] = orig_infilesize;
+	reset_filedata_counters(dz);
+	return(FINISHED);
+}
+
+/**************************** DO_INSITU_UPSPLICE ****************************/
+
+void do_insitu_upsplice(int rel_bufstart,dataptr dz)
+{
+	float *samp = dz->sampbuf[0] + rel_bufstart;
+	double val;
+	int chans = dz->infile->channels, i, j;
+	for(i=0; i < SHRED_SPLICELEN; i++) {
+		for(j=0;j<chans;j++) {
+			val = (*samp) * (double)i/SHRED_SPLICELEN;
+			*samp = (float)val;
+			samp++;
+		}
+	}
+}
+
+/**************************** DO_INSITU_SPLICE ****************************/
+
+void do_insitu_splice(int start,int end,int splicecnt,int chans, dataptr dz)
+{
+	float *samp = dz->sampbuf[0] + start;
+	double val;
+	int i;
+	int j, k = SHRED_SPLICELEN - splicecnt;
+	for(i= start; i < end; i+= chans) {
+		k--;
+		for(j=0;j<chans;j++) {
+			val = (*samp) * (double)k/SHRED_SPLICELEN;
+			*samp = (float)val;
+			samp++;
+		}
+	}
+}
+
+/**************************** GET_LENGTHS ****************************/
+
+int get_lengths(int stereo_splicelen,dataptr dz)
+{   
+	int m, n;
+
+	for(m=0,n=1;n< dz->iparam[RC_CHCNT];n++,m++)
+		dz->lparray[0][m] = dz->iparam[RC_UNITLEN] * n;
+	dz->lparray[0][m] = dz->insams[0];
+
+	if(dz->param >= 0) {
+		if(!dz->iparam[RC_SCAT])	
+			normal_scat(dz);											/* 1 */
+		else	
+			heavy_scat(stereo_splicelen,dz);
+	}
+	return(FINISHED);
+}
+
+/**************************** NORMAL_SCAT ****************************/
+
+void normal_scat(dataptr dz)
+{   
+	double this_scatter;
+	int n;
+	int chunkscat, total_len = dz->iparam[RC_UNITLEN];	/* 1 */
+	int cnt_less_one = dz->iparam[RC_CHCNT] - 1;
+
+	for(n=0;n<cnt_less_one;n++) {			/* 2 */
+		this_scatter  = (drand48() - 0.5) * dz->param[RC_SCAT];
+		chunkscat = (int)(this_scatter * dz->iparam[RC_UNITLEN]);
+		if(ODD(chunkscat))   
+			chunkscat--;		/* 3 */
+		dz->lparray[0][n]= total_len + chunkscat;
+		total_len  += dz->iparam[RC_UNITLEN];			/* 4 */
+	}
+	dz->lparray[0][n] = dz->insams[0];
+}
+
+/*********************** 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(int stereo_splicelen,dataptr dz)
+{   
+	int	thiss = 1, that, start, n, m, OK;						/* 1 */
+	int startptr = 0;											/* 2 */
+	int first = 1;												/* 3 */
+	int *chunkptr = dz->lparray[0];
+	chunkptr[0] = 0;
+	for(n=0;n<dz->iparam[RC_SCATGRPCNT];n++) {					/* 4 */
+		start = thiss;											/* 5 */
+		for(m=first;m<dz->iparam[RC_SCAT];m++) {				/* 6 */
+			do {												/* 7 */
+				OK = 1;					
+				chunkptr[thiss] = (int)(drand48()*dz->iparam[RC_RANGE]); 	/* TRUNCATE (?)*/
+				chunkptr[thiss] += startptr; 					/* 8 */
+				if(ODD(chunkptr[thiss]))   
+					chunkptr[thiss]--;	
+				for(that=start-1; that<thiss; that++) {
+					if(abs(chunkptr[thiss] - chunkptr[that])<stereo_splicelen * 2) {
+						OK = 0;									/* 9 */
+						break;
+					}
+				}
+			} while(!OK);										/* 10 */
+			thiss++;											/* 11 */
+		}
+		startptr += dz->iparam[RC_RANGE];						/* 12 */
+		first = 0;												/* 13 */
+	}
+	if(dz->iparam[RC_ENDSCAT]) {								/* 14 */
+		start = thiss;
+		for(m=0;m<dz->iparam[RC_ENDSCAT];m++) {
+			do {
+				OK = 1;
+				chunkptr[thiss] = (int)(drand48() * dz->iparam[RC_ENDRANGE]);	  /* TRUNCATE (?) */
+				chunkptr[thiss] += startptr;
+				if(ODD(chunkptr[thiss]))   
+					chunkptr[thiss]--;	
+				for(that=start-1; that<thiss; that++) {
+					if(abs(chunkptr[thiss] - chunkptr[that])<stereo_splicelen * 2) {
+						OK = 0;
+						break;
+					}
+				}
+			} while(!OK);
+			thiss++;
+		}
+	}
+	ptr_sort(thiss,dz);
+}
+
+/************************** PTR_SORT ***************************/
+
+void ptr_sort(int end,dataptr dz)
+{   
+	int i,j;
+	int a;
+	int *chunkptr = dz->lparray[0];
+	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;
+	}
+	for(i=0, j=1; j < dz->iparam[RC_CHCNT]; i++, j++)
+		chunkptr[i] = chunkptr[j];
+	chunkptr[dz->iparam[RC_CHCNT]-1] = dz->insams[0];
+}    
+
+/************************** DO_RANDCHUNKS ***************************/
+
+int do_randchunks(dataptr dz)
+{   
+	double range, multiplier, total, addrange;
+    int rangecnt;
+
+    initrand48();
+ 	if(dz->param[MINCHUNK] > dz->param[MAXCHUNK])
+		swap(&dz->param[MINCHUNK],&dz->param[MAXCHUNK]);
+    range = dz->duration - dz->param[MINCHUNK];
+    if(range > dz->param[MAXCHUNK])
+		range = dz->param[MAXCHUNK];
+    if(dz->vflag[FROMSTART])
+		return do_fromstart(dz);
+    if(dz->vflag[LINEAR]) {
+    	if((rangecnt = (int)(range/MINOUTDUR))<1) {
+		    fprintf(stdout,"INFO: incompatible source duration and MINIMUM PERMITTED DUR %.2lf\n",MINOUTDUR);
+		    return(GOAL_FAILED);
+		}
+		if(rangecnt < dz->iparam[CHUNKCNT])
+		    addrange = (range - dz->param[MINCHUNK])/dz->iparam[CHUNKCNT];
+	    else
+			addrange = (range - dz->param[MINCHUNK])/rangecnt;
+		return do_linear(dz,range,rangecnt,addrange);
+    } else {
+    	multiplier = 1.5;
+    	rangecnt = dz->iparam[CHUNKCNT];
+    	while(dz->iparam[CHUNKCNT] < rangecnt) {
+		    rangecnt = 1;
+		    total    = dz->param[MINCHUNK];
+		    addrange = MINOUTDUR;
+		    multiplier += .5;
+    	    while(total < range) {
+		    	total += addrange;
+		    	addrange *= multiplier;
+		    	rangecnt++;
+            }
+		    rangecnt--;
+		}
+		return do_nonlinear(dz,range,rangecnt,multiplier);
+    }
+}
+
+/************************** DO_LINEAR ***************************/
+
+int do_linear(dataptr dz,double range,int rangecnt,double addrange)
+{   int m = 0, n, count, exit_status;
+	double mindur = dz->param[MINCHUNK];
+    double thisrange = dz->param[MINCHUNK], totalrange, k, thislength;
+    thislength = thisrange;
+	count = dz->iparam[CHUNKCNT];
+
+    for(n=0;n<count;n++) {
+        if(m >= rangecnt || thisrange >= range) {
+		    m = 0;
+		    thislength = thisrange = mindur;
+		}
+		totalrange = dz->duration - thisrange;
+	    k = drand48() * totalrange;
+		if((exit_status = cut_chunk(dz,k,k+thislength,n))<0)
+			return(exit_status);
+		m++;
+    	thisrange += addrange;
+		thislength = thisrange - (addrange * drand48() * 0.5);
+    }
+	return(FINISHED);
+}
+
+/************************** DO_NONLINEAR ***************************/
+
+int do_nonlinear(dataptr dz,double range,int rangecnt,double multiplier)
+{   int m = 0, n, count, exit_status;
+	double mindur = dz->param[MINCHUNK];
+    double thislength, thisrange = dz->param[MINCHUNK];
+    double addrange  = dz->param[MINCHUNK], totalrange, k;
+    thislength = thisrange;
+	count = dz->iparam[CHUNKCNT];
+    for(n=0;n<count;n++) {
+        if(m >= rangecnt || thisrange >= range) {
+			m = 0;
+	   		thislength = thisrange  = mindur;
+	   		addrange   = mindur;
+		}
+		totalrange = dz->duration - thisrange;
+     	k = drand48() * totalrange;
+		if((exit_status = cut_chunk(dz,k,k+thislength,n))<0)
+			return(exit_status);
+		m++;
+    	thisrange += addrange;
+    	thislength = thisrange - (addrange * drand48() * 0.5);
+		addrange  *= multiplier;
+    }
+	return(FINISHED);
+}
+
+/************************** DO_FROMSTART ***************************/
+
+int do_fromstart(dataptr dz)
+{   
+	int n, count,exit_status;
+	double mindur = dz->param[MINCHUNK], maxdur = dz->param[MAXCHUNK];
+    double k = 0.0, range = dz->param[MAXCHUNK] - dz->param[MINCHUNK], outdur, step;
+	count = dz->iparam[CHUNKCNT];
+    switch(dz->vflag[LINEAR]) {
+    case(0):
+    	for(n=0;n<count;n++) {
+    	    k = drand48() * range;
+			if((exit_status = cut_chunk(dz,0.0,k+mindur,n))<0)
+				return(exit_status);
+    	}
+		break;
+    case(1):
+    	if((exit_status = cut_chunk(dz,0.0,mindur,0))<0)
+			return(exit_status);
+		outdur = mindur;
+		step   = range/(double)(count-2);
+		count--;
+    	for(n=1;n<count;n++) {
+    	    k = drand48() * step;
+		    if((exit_status = cut_chunk(dz,0.0,outdur + k,n))<0)
+				return(exit_status);
+    	    outdur += step;
+    	}
+    	if((exit_status = cut_chunk(dz,0.0,maxdur,n))<0)
+			return(exit_status);
+		break;
+    default:
+		fprintf(stderr,"\nImpossible!!! invalid value of 'linear'");
+		break;
+    }
+	return(FINISHED);
+}
+
+/************************** CUT_CHUNK ***************************/
+
+int cut_chunk(dataptr dz,double startcut,double endcut,int count)
+{
+	int exit_status;
+	int origprocess = dz->process, origmode = dz->mode, namelen, numlen = 1;
+	char *outfilename;
+	char *p, *q, *r;
+	if(!sloom) {
+		namelen = strlen(dz->wordstor[0]);
+		q = dz->wordstor[0];
+		r = dz->wordstor[0] + namelen;
+		p = r - 1;
+		/*RWD 6:2001 added trap for ':' */
+		while((*p != '\\') && (*p != '/') && (*p != ':')) {
+			p--	;
+			if(p < dz->wordstor[0])
+				break;
+		}
+		if(p > dz->wordstor[0]) {
+			p++;
+			while(p <= r)
+				*q++ = *p++;
+		}
+	}
+	dz->process = EDIT_CUT;
+	dz->mode = EDIT_SECS;
+	dz->param[CUT_CUT] = startcut;	
+	dz->param[CUT_END] = endcut;
+	dz->param[CUT_SPLEN] = EDIT_SPLICELEN;
+	namelen = strlen(dz->wordstor[0]);
+	namelen--;
+	if(count > 99)
+		numlen = 3;
+	else if(count > 9)
+		numlen = 2;
+	reset_filedata_counters(dz);
+	if((outfilename = (char *)malloc((namelen + numlen + 1) * sizeof(char)))==NULL) {
+		sprintf(errstr,"INSUFFICIENT MEMORY for outfilename.\n");
+		return(MEMORY_ERROR);
+	}				
+    strcpy(outfilename,dz->wordstor[0]);
+	insert_new_number_at_filename_end(outfilename,count,1);
+
+	dz->process_type = UNEQUAL_SNDFILE;		/* allow sndfile to be created */
+	dz->outfiletype  = SNDFILE_OUT;			/* allows header to be written  */
+	if((exit_status = create_sized_outfile(outfilename,dz))<0)
+		return(exit_status);
+	if((exit_status = edit_pconsistency(dz))<0)
+		return exit_status;
+	if((exit_status = edit_preprocess(dz))<0)
+		return exit_status;
+	if((exit_status = do_cut(dz))<0)
+		return exit_status;
+	if((exit_status = complete_output(dz))<0)
+		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->process_type = OTHER_PROCESS;
+	dz->outfiletype  = NO_OUTPUTFILE;		/* restore true status */
+	free(outfilename);
+	dz->ofd = -1;
+	dz->process = origprocess;
+	dz->mode = origmode;
+	return(FINISHED);
+}
+
+/************************** CUT_MANY ***************************/
+
+int cut_many(dataptr dz)
+{
+	float *ibuf, *obuf;
+	char filename[64];
+	int k, startsplice, endsplice;
+	int startcut, endcut, samps_left, startseek, offset;
+	int outcnt = 0, n = 0, splice_start, samps_to_write, samps_written;
+	int exit_status;
+	int last_fileout = (dz->itemcnt/2) - 1;
+
+	while(n < dz->itemcnt) {
+		if(outcnt > 0) {
+			strcpy(filename,dz->wordstor[0]);
+			if(sloom)
+				insert_new_number_at_filename_end(filename,outcnt,1);
+			else
+				insert_new_number_at_filename_end(filename,outcnt+1,0);
+			if((exit_status = create_sized_outfile(filename,dz))<0) {
+				sprintf(errstr, "ERROR: Soundfile %s already exists: cannot proceed further\n", filename);
+				return(exit_status);
+			}
+		}
+		startcut = dz->lparray[0][n++];
+		endcut   = dz->lparray[0][n++];
+		samps_left = endcut - startcut;
+		startsplice = (samps_left - dz->iparam[CM_SPLICE_TOTSAMPS]) % dz->buflen;
+		startseek = (startcut/F_SECSIZE) * F_SECSIZE;
+		offset = startcut - startseek;
+		sndseekEx(dz->ifd[0],startseek,0);
+		ibuf = dz->bigbuf; 
+		obuf = ibuf + offset;
+		dz->buflen += F_SECSIZE;
+		if((exit_status = read_samps(ibuf,dz))<0)
+			return(SYSTEM_ERROR);
+		dz->buflen -= F_SECSIZE;
+		ibuf += F_SECSIZE; 
+		k = 0;
+		splice_start = 0;
+		dz->total_samps_written = 0;
+		do {
+			samps_to_write = min(samps_left,dz->buflen); 
+			if(k == 0)								
+				splice_obuf_start(obuf,dz);
+			if(samps_left < dz->buflen + dz->iparam[CM_SPLICE_TOTSAMPS]) {
+				if(splice_start == 0)	{
+					if((endsplice = startsplice + dz->iparam[CM_SPLICE_TOTSAMPS]) <= dz->buflen) {
+						splice_obuf_end(obuf,&splice_start,startsplice,endsplice,dz);
+					} else {
+						splice_obuf_end(obuf,&splice_start,startsplice,dz->buflen,dz);
+					}
+				} else {
+					splice_obuf_end(obuf,&splice_start,0,samps_left,dz);
+				}
+			}
+			if(samps_to_write > 0) {
+				if((exit_status = write_samps_no_report(obuf,samps_to_write,&samps_written,dz))<0)
+					return(exit_status);
+			}
+			if((samps_left -= samps_to_write) >  0) {
+				memcpy((char *)obuf,(char *)(obuf + dz->buflen),(F_SECSIZE - offset) * sizeof(float));
+				if((exit_status = read_samps(ibuf,dz))<0)
+					return(exit_status);
+			}
+			k++;
+		} while(samps_left > 0);
+		if(outcnt != last_fileout) {
+			if((exit_status = headwrite(dz->ofd,dz))<0)
+				return(exit_status);
+			if((exit_status = reset_peak_finder(dz))<0)
+				return(exit_status);
+			if(sndcloseEx(dz->ofd)<0) {
+				sprintf(errstr,"Failed to close output soundfile.\n");
+				return(SYSTEM_ERROR);
+			}
+			dz->ofd = -1;
+		}
+		outcnt++;
+		display_virtual_time(outcnt,dz);
+	}
+	return(FINISHED);
+}
+
+/************************** SPLICE_OBUF_START ***************************/
+
+void splice_obuf_start(float *obuf,dataptr dz)
+{
+	int n, m;
+	double aincr = dz->param[CM_SPLICEINCR];
+	double mult = 0;
+	int chans = dz->infile->channels;
+	int splicelen = dz->iparam[CM_SPLICESAMPS] * dz->infile->channels;
+	for(n = 0;n < splicelen; n+=chans) {
+		for(m = 0;m < chans; m++)
+			obuf[n+m] = (float)(obuf[n+m] * mult);
+		mult += aincr;
+	}
+}
+
+/************************** SPLICE_OBUF_END ***************************/
+
+void splice_obuf_end(float *obuf,int *splice_start,int startsamp,int endsamp,dataptr dz)
+{
+	int n, m;
+	double aincr = dz->param[CM_SPLICEINCR];
+	double mult = 1.0 - (aincr * (*splice_start + 1));
+	int chans = dz->infile->channels;				   
+	int splicelen = (endsamp - startsamp)/chans;
+	for(n = startsamp;n < endsamp; n+=chans) {
+		for(m = 0;m < chans; m++)
+			obuf[n+m] = (float)(obuf[n+m] * mult);
+		mult -= aincr;
+	}
+	*splice_start += splicelen;
+}
+
+/********************************** DO_NOISE_SUPPRESSION **********************************
+ *
+ * Creating envelope to splice out non_pitched material based on wavset-len,
+ * and eliminating any bits of tone which are too short
+ */
+
+int do_noise_suppression(dataptr dz)
+{
+	float *ibuf = dz->sampbuf[0];
+	int getnextbuf = 0, phase, isnoise = -1, doincr, noisefirst = 0, spliceafter;
+	int in_noise = 0, in_splice = 0, OK, exit_status;
+	int j, k, n = 0, m, nextpoint, splice_cnt, edit_position, next_edit_position;
+	int twosplices;
+	int brkpntcnt = 0, last_total_samps_read = 0, lastzcross = 0;
+	double splincr;
+	int thispos, lastpos = 0;
+
+	splincr = 1.0/(double)dz->iparam[NOISE_SPLEN];
+
+	if((exit_status = read_samps(ibuf,dz))<0)
+		return(exit_status);
+	else if(dz->ssampsread <= 0) {
+		sprintf(errstr,"Failed to read sound from input file\n");
+		return(DATA_ERROR);
+	}
+
+	/* ESTABLISH INITIAL PHASE OF SIGNAL */
+
+	do {
+		if(dz->ssampsread <= 0)
+			break;
+		n = 0;
+		getnextbuf = 0;
+		while(smpflteq(ibuf[n],0.0)) {
+			if(++n >= dz->ssampsread) {
+				getnextbuf = 1;
+				break;
+			}
+		}
+		if(!getnextbuf)
+			break;
+		last_total_samps_read = dz->total_samps_read;
+	} while((exit_status = read_samps(ibuf,dz))>=0);
+	
+	if(exit_status < 0)
+		return(exit_status);
+	if(getnextbuf) {
+		sprintf(errstr,"Failed to find any wavecycles in file.\n");
+		return(DATA_ERROR);
+	}	
+	if(ibuf[n] > 0.0)
+		phase = 0;
+	else
+		phase = 1;
+	
+	/* LOCATE NOISE: non-NOISE SWITCHES */
+
+	for(;;) {	/* READ INPUT BUFFERS LOOP */
+
+		for(;;) {	/* LOCATE WAVECYCLE IN CURRENT BUFFER, LOOP */
+
+			/* FIND A WAVECYCLE */
+			
+			if(phase == 0) {
+				while(ibuf[n] > 0.0) {
+					if(++n >= dz->ssampsread) {
+						getnextbuf = 1;
+						break;
+					}
+				}
+				if(getnextbuf)
+					break;
+				while(ibuf[n] <= 0.0) {
+					if(++n >= dz->ssampsread) {
+						getnextbuf = 1;
+						break;
+					}
+				}
+				if(getnextbuf)
+					break;
+			} else {
+				while(ibuf[n] <= 0.0) {
+					if(++n >= dz->ssampsread) {
+						getnextbuf = 1;
+						break;
+					}
+				}
+				if(getnextbuf)
+					break;
+				while(ibuf[n] > 0.0) {
+					if(++n >= dz->ssampsread) {
+						getnextbuf = 1;
+						break;
+					}
+				}
+				if(getnextbuf)
+					break;
+			}
+			thispos = last_total_samps_read + n;
+			doincr  = 0;
+
+			/* MEASURE WAVE-CYCLE LENGTH, AND TEST FOR NOISE */
+			/* IF SIGNAL SWITCHES FROM NOISE  to NOT-NOISE or vice versa, STORE THAT POSITION */
+			
+			if(thispos - lastzcross < dz->iparam[NOISE_MINFRQ]) {
+				if(isnoise < 0)				/* if at signal start ... */
+					noisefirst = 1;			/* flag signal starts with noise - (don't store position [i.e. count brkpnts] yet) */
+				else if(isnoise == 0) {		/* elseif switched into noise ... */
+					if(brkpntcnt == 0) {
+						if(thispos > dz->iparam[MIN_TONELEN])	/* if enough tone present */
+							doincr = 1;			/* ... --- keep point (i.e. count brkpnt & incr brkpnt pointer) */
+						else
+							noisefirst = 1;
+					} else {
+						if(thispos - lastpos > dz->iparam[MIN_TONELEN])
+							doincr = 1;			/* ... --- keep point (i.e. count brkpnt & incr brkpnt pointer) */
+						else {					/* if NOT ENOUGH tone present */
+							brkpntcnt--;		/* eliminate the previous breakpoint, which started the tone segment */
+							thispos = lastpos;
+						}
+					}
+				}
+				isnoise = 1;
+			} else {
+				if(isnoise < 0)				/* if at signal start ... */
+					noisefirst = 0;			/* flag signal doesn't start with noise - (don't store position [i.e. count brkpnts] yet) */
+				else if(isnoise == 1) {		/* elseif switched out of noise ... */
+					if(brkpntcnt == 0) {
+						if(thispos > dz->iparam[MIN_NOISLEN])
+							doincr = 1;
+						else
+							noisefirst = 0;
+					} else {					/* if enough noise present ... */
+						if(thispos - lastpos > dz->iparam[MIN_NOISLEN])
+							doincr = 1;			/* ....--- keep point (i.e. count brkpnt & incr brkpnt pointer) */
+						else {					/* if NOT ENOUGH noise present */
+							brkpntcnt--;		/* eliminate the previous breakpoint, which started the noise segment */
+							thispos = lastpos;
+						}
+					}
+				}
+				isnoise = 0;
+			}										/* store position of last waveset end... */
+			lastzcross = thispos;	/* regardless of whether position is stored in brkpnt array */
+
+			if(doincr) {					/* if point retained in brkpoint array, move along array */
+				lastpos = thispos;
+				brkpntcnt++;
+			}
+		}		/* READ NEXT BUFFER */
+		last_total_samps_read = dz->total_samps_read;
+		if((exit_status = read_samps(ibuf,dz)) < 0)
+			return(exit_status);
+		else if(dz->ssampsread <= 0)
+			break;
+		n = 0;
+		getnextbuf = 0;
+	}
+//TW ADDED TEST BEFORE MALLOCS ATTEMPTED: JULY 2006
+	if(brkpntcnt<=1) {
+		if(isnoise) {
+			sprintf(errstr,"Sound is all noise.");
+			return(GOAL_FAILED);
+		} else {
+			sprintf(errstr,"Sound has no noise.");
+			return(GOAL_FAILED);
+		}
+	}
+//TW late july :TO AVOID realooc PROBLEMS, GRAB THE DOUBLE WADGE OF MEMORY HERE
+	if((dz->lparray[0] = (int *)malloc(brkpntcnt * 2 * sizeof(int)))==NULL) {
+		sprintf(errstr,"Insufficient memory for edit points.");
+		return(MEMORY_ERROR);
+	}
+	sndseekEx(dz->ifd[0],0,0);
+//TW RESET VARIABLE BELOW
+	last_total_samps_read = 0;
+	reset_filedata_counters(dz);
+	brkpntcnt = 0;
+	if((exit_status = read_samps(ibuf,dz))<0)
+		return(exit_status);
+	else if(dz->ssampsread <= 0) {
+		sprintf(errstr,"Failed to read sound from input file\n");
+		return(DATA_ERROR);
+	}
+	do {
+		if(dz->ssampsread <= 0)
+			break;
+		n = 0;
+		getnextbuf = 0;
+		while(smpflteq(ibuf[n],0.0)) {
+			if(++n >= dz->ssampsread) {
+				getnextbuf = 1;
+				break;
+			}
+		}
+		if(!getnextbuf)
+			break;
+		last_total_samps_read = dz->total_samps_read;
+	} while((exit_status = read_samps(ibuf,dz))>=0);
+	
+	if(exit_status < 0)
+		return(exit_status);
+	if(getnextbuf) {
+		sprintf(errstr,"Failed to find any wavecycles in file.\n");
+		return(DATA_ERROR);
+	}	
+	if(ibuf[n] > 0.0)
+		phase = 0;
+	else
+		phase = 1;
+	
+	/* LOCATE NOISE: non-NOISE SWITCHES */
+	
+	for(;;) {	/* READ INPUT BUFFERS LOOP */
+
+		for(;;) {	/* LOCATE WAVECYCLE IN CURRENT BUFFER, LOOP */
+
+			/* FIND A WAVECYCLE */
+			
+			if(phase == 0) {
+				while(ibuf[n] > 0.0) {
+					if(++n >= dz->ssampsread) {
+						getnextbuf = 1;
+						break;
+					}
+				}
+				if(getnextbuf)
+					break;
+				while(ibuf[n] <= 0.0) {
+					if(++n >= dz->ssampsread) {
+						getnextbuf = 1;
+						break;
+					}
+				}
+				if(getnextbuf)
+					break;
+			} else {
+				while(ibuf[n] <= 0.0) {
+					if(++n >= dz->ssampsread) {
+						getnextbuf = 1;
+						break;
+					}
+				}
+				if(getnextbuf)
+					break;
+				while(ibuf[n] > 0.0) {
+					if(++n >= dz->ssampsread) {
+						getnextbuf = 1;
+						break;
+					}
+				}
+				if(getnextbuf)
+					break;
+			}
+			dz->lparray[0][brkpntcnt] = last_total_samps_read + n;
+			doincr  = 0;
+
+			/* MEASURE WAVE-CYCLE LENGTH, AND TEST FOR NOISE */
+			/* IF SIGNAL SWITCHES FROM NOISE  to NOT-NOISE or vice versa, STORE THAT POSITION */
+			
+			if(dz->lparray[0][brkpntcnt] - lastzcross < dz->iparam[NOISE_MINFRQ]) {
+				if(isnoise < 0)				/* if at signal start ... */
+					noisefirst = 1;			/* flag signal starts with noise - (don't store position [i.e. count brkpnts] yet) */
+				else if(isnoise == 0) {		/* elseif switched into noise ... */
+					if(brkpntcnt == 0) {
+						if(dz->lparray[0][brkpntcnt] > dz->iparam[MIN_TONELEN])	/* if enough tone present */
+							doincr = 1;			/* ... --- keep point (i.e. count brkpnt & incr brkpnt pointer) */
+						else
+							noisefirst = 1;
+					} else {
+						if(dz->lparray[0][brkpntcnt] - dz->lparray[0][brkpntcnt-1] > dz->iparam[MIN_TONELEN])
+							doincr = 1;			/* ... --- keep point (i.e. count brkpnt & incr brkpnt pointer) */
+						else					/* if NOT ENOUGH tone present */
+							brkpntcnt--;		/* eliminate the previous breakpoint, which started the tone segment */
+					}
+				}
+				isnoise = 1;
+			} else {
+				if(isnoise < 0)				/* if at signal start ... */
+					noisefirst = 0;			/* flag signal doesn't start with noise - (don't store position [i.e. count brkpnts] yet) */
+				else if(isnoise == 1) {		/* elseif switched out of noise ... */
+					if(brkpntcnt == 0) {
+						if(dz->lparray[0][brkpntcnt] > dz->iparam[MIN_NOISLEN])
+							doincr = 1;
+						else
+							noisefirst = 0;
+					} else {					/* if enough noise present ... */
+						if(dz->lparray[0][brkpntcnt] - dz->lparray[0][brkpntcnt-1] > dz->iparam[MIN_NOISLEN])
+							doincr = 1;			/* ....--- keep point (i.e. count brkpnt & incr brkpnt pointer) */
+						else					/* if NOT ENOUGH noise present */
+							brkpntcnt--;		/* eliminate the previous breakpoint, which started the noise segment */
+					}
+				}
+				isnoise = 0;
+			}										/* store position of last waveset end... */
+			lastzcross = dz->lparray[0][brkpntcnt];	/* regardless of whether position is stored in brkpnt array */
+
+			if(doincr)							/* if point retained in brkpoint array, move along array */
+				++brkpntcnt;
+		}		/* READ NEXT BUFFER */
+		last_total_samps_read = dz->total_samps_read;
+		if((exit_status = read_samps(ibuf,dz))<0)
+			return(exit_status);
+		else if(dz->ssampsread <= 0)
+			break;
+		n = 0;
+		getnextbuf = 0;
+	}
+
+	/* CHECK THAT ANY NOISE : non-NOISE SWITCHES FOUND */
+
+	if(brkpntcnt<=1) {
+		if(isnoise) {
+			sprintf(errstr,"Sound is all noise.");
+			return(GOAL_FAILED);
+		} else {
+			sprintf(errstr,"Sound has no noise.");
+			return(GOAL_FAILED);
+		}
+	}
+
+	/* ELIMINATE ANY TONE-SEGS SHORTER THAN 2 SPLICELENS */
+
+	twosplices = (dz->iparam[NOISE_SPLEN] * 2);
+	if(noisefirst) 
+		k = 1;
+	else
+		k = 2;
+	for(n=k;n<brkpntcnt;n++) {
+		if(dz->lparray[0][n] - dz->lparray[0][n-1] <= twosplices) {
+			for(j=n+1,m=n-1;j<brkpntcnt;j++,m++)
+				dz->lparray[0][m] =dz->lparray[0][j];
+			brkpntcnt -= 2;
+			n -= 2;
+		}
+	}
+
+	/* ADD SPLICE STARTS AND ENDS TO ARRAY of SWITCH-POINTS */
+
+//TW: late july : AVOID realloc PROBLEMS ... EXTRA SPACE INCLUDED IM INITIAL malloc INSTERAD OF ADDING IT HERE
+//	if((dz->lparray[0] = (int *)realloc(dz->lparray[0],brkpntcnt * 2 * sizeof(int)))==NULL) {
+//		sprintf(errstr,"No more memory for splice points.");
+//		return(MEMORY_ERROR);
+//	}
+	
+	if((noisefirst && EVEN(brkpntcnt)) || (!noisefirst && ODD(brkpntcnt)))		/* ends with noise */
+		spliceafter = 0;
+	else																		/* ends with tone */
+		spliceafter = 1;
+	for(n = brkpntcnt-1; n >= 0; n--) {
+		m = n * 2;
+		if(spliceafter) {
+			dz->lparray[0][m]   = dz->lparray[0][n];
+			dz->lparray[0][m+1] = dz->lparray[0][n] + dz->iparam[NOISE_SPLEN];
+		} else {
+			dz->lparray[0][m+1] = dz->lparray[0][n];
+			dz->lparray[0][m]   = dz->lparray[0][n] - dz->iparam[NOISE_SPLEN];
+		}
+		spliceafter = !spliceafter;
+	}
+	brkpntcnt *= 2;
+
+	/* ELIMINATE BAD POINTS AT START OR END */
+											/* as original [noise to non-noise ot vice versa] pts MUST lie within sound..... */
+	if(dz->lparray[0][0] < 0) {				/* 1st splice can start BEFORE snd start only if it's a 'splicebefore' */
+											/* from tone->noise at start of sound, and that tone is too short */
+		for(j=0,n=2;n < brkpntcnt;n++,j++)	/* eliminate it by eliminating opening splice */
+			dz->lparray[0][j] = dz->lparray[0][n];
+		brkpntcnt -= 2;						/* AND indicating sounds now starts with noise */
+		noisefirst = 1;
+	}										/* final splice can end AFTER sound end only if it's a 'spliceafter' */
+											/* from noise->tone at end of sound, and that tone is too short */
+											/* so, by eliminating last splice, we eliminate that tone */
+	if(dz->lparray[0][brkpntcnt-1] > dz->insams[0])
+		brkpntcnt -= 2;						
+
+	if(brkpntcnt<=2) {
+		if(isnoise) {
+			sprintf(errstr,"Sound is all noise.");
+			return(GOAL_FAILED);
+		} else {
+			sprintf(errstr,"Sound has no noise.");
+			return(GOAL_FAILED);
+		}
+	}
+
+	/* RETAIN SPLICE STARTS ONLY */
+	
+	for(n=1,m=2;m <brkpntcnt;n++, m+=2)
+		dz->lparray[0][n] = dz->lparray[0][m];
+	brkpntcnt = n;
+
+	/* NOW EDIT SOUND */
+	sndseekEx(dz->ifd[0],0,0);
+	dz->total_samps_read = 0;
+	display_virtual_time(0,dz);
+
+	in_splice = 0;
+	splice_cnt = 0;
+	if(dz->vflag[GET_NOISE])
+		noisefirst = !noisefirst;
+	
+	if(noisefirst)
+		in_noise = 1;
+	else
+		in_noise = 0;
+
+	k = -1;		
+	OK = JUST_CONTINUE;
+
+	/* BUFFER READING:WRITING LOOP */
+	
+	while(OK == JUST_CONTINUE) {
+		last_total_samps_read = dz->total_samps_read;
+		if((exit_status = read_samps(ibuf,dz))<0)
+			return(exit_status);		/* reads first, or subsequent buffer */
+		else if(dz->ssampsread <= 0) {
+			OK = CUTOFF_OUTPUT;			/* if infile exhausted, flag no more output file here */
+			break;						/* which means we can break from read loop WITHOUT writing more data */
+		}
+		edit_position  = 0;				/* point to start of buffer, earliest position where edits can take effect */
+		if(in_splice) {					/* if editing process has begun before start of this buffer */
+										/* .... and we're in midst of a splice at start of buffer, complete splice */
+										/* (guaranteed to be completed within current buffer, due to bufsize checks) */
+			in_splice = do_alternating_splices(&in_noise,&splice_cnt,&edit_position,splincr,dz);
+			k++;
+		}
+
+	/* EDITING OF CURRENT BUFFER, LOOP */
+	
+		for(;;) {
+			if(in_splice)				/* If a splice fails to finish during treatment of current buffer ...  */
+				break;					/* .... we must be at end of buffer, so break from buffer-editing loop */
+
+			if(++k >= brkpntcnt) {		/* if there are no more editpoints to read ... */
+				if(in_noise) {						/* this indicates final seg is noise  */
+					dz->ssampsread = edit_position;	/* so we can curtail outfile to START of this final [edited out] noise seg */
+					OK = CUTOFF_OUTPUT;
+				} else							/* otherwise, final segment is retainable signal */
+					OK = WRITERESTOF_INPUT;		/* so flag that we want to write the rest of input to output */
+				break;						/* in BOTH cases, exit from the buffer-editing loop */
+
+			} else						/* else, get next edit point */
+				nextpoint = dz->lparray[0][k];	
+										/* if next edit point lies within current buffer */
+			if(nextpoint < dz->total_samps_read) {
+				next_edit_position = nextpoint - last_total_samps_read;	/* get position of edit-point WITHIN buffer */
+				if(in_noise)				/* remove noise by zeroing signal from previous edit_end to current edit_start */
+					memset((char *)(ibuf + edit_position),0,(next_edit_position - edit_position) * sizeof(float));	
+				edit_position = next_edit_position;		/* reset edit_position */
+				splice_cnt = 0;				/* reset the splice-counter to zero, for new splice */
+											/* do-splice, automatically resetting 'in_noise' flag if splice completed */
+											/* ...but setting in_splice flag to TRUE if splice NOT completed */
+				in_splice = do_alternating_splices(&in_noise,&splice_cnt,&edit_position,splincr,dz);
+			} else {					/* next edit point lies within current buffer */
+				k--;					/* restore counter when buffer switches */
+				break;					/* so, exit buffer-editing loop and go write-output and read next buffer */
+			}
+		}								
+									/* EXITED  buffer-editing loop */
+									/* if still in noise, remove noise at end of buffer  */
+		if((edit_position < dz->ssampsread) && in_noise)
+			memset((char *)(ibuf + edit_position),0,(dz->ssampsread - edit_position) * sizeof(float));
+									/* write the edited buffer */
+		if(dz->ssampsread > 0) {
+			if((exit_status = write_samps(ibuf,dz->ssampsread,dz))< 0)
+				return(exit_status);
+		}							/* go [round loop] to read next buffer */
+	}
+
+	if(OK==WRITERESTOF_INPUT) {
+		if((exit_status = read_samps(ibuf,dz))<0)
+			return(exit_status);
+		while(dz->ssampsread > 0) {
+			if((exit_status = write_samps(ibuf,dz->ssampsread,dz))< 0)
+				return(exit_status);
+			if((exit_status = read_samps(ibuf,dz))<0)
+				return(exit_status);
+		}
+	}
+	return(FINISHED);
+}
+
+/********************************** DO_ALTERNATING_SPLICES **********************************/
+
+int do_alternating_splices(int *in_noise,int *splice_cnt,int *edit_position,double splincr,dataptr dz)
+{
+	double newval, spliceval = (double)(*splice_cnt)/(double)dz->iparam[NOISE_SPLEN];
+	double this_splincr = splincr;
+	
+	if(!(*in_noise)) {
+		spliceval = 1.0 - spliceval;
+		this_splincr = -this_splincr;
+	}
+	while(*splice_cnt < dz->iparam[NOISE_SPLEN]) {
+		newval = dz->sampbuf[0][*edit_position] * spliceval;
+		dz->sampbuf[0][*edit_position] = (float)newval;
+		(*edit_position)++;
+		(*splice_cnt)++;
+		if(*edit_position >= dz->ssampsread)
+			break;
+		spliceval += this_splincr;
+	}
+	if(*splice_cnt >= dz->iparam[NOISE_SPLEN]) {
+		(*in_noise) = !(*in_noise);
+		return(0);
+	}
+	return(1);
+}
+
+/********************************** SETUP_INSERT2_OVERWRITE_FLAG **********************************/
+
+int setup_insert2_overwrite_flag(dataptr dz)
+{
+	int flags_needed = INSERT_OVERWRITE + 1;
+	if(dz->application->vflag_cnt <= INSERT_OVERWRITE) {
+		if(dz->application->vflag_cnt <=0) {
+			if((dz->vflag  = (char *)malloc(flags_needed * sizeof(char)))==NULL) {
+				sprintf(errstr,"INSUFFICIENT MEMORY: vflag store,\n");
+				return(MEMORY_ERROR);
+			}
+		} else {
+			if((dz->vflag  = (char *)realloc((char *)dz->vflag,flags_needed * sizeof(char)))==NULL) {
+				sprintf(errstr,"INSUFFICIENT MEMORY: vflag store,\n");
+				return(MEMORY_ERROR);
+			}
+		}
+	}
+	dz->vflag[INSERT_OVERWRITE] = 1;
+	return FINISHED;
+}
+
+/*************************** DO_PATTERNED_JOINING *****************************
+ *
+ * Exactly as do_joining, except for commented  stuff.
+ */
+
+int do_patterned_joining(dataptr dz)
+{
+	int  exit_status;
+	int total_fsamps_read, samps_to_get, samps_read, samps_to_write;
+	int	 n, m, k, nextfile, readcnt, lmt = 0;
+	int  overspill, splice_remnant;
+	int	 tempfile = -1;
+	char tempfilename[200];
+	int thisifd;
+	unsigned int this_size, hold_samps;
+
+	strcpy(tempfilename,dz->wordstor[0]);
+	strcat(tempfilename,"_");
+	insert_new_number_at_filename_end(tempfilename,dz->infilecnt,0);	/* create name for temp file */
+
+	dz->iparam[CUT_SMPSREMAIN] = dz->buflen;
+	dz->sampbuf[READBUF]       = dz->sampbuf[BBUF];
+	if(dz->iparam[CUT_SPLEN]==0)
+		lmt = -1;
+
+	for(m=0;m < dz->itemcnt;m++) {					/* get next file in pattern */
+		if(dz->process == JOIN_SEQ && m >= dz->iparam[MAX_LEN])
+			break;
+		n = dz->iparray[0][m];
+		if(n >= dz->infilecnt) {
+			sndseekEx(dz->other_file,0,0);
+			fprintf(stdout,"INFO: Processing FILE %d\n",tempfile+1);
+		} else {										/* reset selected file to start */
+			sndseekEx(dz->ifd[n],0,0);					
+			fprintf(stdout,"INFO: Processing FILE %d\n",n+1);
+		}
+		fflush(stdout);
+		if(m < dz->itemcnt - 1)						/* check the succeeding file in the pattern */
+			nextfile = dz->iparray[0][m+1];
+		else 
+			nextfile = -1;
+		if(n == nextfile) {							/* if same file is used contiguously */
+			if(tempfile != n) {						/* if the temporary file is not the same as this one */
+				if(tempfile != -1) {
+					char pfname[_MAX_PATH];
+					strcpy(pfname, snd_getfilename(dz->other_file));
+					sndcloseEx(dz->other_file);
+					if(remove(/*outfilename*/pfname)<0) {
+						fprintf(stdout,"WARNING: Tempfile %s not removed: ",tempfilename);
+						fflush(stdout);
+					}
+					dz->other_file = -1;
+				}									/* create a temporary file */
+				if((dz->other_file=sndcreat_formatted(tempfilename,dz->insams[n],SAMP_FLOAT,
+				dz->infile->channels,dz->infile->srate,CDP_CREATE_NORMAL))<0) {
+					sprintf(errstr,"Cannot open temporary file %s: %s\n", tempfilename,sferrstr());
+					return(SYSTEM_ERROR);
+				}									/* copy current file into temporary file */
+				do {
+					if((samps_read  = fgetfbufEx(dz->sampbuf[COPYBUF], dz->buflen,dz->ifd[n],0))<0) {
+						sprintf(errstr,"Sound read error.\n");
+						return(SYSTEM_ERROR);
+					}
+					if(samps_read > 0) {
+						hold_samps = dz->total_samps_written;
+						if((exit_status = 
+							write_samps_to_elsewhere(dz->other_file,dz->sampbuf[COPYBUF],samps_read,dz))<0) {
+							sprintf(errstr, "Can't write copied samples to temporary soundfile:  (is hard-disk full?).\n");
+							return(SYSTEM_ERROR);
+						}
+						dz->total_samps_written = hold_samps;
+					}
+				} while (samps_read > 0);			
+				memset((char *)dz->sampbuf[COPYBUF],0,dz->buflen * sizeof(float));
+				sndseekEx(dz->ifd[n],0,0);				/* reset copy buffer (safety only), and current file position */
+				tempfile = n;						/* remember which file's data is in the temporary file */			
+			}
+			dz->iparray[0][m+1] = dz->infilecnt;	/* set up next-file-to-use as the temporary file */
+		}
+		if(n >= dz->infilecnt)						/* if temporary file in use */
+			this_size = dz->insams[tempfile];		/* find its size by reference to file copied from */
+		else										/* else find size of current normal file */
+			this_size = dz->insams[n];
+		if((samps_to_get = this_size - dz->iparam[CUT_SPLEN])<=0) {
+			sprintf(errstr,"File %d is too short for the given splicelength\n",n+1);
+			return(GOAL_FAILED);
+		}
+		total_fsamps_read = 0;
+		readcnt = 0;
+		for(;;) {
+			if(n >= dz->infilecnt)					/* if temporary file in use, get its filepointer */
+				thisifd = dz->other_file;
+			else									/* else get filepointer of current file */
+				thisifd = dz->ifd[n];
+			if((samps_read = fgetfbufEx(dz->sampbuf[READBUF],dz->iparam[CUT_SMPSREMAIN],thisifd,0))<0) {
+				sprintf(errstr, "Can't read samples from input soundfile\n");
+				return(SYSTEM_ERROR);
+			}
+			if(dz->process == JOIN_SEQDYN) {
+				for(k = 0;k < samps_read; k++)
+					dz->sampbuf[READBUF][k] = (float)(dz->sampbuf[READBUF][k] * dz->parray[2][m]);
+			}
+			overspill = (total_fsamps_read += samps_read) - samps_to_get;
+			if(overspill > lmt)
+				break;
+			if(dz->iparam[CUT_SPLEN]>0 && readcnt==0)
+				do_join_startsplice(n,dz);
+			if((exit_status = write_exact_samps(dz->sampbuf[BBUF],dz->buflen,dz))<0)	
+				return(exit_status);
+			housekeep2(samps_read,dz);
+			readcnt++;
+		}
+		if(dz->iparam[CUT_SPLEN]>0) {
+			if(readcnt==0)
+				do_join_startsplice(n,dz);
+			housekeep1(samps_read,overspill,dz);
+			if((splice_remnant = dz->iparam[CUT_SPLEN] - overspill)>0)	{
+				if((exit_status = do_join_write(n,splice_remnant,overspill,dz))<0)
+					return(exit_status);
+			} else {
+				if((exit_status = reset_join_buffer_params(dz))<0)
+					return(exit_status);
+			}
+		} else {
+			dz->sbufptr[ENDSPLICE_ADDR] = dz->sampbuf[READBUF] + samps_read;
+			if((exit_status = reset_join_buffer_params(dz))<0)
+				return(exit_status);
+		}
+	}
+	if(dz->iparam[CUT_SPLEN]>0) {
+		if(dz->vflag[SPLICE_END])
+			do_join_endsplice(dz);
+		memcpy((char *)dz->sampbuf[READBUF],(char *)dz->sampbuf[SPLICEBUF],dz->iparam[CUT_SPLEN] * sizeof(float));
+	}		
+	samps_to_write = dz->sampbuf[READBUF] + dz->iparam[CUT_SPLEN] - dz->sampbuf[BBUF];
+	if(samps_to_write > 0)
+		exit_status = write_samps(dz->sampbuf[BBUF],samps_to_write,dz);
+	else
+		exit_status = FINISHED;
+	if(tempfile != -1) {			
+		char pfname[_MAX_PATH];
+		strcpy(pfname, snd_getfilename(dz->other_file));
+		sndcloseEx(dz->other_file);
+		if(remove(/*outfilename*/pfname)<0) {
+			fprintf(stdout,"WARNING: Tempfile %s not removed: ",tempfilename);
+			fflush(stdout);
+		}
+		dz->other_file = -1;
+	}
+	return exit_status;
+}
+
+/*************************** DO_MANY_ZCUTS *****************************/
+
+int do_many_zcuts(dataptr dz) {
+	int exit_status, outcnt, last_fileout = 0;
+	char filename[400];
+	int n, m;
+	outcnt = 0;
+	for(n=0,m=0;m < dz->itemcnt;n++,m+=2) {
+		if((outcnt > 0) && (last_fileout != outcnt)) {
+			strcpy(filename,dz->wordstor[0]);
+			if(sloom)
+				insert_new_number_at_filename_end(filename,outcnt,1);
+			else
+				insert_new_number_at_filename_end(filename,outcnt+1,0);
+			if((exit_status = create_sized_outfile(filename,dz))<0) {
+				sprintf(errstr, "ERROR: Soundfile %s already exists: cannot proceed further\n", filename);
+				fflush(stdout);
+			}
+		}
+		dz->iparam[CUT_CUT] = (int)dz->lparray[0][m];
+		dz->iparam[CUT_END] = (int)dz->lparray[0][m+1];
+		sndseekEx(dz->ifd[0],0,0);
+		dz->total_samps_read = 0;
+		memset((char *)dz->sampbuf[OBUF],0,dz->buflen * sizeof(float));
+		memset((char *)dz->sampbuf[IBUF],0,dz->buflen * sizeof(float));
+		if((exit_status = do_zcut(dz)) < 0) {
+			fprintf(stdout,"INFO: FAILED TO MAKE EDIT %d\n",n+1);
+			fflush(stdout);
+			continue;
+		} else {
+			if((exit_status = headwrite(dz->ofd,dz))<0)
+				return(exit_status);
+			if((exit_status = reset_peak_finder(dz))<0)
+				return(exit_status);
+			if(sndcloseEx(dz->ofd)<0) {
+				sprintf(errstr,"Failed to close output soundfile.\n");
+				return(SYSTEM_ERROR);
+			}
+			dz->ofd = -1;
+			last_fileout = outcnt;
+			outcnt++;
+			display_virtual_time(outcnt,dz);
+		}
+	}
+	if(outcnt == 0) {
+		sprintf(errstr,"NO EDITS MADE");
+		return(GOAL_FAILED);
+	}
+	return FINISHED;
+}
+	

+ 242 - 0
dev/editsf/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
+ *
+ */
+
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <structures.h>
+#include <tkglobals.h>
+#include <edit.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 = "7.1.0";
+
+/**************************************** MAIN *********************************************/
+
+int main(int argc,char *argv[])
+{
+	int exit_status;
+//	FILE *fp   = NULL;
+	dataptr dz = NULL;
+//	char *special_data_string = NULL;
+	char **cmdline;
+	int  cmdlinecnt;
+	aplptr ap;
+	int *valid = NULL;
+	int is_launched = FALSE;
+	int  validcnt = 0;
+
+	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((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 = 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);
+}
+

+ 695 - 0
dev/editsf/twixt.c

@@ -0,0 +1,695 @@
+/*
+ * 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 */
+/*
+cmdline...
+sfedit twixt mode infile(s) outfile switch-times splicelen (segcnt) [-wweight] [-r]\n\n"
+
+SWITCH_TIMES	 = special
+SPLICETIME in MS = IS_SPLEN
+SWITCH_WEIGHT	 = IS_WEIGHT
+FLAG	IS_NOTCYCL
+
+
+TO SPLICE BETWEEN A SERIES OF INFILES USING A LIST OF GIVEN TIMES
+
+*/
+
+#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 <edit.h>
+#include <processno.h>
+#include <modeno.h>
+#include <globcon.h>
+#include <logic.h>
+#include <filetype.h>
+#include <mixxcon.h>
+#include <flags.h>
+#include <speccon.h>
+#include <arrays.h>
+#include <special.h>
+#include <formants.h>
+#include <sfsys.h>
+#include <osbind.h>
+
+#if defined unix || defined __GNUC__ 
+#define round(x) lround((x))
+#endif
+
+static void GetTimes(int fileno,int n,double *lasttime, double *nexttime,dataptr dz);
+static int  do_output(int fileno,int n,int limit,double lasttime,double nexttime,
+				double splicestep,int *obufend,int *total_outsamps,dataptr dz);
+static int Convert_to_samp(double time,dataptr dz);
+static void do_startsplice_in_outbuf(float *buf,double splicestep,dataptr dz);
+static void do_startof_endsplice_in_outbuf(float *buf,int splicetodo,double splicestep,dataptr dz);
+static int 	output_samps(int segno,int firsttime,float *outbuf,int outsamps,int *obufend,dataptr dz);
+static int 	flush_outbuf(int segno,int obufend,dataptr dz);
+static void randperm(int z,int setlen,dataptr dz);
+static void hprefix(int z,int m,int setlen,dataptr dz);
+static void hinsert(int z,int m,int t,int setlen,dataptr dz);
+static void hshuflup(int z,int k,int setlen,dataptr dz);
+static int 	output_cut_sndfile(dataptr dz);
+static int 	setup_new_outfile(int n,dataptr dz);
+static void	generate_splicelen(dataptr dz);
+static int 	Getnextfile(int n,int permcnt,dataptr dz);
+static void do_endsplice_in_outbuf(float *buf,double splicestep,dataptr dz);
+
+//TW replaced by global F_SECSIZE
+//#define FSECSIZE (256)		   /*RWD*/
+
+/********************************* DO_INTERSPLICE *************************************
+ *
+ * THE ALGORITHM
+ * 
+ * A TWO-STAGE PROCESS:
+ * 1) We read from an infile into a sector-aligned buffer
+ * 2) We read from a point in inbuffer (not ness coinciding with its start(which is a sector boundary))
+ * 	     putting in splice at start of read (and, eventually, splice at end of all reads from this infile)
+ * 3) WE copy each read to an outbuffer
+ * 4) Except on very first use, outbuffer always retains a SPLICELEN-segment of data from the previous read
+ * 		ready for splice to be made to next file copied into it.
+ * 5) At start of this copy-to-outbuf we ADD the upsplice-part of new file to end downsplice of previous file
+ * 		before proceeding to straightforward copying
+ */
+
+int do_twixt(dataptr dz)
+{
+	int exit_status, n = 0, limit, fileno;
+	double lasttime=0.0, nexttime=0.0, splicestep;
+	int obufend = 0, permcnt = 0, outsamps;
+
+	splicestep = 1.0/(SPLICELEN/dz->infile->channels);
+
+	if(dz->process != TWIXT || dz->mode != TRUE_EDIT)
+		permcnt = dz->infilecnt + dz->iparam[IS_WEIGHT] - 1;
+
+	if(dz->process == TWIXT && dz->mode == TRUE_EDIT)
+		limit = dz->itemcnt - 1; 
+	else {
+		switch(dz->mode) {
+		case(IN_SEQUENCE): 	
+			limit = dz->itemcnt - 1;
+			break;
+		default:			
+			limit = dz->iparam[IS_SEGCNT]; 
+			break;	
+		}
+	}
+	dz->tempsize = (int)limit;
+
+	while(n<limit) {
+		fileno = Getnextfile(n,permcnt,dz);
+		GetTimes(fileno,n,&lasttime,&nexttime,dz);
+		if((exit_status = do_output(fileno,n,limit,lasttime,nexttime,splicestep,&obufend,&outsamps,dz))<0)
+			return(exit_status);
+		n++;
+	}
+	if((exit_status = flush_outbuf(n-1,obufend,dz))<0)
+		return exit_status;
+	if(dz->process == TWIXT && dz->mode == TRUE_EDIT) {
+		if((exit_status = output_cut_sndfile(dz))<0)
+			return exit_status;
+	}
+	return (FINISHED);
+}
+
+/********************************* GETTIMES *************************************/
+
+void GetTimes(int arrayno,int n,double *lasttime, double *nexttime,dataptr dz)
+{
+	int k, j, lastperm;
+	static int init = 1;
+	int span = dz->itemcnt-1;
+
+	if(dz->process == TWIXT)	/* only one aray of times, for TWIXT */
+		arrayno = 0;
+	if(dz->process == TWIXT && dz->mode == TRUE_EDIT) {
+		*lasttime = dz->parray[arrayno][n++];
+		*nexttime = dz->parray[arrayno][n];
+	} else {
+		switch(dz->mode) {
+		case(IN_SEQUENCE):
+			*lasttime = dz->parray[arrayno][n++];
+			*nexttime = dz->parray[arrayno][n];
+			break;
+		case(RAND_REORDER):
+			n %= span;
+			if(n == 0) {
+				if(init) {
+					randperm(0,span,dz);
+					init = 0;
+				} else {
+//TW UPDATE
+//					lastperm = dz->iparray[arrayno][span-1];
+					lastperm = dz->iparray[0][span-1];
+					randperm(0,span,dz);
+//TW UPDATE
+//					if(lastperm == dz->iparray[arrayno][0]) {
+//						for(j=0;j < span; j++) {
+//							if(dz->iparray[arrayno][j] != lastperm) {
+//								dz->iparray[arrayno][0] = dz->iparray[arrayno][j];
+//								dz->iparray[arrayno][j] = lastperm;
+					if(lastperm == dz->iparray[0][0]) {
+						for(j=0;j < span; j++) {
+							if(dz->iparray[0][j] != lastperm) {
+								dz->iparray[0][0] = dz->iparray[0][j];
+								dz->iparray[0][j] = lastperm;
+								break;
+							}
+						}
+					}
+				}
+			}
+//TW UPDATE
+//			k = dz->iparray[arrayno][n];
+			k = dz->iparray[0][n];
+			*lasttime = dz->parray[arrayno][k++];
+			*nexttime = dz->parray[arrayno][k];
+			break;
+		case(RAND_SEQUENCE):
+			k = (int)floor(drand48() * span);
+			*lasttime = dz->parray[arrayno][k++];
+			*nexttime = dz->parray[arrayno][k];
+			break;
+		}
+	}
+}
+
+/********************************* DO_OUTPUT *************************************/
+/*RWD 6:2001: NB permcnt,n unused */
+int do_output(int fileno,int n,int limit,double lasttime,double nexttime,double splicestep,
+			int *obufend,int *total_outsamps,dataptr dz)
+{
+	int exit_status;
+	static int init;
+	int lastsamp = Convert_to_samp(lasttime,dz);
+	int nextsamp = Convert_to_samp(nexttime,dz);
+	int firsttime = 1;
+	int remaining_samps_to_write, startbuf, offset, rotate, max_possible_outsamps, outsamps, startsplice;
+	float *inbuf, *outbuf;
+
+	if(nextsamp - lastsamp < SPLICELEN)	/* Possible for final segment */
+		return(FINISHED);
+	lastsamp = max(0,lastsamp - SPLICELEN);	/* adjust so upsplice starts before start of segment */
+	remaining_samps_to_write = nextsamp - lastsamp;
+	*total_outsamps = remaining_samps_to_write;
+	startbuf = (lastsamp/dz->iparam[IS_SHSECSIZE]) * dz->iparam[IS_SHSECSIZE];
+	offset = lastsamp - startbuf;
+	rotate = dz->iparam[IS_SHSECSIZE] - offset;
+
+/*
+ *	x = offset, start of outbuf
+ *	y = SECTOR-minus-x left at end
+ *
+ *	 	 b_________________________________c
+ *	  x |								    |y
+ *	|_____________INBUF positioned ___________|
+ *	        so y can be copied to its start
+ *
+ *	1st time, output from b to c = sampbuflen - dz->iparam[IS_SHSECSIZE]
+ *	then copy 'y' to before start of inbuf
+ *	Other reads, output from a to c. = sampbuflen
+ *	then copy 'y' to before start of inbuf
+ *
+ *  a_____b_________________________________c
+ *|y|  x  |
+ *|_____sampbuf = standardsize + SECTOR_________|
+ *
+ */
+
+	inbuf = dz->sampbuf[0] + (dz->iparam[IS_SHSECSIZE] - offset);			
+	outbuf = inbuf + offset;
+	max_possible_outsamps = dz->buflen - dz->iparam[IS_SHSECSIZE];
+	sndseekEx(dz->ifd[fileno],startbuf,0);
+	dz->total_samps_read = startbuf;
+	do {
+		if(n!=0 && (dz->process == TWIXT) && (dz->mode == TRUE_EDIT) && firsttime) {
+			if((exit_status = setup_new_outfile(n,dz))<0)
+				return(exit_status);
+		}
+	 	if((dz->ssampsread = fgetfbufEx(inbuf, dz->buflen,dz->ifd[fileno],0)) < 0) {
+			sprintf(errstr,"Can't read samples from input soundfile.\n");
+			return(SYSTEM_ERROR);
+		}
+		if(dz->ssampsread == 0)
+			break;
+ 		if(firsttime && !init)
+			do_startsplice_in_outbuf(outbuf,splicestep,dz);
+		else
+			init = 0;
+		if(max_possible_outsamps >= remaining_samps_to_write) {
+			outsamps = remaining_samps_to_write;
+			do_endsplice_in_outbuf(outbuf + outsamps - SPLICELEN,splicestep,dz);
+		} else {
+			outsamps = max_possible_outsamps;
+			 if ((startsplice = remaining_samps_to_write - SPLICELEN) < outsamps)
+				do_startof_endsplice_in_outbuf(outbuf + startsplice,outsamps - startsplice,splicestep,dz);
+		}
+		output_samps(n,firsttime,outbuf,outsamps,obufend,dz);
+		remaining_samps_to_write -= outsamps;
+		memcpy((char *)dz->sampbuf[0],(char *)(outbuf + outsamps),rotate * sizeof(float));
+		outbuf = dz->sampbuf[0];					/* after first output */
+		max_possible_outsamps = dz->buflen;
+		firsttime = 0;
+	} while(remaining_samps_to_write > 0);
+
+	if((dz->process == TWIXT) && (dz->mode == TRUE_EDIT) && (n != limit - 1)) {
+		if((exit_status = flush_outbuf(n,*obufend,dz))<0)
+			return exit_status;
+		*obufend = 0;
+		return output_cut_sndfile(dz);
+	}
+	return(FINISHED);
+}
+
+/********************************* CONVERT_TO_SAMP *************************************/
+
+int Convert_to_samp(double time,dataptr dz)
+{
+	int sampcnt = (int)round(time * dz->infile->srate);
+	sampcnt *= dz->infile->channels;
+	return(sampcnt);
+}
+
+/********************************* DO_STARTSPLICE_IN_OUTBUF *************************************/
+
+void do_startsplice_in_outbuf(float *buf,double splicestep,dataptr dz)
+{
+	int chans = dz->infile->channels;
+	double q, mult = 0.0;
+	int k, n = 0;
+	while(n < SPLICELEN) {
+		mult += splicestep;
+		for(k = 0; k < chans; k++) {
+			q = *buf * mult;
+			*buf++ = (float) /*round*/(q);
+			n++;
+		}
+	}
+}
+
+/********************************* DO_ENDSPLICE_IN_OUTBUF *************************************/
+
+void do_endsplice_in_outbuf(float *buf,double splicestep,dataptr dz)
+{
+	int chans = dz->infile->channels;
+	double q, mult = 1.0;
+	int k, n = 0;
+	while(n < SPLICELEN) {
+		mult -= splicestep;
+		for(k = 0; k < chans; k++) {
+			q = *buf * mult;
+			*buf++ = (float) /*round*/(q);
+			n++;
+		}
+	}
+}
+
+/********************************* DO_STARTOF_ENDSPLICE_IN_OUTBUF *************************************/
+
+void do_startof_endsplice_in_outbuf(float *buf,int splicetodo,double splicestep,dataptr dz)
+{
+	int chans = dz->infile->channels;
+	double q, mult = 1.0;
+	int k, n = 0;
+	while(n < splicetodo) {
+		mult -= splicestep;
+		for(k = 0; k < chans; k++) {
+			q = *buf * mult;
+			*buf++ = (float) /*round*/(q);
+			n++;
+		}
+	}
+}		
+
+/********************************* OUTPUT_SAMPS *************************************/
+
+int output_samps(int segno,int firsttime,float *outbuf,int outsamps,int *obufend,dataptr dz)
+{
+	/* true length of buf = buflen + SPLICELEN */
+	int exit_status;
+	int n, samps_to_copy, xs;
+	int samps_to_write = dz->buflen ;
+	int space_in_outbuf = dz->buflen + SPLICELEN - *obufend;
+	float *thisbuf = dz->sampbuf[1] + *obufend;
+	static int ob_firsttime = 1;
+
+	if(ob_firsttime) {
+		memcpy((char *)thisbuf,(char *)outbuf,outsamps * sizeof(float));
+		*obufend = outsamps;
+		ob_firsttime = 0;
+	} else {
+		if(firsttime && (dz->process != TWIXT || dz->mode != TRUE_EDIT)) {
+			thisbuf -= SPLICELEN;
+			for(n=0; n < SPLICELEN; n++)
+				thisbuf[n] = (float)(thisbuf[n] + outbuf[n]);
+			thisbuf += SPLICELEN;
+			outbuf  += SPLICELEN;
+			samps_to_copy = outsamps - SPLICELEN;
+		} else
+			samps_to_copy = outsamps;
+		if((xs = samps_to_copy - space_in_outbuf) < 0) {
+			memcpy((char *)thisbuf,(char *)outbuf,samps_to_copy * sizeof(float));
+			*obufend += samps_to_copy;
+		} else {
+			memcpy((char *)thisbuf,(char *)outbuf,space_in_outbuf * sizeof(float));
+			samps_to_write = dz->buflen;
+			superzargo = segno + 1;
+			if((exit_status = write_samps(dz->sampbuf[1],samps_to_write,dz))<0)
+				return(exit_status);
+			thisbuf = dz->sampbuf[1];
+			memcpy((char *)thisbuf,(char *)(thisbuf + dz->buflen),SPLICELEN * sizeof(float));
+			memset((char *)(thisbuf+SPLICELEN),0,samps_to_write);
+			*obufend = SPLICELEN;
+			if(xs > 0) {
+				thisbuf += *obufend; 
+				outbuf += space_in_outbuf;
+				memcpy((char *)thisbuf,(char *)outbuf,xs * sizeof(float));
+				*obufend += xs;
+			}
+		}
+	}
+	return(FINISHED);
+}	
+		
+/********************************* FLUSH_OUTBUF *************************************/
+
+int flush_outbuf(int segno,int obufend,dataptr dz)
+{
+	int exit_status;
+	int samps_to_write = obufend;
+	superzargo = segno+1;
+	if(samps_to_write > 0) {
+		if((exit_status = write_samps(dz->sampbuf[1],samps_to_write,dz))<0)
+			return(exit_status);
+	}
+	return(FINISHED);
+}
+
+/********************************* RANDPERM *************************************/
+
+void randperm(int z,int setlen,dataptr dz)
+{
+	int n, t;
+	for(n=0;n<setlen;n++) {
+		t = (int)floor(drand48() * (n+1));
+		if(t>=n)
+			hprefix(z,n,setlen,dz);
+		else
+			hinsert(z,n,t,setlen,dz);
+	}
+}
+
+/***************************** HINSERT **********************************
+ *
+ * Insert the value m AFTER the T-th element in iparray[].
+ */
+
+void hinsert(int z,int m,int t,int setlen,dataptr dz)
+{   
+	hshuflup(z,t+1,setlen,dz);
+	dz->iparray[z][t+1] = m;
+}
+
+/***************************** HPREFIX ************************************
+ *
+ * Insert the value m at start of the permutation iparray[].
+ */
+
+void hprefix(int z,int m,int setlen,dataptr dz)
+{
+	hshuflup(z,0,setlen,dz);
+	dz->iparray[z][0] = m;
+}
+
+/****************************** HSHUFLUP ***********************************
+ *
+ * move set members in iparray[] upwards, starting from element k.
+ */
+
+void hshuflup(int z,int k,int setlen,dataptr dz)
+{   
+	int n, *i;
+	int y = setlen - 1;
+	i = (dz->iparray[z]+y);
+	for(n = y;n > k;n--) {
+		*i = *(i-1);
+		i--;
+	}
+}
+
+/********************************** OUTPUT_CUT_SNDFILE ********************************/
+
+int output_cut_sndfile(dataptr dz)
+{
+	int exit_status;
+	char filename[64];
+	if((exit_status = headwrite(dz->ofd,dz))<0)
+		return(exit_status);
+	dz->process_type = OTHER_PROCESS;		/* stop process trying to deal with outfile later */
+	dz->outfiletype  = NO_OUTPUTFILE;		/* stop process trying to deal with outfile later */
+	if(sndcloseEx(dz->ofd) < 0) {
+		fprintf(stdout,"WARNING: Can't close output soundfile %s\n",filename);
+		fflush(stdout);
+	}
+	dz->ofd = -1;
+	return(FINISHED);
+}
+
+/********************************** SETUP_NEW_OUTFILE ********************************/
+
+int setup_new_outfile(int n,dataptr dz)
+{
+	int exit_status;
+	char filename[64];
+	strcpy(filename,dz->wordstor[0]);
+	insert_new_number_at_filename_end(filename,n,1);
+
+	dz->process_type = UNEQUAL_SNDFILE;	/* allow sndfile to be created */
+	dz->outfiletype  = SNDFILE_OUT;		/* allows header to be written  */
+	if((exit_status = create_sized_outfile(filename,dz))<0) {
+		fprintf(stdout, "WARNING: Cannot create Soundfile %s : %s\n", filename, rsferrstr);
+		fflush(stdout);
+		dz->process_type = OTHER_PROCESS;
+		dz->outfiletype  = NO_OUTPUTFILE;		/* stop process trying to deal with outfile later */
+		dz->ofd = -1;
+		return(GOAL_FAILED);
+	}
+	return(FINISHED);
+}
+
+/*************************** CREATE_TWIXT_BUFFERS **************************/
+
+int create_twixt_buffers(dataptr dz)
+{
+	int bigsize;
+	size_t bigbufsize;
+	int framesize = F_SECSIZE * dz->infile->channels;
+	if(dz->sbufptr == 0 || dz->sampbuf==0) {
+		sprintf(errstr,"buffer pointers not allocated: create_sndbufs()\n");
+		return(PROGRAM_ERROR);
+	}
+	bigbufsize = (size_t) Malloc(-1);
+	bigbufsize -= (SPLICELEN + F_SECSIZE) * sizeof(float);
+	bigbufsize /= dz->bufcnt;
+	dz->buflen = (int)(bigbufsize/sizeof(float));
+	dz->buflen  =  (dz->buflen / framesize)	* framesize;
+	if(dz->buflen <= 0)
+		dz->buflen = framesize;
+
+	bigsize = (dz->buflen * dz->bufcnt) + SPLICELEN + F_SECSIZE;
+	if((dz->bigbuf = (float *)malloc(bigsize * sizeof(float))) == NULL) {
+		sprintf(errstr,"INSUFFICIENT MEMORY to create sound buffers.\n");
+		return(PROGRAM_ERROR);
+	}
+	dz->sbufptr[0] = dz->sampbuf[0] = dz->bigbuf;
+	dz->sbufptr[1] = dz->sampbuf[1] = dz->sampbuf[0] + dz->buflen + dz->iparam[IS_SHSECSIZE];
+	dz->sampbuf[2] = dz->sampbuf[1] + dz->buflen + SPLICELEN;
+	memset((char *)dz->bigbuf,0,bigsize * sizeof(float));
+	return(FINISHED);
+}
+
+/*************************** TWIXT_PREPROCESS **************************/
+
+int twixt_preprocess(dataptr dz)		
+{
+	double *p, last, next = 0.0;
+	int n;
+	int minsamps = dz->insams[0];
+	for(n = 1; n<dz->infilecnt;n++)
+		minsamps = min(minsamps,dz->insams[n]);
+	dz->duration = (double)(minsamps/dz->infile->channels)/(double)dz->infile->srate;
+	if(dz->mode != TRUE_EDIT) {
+		if((dz->iparray[1] = (int *)malloc((dz->infilecnt + dz->iparam[IS_WEIGHT] - 1) * sizeof(int)))==NULL) {
+			sprintf(errstr,"INSUFFICIENT MEMORY to allocate file permutation store.\n");
+			return(MEMORY_ERROR);
+		}
+	}
+	generate_splicelen(dz);
+	p = dz->parray[0];
+	if((last = *p++) > dz->duration) {
+		sprintf(errstr,"First time in datafile is beyond end of shortest input soundfile (%lf)\n",dz->duration);
+		return(DATA_ERROR);
+	}
+	n = 2;
+	while(n <= dz->itemcnt) {
+		if((next = *p++) > dz->duration) {
+			sprintf(errstr,"Times beyond number %d ( = %lf) in datafile are beyond end of shortest input soundfile (%lf)\n",
+			n-1,last,dz->duration);
+			return(DATA_ERROR);
+		}
+		if(next - last <= dz->param[IS_SPLICETIME]) {
+			sprintf(errstr,"distant between splicepoints %d & %d (%lf) less than time needed for splices (%lf)\n",
+				n,n-1,next-last,dz->param[IS_SPLICETIME]);
+			return(DATA_ERROR);
+		}
+		last = next;
+		n++;
+	}
+	if(dz->duration - next > dz->param[IS_SPLICETIME])  {
+		if((dz->parray[0] = (double *)realloc((char *)dz->parray[0],(dz->itemcnt+1) * sizeof(double)))==NULL) {
+			sprintf(errstr,"Insufficient memory to store time-switch data.\n");
+			return(MEMORY_ERROR);
+		}
+		dz->parray[0][dz->itemcnt] = dz->duration;
+		dz->itemcnt++;
+	}
+	return(FINISHED);
+}
+
+/*************************** SPHINX_PREPROCESS **************************/
+
+int sphinx_preprocess(dataptr dz)		
+{
+	double *p, last, next;
+	int n, k;
+	if((dz->iparray[1] = (int *)malloc((dz->infilecnt + dz->iparam[IS_WEIGHT] - 1) * sizeof(int)))==NULL) {
+		sprintf(errstr,"INSUFFICIENT MEMORY to allocate file permutation store.\n");
+		return(MEMORY_ERROR);
+	}
+	generate_splicelen(dz);
+	for(k=0;k<dz->array_cnt;k++) {
+		p = dz->parray[k];
+		last = *p++;
+		n = 2;
+		while(n <= dz->itemcnt) {
+			next = *p++;
+			if(next - last <= dz->param[IS_SPLICETIME]) {
+				sprintf(errstr,"distant between splicepoints %d & %d (%lf) less than time needed for splices (%lf)\n",
+					n,n-1,next-last,dz->param[IS_SPLICETIME]);
+				return(DATA_ERROR);
+			}
+			last = next;
+			n++;
+		}
+	}
+	return(FINISHED);
+}
+
+/*************************** GENERATE_SPLICELEN **************************/
+
+void generate_splicelen(dataptr dz)
+{
+	double splicetime;
+	int j;
+
+	dz->iparam[IS_SHSECSIZE] = F_SECSIZE;
+	splicetime = dz->param[IS_SPLEN] * MS_TO_SECS;
+	j = round(splicetime * dz->infile->srate);
+	j *= dz->infile->channels;
+	SPLICELEN = j;
+	dz->param[IS_SPLICETIME] = (double)(SPLICELEN/dz->infile->channels)/(double)dz->infile->srate;
+}
+
+/*************************** GETNEXTFILE **************************/
+
+int Getnextfile(int n,int permcnt,dataptr dz)
+{
+	int lastperm, j, k;
+	static int init = 1;
+	if(dz->process == TWIXT && dz->mode == TRUE_EDIT)
+		return 0;
+	n %= permcnt;
+	if((permcnt == dz->infilecnt) && !dz->vflag[IS_NOTCYCL])	/* with no weighting, and cyclic files specified */
+		return n;																				
+	if(n == 0) {
+		if(init) {
+			randperm(1,permcnt,dz);
+			for(j=0;j < permcnt;j++) {
+				if(dz->iparray[1][j] >= dz->infilecnt)	/* substitute file1 for extra spaces in perm */
+					dz->iparray[1][j] = 0;
+			}
+			if(dz->iparray[1][0] != 0) {
+				for(j=1;j < permcnt;j++) {	 			/* Force first file to be first !! */
+					if(dz->iparray[1][j] == 0) {
+						dz->iparray[1][j] = dz->iparray[1][0];
+						dz->iparray[1][0] = 0;
+						break;
+					}
+				}
+			}
+			if(!dz->vflag[IS_NOTCYCL]) {
+				k = 1;
+				for(j=1;j < permcnt;j++) {	 		/* Force un-first files to be in order */
+					if(dz->iparray[1][j] != 0)
+						dz->iparray[1][j] = k++;
+				}
+			}
+			init = 0;
+		} else {
+			lastperm = dz->iparray[1][permcnt - 1];
+			randperm(1,permcnt,dz);
+			for(j=0;j < permcnt;j++) {				/* substitute file1 for extra spaces in perm */
+				if(dz->iparray[1][j] >= dz->infilecnt)
+					dz->iparray[1][j] = 0;
+			}										/* avoid repets at perm boundaries */
+			if((dz->iparray[1][0] == lastperm) && ((lastperm != 0) || (dz->iparam[IS_WEIGHT] == 1))) {
+				for(j=1;j < permcnt;j++) {
+					if(dz->iparray[1][j] != lastperm) {
+						dz->iparray[1][0] = dz->iparray[1][j];
+						dz->iparray[1][j] = lastperm;
+						break;
+					}
+				}
+			}
+			if(!dz->vflag[IS_NOTCYCL]) {
+				k = 1;
+				for(j=1;j < permcnt;j++) {	 		/* Force un-first files to be in order */
+					if(dz->iparray[1][j] != 0)
+						dz->iparray[1][j] = k++;
+				}
+			}
+		}
+	}
+	return dz->iparray[1][n];
+}

+ 21 - 0
dev/env/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(envel main.c ap_envel.c envel.c envfuncs.c envimpos.c envprepro.c
+	envprocess.c envxtract.c pluck.c)
+
+target_link_libraries(envel cdp2k sfsys ${EXTRA_LIBRARIES})
+
+my_install(envel)
+

+ 1802 - 0
dev/env/ap_envel.c

@@ -0,0 +1,1802 @@
+/*
+ * 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 <envel.h>
+#include <processno.h>
+#include <modeno.h>
+#include <globcon.h>
+#include <logic.h>
+#include <filetype.h>
+
+#include <mixxcon.h>
+#include <flags.h>
+#include <speccon.h>
+#include <arrays.h>
+#include <special.h>
+#include <formants.h>
+#include <sfsys.h>
+#include <osbind.h>
+
+#include <srates.h>
+
+#if defined unix || defined __GNUC__
+#define round(x) lround((x))
+#endif
+/********************************************************************************************/
+/********************************** FORMERLY IN buffers.c ***********************************/
+/********************************************************************************************/
+
+static int  do_special_brkpnt_envelling_buffer(dataptr dz);
+static int  create_pluck_buffers(dataptr dz);
+
+/********************************************************************************************/
+/********************************** FORMERLY IN pconsistency.c ******************************/
+/********************************************************************************************/
+
+static int  setup_envel_windowsize(dataptr dz);
+static double  get_outfile_wsize_in_msecs(int envwindow_sampsize,dataptr dz);
+static void inject_dbl_parameter(int paramno,dataptr dz);
+static int  setup_endofsndfile_value_if_needed(dataptr dz);
+static int  create_envsyn_buf(dataptr dz);
+/********************************************************************************************/
+/********************************** FORMERLY IN specialin.c *********************************/
+/********************************************************************************************/
+
+static int  read_env_create_file(char *str,dataptr dz);
+static int  read_createfile_level(char *q,int cnt,dataptr dz);
+static int  reallocate_create_table_memory(int thissize,dataptr dz);
+static int  read_envsyn_file(char *str,dataptr dz);
+/***************************************************************************************/
+/************************************ NEW FUNCTIONS ************************************/
+/***************************************************************************************/
+
+//TW UPDATE
+static int scale_envelope_data(dataptr dz);
+
+/***************************** 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(ENV_EXTRACT):
+    case(ENV_WARPING):
+    case(ENV_REPLACE):
+        dz->extra_bufcnt = 0;   dz->bufcnt = 1;     break;
+    case(ENV_IMPOSE):
+        switch(dz->mode) {
+        case(ENV_DB_BRKFILE_IN):
+        case(ENV_BRKFILE_IN):   
+            dz->extra_bufcnt = 0;   dz->bufcnt = 3;     break;
+        default:                
+            dz->extra_bufcnt = 0;   dz->bufcnt = 1;     break;
+        }
+        break;
+//TW NEW CASE
+    case(ENV_PROPOR):
+        dz->extra_bufcnt = 0;   dz->bufcnt = 3;     break;
+    case(ENV_DOVETAILING):
+    case(ENV_CURTAILING):
+    case(ENV_SWELL):
+    case(ENV_ATTACK):
+        dz->extra_bufcnt = 0;   dz->bufcnt = 3;     break;
+    case(ENV_PLUCK):
+        dz->extra_bufcnt = 0;   dz->bufcnt = 5;     break;
+    case(ENV_TREMOL):
+//TW NEW CASE
+    case(TIME_GRID):
+        dz->extra_bufcnt = 0;   dz->bufcnt = 1;     break;
+    case(ENVSYN):
+        dz->extra_bufcnt =  0;  dz->bptrcnt = 1;    break;
+    case(ENV_ENVTOBRK):
+    case(ENV_ENVTODBBRK):
+    case(ENV_BRKTOENV):
+    case(ENV_CREATE):
+    case(ENV_RESHAPING):
+    case(ENV_REPLOTTING):
+    case(ENV_DBBRKTOENV):
+    case(ENV_DBBRKTOBRK):
+    case(ENV_BRKTODBBRK):
+        dz->extra_bufcnt = 0;   dz->bufcnt = 0;     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);
+    }
+    if(dz->process == ENVSYN)
+        return establish_spec_bufptrs_and_extra_buffers(dz);
+    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(ENV_CREATE):
+    case(ENV_DOVETAILING):
+    case(ENV_CURTAILING):
+    case(ENV_SWELL):
+    case(ENV_ATTACK):
+        dz->array_cnt = 4; dz->iarray_cnt = 1; dz->larray_cnt = 0; dz->ptr_cnt = 0; dz->fptr_cnt = 0; break;
+    case(ENV_TREMOL):
+        dz->array_cnt = 1; dz->iarray_cnt = 0; dz->larray_cnt = 0; dz->ptr_cnt = 0; dz->fptr_cnt = 0; break;
+    case(ENV_EXTRACT):
+    case(ENV_IMPOSE):
+//TW NEW CASE
+    case(ENV_PROPOR):
+    case(ENV_REPLACE):
+    case(ENV_ENVTOBRK):
+    case(ENV_ENVTODBBRK):
+    case(ENV_BRKTOENV):
+    case(ENV_DBBRKTOENV):
+    case(ENV_DBBRKTOBRK):
+    case(ENV_BRKTODBBRK):
+    case(ENV_WARPING):
+    case(ENV_RESHAPING):
+    case(ENV_REPLOTTING):
+    case(ENV_PLUCK):
+        dz->array_cnt = 0; dz->iarray_cnt = 0; dz->larray_cnt = 0; dz->ptr_cnt = 0; dz->fptr_cnt = 0; break;
+//TW NEW CASE
+    case(TIME_GRID):
+        dz->array_cnt = 2; dz->iarray_cnt = 0; dz->larray_cnt = 0; dz->ptr_cnt = 0; dz->fptr_cnt = 0; break;
+    case(ENVSYN):
+        dz->array_cnt = 1; dz->iarray_cnt = 0; dz->larray_cnt = 0; dz->ptr_cnt = 2; 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)   {      
+//TW FIXED
+//      if((dz->fptr = (float  **)malloc(dz->fptr_cnt * sizeof(int *)))==NULL) {
+        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(ENV_DOVETAILING): setup_process_logic(SNDFILES_ONLY,       EQUAL_SNDFILE,      SNDFILE_OUT,    dz);    break;
+    case(ENV_CURTAILING):  setup_process_logic(SNDFILES_ONLY,       UNEQUAL_SNDFILE,    SNDFILE_OUT,    dz);    break;
+    case(ENV_SWELL):       setup_process_logic(SNDFILES_ONLY,       EQUAL_SNDFILE,      SNDFILE_OUT,    dz);    break;
+    case(ENV_ATTACK):      setup_process_logic(SNDFILES_ONLY,       EQUAL_SNDFILE,      SNDFILE_OUT,    dz);    break;
+    case(ENV_ENVTOBRK):    setup_process_logic(ENVFILES_ONLY,       TO_TEXTFILE,        BRKFILE_OUT,    dz);    break;
+    case(ENV_ENVTODBBRK):  setup_process_logic(ENVFILES_ONLY,       TO_TEXTFILE,        BRKFILE_OUT,    dz);    break;
+    case(ENV_BRKTOENV):    setup_process_logic(BRKFILES_ONLY,       CREATE_ENVFILE,     ENVFILE_OUT,    dz);    break;
+    case(ENV_WARPING):     setup_process_logic(SNDFILES_ONLY,       EQUAL_SNDFILE,      SNDFILE_OUT,    dz);    break;
+    case(ENV_RESHAPING):
+        switch(dz->mode) {
+        case(ENV_TSTRETCHING):
+                           setup_process_logic(ENVFILES_ONLY,       UNEQUAL_ENVFILE,    ENVFILE_OUT,    dz);    break;
+        default:
+                           setup_process_logic(ENVFILES_ONLY,       EQUAL_ENVFILE,      ENVFILE_OUT,    dz);    break;
+        }
+        break;
+    case(ENV_REPLOTTING):  setup_process_logic(BRKFILES_ONLY,       TO_TEXTFILE,        BRKFILE_OUT,    dz);    break;
+    case(ENV_DBBRKTOENV):  setup_process_logic(DB_BRKFILES_ONLY,    CREATE_ENVFILE,     ENVFILE_OUT,    dz);    break;
+    case(ENV_DBBRKTOBRK):  setup_process_logic(DB_BRKFILES_ONLY,    TO_TEXTFILE,        BRKFILE_OUT,    dz);    break;
+    case(ENV_BRKTODBBRK):  setup_process_logic(BRKFILES_ONLY,       TO_TEXTFILE,        BRKFILE_OUT,    dz);    break;
+    case(ENV_CREATE):
+        switch(dz->mode) {
+        case(ENV_ENVFILE_OUT):
+                           setup_process_logic(NO_FILE_AT_ALL,      CREATE_ENVFILE,     ENVFILE_OUT,    dz);    break;
+
+        case(ENV_BRKFILE_OUT):
+                           setup_process_logic(NO_FILE_AT_ALL,      TO_TEXTFILE,        BRKFILE_OUT,    dz);    break;
+        default:
+            sprintf(errstr,"Unknown case for ENV_CREATE in assign_process_logic()\n");
+            return(PROGRAM_ERROR);
+        }
+        break;
+    case(ENV_EXTRACT):
+        switch(dz->mode) {
+        case(ENV_ENVFILE_OUT):
+                           setup_process_logic(SNDFILES_ONLY,       EXTRACT_ENVFILE,    ENVFILE_OUT,    dz);    break;
+
+        case(ENV_BRKFILE_OUT):
+                           setup_process_logic(SNDFILES_ONLY,       TO_TEXTFILE,        BRKFILE_OUT,    dz);    break;
+        default:
+            sprintf(errstr,"Unknown case for ENV_EXTRACT in assign_process_logic()\n");
+            return(PROGRAM_ERROR);
+        }
+        break;
+//TW NEW CASE
+    case(ENV_PROPOR):
+       setup_process_logic(SNDFILE_AND_UNRANGED_BRKFILE,    UNEQUAL_SNDFILE,    SNDFILE_OUT,    dz);
+       break;
+
+    case(ENV_IMPOSE):
+        switch(dz->mode) {
+        case(ENV_ENVFILE_IN):
+                           setup_process_logic(SNDFILE_AND_ENVFILE, EQUAL_SNDFILE,      SNDFILE_OUT,    dz);    break;
+        case(ENV_SNDFILE_IN):
+                           setup_process_logic(TWO_SNDFILES,        EQUAL_SNDFILE,      SNDFILE_OUT,    dz);    break;
+        case(ENV_BRKFILE_IN):
+                           setup_process_logic(SNDFILE_AND_UNRANGED_BRKFILE,    UNEQUAL_SNDFILE,    SNDFILE_OUT,    dz);    break;
+        case(ENV_DB_BRKFILE_IN):
+                         setup_process_logic(SNDFILE_AND_DB_BRKFILE,UNEQUAL_SNDFILE,    SNDFILE_OUT,    dz);    break;
+        default:
+            sprintf(errstr,"Unknown case for ENV_IMPOSE in assign_process_logic()\n");
+            return(PROGRAM_ERROR);
+        }
+        break;
+    case(ENV_REPLACE):
+        switch(dz->mode) {
+        case(ENV_ENVFILE_IN):
+                           setup_process_logic(SNDFILE_AND_ENVFILE, EQUAL_SNDFILE,      SNDFILE_OUT,    dz);    break;
+        case(ENV_SNDFILE_IN):
+                           setup_process_logic(TWO_SNDFILES,        EQUAL_SNDFILE,      SNDFILE_OUT,    dz);    break;
+        case(ENV_BRKFILE_IN):
+                           setup_process_logic(SNDFILE_AND_BRKFILE, UNEQUAL_SNDFILE,    SNDFILE_OUT,    dz);    break;
+        case(ENV_DB_BRKFILE_IN):
+                         setup_process_logic(SNDFILE_AND_DB_BRKFILE,UNEQUAL_SNDFILE,    SNDFILE_OUT,    dz);    break;
+        default:
+            sprintf(errstr,"Unknown mode for ENV_REPLACE in assign_process_logic()\n");
+            return(PROGRAM_ERROR);
+        }
+        break;
+    case(ENV_PLUCK):       setup_process_logic(SNDFILES_ONLY,       UNEQUAL_SNDFILE,    SNDFILE_OUT,    dz);    break;
+    case(ENV_TREMOL):      setup_process_logic(SNDFILES_ONLY,       EQUAL_SNDFILE,      SNDFILE_OUT,    dz);    break;
+//TW NEW CASE
+    case(TIME_GRID):       setup_process_logic(SNDFILES_ONLY,       EQUAL_SNDFILE,      SNDFILE_OUT,    dz);    break;
+    case(ENVSYN):          setup_process_logic(NO_FILE_AT_ALL,      CREATE_ENVFILE,     ENVFILE_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(ENV_IMPOSE):
+//TW NEW CASE
+    case(ENV_PROPOR):
+    case(ENV_REPLACE):
+        dz->has_otherfile = TRUE;
+        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) {
+                        /* DANGER: if programs with >1 options added!! */
+                        /* comment: these programs have NO options.  1st internal param is a dummy to ensure */
+                        /* ENV_SAMP_WSIZE is always dz->iparam[5]      */
+    case(ENV_CREATE):       case(ENV_WARPING):      case(ENV_RESHAPING):
+    case(ENV_IMPOSE):       case(ENV_REPLACE):      case(ENV_BRKTOENV):             
+    case(ENV_DBBRKTOENV):   case(ENV_DBBRKTOBRK):   case(ENV_BRKTODBBRK):
+//TW + NEW CASE
+    case(ENV_SWELL):        case(ENV_PROPOR):
+                        exit_status = set_internalparam_data("0i",ap);              break;
+    case(ENV_EXTRACT):                  
+        switch(mode) {
+        case(ENV_ENVFILE_OUT):      /*DANGER: as above */
+                        exit_status = set_internalparam_data("0i",ap);              break;
+        case(ENV_BRKFILE_OUT):      /* as below */ 
+                        exit_status = set_internalparam_data("i",ap);                   break;
+        }
+        break;
+
+ /* comment: these programs have 1 option. No dummy internal param needed. */
+    case(ENV_REPLOTTING):
+    case(ENV_DOVETAILING):          
+    case(ENV_CURTAILING):           
+    case(ENV_ENVTOBRK):
+    case(ENV_ENVTODBBRK):
+                        exit_status = set_internalparam_data("i",ap);                   break;
+
+ /* commrnt: these progs work differently: no problems here!! */
+    case(ENV_ATTACK):   exit_status = set_internalparam_data("id",ap);              break;
+    case(ENV_PLUCK):    exit_status = set_internalparam_data("ii",ap);              break;
+    case(ENV_TREMOL):   exit_status = set_internalparam_data("",ap);                    break;
+//TW NEW CASE
+    case(TIME_GRID):    exit_status = set_internalparam_data("",ap);                break;
+    case(ENVSYN):       exit_status = set_internalparam_data("",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)    
+{
+//  int exit_status = FINISHED;
+    aplptr ap = dz->application;
+
+    switch(ap->special_data) {
+    case(ENV_TRIGGER_RAMP):     return read_env_ramp_brk(str,dz);
+    case(ENV_CREATEFILE):       return read_env_create_file(str,dz);
+    case(ENVSYN_ENVELOPE):      return read_envsyn_file(str,dz);
+    default:
+        sprintf(errstr,"Unknown special_data type: read_special_data()\n");
+        return(PROGRAM_ERROR);
+    }
+    return(FINISHED);   /* NOTREACHED */
+}
+
+/************************* READ_ENV_RAMP_BRK *****************************/
+
+int read_env_ramp_brk(char *filename,dataptr dz)
+{
+//  double maxval = 1.0;
+//  double minval = 0.0;
+    int arraysize = BIGARRAY;
+    double *p, lasttime = 0.0;
+    int  istime = TRUE;
+    int n = 0, final_size;
+    char temp[200], *q;
+    FILE *fp;
+    if((fp = fopen(filename,"r"))==NULL) {          
+        sprintf(errstr,"Failed to open envelope ramp file %s\n",filename);
+        return(DATA_ERROR);
+    }
+    if((dz->rampbrk = (double *)malloc(arraysize * sizeof(double)))==NULL) {
+        sprintf(errstr,"INSUFFICIENT MEMORY to create ramp array.\n");
+        return(MEMORY_ERROR);
+    }
+    p = dz->rampbrk;
+    while(fgets(temp,200,fp)!=NULL) {    /* READ AND TEST BRKPNT VALS */
+        q = temp;
+        while(get_float_from_within_string(&q,p)) {
+            if(istime) {
+                if(p!=dz->rampbrk) {
+                    if(*p <= lasttime) {
+                        sprintf(errstr,"Times (%lf & %lf) in ramp brkpntfile %s are not in increasing order.\n",
+                        lasttime,*p,filename);
+                        return(DATA_ERROR);
+                    }
+                }
+                lasttime = *p;
+            } else {
+                if(*p < 0.0 || *p > 1.0) {
+                    sprintf(errstr,"Brkpntfile value (%lf) out of range (0 - 1)\n",*p);
+                    return(DATA_ERROR);
+                }
+            }
+            istime = !istime;
+            p++;
+            if(++n >= arraysize) {
+                arraysize += BIGARRAY;
+                if((dz->rampbrk = (double *)realloc((char *)(dz->rampbrk),arraysize * sizeof(double)))==NULL) {
+                    sprintf(errstr,"INSUFFICIENT MEMORY to reallocate ramp array.\n");
+                    return(MEMORY_ERROR);
+                }
+                p = dz->rampbrk + n;        
+            }
+        }
+    }       
+    if(n < 2) {
+        sprintf(errstr,"No significant data in ramp brkpnt file %s\n",filename);
+        return(DATA_ERROR);
+    }
+    if(ODD(n)) {
+        sprintf(errstr,"Data not paired correctly in ramp brkpntfile %s\n",filename);
+        return(DATA_ERROR);
+    }
+    final_size = n;
+    if(dz->rampbrk[0] != 0.0) { /* Force base-time to zero */
+        for(n=0;n<final_size;n+=2)
+            dz->rampbrk[n] -= dz->rampbrk[0];           
+    }
+    if((dz->rampbrk = (double *)realloc((char *)(dz->rampbrk),final_size * sizeof(double)))==NULL) {
+        sprintf(errstr,"INSUFFICIENT MEMORY to reallocate ramp array.\n");
+        return(MEMORY_ERROR);
+    }
+    dz->rampbrksize = final_size/2;
+    return(FINISHED);
+}
+
+/************************* READ_ENV_CREATE_FILE *****************************/
+
+int read_env_create_file(char *str,dataptr dz)
+{
+    int exit_status;
+    int cnt  = 0;
+    double lasttime = 0.0;
+    int gotlevel = TRUE;
+    char temp[200], *q, *p;
+    int arraysize = BIGARRAY;
+    FILE *fp;
+    if((fp = fopen(str,"r"))==NULL) {           
+        sprintf(errstr,"Cannot open envelope create file %s\n",str);
+        return(DATA_ERROR);
+    }
+    if((dz->parray[ENV_CREATE_INLEVEL] = (double *)malloc(arraysize * sizeof(double)))==NULL) {
+        sprintf(errstr,"INSUFFICIENT MEMORY to make level data array.\n");
+        return(MEMORY_ERROR);
+    }
+    if((dz->parray[ENV_CREATE_INTIME]  = (double *)malloc(arraysize * sizeof(double)))==NULL) {
+        sprintf(errstr,"INSUFFICIENT MEMORY to make time data array.\n");
+        return(MEMORY_ERROR);
+    }
+    if((dz->iparray[ENV_SLOPETYPE]  = (int *)malloc(arraysize * sizeof(int)))==NULL) {
+        sprintf(errstr,"INSUFFICIENT MEMORY to make slope data array.\n");
+        return(MEMORY_ERROR);
+    }
+    while(fgets(temp,200,fp)!=NULL) {    /* READ AND TEST BRKPNT VALS */
+        q = temp;
+        while(get_word_from_string(&q,&p)) {
+            if(gotlevel) {
+                if(*p=='e') {
+                    sprintf(errstr,"Time and (exponential) level out of sequence in createfile.\n");
+                    return(DATA_ERROR);
+                }
+                if(sscanf(p,"%lf",&dz->parray[ENV_CREATE_INTIME][cnt])!=1) {
+                    sprintf(errstr,"Cannot read time %d\n",cnt);
+                    return(PROGRAM_ERROR);
+                }
+                if(dz->parray[ENV_CREATE_INTIME][cnt] < dz->application->min_special
+                || dz->parray[ENV_CREATE_INTIME][cnt] > dz->application->max_special) {
+                    sprintf(errstr,"Envelope time out of range %lf - %lf.\n",
+                    dz->application->min_special,dz->application->max_special);
+                    return(DATA_ERROR);
+                }
+                if((cnt > 0)
+                && (dz->parray[ENV_CREATE_INTIME][cnt] <= lasttime + (2.0 * ENV_MIN_WSIZE * MS_TO_SECS))) {
+                    sprintf(errstr,"timegap %lf - %lf is too small.\n",
+                    dz->parray[ENV_CREATE_INTIME][cnt],dz->parray[ENV_CREATE_INTIME][cnt-1]);
+                    return(DATA_ERROR);
+                }
+                lasttime = dz->parray[ENV_CREATE_INTIME][cnt];
+                gotlevel = FALSE;
+            } else {
+                switch(*p) {
+                case('e'):  dz->iparray[ENV_SLOPETYPE][cnt] = ENVTYPE_EXP;  p++;    break;
+                default:    dz->iparray[ENV_SLOPETYPE][cnt] = ENVTYPE_LIN;          break;
+                }
+                if((exit_status = read_createfile_level(p,cnt,dz))<0)
+                    return(exit_status);
+                if(++cnt >= arraysize) {
+                    arraysize += BIGARRAY;
+                    if((exit_status = reallocate_create_table_memory(arraysize,dz))<0)
+                        return(exit_status);
+                }
+                gotlevel = TRUE;
+            }
+        }
+    }
+    if(!gotlevel) {
+        sprintf(errstr,"Levels and Times not correctly paired: read_env_create_file()\n");
+        return(DATA_ERROR); 
+    }
+    if(cnt<=0) {
+        sprintf(errstr,"Failed to read any data from file %s.\n",str);
+        return(DATA_ERROR);
+    }
+    if((exit_status = reallocate_create_table_memory(cnt,dz))<0)
+        return(exit_status);
+    dz->itemcnt = cnt;
+    return(FINISHED);
+}
+
+/**************************** READ_CREATEFILE_LEVEL ********************************/
+
+int read_createfile_level(char *q,int cnt,dataptr dz)
+{
+    int exit_status;
+    int is_a_dB_val = is_dB(q);
+    if(sscanf(q,"%lf",&(dz->parray[ENV_CREATE_INLEVEL][cnt]))!=1) {
+        sprintf(errstr,"Cannot read level %d: read_createfile_level()\n",cnt);
+        return(PROGRAM_ERROR);
+    }
+    if(is_a_dB_val) {
+        if((exit_status = convert_dB_at_or_below_zero_to_gain(&(dz->parray[ENV_CREATE_INLEVEL][cnt])))<0)
+            return(exit_status);
+    } else if(dz->parray[ENV_CREATE_INLEVEL][cnt] < dz->application->min_special2 
+           || dz->parray[ENV_CREATE_INLEVEL][cnt] > dz->application->max_special2) {
+        sprintf(errstr,"Level value %lf out of range\n",dz->parray[ENV_CREATE_INLEVEL][cnt]);
+        return(DATA_ERROR);
+    }
+    if(flteq(dz->parray[ENV_CREATE_INLEVEL][cnt],dz->parray[ENV_CREATE_INLEVEL][cnt-1]))   
+        dz->iparray[ENV_SLOPETYPE][cnt] = ENVTYPE_LIN;      /* Force linear interp, for equal levels */
+    return(FINISHED);
+}
+
+/************** REALLOCATE_CREATE_TABLE_MEMORY ***********/
+
+int reallocate_create_table_memory(int thissize,dataptr dz)
+{
+    if((dz->parray[ENV_CREATE_INLEVEL]= (double *)realloc(dz->parray[ENV_CREATE_INLEVEL],thissize * sizeof(double)))==NULL
+    || (dz->parray[ENV_CREATE_INTIME] = (double *)realloc(dz->parray[ENV_CREATE_INTIME],thissize * sizeof(double)))==NULL
+    || (dz->iparray[ENV_SLOPETYPE]    = (int *)realloc(dz->iparray[ENV_SLOPETYPE],thissize * sizeof(int)))==NULL) {
+        sprintf(errstr,"INSUFFICIENT MEMORY to reallocate envelope arrays.\n");
+        return(MEMORY_ERROR);
+    }
+    return(FINISHED);
+}
+
+/********************************************************************************************/
+/********************************** FORMERLY IN preprocess.c ********************************/
+/********************************************************************************************/
+
+/****************************** PARAM_PREPROCESS *********************************/
+
+int param_preprocess(dataptr dz)    
+{
+//  int exit_status = FINISHED;
+
+    switch(dz->process) {
+    case(ENV_CREATE):       case(ENV_EXTRACT):      case(ENV_IMPOSE):    
+    case(ENV_REPLACE):      case(ENV_ENVTOBRK):     case(ENV_ENVTODBBRK):
+    case(ENV_BRKTOENV):     case(ENV_DBBRKTOENV):   case(ENV_DBBRKTOBRK):   
+    case(ENV_BRKTODBBRK):   case(ENV_WARPING):      case(ENV_RESHAPING):    
+    case(ENV_REPLOTTING):   case(ENV_DOVETAILING):  case(ENV_CURTAILING):
+    case(ENV_SWELL):        case(ENV_ATTACK):       case(ENV_PLUCK):    
+//TW + NEW CASES
+    case(ENV_TREMOL):       case(ENV_PROPOR):       case(TIME_GRID):
+        return envel_preprocess(dz);
+    case(ENVSYN):
+        break;
+    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;
+
+    switch(dz->process) {
+    case(ENV_EXTRACT):      case(ENV_IMPOSE):       case(ENV_REPLACE):
+    case(ENV_WARPING):      case(ENV_RESHAPING):    case(ENV_REPLOTTING):
+    case(ENV_DOVETAILING):  case(ENV_CURTAILING):   case(ENV_SWELL):        
+    case(ENV_ATTACK):       case(ENV_PLUCK):        case(ENV_TREMOL):
+//TW NEW CASES
+    case(ENV_PROPOR):       case(TIME_GRID):
+        display_virtual_time(0L,dz);
+        break;
+    }
+    switch(dz->process) {
+    case(ENV_CREATE):       case(ENV_EXTRACT):      case(ENV_IMPOSE):     case(ENV_REPLACE):
+    case(ENV_ENVTOBRK):     case(ENV_ENVTODBBRK):
+    case(ENV_BRKTOENV):     case(ENV_DBBRKTOENV):   case(ENV_DBBRKTOBRK): case(ENV_BRKTODBBRK):
+    case(ENV_WARPING):      case(ENV_RESHAPING):    case(ENV_REPLOTTING):
+    case(ENV_DOVETAILING):  case(ENV_CURTAILING):
+    case(ENV_SWELL):        case(ENV_ATTACK):       case(ENV_PLUCK):      case(ENV_TREMOL):
+//TW NEW CASE
+    case(ENV_PROPOR):
+        if((exit_status = process_envelope(dz))<0)
+            return(exit_status);
+        break;
+//TW NEW CASE
+    case(TIME_GRID):
+        if((exit_status = do_grids(dz))<0)
+            return(exit_status);
+        break;
+    case(ENVSYN):
+        if((exit_status = envsyn(dz))<0)
+            return(exit_status);
+        break;
+    default:
+        sprintf(errstr,"Unknown case in process_file()\n");
+        return(PROGRAM_ERROR);
+    }
+    return(FINISHED);
+}
+
+/********************************************************************************************/
+/********************************** FORMERLY IN pconsistency.c ******************************/
+/********************************************************************************************/
+
+/****************************** CHECK_PARAM_VALIDITY_AND_CONSISTENCY *********************************/
+
+int check_param_validity_and_consistency(dataptr dz)
+{
+    int exit_status = FINISHED, chans = 0;
+    int srate = 0;
+//TW UPDATE
+//  handle_pitch_zeros(dz);
+    switch(dz->process) {
+    case(ENV_BRKTOENV):     
+    case(ENV_DBBRKTOENV):   
+        if((exit_status = setup_envel_windowsize(dz))<0)
+            return(exit_status);
+        dz->infile->srate = round(SECS_TO_MS/dz->outfile->window_size);
+        dz->infile->channels = 1;
+        return create_sized_outfile(dz->outfilename,dz);
+    case(ENV_CREATE):
+        if((exit_status = setup_envel_windowsize(dz))<0)
+            return(exit_status);
+        if(dz->mode == ENV_ENVFILE_OUT) {
+            dz->infile->srate = round(SECS_TO_MS/dz->outfile->window_size);
+            dz->infile->channels = 1;
+        }
+        return create_sized_outfile(dz->wordstor[0],dz);
+    case(ENV_EXTRACT):      
+        if((exit_status = setup_envel_windowsize(dz))<0)
+            return(exit_status);
+        if(dz->mode == ENV_ENVFILE_OUT) {
+            chans = dz->infile->channels;
+            srate = dz->infile->srate;
+            dz->infile->channels = 1;
+            dz->infile->srate    = round(SECS_TO_MS/dz->outfile->window_size);
+        }
+        if((exit_status = create_sized_outfile(dz->wordstor[0],dz))<0)
+            return(exit_status);
+        if(dz->mode == ENV_ENVFILE_OUT) {
+            dz->infile->channels = chans;
+            dz->infile->srate    = srate;
+        }
+        break;
+//TW + NEW CASE
+    case(ENV_IMPOSE):       case(ENV_REPLACE):      case(ENV_PROPOR):
+    case(ENV_ENVTOBRK):     case(ENV_ENVTODBBRK):   case(ENV_DBBRKTOBRK):   
+    case(ENV_BRKTODBBRK):   case(ENV_WARPING):      case(ENV_RESHAPING):    
+    case(ENV_REPLOTTING):   case(ENV_DOVETAILING):  case(ENV_CURTAILING):   
+    case(ENV_SWELL):        case(ENV_ATTACK):
+        return setup_envel_windowsize(dz);
+    case(ENVSYN):
+        if((exit_status = setup_envel_windowsize(dz))<0)
+            return(exit_status);
+        dz->infile->srate = round((double)SECS_TO_MS/(double)dz->outfile->window_size);
+        dz->infile->channels = 1;
+        if((exit_status = create_sized_outfile(dz->wordstor[0],dz))<0)
+            return(exit_status);
+        break;
+    }
+    return(FINISHED);
+}
+
+/************************* SETUP_ENVEL_WINDOWSIZE *********************
+ *
+ * This operation performed here because ENV_SAMP_WSIZE needed for buffer_definition.
+ */
+
+int setup_envel_windowsize(dataptr dz)
+{
+    int exit_status;
+    switch(dz->process) {
+    case(ENV_DBBRKTOBRK):
+    case(ENV_BRKTODBBRK):
+        break;
+    case(ENV_CREATE):
+        if(dz->mode==ENV_ENVFILE_OUT)
+            dz->outfile->window_size = (float)dz->param[ENV_WSIZE];     /* 0 buffers */
+        break;
+    case(ENV_REPLOTTING):
+    case(ENVSYN):
+        dz->outfile->window_size = (float)dz->param[ENV_WSIZE];     /* 0 buffers */ 
+        break;
+    case(ENV_BRKTOENV):                                         /* 0 buffers */
+    case(ENV_DBBRKTOENV):
+        dz->outfile->window_size = (float)dz->param[ENV_WSIZE];
+        break;
+    case(ENV_ENVTOBRK):                                         /* 0 buffers */
+    case(ENV_ENVTODBBRK):
+        inject_dbl_parameter(ENV_WSIZE,dz);
+        dz->param[ENV_WSIZE] = (double)dz->infile->window_size;         
+        break;
+    case(ENV_RESHAPING):                                        /* 0 buffers */
+        inject_dbl_parameter(ENV_WSIZE,dz);
+        dz->param[ENV_WSIZE] = (double)dz->infile->window_size;
+        if((exit_status = generate_samp_windowsize(dz->infile,dz)) < 0)
+            return(exit_status);
+        dz->outfile->window_size = dz->infile->window_size;
+        break;
+    case(ENV_EXTRACT):
+        if((exit_status = generate_samp_windowsize(dz->infile,dz)) < 0)
+            return(exit_status);
+        dz->outfile->window_size = 
+            (float)get_outfile_wsize_in_msecs((int)dz->iparam[ENV_SAMP_WSIZE],dz);
+        break;
+    case(ENV_WARPING):
+        if((exit_status = generate_samp_windowsize(dz->infile,dz))<0)
+            return(exit_status);
+        dz->outfile->window_size = 
+            (float)get_outfile_wsize_in_msecs((int)dz->iparam[ENV_SAMP_WSIZE],dz);
+        break;
+//TW NEW CASE
+    case(ENV_PROPOR):
+        if(dz->extrabrkno < 0) {
+            sprintf(errstr,"extrabrkno not established: setup_envel_windowsize()\n");
+            return(PROGRAM_ERROR);
+        }
+        if(dz->brksize[dz->extrabrkno] < 2) {
+            sprintf(errstr,"Brktable must have at least 2 value-pairs.\n");
+            return(DATA_ERROR);
+        }
+        if((exit_status = scale_envelope_data(dz))<0)
+            return(exit_status);
+        dz->iparam[ENV_SAMP_WSIZE] = 0; /* forces default size onto buffers for */
+        break;                          /* non-standard brkpnt-applied envelling */
+
+    case(ENV_IMPOSE):
+        switch(dz->mode) {
+        case(ENV_ENVFILE_IN):
+            inject_dbl_parameter(ENV_WSIZE,dz);         
+            dz->param[ENV_WSIZE] = (double)dz->otherfile->window_size;  /* wsize is derived from 2nd input file */
+            return generate_samp_windowsize(dz->infile,dz);
+        case(ENV_SNDFILE_IN):/* wsize is a user input parameter. Apply it to 'otherfile' as that ENV extracted 1st, */ 
+            return generate_samp_windowsize(dz->otherfile,dz); /* while 2nd file may have different srate or chans. */  
+        case(ENV_BRKFILE_IN):
+        case(ENV_DB_BRKFILE_IN):
+            if(dz->extrabrkno < 0) {
+                sprintf(errstr,"extrabrkno not established: setup_envel_windowsize()\n");
+                return(PROGRAM_ERROR);
+            }
+            if(dz->brksize[dz->extrabrkno] < 2) {
+                sprintf(errstr,"Brktable must have at least 2 value-pairs.\n");
+                return(DATA_ERROR);
+            }
+            if((exit_status = setup_endofsndfile_value_if_needed(dz))<0)
+                return(exit_status);
+            dz->iparam[ENV_SAMP_WSIZE] = 0; /* forces default size onto buffers for */
+            break;                          /* non-standard brkpnt-applied envelling */
+        default:
+            sprintf(errstr,"Unknown case for ENV_IMPOSE in setup_envel_windowsize()\n");
+            return(PROGRAM_ERROR);
+        }
+        break;                                          
+    case(ENV_REPLACE):
+        switch(dz->mode) {
+        case(ENV_ENVFILE_IN):
+            inject_dbl_parameter(ENV_WSIZE,dz);         
+            dz->param[ENV_WSIZE] = (double)dz->otherfile->window_size;  /* wsize is derived from 2nd input file */
+            return generate_samp_windowsize(dz->infile,dz);
+        case(ENV_SNDFILE_IN):  /* wsize is a user input parameter: Apply to 'otherfile' as that ENV extracted 1st, */
+            return generate_samp_windowsize(dz->otherfile,dz); /* while 2nd file may have different srate or chans */   
+        case(ENV_BRKFILE_IN):
+        case(ENV_DB_BRKFILE_IN):
+            if(dz->extrabrkno < 0) {
+                sprintf(errstr,"extrabrkno not established: setup_envel_windowsize()\n");
+                return(PROGRAM_ERROR);
+            }
+//DELETED AUGUST 2005
+//          inject_dbl_parameter(ENV_WSIZE,dz);                 /* envelling done in standard way */
+//          dz->param[ENV_WSIZE] = ENV_DEFAULT_WSIZE;           /* wsize is set to a default value */
+            return generate_samp_windowsize(dz->infile,dz);
+        default:
+            sprintf(errstr,"Unknown case for ENV_REPLACE in setup_envel_windowsize()\n");
+            return(PROGRAM_ERROR);
+        }                                                       
+        break;                                          
+    case(ENV_CURTAILING):
+    case(ENV_DOVETAILING):
+    case(ENV_SWELL):
+    case(ENV_ATTACK):
+        dz->iparam[ENV_WSIZE] = 0;      /* forces default size onto buffers */
+        break;
+    default:
+        sprintf(errstr,"Unknown case in setup_envel_windowsize()\n");
+        return(PROGRAM_ERROR);
+    }
+    return(FINISHED);
+}
+
+/**************************** GENERATE_SAMP_WINDOWSIZE [GENERATE_BLOK] ************************/
+
+int generate_samp_windowsize(fileptr thisfile,dataptr dz)
+{
+    int unadjusted_envwindow_sampsize, j, k, chansecsize;
+    int  channels = thisfile->channels;
+    int srate = thisfile->srate;
+
+    chansecsize = (int)(ENV_FSECSIZE * channels);
+
+    unadjusted_envwindow_sampsize = round(dz->param[ENV_WSIZE] * MS_TO_SECS * (double)srate) * channels;
+    if(unadjusted_envwindow_sampsize < chansecsize) {
+        k = chansecsize;
+        while(unadjusted_envwindow_sampsize<k)
+            k /= 2;
+        j = k * 2;
+        if(j - unadjusted_envwindow_sampsize > unadjusted_envwindow_sampsize - k)
+            dz->iparam[ENV_SAMP_WSIZE] = (int)k;
+        else
+            dz->iparam[ENV_SAMP_WSIZE] = (int)j;
+    } else if(unadjusted_envwindow_sampsize >= chansecsize) {
+        k = round((double)unadjusted_envwindow_sampsize/(double)chansecsize);
+        dz->iparam[ENV_SAMP_WSIZE] = (int)(chansecsize * k);
+    }
+    return(FINISHED);
+}
+
+/************************* GET_OUTFILE_WSIZE_IN_MSECS *********************/
+
+double get_outfile_wsize_in_msecs(int envwindow_sampsize,dataptr dz)
+{
+    double size = (double)(envwindow_sampsize/dz->infile->channels)/(double)dz->infile->srate;
+    size *= SECS_TO_MS;
+    return(size);
+}
+
+/******************************** INJECT_DBL_PARAMETER *************************/
+
+void inject_dbl_parameter(int paramno,dataptr dz)
+{
+    dz->is_active[paramno] = (char)1; 
+    dz->is_int[paramno]    = (char)0;
+    dz->no_brk[paramno]    = (char)1;
+}
+
+/***************************** SETUP_ENDOFSNDFILE_VALUE_IF_NEEDED **************************
+ *
+ *  If envtable longer than sound, curtail to length of sndfile.
+ *  Prevents ridiculously long interpolation vals occuring at end of envfile.
+ */
+
+int setup_endofsndfile_value_if_needed(dataptr dz)
+{
+    int paramno = dz->extrabrkno;
+    double lasttime, lastval, nexttime, nextval, timediff, valdiff, timeratio, endval;
+    double endtime;
+    double infiledur = (double)(dz->insams[0]/dz->infile->channels)/(double)(dz->infile->srate);
+    double *startaddr = dz->brk[paramno];
+    double *endaddr   = dz->brk[paramno] + ((dz->brksize[paramno] - 1) * 2);
+    if(*startaddr >= infiledur - FLTERR) {
+        sprintf(errstr,"Envelope starts effectively beyond end of sndfile: can't proceed.\n");
+        return(DATA_ERROR);
+    }
+    if((endtime = *endaddr) > infiledur + FLTERR) {
+        while(endaddr > startaddr) {
+            endtime = *endaddr;
+            if(endtime > infiledur+FLTERR)
+                endaddr -= 2;
+            else
+                break;
+        }
+        lasttime  = *endaddr;
+        lastval   = *(endaddr + 1);
+        endaddr  += 2;
+        nexttime  = *endaddr;
+        nextval   = *(endaddr + 1);
+        timediff  = nexttime - lasttime;
+        timeratio = (infiledur - lasttime)/timediff;
+        valdiff   = nextval - lastval;
+        endval    = (valdiff * timeratio) + lastval;
+        *endaddr  = infiledur;
+        *(endaddr+1) = endval;
+        dz->brksize[paramno] = ((endaddr - startaddr)/2) + 1;
+    }
+    return(FINISHED);
+}
+/********************************************************************************************/
+/********************************** FORMERLY IN buffers.c ***********************************/
+/********************************************************************************************/
+
+/**************************** ALLOCATE_LARGE_BUFFERS ******************************/
+
+int allocate_large_buffers(dataptr dz)
+{
+    switch(dz->process) {
+    case(ENV_DOVETAILING):  case(ENV_CURTAILING):   case(ENV_EXTRACT):      
+    case(ENV_WARPING):      case(ENV_IMPOSE):       case(ENV_REPLACE):
+    case(ENV_SWELL):        case(ENV_ATTACK):
+//TW NEW CASE
+    case(ENV_PROPOR):
+        return create_sndbufs_for_envel(dz);
+
+    case(ENV_PLUCK):        
+        return create_pluck_buffers(dz);
+    case(ENV_TREMOL):       
+//TW NEW CASE
+    case(TIME_GRID):        
+        return create_sndbufs(dz);
+
+    case(ENV_ENVTOBRK):     case(ENV_ENVTODBBRK):   case(ENV_BRKTOENV):     
+    case(ENV_DBBRKTOENV):   case(ENV_DBBRKTOBRK):   case(ENV_BRKTODBBRK):
+    case(ENV_CREATE):       case(ENV_RESHAPING):    case(ENV_REPLOTTING):   
+        return(FINISHED);
+    case(ENVSYN):
+        return create_envsyn_buf(dz);
+    default:
+        sprintf(errstr,"Unknown program no. in allocate_large_buffers()\n");
+        return(PROGRAM_ERROR);
+    }
+    return(FINISHED);   /* NOTREACHED */
+}
+
+/*************************** CREATE_SNDBUFS_FOR_ENVEL **************************
+ *
+ * 1)   some processes use NO sndfile-buffers: ENV_CREATE: ENV_REPLOTTING: ENV_CONVERTBRK: ENV_CONVERTENV 
+ * 2)   some processes have no ENV_SAMP_WSIZE: default set to ZERO, DOVETAILING: CURTAILING. 
+ * 3)   Also, ENV_SAMP_WSIZE may be LESS than SECSIZE, but if so,
+ *      will always be a simple fraction thereof (see generate_samp_windowsize()).
+ */
+
+int create_sndbufs_for_envel(dataptr dz)
+{
+    size_t bigbufsize;
+    int n;
+    int bufactor;
+    if(dz->bufcnt==0)                       /* Processes with no soundfiles */
+        return(FINISHED);   
+
+    if(dz->iparam[ENV_SAMP_WSIZE]==0) {     /* Processes which apply brkfiles directly to snd */
+        if(dz->process != ENV_CURTAILING 
+        && dz->process != ENV_DOVETAILING 
+        && dz->process != ENV_SWELL
+        && dz->process != ENV_ATTACK
+//TW NEW CASE
+        && dz->process != ENV_PROPOR
+        && !(dz->process == ENV_IMPOSE && (dz->mode == ENV_BRKFILE_IN || dz->mode == ENV_DB_BRKFILE_IN))) {
+            sprintf(errstr,"Error in setting ENV_SAMP_WSIZE prior to create_sndbufs_for_envel()\n");
+            return(PROGRAM_ERROR);
+        }
+        if(dz->bufcnt!=3) {
+            sprintf(errstr,"Insufficient pointers: create_sndbufs_for_envel()\n");
+            return(PROGRAM_ERROR);
+        }
+        return do_special_brkpnt_envelling_buffer(dz);
+    }
+
+    /* All other cases */
+    bufactor = max((int)dz->iparam[ENV_SAMP_WSIZE],ENV_FSECSIZE);   /* 2 */ /* 3 */
+
+    if(dz->sbufptr == 0 || dz->sampbuf == 0) {
+        sprintf(errstr,"buffer pointers not allocated: create_sndbufs_for_envel()\n");
+        return(PROGRAM_ERROR);
+    }
+    bigbufsize = (size_t) Malloc(-1);
+    bigbufsize /= dz->bufcnt;
+
+    dz->buflen = (int)(bigbufsize/sizeof(float));
+
+    if((dz->buflen  = (dz->buflen/bufactor) * bufactor)<=0) {
+        dz->buflen  = bufactor;
+    }
+
+    bigbufsize = dz->buflen * sizeof(float);
+
+    if((dz->bigbuf = (float *)malloc((bigbufsize * dz->bufcnt))) == NULL) {
+        sprintf(errstr,"INSUFFICIENT MEMORY to create sound buffers.\n");
+        return(MEMORY_ERROR);
+    }
+    for(n=0;n<dz->bufcnt;n++)
+        dz->sbufptr[n] = dz->sampbuf[n] = dz->bigbuf + (dz->buflen * n);
+    dz->sampbuf[n] = dz->bigbuf + (dz->buflen * n);
+    return(FINISHED);
+}
+
+/*************************** DO_SPECIAL_BRKPNT_ENVELLING_BUFFER **************************/
+
+int do_special_brkpnt_envelling_buffer(dataptr dz)
+{
+    size_t bigbufsize;
+    size_t fsecsizebytes = ENV_FSECSIZE * sizeof(float);
+    size_t extended_buffer_size = (size_t) Malloc(-1);
+    
+    extended_buffer_size = (extended_buffer_size/fsecsizebytes) * fsecsizebytes;
+    bigbufsize = extended_buffer_size - fsecsizebytes;  /* overflow sector */
+    dz->buflen = (int)(bigbufsize/sizeof(float));
+    if((dz->bigbuf = (float *)malloc(extended_buffer_size)) == NULL) {
+        sprintf(errstr, "INSUFFICIENT MEMORY to create sound buffer.\n");
+        return(MEMORY_ERROR);
+    }
+    dz->sbufptr[0] = dz->sampbuf[0] = dz->bigbuf;           /* INITIAL POSITION OF buffer start */
+    return(FINISHED);
+}
+
+/*************************** CREATE_PLUCK_BUFFERS ***************************/
+
+int create_pluck_buffers(dataptr dz)
+{   
+    size_t bigbufsize;
+    int sec_cnt=0, extrasamps;
+    int obuf_offset, ibuf_offset;
+    int pluklen = dz->iparam[ENV_PLK_WAVELEN] * dz->iparam[ENV_PLK_CYCLEN];
+    int shsecsize = ENV_FSECSIZE;
+    int fsecsizebytes = ENV_FSECSIZE * sizeof(float);
+
+    if((extrasamps = max(0,pluklen - dz->iparam[ENV_PLK_ENDSAMP])) > 0) {
+        if(((sec_cnt = extrasamps/ENV_FSECSIZE) * ENV_FSECSIZE)!=extrasamps)
+            sec_cnt++;
+        extrasamps = sec_cnt * ENV_FSECSIZE;
+    } 
+    bigbufsize = (size_t)Malloc(-1);
+    bigbufsize = (bigbufsize/fsecsizebytes) * fsecsizebytes;
+
+    /*RWD*/
+    dz->buflen = (int)(bigbufsize / sizeof(float));
+    if(dz->buflen <= 0) {
+        sprintf(errstr,"INSUFFICIENT MEMORY for sound buffers.\n");
+        return(MEMORY_ERROR);
+    }
+    dz->buflen += extrasamps;
+
+    if((dz->bigbuf = (float *)Malloc(dz->buflen * sizeof(float)))==NULL) {
+        sprintf(errstr,"INSUFFICIENT MEMORY to create sound buffers.\n");
+        return(MEMORY_ERROR);
+    }
+    dz->sampbuf[PLK_BUFEND] = dz->bigbuf + dz->buflen;
+
+    dz->sampbuf[PLK_INITBUF] = dz->bigbuf + extrasamps;
+    if((dz->sampbuf[PLK_PLUKEND] = dz->sampbuf[PLK_INITBUF] + dz->iparam[ENV_PLK_ENDSAMP]) >dz->sampbuf[PLK_BUFEND]) {
+        sprintf(errstr,"INSUFFICIENT MEMORY: Pluck too long for buffers.\n");
+        return(MEMORY_ERROR);
+    }   
+    if((dz->sampbuf[PLK_OUTBUF]  = dz->sampbuf[PLK_PLUKEND] - pluklen) < dz->bigbuf) {
+        sprintf(errstr,"Problem in buffer arithmetic: create_pluck_buffers(): 1\n");
+        return(PROGRAM_ERROR);
+    } 
+
+    obuf_offset = (dz->sampbuf[PLK_OUTBUF] - dz->bigbuf);
+
+    if(((sec_cnt = obuf_offset/ENV_FSECSIZE) * ENV_FSECSIZE)!=obuf_offset)
+        sec_cnt++;
+    ibuf_offset = sec_cnt * ENV_FSECSIZE;
+    dz->sampbuf[PLK_INBUF] = dz->bigbuf + (ibuf_offset);
+
+    sec_cnt = (dz->sampbuf[PLK_BUFEND] - dz->sampbuf[PLK_OUTBUF]) / shsecsize;
+    dz->iparam[ENV_PLK_OBUFLEN] = sec_cnt * shsecsize;
+
+    if(dz->sampbuf[PLK_INBUF] + dz->iparam[ENV_PLK_OBUFLEN] != dz->sampbuf[PLK_BUFEND]) {
+        sprintf(errstr,"Problem in buffer arithmetic: create_pluck_buffers(): 2\n");
+        return(PROGRAM_ERROR);
+    } 
+
+    if((dz->iparam[ENV_PLK_OWRAPLEN]  = dz->sampbuf[PLK_INBUF] - dz->sampbuf[PLK_OUTBUF])<0) {
+        sprintf(errstr,"Problem in buffer arithmetic: create_pluck_buffers(): 3\n");
+        return(PROGRAM_ERROR);
+    } 
+//TW : THIS IS CORRECT: original code was incorrect
+    if(dz->iparam[ENV_PLK_OWRAPLEN]  >= ENV_FSECSIZE) {
+        sprintf(errstr,"Problem in buffer arithmetic: create_pluck_buffers(): 4\n");
+        return(PROGRAM_ERROR);
+    } 
+
+    dz->sampbuf[PLK_OBUFWRAP] = dz->sampbuf[PLK_OUTBUF] + dz->iparam[ENV_PLK_OBUFLEN];
+
+    if(dz->sampbuf[PLK_BUFEND] - dz->sampbuf[PLK_OBUFWRAP] != dz->iparam[ENV_PLK_OWRAPLEN]) {
+        sprintf(errstr,"Problem in buffer arithmetic: create_pluck_buffers(): 5\n");
+        return(PROGRAM_ERROR);
+    } 
+    memset((char *)dz->bigbuf,0,dz->buflen * sizeof(float));
+    return(FINISHED);
+}
+
+/********************************************************************************************/
+/********************************** FORMERLY IN cmdline.c ***********************************/
+/********************************************************************************************/
+
+int get_process_no(char *prog_identifier_from_cmdline,dataptr dz)
+{
+    if     (!strcmp(prog_identifier_from_cmdline,"create"))         dz->process = ENV_CREATE;
+    else if(!strcmp(prog_identifier_from_cmdline,"extract"))        dz->process = ENV_EXTRACT;
+    else if(!strcmp(prog_identifier_from_cmdline,"impose"))         dz->process = ENV_IMPOSE;
+    else if(!strcmp(prog_identifier_from_cmdline,"replace"))        dz->process = ENV_REPLACE;
+    else if(!strcmp(prog_identifier_from_cmdline,"brktoenv"))       dz->process = ENV_BRKTOENV;
+    else if(!strcmp(prog_identifier_from_cmdline,"envtobrk"))       dz->process = ENV_ENVTOBRK;
+    else if(!strcmp(prog_identifier_from_cmdline,"envtodb"))        dz->process = ENV_ENVTODBBRK;
+    else if(!strcmp(prog_identifier_from_cmdline,"warp"))           dz->process = ENV_WARPING;
+    else if(!strcmp(prog_identifier_from_cmdline,"reshape"))        dz->process = ENV_RESHAPING;
+    else if(!strcmp(prog_identifier_from_cmdline,"replot"))         dz->process = ENV_REPLOTTING;
+    else if(!strcmp(prog_identifier_from_cmdline,"dovetail"))       dz->process = ENV_DOVETAILING;
+    else if(!strcmp(prog_identifier_from_cmdline,"curtail"))        dz->process = ENV_CURTAILING;
+    else if(!strcmp(prog_identifier_from_cmdline,"dbtoenv"))        dz->process = ENV_DBBRKTOENV;
+    else if(!strcmp(prog_identifier_from_cmdline,"dbtogain"))       dz->process = ENV_DBBRKTOBRK;
+    else if(!strcmp(prog_identifier_from_cmdline,"gaintodb"))       dz->process = ENV_BRKTODBBRK;
+    else if(!strcmp(prog_identifier_from_cmdline,"swell"))          dz->process = ENV_SWELL;
+    else if(!strcmp(prog_identifier_from_cmdline,"attack"))         dz->process = ENV_ATTACK;
+    else if(!strcmp(prog_identifier_from_cmdline,"pluck"))          dz->process = ENV_PLUCK;
+    else if(!strcmp(prog_identifier_from_cmdline,"tremolo"))        dz->process = ENV_TREMOL;
+//TW NEW CASES
+    else if(!strcmp(prog_identifier_from_cmdline,"scaled"))         dz->process = ENV_PROPOR;
+    else if(!strcmp(prog_identifier_from_cmdline,"timegrid"))       dz->process = TIME_GRID;
+    else if(!strcmp(prog_identifier_from_cmdline,"cyclic"))         dz->process = ENVSYN;
+    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)
+{
+    fprintf(stdout,
+    "\nUSAGE: envel NAME (mode) (infile) (infile2) outfile parameters:\n"
+    "\n"
+    "where NAME can be any one of\n"
+    "\n"
+    "    ENVELOPE GENERATION OPERATIONS\n"
+    "create      cyclic\n"
+    "\n"
+    "    ENVELOPE OPERATION ON A SNDFILE\n"
+    "extract     impose      replace      warp\n"
+    "tremolo     swell       attack       pluck\n"
+//TW NEW CASES
+    "dovetail    curtail     scaled       timegrid\n"
+    "\n"
+    "    ENVELOPE OPERATION ON AN ENVELOPE-FILE\n"
+    "reshape\n"
+    "envtobrk    envtodb\n"
+    "\n"
+    "    ENVELOPE OPERATION ON A BRKPNT (TEXT) FILE\n\n"
+    "replot\n"
+    "dbtogain    gaintodb\n"
+    "brktoenv    dbtoenv\n"
+    "\n"
+    "Type 'envel warp' for more info on envel warp.. ETC.\n");
+    return(USAGE_ONLY);
+}
+
+/******************************** USAGE2 ********************************/
+
+int usage2(char *str)
+{
+    if(!strcmp(str,"create"))   {       
+        fprintf(stdout,
+        "CREATE AN ENVELOPE.\n\n"
+        "USAGE: envel create 1 envfile createfile  wsize\n"
+        "OR:    envel create 2 brkfile createfile\n\n"
+        "MODES..\n" 
+        "1) creates a BINARY envelope file:\n"
+        "   If you specify starttime > 0,vals from 0 to starttime hold your startlevel.\n"
+        "2) creates a (TEXT) BRKPNT file:   File starts at time you specify.\n\n"
+        "WSIZE      window_size (in MS) of envelope to be created.\n"    
+        "           Range (%.0lf - filelen)\n"   
+        "CREATEFILE is a textfile with the following format:\n"
+        "           time [e]level time [e]level ......\n"
+        "where time-level pairs can be repeated as often as desired.\n"
+        "Level is a number between 0 and 1, or a dB value between %.0lfdB and 0dB\n"
+        "(you must write 'dB' if you want dB).\n"
+        "If preceded by an 'e', envelope rises[falls] exponentially to that level.\n"
+        "Default is linear rise[fall].\n\n"
+        "Times are in seconds, must increase through the file,\n"
+        "and be separated by at least %.3lf secs\n",
+        ENV_MIN_WSIZE,MIN_DB_ON_16_BIT,2.0 * ENV_MIN_WSIZE * MS_TO_SECS);
+    } else if(!strcmp(str,"extract"))   {       
+        fprintf(stdout,
+        "EXTRACT ENVELOPE FROM AN INPUT SOUNDFILE.\n\n"
+        "USAGE: envel extract  1  infile outenvfile  wsize\n"
+        "OR:    envel extract  2  infile outbrkfile  wsize  [-ddatareduce]\n\n"
+        "MODE 1 extracts a binary envelope file:\n"
+        "MODE 2 extracts a (text) brkpnt file.\n\n"
+        "WSIZE      window_size (in MS) for scanning envelope: Range (%.0lf - filelen)\n"
+        "DATAREDUCE variable determines quantity v. accuracy of data written to brkfile\n"
+        "           Range(0 - 1)\n",ENV_MIN_WSIZE);
+    } else if(!strcmp(str,"impose"))    {       
+        fprintf(stdout,
+        "IMPOSE AN ENVELOPE ON AN INPUT SOUNDFILE.\n\n"
+        "USAGE: envel impose  1  input_sndfile imposed-sndfile    outsndfile    wsize\n"
+        "USAGE: envel impose  2  input_sndfile imposed-envfile    outsndfile\n"
+        "USAGE: envel impose  3  input_sndfile imposed-brkfile    outsndfile\n"
+        "USAGE: envel impose  4  input_sndfile imposed-brkfile-dB outsndfile\n\n"
+        "MODE 1 imposes an envelope extracted from another sndfile.\n"
+        "MODE 2 imposes an envelope from a binary envelope file.\n"
+        "MODE 3 imposes an envelope from a (text) brkpnt file: val range (0 - 1).\n"
+        "MODE 4 imposes an envelope from a (text) brkpnt file with dB vals (%.0lf to 0).\n\n"
+        "WSIZE      window_size (in MS) for scanning envelope: Range (%.0lf - filelen)\n\n"
+        "In MODES 1 & 2, the whole sndfile is enveloped.\n"
+        "In MODES 3 & 4, brkpnt may start (and end) at any time in file,\n"
+        "                effectively editing it. Must have at least 2 brkpnt pairs.\n",
+        MIN_DB_ON_16_BIT,ENV_MIN_WSIZE);
+    } else if(!strcmp(str,"replace"))   {       
+        fprintf(stdout,
+        "REPLACE THE EXISTING ENVELOPE OF AN INPUT SOUNDFILE\n"
+        "            WITH A DIFFERENT ENVELOPE.\n\n"
+        "USAGE: envel replace 1 input_sndfile replacing-sndfile    outsndfile wsize\n"
+        "USAGE: envel replace 2 input_sndfile replacing-envfile    outsndfile\n"
+        "USAGE: envel replace 3 input_sndfile replacing-brkfile    outsndfile\n"
+        "USAGE: envel replace 4 input_sndfile replacing-brkfile-dB outsndfile\n\n"
+        "MODES:\n"
+        "1 replaces envelope with new one extracted from another sndfile.\n"
+        "2 replaces envelope with new one from a binary envelope file.\n"
+        "3 replaces envelope with new one from (text) brkpnt file: valrange 0-1.\n"
+        "4 replaces envelope with new one from (text) brkpnt file in dB (-96 to 0).\n\n"
+        "In all cases, the entire sndfile is enveloped\n\n"
+        "WSIZE      window_size (in MS) for scanning envelope: Range (%.0lf - filelen)\n\n"
+        "MODE 1 is especially useful for restoring the amplitude contour of a sound\n"
+        "after filtering with time-varying Q-value.\n",ENV_MIN_WSIZE);
+    } else if(!strcmp(str,"brktoenv"))  {       
+        fprintf(stdout,
+        "CONVERT A (TEXT) BRKPNT ENVELOPE TO A BINARY ENVELOPE FILE.\n\n"
+        "USAGE: envel brktoenv inbrkfile outenvfile  wsize\n\n"
+        "WSIZE      window_size (in MS) for scanning envelope: Range (%.0lf - filelen)\n\n"
+        "If brkpnt starttime > zero, new envelope will start from zero,\n"
+        "holding the brktabel startval as far as first brktable time.\n",ENV_MIN_WSIZE);
+    } else if(!strcmp(str,"envtobrk"))  {       
+        fprintf(stdout,
+        "CONVERT A BINARY ENVELOPE FILE TO A (TEXT) BRKPNT ENVELOPE.\n\n"
+        "USAGE: envel envtobrk inenvfile outbrkfile  [-ddatareduce]\n\n"
+        "DATAREDUCE variable determines quantity v. accuracy of data written to brkfile.\n"
+        "           Range(0 - 1)\n");
+    } else if(!strcmp(str,"envtodb"))   {       
+        fprintf(stdout,
+        "CONVERT A BINARY ENVELOPE FILE TO A (TEXT) BRKPNT ENVELOPE WITH dB VALUES.\n\n"
+        "USAGE: envel envtodb inenvfile outbrkfile  [-ddatareduce]\n\n"
+        "DATAREDUCE variable determines quantity v. accuracy of data written to brkfile.\n"
+        "           Range(0 - 1)\n");
+    } else if(!strcmp(str,"dovetail")){     
+        fprintf(stdout,
+            "DOVETAIL SNDFILE BY ENVELOPING THE START AND END OF IT.\n\n"
+            "USAGE:\nenvel dovetail 1 infile outfile infadedur outfadedur intype outtype [-ttimes]\n"
+            "OR:   \nenvel dovetail 2 infile outfile infadedur outfadedur [-ttimes]\n\n"
+            "In mode 2, the dovetail slopes are doubly exponential (steeper).\n\n"
+            "INFADE-DUR  is duration of start-of-file fade-in.\n"
+            "OUTFADE-DUR is duration of end-of-file fade-out.\n"
+            "            Infade-dur and Outfade-dur must not overlap each another.\n"
+//TW UPDATES
+            "INTYPE      0 for linear fade, 1 (default) for exponential fade, at start.\n"
+            "OUTTYPE     0 for linear fade, 1 (default) for exponential fade, at end.\n"
+            "-t          times for fade durations are given in the units....\n"
+            "            seconds (-t0) samples (-t1), or grouped-samples (-t2)\n");
+    } else if(!strcmp(str,"curtail")){      
+         fprintf(stdout,
+            "CURTAIL SNDFILE BY FADING TO ZERO AT SOME TIME WITHIN IT.\n\n"
+            "USAGE: envel curtail 1 sndfile outfile fadestart fadeend  envtype [-ttimes]\n"
+            "OR:    envel curtail 2 sndfile outfile fadestart fade-dur envtype [-ttimes]\n"
+            "OR:    envel curtail 3 sndfile outfile fadestart          envtype [-ttimes]\n\n"
+            "OR:    envel curtail 4 sndfile outfile fadestart fadeend          [-ttimes]\n"
+            "OR:    envel curtail 5 sndfile outfile fadestart fade-dur         [-ttimes]\n"
+            "OR:    envel curtail 6 sndfile outfile fadestart                  [-ttimes]\n\n"
+            "MODES 4-6 produce doubly exponential (steeper) editing slope.\n\n"
+            "FADESTART is start-time of fade.\n"
+            "FADEEND   is end-time of fade. (In MODE 3, assumed to be endtime of origsnd).\n"
+            "FADE-DUR  is duration of fade-out.\n"
+            "ENVTYPE   0 for linear fade, 1 (default) for exponential fade.\n"
+            "-t        TIMES for fade start, end or duration are given in the units....\n"
+            "          seconds (-t0) samples (-t1), or grouped-samples (-t2)\n");       
+    } else if(!strcmp(str,"warp")) {        
+        fprintf(stdout,
+        "WARP THE ENVELOPE OF AN SOUNDFILE\n\n"
+        "envel warp 1-12  sndfile outsndfile          wsize various_params\n"
+        "envel warp 13    sndfile outsndfile rampfile wsize various_params\n"
+        "envel warp 14-15 sndfile outsndfile          wsize various_params\n\n"
+        "where MODE NUMBERS stand for are....\n"
+        "1 NORMALISE       5 LIFT            9  INVERT       13 TRIGGER\n"  
+        "2 REVERSE         6 TIMESTRETCH     10 LIMIT        14 CEILING\n"
+        "3 EXAGGERATE      7 FLATTEN         11 CORRUGATE    15 DUCKED\n"
+        "4 ATTENUATE       8 GATE            12 EXPAND \n\n"
+        "WSIZE is duration of enveloping window, in MS.\n\n"
+        "for more info on MODES, and their 'various_params', type e.g.:\n"
+        "      'envel warp normalise' for more info on 'normalise' option... etc\n");
+    } else if(!strcmp(str,"reshape")) {     
+        fprintf(stdout,
+        "WARP THE ENVELOPE IN A BINARY ENVELOPE FILE\n\n"
+        "envel reshape 1-12  envfile outenvfile          various_params\n"
+        "envel reshape 13    envfile outenvfile rampfile various_params\n"
+        "envel reshape 14-15 envfile outenvfile          various_params\n\n"
+        "where MODE NUMBERS stand for are....\n"
+        "1 NORMALISE       5 LIFT            9  INVERT       13 TRIGGER\n"  
+        "2 REVERSE         6 TIMESTRETCH     10 LIMIT        14 CEILING\n"     
+        "3 EXAGGERATE      7 FLATTEN         11 CORRUGATE    15 DUCKED\n"
+        "4 ATTENUATE       8 GATE            12 EXPAND \n\n"
+        "for more info on MODES, and their 'various_params', type e.g.:\n"
+        "      'envel reshape normalise' for more info on 'normalise' option... etc\n");
+    } else if(!strcmp(str,"replot")) {      
+        fprintf(stdout,
+        "WARP THE ENVELOPE IN A (TEXT) BRKPNT ENVELOPE FILE\n\n"
+        "envel replot 1-12  brkfile outbrkfile          wsize various_params [-dreduce]\n"
+        "envel replot 13    brkfile outbrkfile rampfile wsize various_params [-dreduce]\n"
+        "envel replot 14-15 brkfile outbrkfile          wsize various_params [-dreduce]\n\n"
+        "where MODE NUMBERS stand for are....\n"
+        "1 NORMALISE       5 LIFT            9  INVERT       13 TRIGGER\n"  
+        "2 REVERSE         6 TIMESTRETCH     10 LIMIT        14 CEILING\n"
+        "3 EXAGGERATE      7 FLATTEN         11 CORRUGATE    15 DUCKED\n"
+        "4 ATTENUATE       8 GATE            12 EXPAND \n\n"
+        "WSIZE   is duration of enveloping window, in MS.\n"
+        "REDUCE  forces interpolation of data in brkpnt outfile\n"
+        "        to reduce unnecessary data output: Range(0-1).\n\n"
+        "for more info on MODES, and their 'various_params', type e.g.:\n"
+        "      'envel replot normalise' for more info on 'normalise' option... etc\n"
+        "NB: TRIGGER works better using reshape or warp.\n");
+    } else if(!strcmp(str,"dbtoenv")) {     
+        fprintf(stdout,
+        "CONVERT A (TEXT) BRKPNT FILE WITH VALS IN dB TO AN ENVELOPE FILE\n\n"
+        "envel dbtoenv db_brkfile outenvfile  wsize\n\n"
+        "WSIZE is duration of enveloping window, in MS.\n");
+    } else if(!strcmp(str,"dbtogain")) {        
+        fprintf(stdout,
+        "CONVERT A (TEXT) BRKPNT FILE WITH dB VALS TO GAIN VALS\n\n"
+        "envel dbtogain db_brkfile outbrkfile\n");
+    } else if(!strcmp(str,"gaintodb")) {        
+        fprintf(stdout,
+        "CONVERT A (TEXT) BRKPNT FILE WITH GAIN VALS TO dB VALS\n\n"
+        "envel gaintodb brkfile out_db_brkfile\n");
+    } else if(!strcmp(str,"swell")) {       
+        fprintf(stdout,
+        "CAUSE SOUND TO FADE IN TO AND OUT FROM A PEAK MOMENT\n\n"
+        "envel swell infile outfile peaktime peaktype\n\n"
+        "PEAKTYPE: 0 linear: 1 (default) exponential\n");
+    } else if(!strcmp(str,"attack")) {      
+        fprintf(stdout,
+        "EMPHASIZE THE ATTACK OF A SOUND\n\n"
+        "envel attack 1 infile outfile gate gain onset decay [-tenvtype]\n"
+        "envel attack 2 infile outfile time gain onset decay [-tenvtype]\n"
+        "envel attack 3 infile outfile time gain onset decay [-tenvtype]\n"
+        "envel attack 4 infile outfile      gain onset decay [-tenvtype]\n\n"
+        "MODES ARE:\n"
+        "1) Set attack point where snd level first exceeds gate-level.\n"
+        "2) attack point at max level around your approx-time (+- %.0lf MS)\n"
+        "3) attack point at your exact-time.\n"
+        "4) attack point at maxlevel in sndfile.\n\n"
+        "GAIN:    Amplification of attack point\n"
+        "GATE:    Level for attack point to be recognised: Range(0 - 1)\n"
+        "TIME:    Time (approx or exact) of attack point,in secs.\n"
+        "ONSET:   Attack onset duration (MS): Range(%.0lf to %.0lf)\n"
+        "DECAY:   Attack decay duration (MS): Range(%.0lf to <infiledur)\n"
+        "ENVTYPE: 0 linear: 1 exponential(default).\n",
+        ENV_ATK_SRCH,ENV_MIN_ATK_ONSET,ENV_MAX_ATK_ONSET,ENV_MIN_ATK_ONSET);
+    } else if(!strcmp(str,"pluck")) {       
+        fprintf(stdout,
+        "PLUCK START OF SOUND (MONO FILES ONLY)\n\n"
+        "envel pluck infile outfile startsamp wavelen [-aatkcycles] [-ddecayrate]\n\n"
+        "STARTSAMP  Sample, in src sound, at which pluck will END:\n"
+        "           must be a sample AT A ZERO_CROSSING...\n"
+        "WAVELEN    no of (absolute) samples in pluck wavelen: \n"
+        "           should be same as src_signal's wavelen immediately after STARTSAMP\n"
+        "ATKCYCLES  no of wavecycles in pluck-attack : Range(%.0lf - %.0lf) (Default %.0lf)\n"
+        "DECAYRATE  rate of decay of the pluck_attack: Range(%.0lf - %.0lf) (Default %.0lf)\n",
+        ENV_PLK_CYCLEN_MIN,ENV_PLK_CYCLEN_MAX,ENV_PLK_CYCLEN_DEFAULT,
+        ENV_PLK_DECAY_MIN,ENV_PLK_DECAY_MAX,ENV_PLK_DECAY_DEFAULT);
+    } else if(!strcmp(str,"tremolo")) {     
+        fprintf(stdout,
+        "TREMOLO A SOUND\n\n"
+        "USAGE: envel tremolo mode infile outfile frq depth gain\n\n"
+        "MODES:\n"
+        "1) Interpolate linearly between frqs in any frq brktable (default).\n"
+        "2) Interpolate logarithmically (like pitch). (Care with zero frqs).\n\n"
+        "FRQ          frequency of tremolo (0 - %.0lf) \n"
+        "DEPTH        depth of tremolo: Range(0 to 1: default %.3lf)\n"
+        "GAIN         Overall signal gain, or envelope: Range(0 to 1: default 1)\n\n"
+        "Frq, Depth and Gain may vary over time.\n",ENV_TREM_MAXFRQ,ENV_TREM_DEFAULT_DEPTH);
+//TW NEW CASES
+    } else if(!strcmp(str,"scaled")) {      
+        fprintf(stdout,
+        "IMPOSE AN ENVELOPE ON AN INPUT SOUNDFILE, SCALING IT TIMEWISE TO SOUND'S DURATION.\n\n"
+        "USAGE: envel  scaled  input_sndfile  imposed-brkfile  outsndfile\n\n"
+        "Must have at least 2 brkpnt pairs.\n");
+    } else if(!strcmp(str,"timegrid")) {        
+        fprintf(stdout,
+        "PARTITION SOUNDFILE INTO STAGGERED GRIDS.\n"
+        "EACH GRID IS SEQUENCE OF WINDOWS FROM SOURCE, AT THEIR ORIGINAL TIMES, SEPARATED BY SILENCE.\n\n"
+        "USAGE: envel timegrid input_sndfile  generic_outsndfile_name gridcnt gridwidth splicelen\n\n"
+        "GRIDCNT      Number of grids (and hence output files).\n"
+        "GRIDWIDTH    Duration of Grid windows, in seconds.\n"
+        "SPLICELEN    Splice length, in mS\n\n"
+        "gridwidth and splicelen may vary over time.\n");
+    } else if(!strcmp(str,"cyclic")) {      
+        fprintf(stdout,
+        "CREATE A SEQUENCE OF REPEATED ENVELOPES, IN A BINARY ENVELOPE FILE.\n\n"
+        "USAGE: envel cyclic 1-3 outf       wsize total-dur cell-dur phase trough env-exp\n"
+        "OR:    envel cyclic 4 outf userenv wsize total-dur cell-dur phase\n\n"
+        "MODES:\n"
+        "(1) Rising. (2) Falling. (3) Troughed (falls then rises)  (4) User-defined\n\n"
+        "WSIZE       Envelope window size (ms) : Resolution of envelope generated.\n"
+        "TOTAL-DUR   Duration of output file.\n"
+        "CELL-DUR    Duration of individual (repeated) units: can vary over time.\n"
+        "PHASE       Where in cell-envelope to begin output: 0=start, 1=end of cell.\n"
+        "TROUGH      Lowest point of envelope cell (Range 0 -1): can vary over time.\n"
+        "ENV-EXP     Shape of env: 1 linear: <1 steep at top, > 1 steep at bottom.\n\n"
+        "USERENV     textfile of time/val(0-1) pairs defining env (time units arbitrary)\n"
+        "            as the envelope is stretched to each unit duration.\n");
+    } else
+        fprintf(stdout,"Unknown option '%s'\n",str);
+
+    return(USAGE_ONLY);
+}
+
+/******************************** USAGE3 ********************************/
+
+int usage3(char *str1,char *str2)
+{
+    if((!strcmp(str1,"warp")) || (!strcmp(str1,"reshape")) || (!strcmp(str1,"replot"))) {
+        if(!strcmp(str2,"normalise")) {
+            fprintf(stdout,
+            "NORMALISE envelope. Expand so that highest env point is max possible.\n\n"
+            "No other extra parameters needed.\n");
+        } else if(!strcmp(str2,"reverse")) {
+            fprintf(stdout,
+            "TIME-REVERSE envelope.\n\n"
+            "No other extra parameters needed.\n");
+        } else if(!strcmp(str2,"ceiling")) {
+            fprintf(stdout,
+            "Force envelope up to its MAXIMUM LEVEL, EVERYWHERE.\n"
+            "No other extra parameters needed.\n");
+        } else if(!strcmp(str2,"ducked")) {
+            fprintf(stdout,
+            "CREATE DUCKING ENVELOPE.\n\n"
+            "2 other parameters.\n"
+            "    GATE:      Range(0 - 1)\n"
+            "    THRESHOLD: Range(0 - 1)\n"
+            "With Envelope Warping:\n"
+            "When input envelope exceeds threshold, output envelope is reduced\n"
+            "to GATE level. Elsewhere it is unchanged.\n\n"
+            "With Envelope Reshaping or Replotting:\n"
+            "When input envelope exceeds threshold, output envelope takes\n"
+            "GATE level. Elsewhere it gives unity gain.\n\n"
+            "This can be used to create an envelope to apply to another sound\n"
+            "which will be mixed with sound from which original envelope extracted.\n"
+            "Gate and Threshold may vary through time.\n");
+        } else if(!strcmp(str2,"exaggerate")) {
+            fprintf(stdout,
+            "EXAGGERATE envelope contour.\n"
+            "1 other parameter :\n"
+            "               EXAGGERATE: Range > 0.0\n"
+            "              <1, Low vals boosted: >1, High vals boosted.\n"
+            "              Value 1, gives no change.\n\n"
+            "Exagg may vary over time\n");
+        } else if(!strcmp(str2,"attenuate")) {
+            fprintf(stdout,
+            "ATTENUATE an envelope.\n"
+            "1 other parameter : ATTENUATION : Range (0-1)\n\n"
+            "Atten may vary over time\n");
+        } else if(!strcmp(str2,"lift")) {
+            fprintf(stdout,
+            "LIFT envelope by fixed amount.\n"
+            "1 other parameter: LIFT: Range (0 - 1)\n\n"
+            "Lift may vary over time\n");
+        } else if(!strcmp(str2,"timestretch")) {
+            fprintf(stdout,
+            "TIMESTRETCH an envelope.\n"
+            "1 other parameter: TIMESTRETCH: Range > 0.0\n"
+            "Note that timestretch < 1.0 shrinks the envelope.\n");
+        } else if(!strcmp(str2,"flatten")) {
+            fprintf(stdout,
+            "FLATTEN envelope contour.\n"
+            "1 other parameter: FLATTEN: Range (1 - %ld windows)\n\n"
+            "Flatten may vary over time\n",round(MAX_ENV_FLATN));
+        } else if(!strcmp(str2,"gate")) {
+            fprintf(stdout,
+            "GATE envelope. Levels less than gate are set to zero.\n"
+            "2 other parameters:\n"
+            "                GATE:      Range (0 - 1)\n"
+            "                SMOOTHING: Range (0 - %ld windows)\n"
+            "SMOOTHING excises low-level segments of less than SMOOTHING windows.\n"
+            "          value zero turns off smoothing effect.\n\n"
+            "Gate may vary over time\n",round(MAX_ENV_SMOOTH));
+        } else if(!strcmp(str2,"invert")) {
+            fprintf(stdout,
+            "INVERT envelope contour.\n"
+            "2 other parameters.    GATE:   Range (0 - <MIRROR)\n"
+            "                       MIRROR: Range (>GATE - 1)\n"
+            "Levels below GATE-level are set to zero. All other levels,\n"
+            "above & below MIRROR, are inverted to other side of mirror.\n\n"
+            "Gate and Mirror may vary over time\n");
+        } else if(!strcmp(str2,"limit")) {
+            fprintf(stdout,
+            "LIMIT the envelope.\n"
+            "2 other parameters   LIMIT:     Range (THRESHOLD - 1)\n"
+            "                     THRESHOLD: Range (0 - LIMIT)\n"
+            "Levels above THRESHOLD are squeezed downwards so maxamp becomes LIMIT.\n\n"
+            "Limit and Threshold may vary over time\n");
+        } else if(!strcmp(str2,"corrugate")) {
+            fprintf(stdout,
+            "CORRUGATE the envelope.  Take all troughs in the envelope to zero.\n"
+            " 2 other parameters:\n"
+            "    TROFDEL:         number of windows to set to zero, per trough.\n"
+            "                     Range(1 to <PEAK_SEPARATION).\n"
+            "    PEAK_SEPARATION: Range(2 - %d): min windows between peaks.\n\n"
+            "Trofdel and Peak_separation may vary over time.\n",MAX_PEAK_SEPARATION);
+        } else if(!strcmp(str2,"expand")) {
+            fprintf(stdout,
+            "EXPAND the envelope level.\n"
+            "3 other parameters.\n"
+            "    GATE:      Range(0 - THRESHOLD)\n"
+            "    THRESHOLD: Range(GATE - 1)\n"
+            "               Levels below GATE set to 0. Other levels squeezed upwards\n"
+            "               so minimum level becomes THRESHOLD.\n\n"
+            "    SMOOTHING: excises low-level segments, < SMOOTHING windows in length.\n"
+            "               Range(0 - %ld) : 0 turns off smoothing effect.\n\n"
+            "Gate and Threshold may vary over time\n",round(MAX_ENV_SMOOTH));
+        } else if(!strcmp(str2,"trigger")) {
+            fprintf(stdout,
+            "Create a new envelope of sudden ON bursts, \n"
+            "TRIGGERED by the rate of rise of the current envelope.\n"
+            "4 other parameters\n"
+            "   RAMPFILE: is your new brkpnt envelope for the (triggered) bursts.\n"
+            "   GATE:     Range(0 - 1): to trigger, average-level must be > gate.\n"
+            "   RISE:     Minimum loudness-step to cause triggering. Range(>0 - 1)\n"
+            "   DUR:      max duration (in MS) of min-loudness step, to trigger.\n"
+            "             Must be  >= ENVELOPE_WINDOW duration.\n"
+            "Gate may vary over time\n");
+        } else
+            fprintf(stdout,"UNKNOWN MODE\n");
+    } else
+        fprintf(stdout,"Insufficient parameters on command line.\n");
+    return(USAGE_ONLY);
+}
+
+/******************************** INNER_LOOP (redundant)  ********************************/
+
+int inner_loop
+(int *peakscore,int *descnt,int *in_start_portion,int *least,int *pitchcnt,int windows_in_buf,dataptr dz)
+{
+//TW PREVENT WARNINGS
+#if 0
+    peakscore = peakscore;
+    descnt = descnt;
+    in_start_portion = in_start_portion;
+    least = least;
+    pitchcnt = pitchcnt;
+    windows_in_buf = windows_in_buf;
+    dz = dz;
+#endif
+    return(FINISHED);
+}
+
+//TW UPDATE : NEW FUNCTION
+/******************************** SCALE_ENVELOPE_DATA ********************************/
+
+int scale_envelope_data(dataptr dz)
+{
+    int n = 0;
+    double scaler;
+    double *ebrk = dz->brk[dz->extrabrkno];
+    int lastindx = (dz->brksize[dz->extrabrkno] - 1) * 2;
+    double firsttime = ebrk[0];
+    double lasttime  = ebrk[lastindx];
+    double timerange = lasttime - firsttime;
+    if(timerange <= 0.0) {
+        sprintf(errstr,"Time range in envelope file is too small, or inverted.\n");
+        return(DATA_ERROR);
+    }
+    if(firsttime > 0.0) {
+        while(n <=lastindx) {
+            ebrk[n] -= firsttime;
+            n += 2;
+        }
+    }
+    if(dz->duration <= 0.0) {
+        sprintf(errstr,"Duration of input file is anomalous.\n");
+        return(DATA_ERROR);
+    }
+    scaler = dz->duration/ebrk[lastindx];
+    n = 0;
+    while(n <= lastindx) {
+        ebrk[n] *= scaler;
+        n += 2;
+    }
+    return(FINISHED);
+}
+
+/******************************** READ_ENVSYN_FILE ********************************/
+
+int  read_envsyn_file(char *str,dataptr dz)
+{
+    int cnt = 0, n;
+    double maxtime;
+    char temp[200], *p;
+    int arraysize = BIGARRAY;
+    
+    FILE *fp;
+    if((dz->parray[ENVSYN_ENV] = (double *)malloc(arraysize * sizeof(double)))==NULL) {
+        sprintf(errstr,"INSUFFICIENT MEMORY for user envelope.\n");
+        return(MEMORY_ERROR);
+    }
+    if((fp = fopen(str,"r"))==NULL) {           /* 2 */
+        sprintf(errstr,"Failed to open envelope file %s\n",str);
+        return(DATA_ERROR);
+    }
+    while(fgets(temp,200,fp)!=NULL) {               /* 3 */
+        p = temp;
+        while(get_float_from_within_string(&p,&(dz->parray[ENVSYN_ENV][cnt]))) {
+            if(cnt==0) {             /* FORCE ZERO-TIME POINT AT TAB START */
+                if(dz->parray[ENVSYN_ENV][cnt]<0.0) {
+                    sprintf(errstr,"-ve time (%lf) line %d in file %s\n",dz->parray[ENVSYN_ENV][cnt],(cnt/2)+1,str);
+                    return(DATA_ERROR);
+                }
+                if(flteq(dz->parray[ENVSYN_ENV][cnt],0.0)) {
+                    dz->parray[ENVSYN_ENV][cnt] = 0.0;  /* FORCE 0.0 TIME TO exactly 0.0 */
+                } else {                                    /* Add zero-time values */
+                    dz->parray[ENVSYN_ENV][2] = dz->parray[ENVSYN_ENV][0];
+                    dz->parray[ENVSYN_ENV][3] = dz->parray[ENVSYN_ENV][1];
+                    dz->parray[ENVSYN_ENV][0] = 0.0;
+                    cnt += 2;
+                }
+            } else {
+                if(EVEN(cnt)) { /* Time vals */
+                        /* CHECK TIME SEQUENCING */
+                    if(dz->parray[ENVSYN_ENV][cnt] <= dz->parray[ENVSYN_ENV][cnt-2]) {
+                        sprintf(errstr,"Time values out of sequence (%lf : %lf)in envelope file at line %d\n",
+                        dz->parray[ENVSYN_ENV][cnt-2],dz->parray[ENVSYN_ENV][cnt],(cnt/2)+1);
+                        return(DATA_ERROR);
+                    }
+                } else {        /* Env values */
+                    if(dz->parray[ENVSYN_ENV][cnt]<dz->application->min_special 
+                    || dz->parray[ENVSYN_ENV][cnt]>dz->application->max_special) {  /* CHECK RANGE */  
+                        sprintf(errstr,"Invalid envelope value (%lf): line %d file %s\n",
+                        dz->parray[ENVSYN_ENV][cnt],(cnt/2)+1,str);
+                        return(DATA_ERROR);
+                    }
+                }
+            }
+            if(++cnt >= arraysize) {
+                arraysize += BIGARRAY;
+                if((dz->parray[ENVSYN_ENV]=
+                (double *)realloc((char *)dz->parray[ENVSYN_ENV],arraysize*sizeof(double)))==NULL){
+                    sprintf(errstr,"INSUFFICIENT MEMORY to reallocate user envelope.\n");
+                    return(MEMORY_ERROR);
+                }
+            }
+        }
+    }
+    if(ODD(cnt)) {
+        sprintf(errstr,"Envelope vals incorrectly paired in file %s\n",str);
+        return(DATA_ERROR);
+    }
+    if(cnt==0) {
+        sprintf(errstr,"No envelope values found in file %s\n",str);
+        return(DATA_ERROR);
+    }
+    
+    if((dz->parray[ENVSYN_ENV]=(double *)realloc(dz->parray[ENVSYN_ENV],cnt * sizeof(double)))==NULL) {
+        sprintf(errstr,"INSUFFICIENT MEMORY to reallocate user envelope.\n");
+        return(MEMORY_ERROR);
+    }
+
+    dz->ptr[ENVSYN_ENVEND] = &(dz->parray[ENVSYN_ENV][cnt]);    /* MARK END OF ENVELOPE DATA */
+
+    maxtime = dz->parray[ENVSYN_ENV][cnt-2];                        /* FIND MAXIMUM TIME IN DATA */
+    for(n=2;n<cnt;n +=2)                          /* NORMALISE DATA TIMES TO LIE BETWEEN 0 AND 1 */
+        dz->parray[ENVSYN_ENV][n] = (float)(dz->parray[ENVSYN_ENV][n]/maxtime);
+    dz->parray[ENVSYN_ENV][cnt-2] = 1.0;                      /* FORCE FINAL TIME TO exactly 1.0 */
+    if(fclose(fp)<0) {
+        fprintf(stdout,"WARNING: Failed to close input textfile %s.\n",str);
+        fflush(stdout);
+    }
+    return(FINISHED);
+}    
+
+/******************************** CREATE_ENVSYN_BUF ********************************/
+/*RWD April 2004: NB bigbufsize strictly a local var now */
+int create_envsyn_buf(dataptr dz)
+{
+    size_t bigbufsize;
+
+    bigbufsize = (size_t) Malloc(-1);
+    bigbufsize = (bigbufsize/SECSIZE) * SECSIZE;
+    if(bigbufsize <= 0) {
+        sprintf(errstr,"INSUFFICIENT MEMORY for envelope data buffers.\n");
+        return(MEMORY_ERROR);
+    }
+    if((dz->bigfbuf = (float *)Malloc(bigbufsize))==NULL) {
+        sprintf(errstr,"INSUFFICIENT MEMORY to create envelope data buffer.\n");
+        return(MEMORY_ERROR);
+    }
+    dz->buflen      = (int)(bigbufsize/sizeof(float));
+    dz->flbufptr[0] = dz->bigfbuf;
+    return(FINISHED);
+}

+ 1002 - 0
dev/env/envel.c

@@ -0,0 +1,1002 @@
+/*
+ * 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 <globcon.h>
+#include <processno.h>
+#include <modeno.h>
+#include <arrays.h>
+#include <envel.h>
+#include <cdpmain.h>
+//TW UPDATE
+#include <logic.h>
+#include <limits.h>
+#include <osbind.h>
+
+#include <sfsys.h>
+
+
+#define INBUF_START		(0)
+#define OUTBUF_START	(1)
+#define OUTBUF_END		(2)
+
+static int  init_outbuf
+	(int startsamp,int *is_simple,int *write_offset,int *samp_offset,int *samps_left_to_process,dataptr dz);
+static int  init_brkpnts
+	(int *sampno,double *starttime,double *gain,double **endbrk,double **nextbrk,
+	 double *nextgain,double *gain_step,double *gain_incr,int *nextbrk_sampno,dataptr dz);
+static int  advance_brkpnts
+	(double starttime,double *gain,double *endbrk,double **nextbrk,double *nextgain,
+	 double *gain_step,double *gain_incr,int *nextbrk_sampno,dataptr dz);
+static int  calc_samps_to_process
+	(int *startsamp,int *samps_left_to_process,dataptr dz);
+static int  simple_envel_processing
+	(int *samps_left_to_process,double starttime,double *endbrk,double **nextbrk,double *nextgain,
+	 int *sampno,double *gain,double *gain_step,double *gain_incr,int *nextbrk_sampno,dataptr dz);
+static int  buf_staggered_envel_processing
+	(int *samps_left_to_process,int samp_offset,int write_offset,double starttime,double *endbrk,double **nextbrk,
+	 double *nextgain,int *sampno,double *gain,double *gain_step,double *gain_incr,int *nextbrk_sampno,dataptr dz);
+static int  read_partbuf_samps
+	(int samps_to_read,int *samps_left_to_process, dataptr dz);
+static int  do_envelope
+	(int samp_cnt,double starttime,double *endbrk,double **nextbrk,double *nextgain,
+	 int *sampno,double *gain,double *gain_step,double *gain_incr,int *nextbrk_sampno,dataptr dz);
+static int  read_ssamps(int samps_to_read,int *samps_left_to_process,dataptr dz);
+static int  do_simple_read(int *samps_left_to_process,int bufsize,dataptr dz);
+static int  do_offset_read(int *samps_left_to_process,int samp_offset,int bufsize,dataptr dz);
+static int  skip_into_file(int startsamp,int extended_buf_sampsize,int *write_offset,int *samp_offset,dataptr dz);
+
+/******************************* APPLY_BRKPNT_ENVELOPE *******************************/
+
+int apply_brkpnt_envelope(dataptr dz)
+{
+	int exit_status;
+	int startsamp, samps_left_to_process;
+	int is_simple;
+	int write_offset, samp_offset, sampno, nextbrk_sampno;
+	double starttime, gain, nextgain, gain_step, gain_incr;
+	double *endbrk, *nextbrk; 
+	if((exit_status = calc_samps_to_process(&startsamp,&samps_left_to_process,dz))<0)
+		return(exit_status);
+	if((exit_status = init_outbuf(startsamp,&is_simple,&write_offset,&samp_offset,&samps_left_to_process,dz))<0)
+		return(exit_status);
+	if((exit_status = init_brkpnts
+	(&sampno,&starttime,&gain,&endbrk,&nextbrk,&nextgain,&gain_step,&gain_incr,&nextbrk_sampno,dz))<0)
+		return(exit_status);
+	exit_status = FINISHED;
+	if(is_simple)
+		exit_status = simple_envel_processing
+		(&samps_left_to_process,starttime,endbrk,&nextbrk,&nextgain,
+		&sampno,&gain,&gain_step,&gain_incr,&nextbrk_sampno,dz);
+	else
+		exit_status = buf_staggered_envel_processing
+		(&samps_left_to_process,samp_offset,write_offset,starttime,endbrk,&nextbrk,
+		&nextgain,&sampno,&gain,&gain_step,&gain_incr,&nextbrk_sampno,dz);
+
+	return(exit_status);
+}
+
+/**************************** INIT_OUTBUF *******************************
+ *
+ *	|-------------extended-buffer-size-----------|
+ *       X    
+ *	     |-------------buffer-size---------------|
+ * 	     		    INBUF		    
+ *	|----|----|----|----|----|----|----|----|----|
+ *	|    |					     				 |
+ *	   | |					     			   | |
+ 	  write					     			(=write
+ 	  offset				     			 offset)
+ *	   | |					     			   | |
+ *	|  |					   				   |
+ *  samp					   				   |
+ * offset					   				   |
+ *	|  |					   				   |
+ *	   |----|----|----|----|----|----|----|----| 
+ *			    OUTBUF
+ *	   |-------------buffer-size---------------|
+ *
+ * IF the brkpoint table starts at 0,
+ * we can use THE SAME buffer for input and output.
+ * 		OTHERWISE.........
+ * (8)	First extimate of the number of samples in the input file which
+ *		we can skip, i.e. the number of complete extended-buffer-fulls
+ *		(see diagram) we can read before reaching first significant sample.
+ * (9)	After counting out these, we can assess how many COMPLETED sectors
+ *		are still to be read and ignored.
+ * (10)	We can now add the number of samples in these sectors to our first
+ *		estimate of samples to be skipped.
+ * (11)	The extent to which the OUTPUT buffer will be offset from the
+ *		INPUT buffer, (samp_offset) is given by the remaining part-sector of samps.
+ *		(see diagram).
+ * (12)	After the initial write, we will WRITE to a block 1 SECTOR later,
+ *		(X in diagram), so the WRITE-OFFSET is as shown.
+ * (13)	We now SEEK an exact number of sectors in the input file (thus
+ *		discarding these samps from our processing).
+ * (14)	If the samp_offset is ZERO, then we input and output buffers are
+ *		the same as at 4,5,6.
+ * (16)	Otherwise, fill the EXTENDED buffer (see diagram).
+ * (17)	Move the address of future read-ins (inbuf) 1 sector forward (to X in diagram).
+ * (18)	Set the address of the read-out buffer at the correct offset.
+ * (19)	Set the flag for the more difficult case.
+ * (20)	Decrement number of samps left to process.
+ *		If this takes samps_left below zero, this means we have
+ *		read a whole sector in place of a part-sector, so we must
+ *		readjust the value of samps_read!!
+ */
+
+int init_outbuf(int startsamp,int *is_simple,int *write_offset,
+				int *samp_offset,int *samps_left_to_process,dataptr dz)
+{
+	int exit_status;
+	int extended_buf_sampsize = dz->buflen;
+	int shsecsize = F_SECSIZE;
+	/*RWD: set the  vars*/
+	*samp_offset = *write_offset = 0;
+
+	if(startsamp==0) {											/* If we start at beginning */
+		dz->sampbuf[OUTBUF_START] = dz->sampbuf[INBUF_START];	/* inbuf and outbuf coincide */
+		if((exit_status = do_simple_read(samps_left_to_process,dz->buflen,dz))<0)
+			return(exit_status);								/* setup simple buffering option */
+		*is_simple = TRUE;											
+	} else {													
+ 		if((exit_status = skip_into_file(startsamp,extended_buf_sampsize,write_offset,samp_offset,dz))<0)
+			return(exit_status);	/* calculate sectors to skip into file, and any part-sector offset, and skip */
+		if(*samp_offset==0) {									 /* If no offset */
+			dz->sampbuf[OUTBUF_START] = dz->sampbuf[INBUF_START];/* inbuf and outbuf coincide */				
+			if((exit_status = do_simple_read(samps_left_to_process,dz->buflen,dz))<0)
+				return(exit_status);
+			*is_simple = TRUE;			
+		} else {												 /*  Otherwise there is an offset */
+			if((exit_status = do_offset_read(samps_left_to_process,*samp_offset,
+				     /*dz->bigbufsize + SECSIZE*/dz->buflen,dz))<0)
+				return(exit_status);							 /* read initial LARGE buffer */							
+			dz->sampbuf[OUTBUF_START] = dz->sampbuf[INBUF_START] + *samp_offset;
+																 /* Set outbuf (write) position */
+			dz->sampbuf[OUTBUF_END]  = dz->sampbuf[OUTBUF_START] + dz->buflen;	
+																 /* Set endpointer of outbuf */
+			dz->sampbuf[INBUF_START] += shsecsize;				 /* Set next read position for inbuf */
+																 /* to permit correct wrap_around of part_sector */
+			*is_simple = FALSE;									 /* Flag staggerd-buffers option */
+		}
+	}
+	return(FINISHED);
+}
+
+/**************************** INIT_BRKPNTS *******************************
+ * NB Here samples are taken to be a short for mono, 2 shorts for stereo, etc.
+ * and times are measured in such 'samples'.
+ */
+
+int init_brkpnts(int *sampno,double *starttime,double *gain,double **endbrk,double **nextbrk,
+double *nextgain,double *gain_step,double *gain_incr,int *nextbrk_sampno,dataptr dz)
+{
+	double nexttime, time_from_start;
+	int paramno = dz->extrabrkno;
+	*endbrk = dz->brk[paramno] + ((dz->brksize[paramno]-1) * 2);
+	*sampno    = 0;
+	*starttime = dz->brk[paramno][0];
+	*gain      = dz->brk[paramno][1];
+	*nextbrk   = dz->brk[paramno] + 2;
+	nexttime   = **nextbrk;
+	*nextgain  = *((*nextbrk) + 1);
+	*gain_step = *nextgain - *gain;
+	time_from_start = nexttime - *starttime;
+/* OCT 1996 */
+	if((*nextbrk_sampno  = (int)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 *****************************
+ * NB Here samples are taken to be a short for mono, 2 shorts for stereo, etc.
+ * and times are measured in such 'samples'.
+ */
+
+int advance_brkpnts(double starttime,double *gain,double *endbrk,double **nextbrk,
+double *nextgain,double *gain_step,double *gain_incr,int *nextbrk_sampno,dataptr dz)
+{
+	double  nexttime, time_from_start;
+	int   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;
+/* OCT 1996 */
+		if((*nextbrk_sampno  = (int)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);
+}
+
+/************************ CALC_SAMPS_TO_PROCESS ****************************
+ *
+ * (1)	Find time of final breakpoint value.
+ * (a)	Find the sample position of the brkpoint-table's starting time.
+ * (b)	Find its samp position.
+ * (2)	Find this time in samples (here samples mean short samples).
+ * (3)  The last samp to be processed is either the samp corresponding
+ *	to the last sample-time in brkpnt file OR the end of the input file.
+ * (4)	Number of samps-to-process = endsamp-time - startsamp-time.
+ * (5)	This also gives the required size of output file.
+ */
+
+int calc_samps_to_process(int *startsamp,int *samps_left_to_process,dataptr dz)
+{
+	int paramno = dz->extrabrkno;
+	int endbrk_samptime, endsamp, start_samp;
+	double lastbrktime, firstbrktime;
+	double infiledur = (double)(dz->insams[0]/dz->infile->channels)/(double)dz->infile->srate;
+
+	lastbrktime = *(dz->brk[paramno] + ((dz->brksize[paramno] - 1) * 2));
+	if(flteq(lastbrktime,infiledur)) {
+		endsamp = dz->insams[0];
+	} else {
+		endbrk_samptime  = round(lastbrktime * (double)dz->infile->srate);
+		endbrk_samptime *= dz->infile->channels;
+		endsamp          = min((int)endbrk_samptime,dz->insams[0]);
+	}
+	firstbrktime = *(dz->brk[paramno]);
+	*startsamp   = round(firstbrktime * (double)dz->infile->srate);
+	*startsamp  *= dz->infile->channels;
+	if((start_samp = *startsamp ) >= dz->insams[0]) {
+		sprintf(errstr,"envelope begins after end of file: can't proceed.\n");
+		return(DATA_ERROR);
+	}	
+	*samps_left_to_process = endsamp - start_samp;
+	return(FINISHED);
+}
+
+/*********************** SIMPLE_ENVEL_PROCESSING ********************************
+ *
+ * Simple case, input and output buffers coincide.
+ *
+ * (1)	If we read beyond number of samps we anticipated, this means
+ * 	we have read to the end of a sector, where we need a part-sector,
+ * 	so we must adjust value of actual samps read!!!
+ */
+
+int simple_envel_processing
+(int *samps_left_to_process,double starttime,double *endbrk,double **nextbrk,double *nextgain,
+int *sampno,double *gain,double *gain_step,double *gain_incr,int *nextbrk_sampno,dataptr dz)
+{
+	int exit_status;
+	while(*samps_left_to_process > 0) {
+		if((exit_status = do_envelope
+		(dz->buflen,starttime,endbrk,nextbrk,nextgain,sampno,gain,gain_step,gain_incr,nextbrk_sampno,dz))<0)
+			return(exit_status);
+		if((exit_status = write_samps(dz->sampbuf[OUTBUF_START],dz->buflen,dz))<0)
+			return(exit_status);
+		if((exit_status = do_simple_read(samps_left_to_process,dz->buflen,dz))<0)
+			return(exit_status);
+	}
+	if((exit_status = do_envelope
+	(dz->ssampsread,starttime,endbrk,nextbrk,nextgain,sampno,gain,gain_step,gain_incr,nextbrk_sampno,dz))<0)
+		return(exit_status);
+	if(dz->ssampsread > 0)
+		return write_samps(dz->sampbuf[OUTBUF_START],dz->ssampsread,dz);
+	return(FINISHED);
+}
+
+/*********************** BUF_STAGGERED_ENVEL_PROCESSING ********************************
+ *
+ * Non-simple case, input  and output buffers do not coincide.
+ *
+ *	     ___________tail is copied thus_________
+ *	    |					    				|
+ *	    |					    				|
+ * 	    v		    INBUF		    			^
+ *	|----|----|----|----|----|----|----|----|----|
+ *	     |					     				 |
+ *	   | |					   				   | |
+ *     write_offset				   				tail
+ *	   | |					   				   | |
+ *	   |					   				   |
+ *	   |----|----|----|----|----|----|----|----| 
+ *			    OUTBUF
+ *
+ * (1)	If we are inside the loop, there are still samps left to read
+ *		from input file, so this input buffer must be FULL.
+ *		This means we can WRITE a full output-buffer.
+ * (2)	Copy the tail-portion of the input buffer (that falls outside the
+ *		end of the output buffer (see diagram)), to the start of the output
+		buffer (see diagram).
+ * (3)	Read samps to inbuf location, decrementing no of samps left to read.
+ * (4)	If first time, (No buffers written: samps were read into VERY START of buf) 
+ *		no. of samps to write equals samps_read 
+ *		MINUS those not needed, in samp_offset area.....
+ * (5)	After first time, (Buffers laready writ: samps now read into the displaced inbuf)
+ *		number of samps to write equals those read
+ *		PLUS those already in start of outbuffer, haing been copied back into the write_offset segment.
+ * (6)	Do envelope on the incomplete (or exactly full) buffer.
+ * (7)	Write this.
+ */
+
+int buf_staggered_envel_processing
+(int *samps_left_to_process,int samp_offset,int write_offset,double starttime,double *endbrk,double **nextbrk,
+double *nextgain,int *sampno,double *gain,double *gain_step,double *gain_incr,int *nextbrk_sampno,dataptr dz)
+{
+	int exit_status;
+	int samps_to_write_here;
+	int  firstime = TRUE;
+	while(*samps_left_to_process > 0) {
+		firstime = FALSE;
+		if((exit_status = do_envelope
+		(dz->buflen,starttime,endbrk,nextbrk,nextgain,sampno,gain,gain_step,gain_incr,nextbrk_sampno,dz))<0)
+			return(exit_status);
+
+		if((exit_status = write_samps(dz->sampbuf[OUTBUF_START],dz->buflen,dz))<0)
+			return(exit_status);										/* 1 */
+		memmove((char *)dz->sampbuf[OUTBUF_START],(char *)dz->sampbuf[OUTBUF_END],write_offset * sizeof(float));
+		if((exit_status = do_simple_read(samps_left_to_process,dz->buflen,dz))<0)		
+			return(exit_status);										/* 3 */
+	}
+	if(firstime)
+		samps_to_write_here = dz->ssampsread - samp_offset;				/* 4 */
+	else 
+		samps_to_write_here = dz->ssampsread + write_offset;			/* 5 */
+	if((exit_status = do_envelope										/* 6 */
+	(samps_to_write_here,starttime,endbrk,nextbrk,nextgain,sampno,gain,gain_step,gain_incr,nextbrk_sampno,dz))<0)
+		return(exit_status);
+																	 	/* 7 */
+	if(samps_to_write_here > 0)
+		return write_samps(dz->sampbuf[OUTBUF_START],samps_to_write_here,dz);
+	return(FINISHED);
+}
+
+/**************************** READ_PARTBUF_SAMPS *****************************/
+
+int read_partbuf_samps(int samps_to_read,int *samps_left_to_process, dataptr dz)
+{
+	if((dz->ssampsread = fgetfbufEx(dz->sampbuf[INBUF_START], samps_to_read,dz->ifd[0],0)) < 0)  {
+		sprintf(errstr,"Can't read samples from input soundfile: read_partbuf_samps()\n");
+		return(SYSTEM_ERROR);
+	}
+	if(dz->ssampsread < samps_to_read) {
+		sprintf(errstr,"Error in buffering arithmetic: read_partbuf_samps()\n");
+		return(PROGRAM_ERROR);
+	}
+	*samps_left_to_process -= dz->ssampsread;
+	return(FINISHED);
+}
+							  
+/************************* DO_ENVELOPE ********************************
+ *
+ * (1)	endsampno (absolute numbering) is the final sample to be treated in this call.
+ *
+ *	  While ever the quit-flag is not set...
+ * (2)	if the sample number of the next break-pnt falls before or at the end
+ *		of this function call...
+ *		Set the 'change' flag, which will cause envelope breakpoints to be
+ *		advanced.
+ * (3)	set end of the inner-loop pass to this next brkpnt.
+ * (4)	If the brkpnt falls exactly at end of pass, set the 'quit' flag.
+ *		Otherwise quit remains FALSE, and the outer loop will be recalled (after
+ *		breakpoints have been advanced).
+ * (5)	Otherwise, the next breakpnt falls beyond the end of this function call.
+ *		So don't advance the breakpoints (change = FALSE), sample at end of inner
+ *		loop (this_endsamp) is the sample at end of this call-to-function
+ *		(endsampno), AND  set flag to quit at end of inner loop.
+ * (6)	Counter for inner loop is this-endsamp minus current position (sampno).
+ * (7)	Inner loop, get gain for each sample, and increment samples accordingly.
+ * (8)	Increment the absolute count of processed samples (sampno).
+ * (9)	If change flag is set, reset gain and advance breakpoints.
+ * (10)	Retain the enveloping gain current at end of buffer.
+ */
+
+int do_envelope
+(int samp_cnt,double starttime,double *endbrk,double **nextbrk,double *nextgain,
+int *sampno,double *gain,double *gain_step,double *gain_incr,int *nextbrk_sampno,dataptr dz)
+{
+	int    exit_status;
+	int   n, m, sampcnt;
+	int   endsampno, this_endsamp, this_sampcnt;
+	float  *obuf = dz->sampbuf[OUTBUF_START];
+	float  *obufend = obuf + dz->buflen;
+	int    quit = FALSE, change;
+	double   val;
+	double this_gain      = *gain;
+	double this_gain_incr = *gain_incr;
+	double this_gain_step = *gain_step;
+	sampcnt = samp_cnt / dz->infile->channels;	/* 'stereo'-samples to process */
+	endsampno = *sampno + sampcnt;				/* 1 */
+	if(sampcnt * dz->infile->channels > dz->buflen) {
+		sprintf(errstr,"Buffering anomaly: do_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 * dz->infile->channels) > obufend) {
+			sprintf(errstr,"array overrun: do_envelope()\n");
+			return(PROGRAM_ERROR);
+		}
+		if(flteq(this_gain,1.0) && flteq(this_gain_step,0.0))
+			obuf += this_sampcnt * dz->infile->channels;				/* no modification of sound */
+		else {
+			for(n=0;n<this_sampcnt;n++) {		/* 7 */
+				this_gain += this_gain_incr;
+				for(m=0;m<dz->infile->channels;m++) {				
+					val = /*round*/((double)(*obuf) * this_gain);
+					*obuf = (float)val;
+					obuf++;
+				}
+			}
+		}
+		*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(int samps_to_read,int *samps_left_to_process,dataptr dz)
+{
+	if((dz->ssampsread = fgetfbufEx(dz->sampbuf[INBUF_START], samps_to_read,dz->ifd[0],0)) < 0) {
+		sprintf(errstr,"Can't read samples 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;
+	return(FINISHED);
+}
+
+/******************************** DO_SIMPLE_READ **********************************/
+
+int do_simple_read(int *samps_left_to_process,int bufsize,dataptr dz)
+{
+	int exit_status;
+	if(*samps_left_to_process < bufsize)
+		exit_status = read_partbuf_samps(*samps_left_to_process,samps_left_to_process,dz);
+	else
+		exit_status = read_ssamps(bufsize,samps_left_to_process,dz);
+	return(exit_status);
+}
+
+/******************************** DO_OFFSET_READ **********************************/
+
+int do_offset_read(int *samps_left_to_process,int samp_offset,int bufsize,dataptr dz)
+{
+	int exit_status;
+	if(*samps_left_to_process < bufsize) {
+		exit_status = read_partbuf_samps(*samps_left_to_process + samp_offset,samps_left_to_process,dz);
+		*samps_left_to_process = 0;
+	} else {
+		exit_status = read_ssamps(bufsize,samps_left_to_process,dz);
+		*samps_left_to_process += samp_offset;	/* some of samps-read are not part of samps-to-process */
+	}
+	return(exit_status);
+}
+
+/******************************** SKIP_INTO_FILE **********************************/
+//RWD ugh! unless this is simply a sndseek to startsamp....
+//TW unfortunately, it's intrinsically tied up with old buffering scheme
+//#ifdef NOTDEF
+int skip_into_file(int startsamp,int extended_buf_sampsize,int *write_offset,int *samp_offset,dataptr dz)
+{
+	int skipsamps=(startsamp/extended_buf_sampsize) * extended_buf_sampsize;	/* 8 */
+	int sampsecsize = ENV_FSECSIZE;
+	int sectors_remaining = (startsamp - skipsamps)/sampsecsize;				/* 9 */
+	skipsamps   += sectors_remaining * sampsecsize;								/* 10 */
+	*samp_offset  = startsamp - skipsamps;										/* 11 */
+	*write_offset = ENV_FSECSIZE - *samp_offset;								/* 12 */
+	if(sndseekEx(dz->ifd[0],skipsamps,0)<0) {									/* 13 */
+		sprintf(errstr,": sndseekEx failed: skip_into_file()\n");
+		return(SYSTEM_ERROR);
+	}
+	return(FINISHED);
+}
+//#endif
+
+//TW UPDATE: NEW CODE
+
+/*** NEW april 2002 ****/
+
+static int fill_grid_array(double starttime,int *firstpass, double *next_gridstart, double **d, int *arraysize, dataptr dz);
+static int check_available_space(dataptr dz);
+static int create_grid_envelope(int n, double *next_gridstart,dataptr dz);
+static int do_grid_envelope(dataptr dz);
+static int do_grid_biz(int sib,int eib,int style,int *splicepos,dataptr dz);
+static void get_nextposition_pair(double *ds,int *startsamp,int *endsamp,int *style,dataptr dz);
+
+#define GRID_ZERO	(0)
+#define GRID_COPY	(1)
+#define GRID_DOWN	(2)
+#define GRID_UP		(3)
+
+/************************************ DO_GRIDS ********************************/
+
+int do_grids(dataptr dz)
+{
+	int exit_status;
+	int n;
+	int namelen, numlen;
+	char *outfilename;
+//TW REVISION DEc 2002
+//	char *outfilenumber;
+	char *p, *q, *r;
+	double next_gridstart;
+
+	numlen  = 4;
+
+	if(!sloom) {
+		namelen = strlen(dz->wordstor[0]);
+		q = dz->wordstor[0];
+		r = dz->wordstor[0] + namelen;
+		p = r - 1;
+		while((*p != '\\') && (*p != '/') && (*p != ':')) {
+			p--	;
+			if(p < dz->wordstor[0])
+				break;
+		}
+		if(p > dz->wordstor[0]) {
+			p++;
+			while(p <= r)
+				*q++ = *p++;
+		}
+	}
+	namelen = strlen(dz->wordstor[0]);		
+//	if(sndunlink(dz->ofd) < 0) {
+//		fprintf(stdout,"WARNING: Can't set initial dummy output soundfile for deletion.\n");
+//		fflush(stdout);
+//	}
+//	if(sndcloseEx(dz->ofd) < 0) {
+//		fprintf(stdout,"ERROR: Can't close initial dummy output soundfile\n");
+//		return(SYSTEM_ERROR);
+//	}
+	dz->ofd = -1;
+	if((exit_status = check_available_space(dz))<0)
+		return(exit_status);
+	if((dz->tempsize = dz->insams[0] * dz->iparam[GRID_COUNT])<0)
+		dz->tempsize = INT_MAX;
+	if(sloom)
+		namelen--;									/* Drop the 0 at end of name */
+	next_gridstart = 0.0;
+	if((exit_status = reset_peak_finder(dz))<0)
+		return(exit_status);
+	for(n=0;n<dz->iparam[GRID_COUNT];n++) {
+		if(sndseekEx(dz->ifd[0],0,0)<0) {
+			sprintf(errstr,"sndseekEx() failed.\n");
+			return(SYSTEM_ERROR);
+		}
+		reset_filedata_counters(dz);
+// FEB 2010 TW
+		if((outfilename = (char *)malloc((namelen + numlen + 10) * sizeof(char)))==NULL) {
+			sprintf(errstr,"INSUFFICIENT MEMORY for outfilename.\n");
+			return(MEMORY_ERROR);
+		}				
+	    strcpy(outfilename,dz->wordstor[0]);
+//TW REvision Dec 2002
+		if(sloom)
+			insert_new_number_at_filename_end(outfilename,n,1);
+// FEB 2010 TW
+		else {
+			insert_separator_on_sndfile_name(outfilename,1);
+			insert_new_number_at_filename_end(outfilename,n,0);
+		}
+		dz->process_type = EQUAL_SNDFILE;	/* allow sndfile to be created */
+		if((exit_status = create_sized_outfile(outfilename,dz))<0) {
+			if(!sloom) {
+				sprintf(errstr, "Soundfile %s already exists: Made %d grids only.\n",outfilename,n-1);
+				free(outfilename);
+				dz->process_type = OTHER_PROCESS;
+				dz->ofd = -1;
+				return(GOAL_FAILED);
+			} else {
+				dz->process_type = OTHER_PROCESS;
+				dz->ofd = -1;
+				sprintf(errstr, "Soundfile %s already exists: Made %d grids only.\n",outfilename,n-1);
+				return(SYSTEM_ERROR);
+			}
+		}							
+		dz->process_type = OTHER_PROCESS;
+		if((exit_status = create_grid_envelope(n,&next_gridstart,dz))<0)
+			return(exit_status);
+		if((exit_status = do_grid_envelope(dz))<0)
+			return(exit_status);
+		dz->process_type = EQUAL_SNDFILE;		/* allows header to be written  */
+		dz->outfiletype  = SNDFILE_OUT;			/* allows header to be written  */
+		if((exit_status = headwrite(dz->ofd,dz))<0) {
+			free(outfilename);
+			return(exit_status);
+		}
+		dz->process_type = OTHER_PROCESS;		/* restore true status */
+		dz->outfiletype  = NO_OUTPUTFILE;		/* restore true 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);
+		}
+		free(outfilename);
+		dz->ofd = -1;
+	}
+	return(FINISHED);
+}
+
+/************************************ CHECK_AVAILABLE_SPACE ********************************/
+#define LEAVESPACE	(10*1024)
+
+int check_available_space(dataptr dz)
+{
+	unsigned int slots;
+	unsigned int freespace = getdrivefreespace("temp") - LEAVESPACE;
+	freespace /= sizeof(float);
+	slots = freespace/dz->insams[0];
+	if(slots < (unsigned int)dz->iparam[COPY_CNT]) {
+		sprintf(errstr,"Insufficient space on disk to create %d copies.\n"
+		               "You have space for %d copies.\n",dz->iparam[COPY_CNT],slots);
+		return(GOAL_FAILED);
+	}
+	return(FINISHED);
+}
+
+/************************************ CREATE_GRID_ENVELOPE ********************************/
+
+int create_grid_envelope(int n, double *next_gridstart,dataptr dz)
+{
+	double *d, time, thistime, grid_step, half_gridsplen;
+	int arraysize = 8, old_arraysize;
+	double starttime;
+	int firstpass, exit_status;
+
+	if(dz->brksize[GRID_WIDTH] == 0) {
+		grid_step = dz->param[GRID_WIDTH] * dz->iparam[GRID_COUNT];
+		switch(n) {
+		case(0):
+			if((dz->parray[0] = (double *)malloc(arraysize * sizeof(double)))==NULL) {
+				sprintf(errstr,"Insufficient memory for grid envelope,\n");
+				return(MEMORY_ERROR);
+			}
+			d = dz->parray[0];
+			for(time = 0.0; time <= dz->duration; time += grid_step) {
+				thistime = time;	
+				if(flteq(time,0.0))
+					*d++ = thistime;
+				else {
+					if(dz->brksize[GRID_SPLEN] > 0)
+						read_value_from_brktable(thistime,GRID_SPLEN,dz);
+					half_gridsplen = dz->param[GRID_SPLEN]/2.0;
+					*d++ = thistime + half_gridsplen;
+				}
+				*d++ = 1.0;
+				thistime += dz->param[GRID_WIDTH];
+				if(dz->brksize[GRID_SPLEN] > 0)
+					read_value_from_brktable(thistime,GRID_SPLEN,dz);
+				half_gridsplen = dz->param[GRID_SPLEN]/2.0;
+				*d++ = thistime - half_gridsplen;
+				*d++ = 1.0;
+				*d++ = thistime + half_gridsplen;
+				*d++ = 0.0;
+				thistime = time + grid_step;
+				if(dz->brksize[GRID_SPLEN] > 0) {
+					read_value_from_brktable(thistime,GRID_SPLEN,dz);
+				}
+				half_gridsplen = dz->param[GRID_SPLEN]/2.0;
+				*d++ = thistime - half_gridsplen;
+				*d++ = 0.0;
+				old_arraysize = arraysize;
+				arraysize += 8;
+				if((dz->parray[0] = (double *)realloc((char *)dz->parray[0],arraysize * sizeof(double)))==NULL) {
+					sprintf(errstr,"Insufficient memory for grid envelope,\n");
+					return(MEMORY_ERROR);
+				}
+				d = dz->parray[0] + old_arraysize;
+				dz->parray[1] = d;		/* mark end of parray */
+			}
+			break;
+		case(1):
+			for(d = dz->parray[1]-2; d >= dz->parray[0];d -= 2) {
+				*(d+4) = (*d) + dz->param[GRID_WIDTH];		/* add time to values, and shift them up two brkpnt places */
+				*(d+5) = *(d+1);
+			}
+			*(dz->parray[0])   = 0.0;						/* Insert a zero time zero val */			
+			*(dz->parray[0]+1) = 0.0;						
+			if(dz->brksize[GRID_SPLEN] > 0) {					/* And a splice-start zero */
+				read_value_from_brktable(*(dz->parray[0]+4),GRID_SPLEN,dz);
+			}
+			half_gridsplen = dz->param[GRID_SPLEN]/2.0;
+			*(dz->parray[0]+2) = *(dz->parray[0]+4) - half_gridsplen;
+			*(dz->parray[0]+3) = 0.0;
+			*(dz->parray[0]+4) += half_gridsplen;
+			dz->parray[1] += 4;								/* mark end of parray */
+			break;
+		default:											/* move grid by grid-width, except zerotime point */
+			for(d = dz->parray[1]-2; d >= dz->parray[0]+2;d -= 2)
+				*d += dz->param[GRID_WIDTH];
+			break;
+		}
+	} else {
+		switch(n) {
+		case(0):
+			starttime = 0.0;
+			firstpass = 1;
+			if((dz->parray[0] = (double *)malloc(arraysize * sizeof(double)))==NULL) {
+				sprintf(errstr,"Insufficient memory for grid envelope,\n");
+				return(MEMORY_ERROR);
+			}
+			d = dz->parray[0];
+			if((exit_status = fill_grid_array(starttime,&firstpass,next_gridstart,&d,&arraysize,dz))<0)
+				return(exit_status);
+			arraysize += 64;	/* safety */
+			if((dz->parray[0] = (double *)realloc((char *)dz->parray[0],arraysize * sizeof(double)))==NULL) {
+				sprintf(errstr,"Insufficient memory for grid envelope,\n");
+				return(MEMORY_ERROR);
+			}
+			break;
+		default:											/* move grid by grid-width, except zerotime point */
+			arraysize = 12;
+			starttime = *next_gridstart;
+			firstpass = 1;
+			d = dz->parray[0] + 4;
+			if((exit_status = fill_grid_array(starttime,&firstpass,next_gridstart,&d,&arraysize,dz))<0)
+				return(exit_status);
+			*(dz->parray[0])   = 0.0;						/* Insert a zero time zero val */			
+			*(dz->parray[0]+1) = 0.0;						
+			if(dz->brksize[GRID_SPLEN] > 0)					/* And a splice-start zero */
+				read_value_from_brktable(*(dz->parray[0]+4),GRID_SPLEN,dz);
+			half_gridsplen = dz->param[GRID_SPLEN]/2.0;
+			*(dz->parray[0]+2) = *(dz->parray[0]+4) - half_gridsplen;
+			*(dz->parray[0]+3) = 0.0;
+			*(dz->parray[0]+4) += half_gridsplen;
+			break;
+		}
+	}
+	return(FINISHED);
+}
+
+/************************************ FILL_GRID_ARRAY ********************************/
+
+int fill_grid_array(double starttime,int *firstpass, double *next_gridstart, double **d, int *arraysize, dataptr dz)
+{
+	double grid_step = 0.0, time, thistime, start_gridwidth, this_gridwidth, half_gridsplen = 0.0;
+	int z;
+	int old_arraysize, k;
+	for(time = starttime; time <=dz->duration; time += grid_step) {
+		grid_step = 0.0;
+		thistime = time;
+		read_value_from_brktable(thistime,GRID_WIDTH,dz);
+		start_gridwidth = dz->param[GRID_WIDTH];
+		if(*firstpass)							/* save initial distance to next grid set */
+			*next_gridstart += start_gridwidth;
+		this_gridwidth = start_gridwidth;
+		grid_step += this_gridwidth;
+		thistime += this_gridwidth;
+		for(z=1;z<dz->iparam[GRID_COUNT];z++) {				  /*sum steps of all grids to get step from */
+			read_value_from_brktable(thistime,GRID_WIDTH,dz); /* current window of this grid, to next window of this grid */
+			this_gridwidth = dz->param[GRID_WIDTH];
+			grid_step += this_gridwidth;
+			thistime += this_gridwidth;
+		}
+		thistime = time;	
+		if(*firstpass)
+			half_gridsplen = 0.0;	/* Envelope starts without splice ... splice added in calling routine */
+		else if(dz->brksize[GRID_SPLEN] > 0) {
+			read_value_from_brktable(thistime,GRID_SPLEN,dz);
+			half_gridsplen = dz->param[GRID_SPLEN]/2.0;
+		}
+		**d = thistime + half_gridsplen;
+		(*d)++;
+		**d = 1.0;
+		(*d)++;
+		thistime += start_gridwidth;
+		if(dz->brksize[GRID_SPLEN] > 0) {
+			read_value_from_brktable(thistime,GRID_SPLEN,dz);
+			half_gridsplen = dz->param[GRID_SPLEN]/2.0;
+		} else if(*firstpass)
+			half_gridsplen = dz->param[GRID_SPLEN]/2.0;	/* if no brkpnt table, only need to calc on first pass */
+		*firstpass = 0;
+		**d = thistime - half_gridsplen;
+		(*d)++;
+		**d = 1.0;
+		(*d)++;
+		**d = thistime + half_gridsplen;
+		(*d)++;
+		**d = 0.0;
+		(*d)++;
+		thistime = time + grid_step;
+		if(dz->brksize[GRID_SPLEN] > 0) {
+			read_value_from_brktable(thistime,GRID_SPLEN,dz);
+			half_gridsplen = dz->param[GRID_SPLEN]/2.0;
+		}
+		**d = thistime - half_gridsplen;
+		(*d)++;
+		**d = 0.0;
+		(*d)++;
+		old_arraysize = *arraysize;
+		*arraysize += 8;
+		k = *d - dz->parray[0];
+		if((dz->parray[0] = (double *)realloc((char *)dz->parray[0],(*arraysize) * sizeof(double)))==NULL) {
+			sprintf(errstr,"Insufficient memory for grid envelope,\n");
+			return(MEMORY_ERROR);
+		}
+		*d = dz->parray[0] + k;
+		dz->parray[1] = *d;	/* mark end of parray */
+	}
+ 	return(FINISHED);
+}
+
+/************************************ DO_GRID_ENVELOPE ********************************/
+
+int do_grid_envelope(dataptr dz)
+{
+	double *ds = dz->parray[0];
+	int sib, eib; /* startpos-ion-buf, edipos-in-buf */
+	int style, exit_status, finished= 0;
+	int startsamp, endsamp, splicepos = 0,last_total_samps_read = 0;
+	sndseekEx(dz->ifd[0],0,0);
+	get_nextposition_pair(ds,&startsamp,&endsamp,&style,dz);
+	sib = startsamp - last_total_samps_read;
+	eib = endsamp   - last_total_samps_read;
+	if((exit_status = read_samps(dz->sampbuf[0],dz)) < 0)
+		return(exit_status);
+	if(dz->ssampsread == 0) {
+		sprintf(errstr,"No data found in input soundfile\n");
+		return(GOAL_FAILED);
+	}
+	while(ds < dz->parray[1] - 2) {
+		do {
+			while(eib < dz->ssampsread) {
+				do_grid_biz(sib,eib,style,&splicepos,dz);
+				if((ds += 2) >= dz->parray[1] - 2) {
+					finished = 1;
+					break;
+				}
+				get_nextposition_pair(ds,&startsamp,&endsamp,&style,dz);
+				sib = startsamp - last_total_samps_read;
+				eib = endsamp   - last_total_samps_read;
+			}
+			if(finished)
+				break;
+			do_grid_biz(sib,dz->ssampsread,style,&splicepos,dz);
+			if(dz->ssampsread > 0) {
+				if((exit_status = write_samps(dz->sampbuf[0],dz->ssampsread,dz))<0)
+					return(exit_status);
+			}
+			last_total_samps_read = dz->total_samps_read;
+			if((exit_status = read_samps(dz->sampbuf[0],dz)) < 0)
+				return(exit_status);
+			if(dz->ssampsread == 0) {
+				finished = 1;
+				break;
+			}
+			sib = 0;
+			eib = endsamp - last_total_samps_read;
+			if(eib == 0) {
+				if((ds += 2) >= dz->parray[1] - 2) {
+					finished = 1;
+					break;
+				}
+				get_nextposition_pair(ds,&startsamp,&endsamp,&style,dz);
+				sib = startsamp - last_total_samps_read;
+				eib = endsamp   - last_total_samps_read;
+			}
+		} while(!finished);
+		if(finished)
+			break;
+	}
+	if(dz->ssampsread > 0) {
+		if((exit_status = write_samps(dz->sampbuf[0],dz->ssampsread,dz))<0)
+			return(exit_status);
+	}
+	return(FINISHED);
+}
+
+/************************************ DO_GRID_BIZ ********************************/
+
+int do_grid_biz(int sib,int eib,int style,int *splicepos,dataptr dz)
+{
+	double splice_incr, splice_val;
+	int n;
+	switch(style) {
+	case(GRID_ZERO):	memset((char *)(dz->sampbuf[0] + sib),0,(eib - sib) * sizeof(float));	break;
+	case(GRID_COPY):	break;
+	case(GRID_UP):
+		dz->iparam[GRID_SPLEN] = (int)round(dz->param[GRID_SPLEN] * dz->infile->srate) * dz->infile->channels;
+		splice_incr = 1.0 / (double)dz->iparam[GRID_SPLEN];
+		splice_val = *splicepos * splice_incr;
+		for(n = sib; n < eib; n++) {
+			dz->sampbuf[0][n] = (float)(dz->sampbuf[0][n] * splice_val);
+			splice_val += splice_incr;
+			(*splicepos)++;
+		}
+		if(*splicepos >= dz->iparam[GRID_SPLEN])
+			*splicepos = 0;
+		break;
+	case(GRID_DOWN):
+		dz->iparam[GRID_SPLEN] = (int)round(dz->param[GRID_SPLEN] * dz->infile->srate) * dz->infile->channels;
+		splice_incr = 1.0 / (double)dz->iparam[GRID_SPLEN];
+		splice_val = 1.0 - (*splicepos * splice_incr);
+		for(n = sib; n < eib; n++) {
+			dz->sampbuf[0][n] = (float)(dz->sampbuf[0][n] * splice_val);
+			splice_val -= splice_incr;
+			(*splicepos)++;
+		}
+		if(*splicepos >= dz->iparam[GRID_SPLEN])
+			*splicepos = 0;
+		break;
+	}
+	return(FINISHED);
+}
+
+/************************************ GET_NEXTPOSITION_PAIR ********************************/
+
+void get_nextposition_pair(double *ds,int *startsamp,int *endsamp,int *style,dataptr dz)
+{
+	double *de = ds+2, startval, endval;
+	*startsamp = round(*ds * dz->infile->srate) * dz->infile->channels;
+	*endsamp   = round(*de * dz->infile->srate) * dz->infile->channels;
+	startval = *(ds+1);		
+	endval   = *(de+1);
+	if(flteq(startval,1.0)) {
+		if(flteq(endval,1.0))
+			*style = GRID_COPY;
+		else
+			*style = GRID_DOWN;
+	} else {
+		if(flteq(endval,1.0))
+			*style = GRID_UP;
+		else
+			*style = GRID_ZERO;
+	}
+}

+ 1693 - 0
dev/env/envfuncs.c

@@ -0,0 +1,1693 @@
+/*
+ * 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 <float.h>
+#include <string.h>
+#include <structures.h>
+#include <tkglobals.h>
+#include <globcon.h>
+#include <processno.h>
+#include <modeno.h>
+#include <arrays.h>
+#include <envel.h>
+#include <cdpmain.h>
+
+#include <sfsys.h>
+
+
+#define MARGIN 	(16)
+
+#define IS_CLICK   (1.0/(3.0 * MS_TO_SECS)) /* from zero to full amplitude in 3ms */
+                                   		 /* anything faster is a 'click'!!   */
+
+#define MINSPAN (16)					 /* spanning points for creating exponential env */
+#define	ATTEN	(3.33333333)			 /* Attenuation for creating exponential env */
+#define	ATTENATOR	(1.7)			 	 /* Attenuation for creating exponential env */
+#define	STEEP_ATTEN	(2.0)			 	 /* For ATTACK */
+
+static int   realloc_envcreate_tables(int tabsize,dataptr dz);
+static int   envnorm(float *env,float *envend);
+static int   envceiling(float *env,float *envend);
+static int   envduck(float *env,float *envend,dataptr dz);
+static int   envrevers(float *env,float *envend);
+static int   envexagg(float *env,float *envend,dataptr dz);
+static int   envatten(float *env,float *envend,dataptr dz);	
+static int   envlift(float *env,float *envend,dataptr dz);	
+static int   envtstretch(float **env,float **envend,dataptr dz);
+static int   envflatn(float *env,float *envend,dataptr dz);	
+static int   envgate(float *env,float *envend,dataptr dz);	
+static int   envinvert(float *env,float *envend,dataptr dz);
+static int   envexpand(float *env,float *envend,dataptr dz);
+static int   envlimit(float *env,float *envend,dataptr dz);	
+static int   envkorrug(float *env,float *envend,dataptr dz);
+static int   envpeakcnt(float *env,float *envend,dataptr dz);
+static int   envtrig(float **env,float **envend,dataptr dz);	
+static int	 envshortn(float **env,float **envend,double timestretch);
+static int 	 envlenthn(float **env,float **envend,double timestretch);
+static float envintpl(double here,double winbase,double base,double next);
+static void  brkdeglitch(double *,double **);
+static int   gen_trigger_envelope(double **brk, double **brkend,dataptr dz);
+static int   gen_reapplied_trigger_envelope(double **brk, double **brkend,dataptr dz);
+static int   gatefilt(float *p,float *envend,double gate,int smoothing);
+static int   do_simple_gating(float *env,float *envend,dataptr dz);
+static int   do_smoothed_gating(float *env,float *envend,int smoothing,dataptr dz);
+static void  do_env_invert(float *p,double upratio,double dnratio,dataptr dz);
+static void  do_expanding(float *p,float *envend,int *gating,double squeeze,int smoothing,dataptr dz);
+static void  digout_trough(float *env,float *envend,float *shadowenv,int del,float *q);
+static int   ispeak(float *env,float *envend,float *q,int width);
+static int   istrough(float *env,float *envend,float *q,int width);
+static int   enlarge_brktable(double **brk,double **brkend, double **q,int *arraysize);
+static void  convert_to_on_triggers(double now,double timestep,double rise,int *triggered,double **q);
+static int   round_off_brktable(double *q,double **brk,double **brkend,double envlen);
+static int   locate_and_size_triggers(float *env,float *envend,double **brk,double **brkend,dataptr dz);
+static int   convert_other_brktable_to_envtable(double *brk,double *brkend,float **env,float **envend,dataptr dz);
+static float read_a_val_from_brktable(double *brk,double *brkend,double thistime);
+
+/*************************** ENVELOPE_WARP ************************/
+ 
+int envelope_warp(float **env,float **envend,dataptr dz)
+{
+	int exit_status;
+	if(flteq((double)dz->outfile->window_size,0.0)) {
+		sprintf(errstr,"dz->outfile->wsize not set: envelope_warp()\n");
+		return(PROGRAM_ERROR);
+	}
+	if(dz->process!=ENV_WARPING && dz->process!=ENV_REPLOTTING && dz->process!=ENV_RESHAPING) {
+		sprintf(errstr,"this function not valid with this process: envelope_warp()\n");
+		return(PROGRAM_ERROR);
+	}
+	switch(dz->mode) {
+	case(ENV_NORMALISE): 	exit_status = envnorm(*env,*envend);		break;
+	case(ENV_REVERSE):   	exit_status = envrevers(*env,*envend);		break;
+	case(ENV_EXAGGERATING):	exit_status = envexagg(*env,*envend,dz);	break;
+	case(ENV_ATTENUATING): 	exit_status = envatten(*env,*envend,dz);	break;
+	case(ENV_LIFTING):	   	exit_status = envlift(*env,*envend,dz);		break;
+	case(ENV_TSTRETCHING): 	exit_status = envtstretch(env,envend,dz);	break;
+	case(ENV_FLATTENING):  	exit_status = envflatn(*env,*envend,dz);	break;
+	case(ENV_GATING):	   	exit_status = envgate(*env,*envend,dz);		break;
+	case(ENV_INVERTING):   	exit_status = envinvert(*env,*envend,dz);	break;
+	case(ENV_EXPANDING):   	exit_status = envexpand(*env,*envend,dz);	break;
+	case(ENV_LIMITING):	  	exit_status = envlimit(*env,*envend,dz);	break;
+	case(ENV_CORRUGATING): 	exit_status = envkorrug(*env,*envend,dz);	break;
+	case(ENV_TRIGGERING):  	exit_status = envtrig(env,envend,dz);		break;
+	case(ENV_CEILING):  	exit_status = envceiling(*env,*envend);		break;
+	case(ENV_DUCKED):  		exit_status = envduck(*env,*envend,dz);		break;
+	case(ENV_PEAKCNT):  	exit_status = envpeakcnt(*env,*envend,dz);	break;
+	default:
+		sprintf(errstr,"Unknown case in	envelope_warp()\n");
+		return(PROGRAM_ERROR);
+	}
+	return(exit_status);
+}
+
+/*************************** ENVNORM ************************/
+ 
+int envnorm(float *env,float *envend)
+{											  
+	float *p = env;
+	double convertor, maxval = 0.0;
+	while(p < envend) {
+		maxval = max(*p,maxval);
+		p++;
+	}
+	if(flteq(maxval,0.0)) {
+		sprintf(errstr,"Envelope level is effectively zero: cannot normalise.\n");
+		return(DATA_ERROR);
+	}
+	p = env;
+	convertor = 1.0/maxval;
+	while(p < envend) {
+		*p = (float)((*p) * convertor);
+		*p = (float)min(*p,1.0);	/* SAFETY */
+		p++;
+	}
+	return(FINISHED);
+}
+
+/*************************** ENVCEILING ************************/
+ 
+int envceiling(float *env,float *envend)
+{											  
+	float *p = env;
+	double maxval = 0.0;
+	while(p < envend) {
+		maxval = max(*p,maxval);
+		p++;
+	}
+	p = env;
+	while(p < envend) {
+		*p = (float)maxval;
+		p++;
+	}
+	return(FINISHED);
+}
+
+/*************************** ENVDUCK ************************/
+ 
+int envduck(float *env,float *envend,dataptr dz)
+{											  
+	int exit_status;
+	float *p = env;
+	double thistime = 0.0;
+	double timestep = dz->outfile->window_size * MS_TO_SECS;
+	switch(dz->process) {
+	case(ENV_WARPING):
+		while(p < envend) {
+			if((exit_status = read_values_from_all_existing_brktables(thistime,dz))<0)
+				return(exit_status);
+			if(*p > dz->param[ENV_THRESHOLD])
+				*p = (float)dz->param[ENV_GATE];
+			thistime += timestep;
+			p++;
+		}
+		break;
+	case(ENV_RESHAPING):
+	case(ENV_REPLOTTING):
+		while(p < envend) {
+			if((exit_status = read_values_from_all_existing_brktables(thistime,dz))<0)
+				return(exit_status);
+			if(*p > dz->param[ENV_THRESHOLD])
+				*p = (float)dz->param[ENV_GATE];
+			else
+				*p = 1.0f; 	
+			thistime += timestep;
+			p++;
+		}
+		break;
+	default:
+		sprintf(errstr,"Unknown case in envduck()\n");
+		return(PROGRAM_ERROR);
+	}
+	return(FINISHED);
+}
+
+/*************************** ENVREVERS ************************/
+ 
+int envrevers(float *env,float *envend)
+{											  
+	float *p = env, *q = envend - 1;
+	float temp;
+	while(q > p) {
+		temp = *p;
+		*p   = *q;
+		*q   = temp;
+		p++;
+		q--;
+	}
+	return(FINISHED);
+}
+
+/*************************** ENVEXAGG ************************/
+
+int envexagg(float *env,float *envend,dataptr dz)
+{											  
+	int exit_status;
+	float  *p = env;
+	double thistime = 0.0;
+	double timestep = dz->outfile->window_size * MS_TO_SECS;
+	if(dz->brk[ENV_EXAG]) {
+		while(p<envend) {
+			if((exit_status = read_value_from_brktable(thistime,ENV_EXAG,dz))<0)
+				return(exit_status);
+			*p = (float)pow((double)*p,dz->param[ENV_EXAG]);
+			p++;
+			thistime += timestep;
+		}
+	} else {
+		while(p<envend) {
+			*p = (float)pow((double)*p,dz->param[ENV_EXAG]);
+			p++;
+		}
+	}
+	return(FINISHED);
+}
+
+/*************************** ENVATTEN *************************/
+
+int envatten(float *env,float *envend,dataptr dz)
+{											  
+	int exit_status;
+	float  *p = env;
+	double thistime = 0.0;
+	double timestep = dz->outfile->window_size * MS_TO_SECS;
+	if(dz->brk[ENV_ATTEN]) {
+		while(p<envend) {
+			if((exit_status = read_value_from_brktable(thistime,ENV_ATTEN,dz))<0)
+				return(exit_status);
+			*p = (float)(*p * dz->param[ENV_ATTEN]);
+			p++;
+			thistime += timestep;
+		}
+	} else {
+		while(p<envend) {
+			*p = (float)(*p * dz->param[ENV_ATTEN]);
+			p++;
+		}
+	}
+	return(FINISHED);
+}
+
+/*************************** ENVLIFT ************************/
+
+int envlift(float *env,float *envend,dataptr dz)
+{											  
+	int exit_status;
+	float *p = env;
+	int saturated = 0;
+	double thistime = 0.0;
+	double timestep = dz->outfile->window_size * MS_TO_SECS;
+	if(dz->brk[ENV_ATTEN]) {
+		while(p<envend) {
+			if((exit_status = read_value_from_brktable(thistime,ENV_LIFT,dz))<0)
+				return(exit_status);
+			if((*p = (float)(*p + dz->param[ENV_LIFT]))> 1.0) {
+				*p = 1.0f;
+				saturated++;
+			}
+			p++;
+			thistime += timestep;
+		}
+	} else {
+		while(p<envend) {
+			if((*p = (float)(*p + dz->param[ENV_LIFT]))> 1.0) {
+				*p = 1.0f;
+				saturated++;
+			}
+			p++;
+		}
+	}
+	if(saturated) {
+		fprintf(stdout,"WARNING: Envelope was clipped, but will not distort sounds.\n");
+		fflush(stdout);
+	}
+	return(FINISHED);
+}
+
+/**************************** ENVTSTRETCH **************************/
+
+int envtstretch(float **env,float **envend,dataptr dz)
+{
+	int exit_status;
+	double timestretch = dz->param[ENV_TSTRETCH];
+	if(dz->brksize[ENV_TSTRETCH]) {
+		sprintf(errstr,"Invalid use of brktable: envtstretch()\n");
+		return(PROGRAM_ERROR);
+	}
+	if(timestretch>1.0) {
+		if((exit_status = envlenthn(env,envend,timestretch))<0)
+			return(exit_status);
+	}
+	if(timestretch<1.0) {
+		if((exit_status = envshortn(env,envend,timestretch))<0)
+			return(exit_status);
+	}
+	return(FINISHED);
+}
+
+/**************************** ENVSHORTN **************************/
+
+int envshortn(float **env,float **envend,double timestretch)
+{
+	int   oldenvlen, newenvlen;
+	int    n, m = 0;
+	float *nuenv, *p;
+	double here, skip, base, winbase, next;
+	skip   = 1.0/timestretch;
+	oldenvlen = *envend - *env; 
+
+	newenvlen = (int)(((double)oldenvlen * timestretch) + 1.0);  /* rescale & round up */
+	newenvlen += MARGIN;
+	if((nuenv = (float *)malloc(newenvlen*sizeof(float)))==NULL) {
+		sprintf(errstr,"INSUFFICIENT MEMORY to create new envelope array.\n");
+		return(MEMORY_ERROR);
+	}
+	p = nuenv;
+	*p++ = **env;
+	for(;;) {
+		if(++m > newenvlen) {
+			sprintf(errstr,"New envelope array bound exceeded in envshortn()\n");
+			return(PROGRAM_ERROR);
+		}
+		here = skip * (double)(m);
+		if(here>=(double)(oldenvlen-1)) {
+			*p = *(p-1);					   
+			newenvlen = p - nuenv;
+			free(*env);
+			if((*env = (float *)realloc(nuenv,newenvlen*sizeof(float)))==NULL) {
+				sprintf(errstr,"envshortn(): 2\n");
+				return(MEMORY_ERROR);
+			}
+			*envend = *env + newenvlen;
+			break;
+		}
+		winbase = floor(here);
+		n		= round(winbase);
+		base  = (double)*((*env) + n);
+		if(n > oldenvlen-1)
+			next = base;
+		else
+			next = (double)*((*env) + n + 1);
+		*p++ = envintpl(here,winbase,base,next);
+	}
+	return(FINISHED);
+}
+
+
+/**************************** ENVLENTHN ***************************/
+
+int envlenthn(float **env,float **envend,double timestretch)
+{
+	int   oldenvlen, newenvlen;
+	int    n = 0, m = 0;
+	double here = 0.0, skip;
+	float  *nuenv, *p;
+	double base, winbase, next;
+	skip   = 1.0/timestretch;
+	oldenvlen = *envend - *env;
+	newenvlen = (int)(((double)oldenvlen * timestretch) + 1.0);
+	newenvlen += MARGIN;
+	if((nuenv = (float *)malloc(newenvlen * sizeof(float)))==NULL) {
+		sprintf(errstr,"INSUFFICIENT MEMORY to create new envelope array.\n");
+		return(MEMORY_ERROR);
+	}
+	p = nuenv;
+	next = (double)**env;
+	for(;;) {
+		base = next;
+		winbase = (double)n;
+		if(++n > oldenvlen-1) {
+			if(!m) {
+				sprintf(errstr,"Anomaly in envlenthn()\n");
+				return(PROGRAM_ERROR);
+			}
+			newenvlen = p - nuenv;
+			free(*env);
+			if((*env = (float *)realloc(nuenv,newenvlen*sizeof(float)))==NULL) {
+				sprintf(errstr,"INSUFFICIENT MEMORY to reallocate new envelope array.\n");
+				return(MEMORY_ERROR);
+			}
+			*envend = *env + newenvlen;
+			break;
+		}
+		next = (double)*((*env) + n);
+		while(here <= (double)n) {
+			*p++ = envintpl(here,winbase,base,next);
+			here = skip * (double)(++m);
+			if(m >= newenvlen) {
+				sprintf(errstr,"envlenthn(): New array bounds exceeded\n");
+				return(PROGRAM_ERROR);
+			}
+		}
+	}
+	return(FINISHED);
+}
+
+/*************************** ENVINTPL ****************************/
+
+float envintpl(double here,double winbase,double base,double next)
+{
+	double tratio = here - winbase;
+	double valdif = next - base;
+	double val    = base + (tratio * valdif); 
+	return((float)val);
+}
+
+/*************************** ENVFLATN *************************/
+
+int envflatn(float *env, float *envend, dataptr dz)
+{
+	int exit_status;
+	float *p, *q, *z, *nuenv;
+	int envlen = envend - env, ppos, qpos;
+	int backovflow, fowdovflow, thisback, n;
+	double thistime = 0.0;
+	double d, sum;
+	double timestep = dz->outfile->window_size * MS_TO_SECS;
+	int  maxflatn;
+	if(dz->brksize[ENV_FLATN]) {
+		if((exit_status = get_maxvalue_in_brktable(&d,ENV_FLATN,dz))<0)
+			return(exit_status);
+		maxflatn = round(d);
+	} else 
+		maxflatn = dz->iparam[ENV_FLATN];
+	if(maxflatn >= envlen) {
+		sprintf(errstr,"Flattening param too large for infile.\n");
+		return(DATA_ERROR);
+	}
+	if((nuenv=(float *)malloc((envlen + maxflatn)*sizeof(float)))==NULL) {
+		sprintf(errstr,"INSUFFICIENT MEMORY to create new envelope array.\n");
+		return(MEMORY_ERROR);
+	}
+	backovflow  = maxflatn/2;
+	fowdovflow  = maxflatn - backovflow - 1;
+	p = env;
+	q = nuenv;
+	for(n=0;n<backovflow;n++)
+		*q++ = *p;
+	while(p < envend)
+		*q++ = *p++;
+	p--;
+	for(n=0;n<fowdovflow;n++)
+		*q++ = *p;
+	p = env;
+	q = nuenv;
+	if(dz->brksize[ENV_FLATN]) {
+		while(p < envend) {
+			if((exit_status = read_value_from_brktable(thistime,ENV_EXAG,dz))<0)
+				return(exit_status);
+			thisback  = dz->iparam[ENV_FLATN]/2;
+			ppos = p - env;
+			qpos = ppos + backovflow - thisback;
+			z = nuenv + qpos;
+			sum = 0.0;
+			for(n=0;n<dz->iparam[ENV_FLATN];n++)
+				sum += *z++;
+			sum /= (double)dz->iparam[ENV_FLATN];
+			*p++ = (float)sum;
+			thistime += timestep;
+		}
+	} else {
+		while(p < envend) {
+			z  = q++;
+			sum = 0.0;
+			for(n=0;n<dz->iparam[ENV_FLATN];n++)
+				sum += *z++;
+			sum /= (double)dz->iparam[ENV_FLATN];
+			*p++ = (float)sum;
+		}
+	}
+	free(nuenv);
+	return(FINISHED);
+}
+
+/********************************* ENVGATE ****************************/
+
+int envgate(float *env,float *envend,dataptr dz)
+{
+	int exit_status;
+	int smoothing  = dz->iparam[ENV_SMOOTH];
+	if(smoothing==0)
+		exit_status = do_simple_gating(env,envend,dz);
+	else
+		exit_status = do_smoothed_gating(env,envend,smoothing,dz);
+	return(exit_status);
+}
+
+/********************************* DO_SIMPLE_GATING ****************************/
+
+int do_simple_gating(float *env,float *envend,dataptr dz)
+{
+	int exit_status;
+	double thistime = 0.0;
+	float *p = env;
+	double timestep = dz->outfile->window_size * MS_TO_SECS;
+	if(dz->brksize[ENV_GATE]) {
+		while(p<envend) {
+			if((exit_status = read_value_from_brktable(thistime,ENV_GATE,dz))<0)
+				return(exit_status);
+			if(*p < dz->param[ENV_GATE])
+				*p = 0.0f;
+			p++;
+			thistime += timestep;
+		}
+	} else {
+		while(p<envend) {
+			if(*p < dz->param[ENV_GATE])
+				*p = 0.0f;
+			p++;
+		}
+	}
+	return(FINISHED);
+}
+
+/********************************* DO_SMOOTHED_GATING ****************************/
+
+int do_smoothed_gating(float *env,float *envend,int smoothing,dataptr dz)
+{
+	int exit_status;
+	double thistime = 0.0;
+	int    gating = TRUE;
+	float  *p = env;
+	double timestep = dz->outfile->window_size * MS_TO_SECS;
+	if(dz->brksize[ENV_GATE]) {
+		while(p<envend) {
+			if((exit_status = read_value_from_brktable(thistime,ENV_GATE,dz))<0)
+				return(exit_status);
+			if((*p >= dz->param[ENV_GATE])                                          /* 1 */
+			&& (!gating || (gating && !gatefilt(p,envend,dz->param[ENV_GATE],smoothing)))) {
+				gating = FALSE;
+			} else {
+				*p = 0.0f;                                           /* 2 */
+				gating = TRUE;
+			}
+			p++;
+			thistime += timestep;
+		}
+	} else {
+		while(p<envend) {
+			if((*p >= dz->param[ENV_GATE])                                          /* 1 */
+			&& (!gating || (gating && !gatefilt(p,envend,dz->param[ENV_GATE],smoothing)))) {
+				gating = FALSE;
+			} else {
+				*p = 0.0f;                                           /* 2 */
+				gating = TRUE;
+			}
+			p++;
+		}
+	}
+	return(FINISHED);
+}
+
+/****************************** GATEFILT *************************/
+ 
+int gatefilt(float *p,float *envend,double gate,int smoothing)
+{
+	int this_smoothfactor, windows_remain;
+	int n;
+	double average = 0.0;
+	float  *q;
+
+	if((windows_remain = envend - p) >= smoothing)
+		this_smoothfactor = smoothing;
+	else
+		this_smoothfactor = windows_remain;
+	q = p;
+	for(n=0;n<this_smoothfactor;n++)
+		average += *q++;
+	average /= (double)this_smoothfactor;
+	if(average<=gate)
+		return(TRUE);
+	return(FALSE);
+}
+
+/*************************** ENVINVERT *************************/
+
+int envinvert(float *env,float *envend,dataptr dz)
+{
+#define NO_BRK		(0)
+#define G_BRK		(1)
+#define M_BRK		(2)
+#define G_AND_M_BRK	(3)
+
+	int exit_status;
+	float  *p;
+	double hirange = 0.0, lorange = 0.0, upratio = 0.0, dnratio = 0.0;
+	double thistime = 0.0;
+	int    thistype;
+	double timestep = dz->outfile->window_size * MS_TO_SECS;
+	if(dz->brksize[ENV_GATE]) {
+		if(dz->brksize[ENV_MIRROR])
+			thistype = G_AND_M_BRK;
+		else {
+			thistype = G_BRK;
+			hirange =  1.0 - dz->param[ENV_MIRROR];	
+		}
+	} else {
+		if(dz->brksize[ENV_MIRROR])
+			thistype = M_BRK;
+		else {
+			thistype = NO_BRK;
+			hirange = 1.0 - dz->param[ENV_MIRROR];	
+			lorange = dz->param[ENV_MIRROR] - dz->param[ENV_GATE];
+			upratio = hirange/lorange;
+			dnratio = lorange/hirange;
+		}
+	}
+	p = env;
+	if(thistype == NO_BRK) {
+	 	while(p<envend) {
+			do_env_invert(p,upratio,dnratio,dz);
+			p++;
+		}
+	} else {
+		while(p<envend) {
+			switch(thistype) {
+			case(G_BRK):	
+				if((exit_status = read_value_from_brktable(thistime,ENV_GATE,dz))<0)
+					return(exit_status);
+				lorange = dz->param[ENV_MIRROR] - dz->param[ENV_GATE];
+				break;
+			case(M_BRK):	
+				if((exit_status = read_value_from_brktable(thistime,ENV_MIRROR,dz))<0)
+					return(exit_status);
+ 				hirange = 1.0 - dz->param[ENV_MIRROR];	
+				lorange = dz->param[ENV_MIRROR] - dz->param[ENV_GATE];
+				break;
+			case(G_AND_M_BRK):	
+				if((exit_status = read_value_from_brktable(thistime,ENV_GATE,dz))<0)
+					return(exit_status);
+				if((exit_status = read_value_from_brktable(thistime,ENV_MIRROR,dz))<0)
+					return(exit_status);
+ 				hirange = 1.0 - dz->param[ENV_MIRROR];	
+				lorange = dz->param[ENV_MIRROR] - dz->param[ENV_GATE];
+				break;
+			}
+			upratio = hirange/lorange;
+			dnratio = lorange/hirange;
+			do_env_invert(p,upratio,dnratio,dz);
+			thistime += timestep;
+			p++;
+		}
+	}
+	return(FINISHED);
+}
+
+/*************************** DO_ENV_INVERT *************************/
+
+void do_env_invert(float *p,double upratio,double dnratio,dataptr dz)
+{
+	if(*p<dz->param[ENV_GATE]) {
+		*p = 0.0f;
+	} else {
+		if(*p<=dz->param[ENV_THRESHOLD])
+			*p = (float)(((dz->param[ENV_THRESHOLD] - *p) * upratio) + dz->param[ENV_THRESHOLD]);
+		else
+			*p = (float)(dz->param[ENV_THRESHOLD] - ((*p - dz->param[ENV_THRESHOLD]) * dnratio)); 
+	}
+}
+
+/**************************** ENVFEXPAND ******************************/
+
+int envexpand(float *env,float *envend,dataptr dz)
+{
+#define NO_BRK		(0)
+#define G_BRK		(1)
+#define T_BRK		(2)
+#define G_AND_T_BRK	(3)
+
+	int exit_status;
+	float  *p;
+	double toprange = 0.0, newrange = 0.0, squeeze = 0.0;
+	double thistime = 0.0;
+	int    gating = TRUE;
+	int	   smoothing = dz->iparam[ENV_SMOOTH];
+	int    thistype;
+	double timestep = dz->outfile->window_size * MS_TO_SECS;
+	if(dz->brksize[ENV_GATE]) {
+		if(dz->brksize[ENV_THRESHOLD])
+			thistype = G_AND_T_BRK;
+		else {
+			thistype = G_BRK;
+			newrange = 1.0 - dz->param[ENV_THRESHOLD];	
+		}
+	} else {
+		toprange = 1.0 - dz->param[ENV_GATE];
+		if(dz->brksize[ENV_THRESHOLD])
+			thistype = T_BRK;
+		else {
+			thistype = NO_BRK;
+			newrange = 1.0 - dz->param[ENV_THRESHOLD];	
+			squeeze  = newrange/toprange;
+		}
+	}
+	p = env;
+	if(thistype == NO_BRK) {
+		while(p<envend) {
+			do_expanding(p,envend,&gating,squeeze,smoothing,dz);
+			p++;
+		}
+	} else {
+		while(p<envend) {
+			switch(thistype) {
+			case(G_AND_T_BRK):	
+				if((exit_status = read_value_from_brktable(thistime,ENV_GATE,dz))<0)
+					return(exit_status);
+				toprange = 1.0 - dz->param[ENV_GATE];
+				/* fall thro */
+			case(T_BRK):	
+				if((exit_status = read_value_from_brktable(thistime,ENV_THRESHOLD,dz))<0)
+					return(exit_status);
+				newrange = 1.0 - dz->param[ENV_THRESHOLD];	
+				break;
+			case(G_BRK):	
+				if((exit_status = read_value_from_brktable(thistime,ENV_GATE,dz))<0)
+					return(exit_status);
+				toprange = 1.0 - dz->param[ENV_GATE];
+				break;
+			}
+			squeeze  = newrange/toprange;
+			do_expanding(p,envend,&gating,squeeze,smoothing,dz);
+			thistime += timestep;
+			p++;
+		}
+	}
+	return(FINISHED);
+}
+
+/**************************** DO_EXPANDING ****************************/
+
+void do_expanding(float *p,float *envend,int *gating,double squeeze,int smoothing,dataptr dz)
+{
+	if(smoothing) {
+		if((*p > dz->param[ENV_GATE])
+		&& (*gating==FALSE || ((*gating==TRUE) && !gatefilt(p,envend,dz->param[ENV_GATE],smoothing)))) {
+			*p = (float)(1.0 - ((1.0 - *p) * squeeze));
+			*gating = FALSE;
+		} else {
+			*p = 0.0f;
+			*gating = TRUE;
+		}
+	} else {
+		if(*p > dz->param[ENV_GATE])
+			*p = (float)(1.0 - ((1.0 - *p) * squeeze));
+		else
+			*p = 0.0f;
+	}		
+}
+
+/**************************** ENVLIMIT ******************************/
+
+int envlimit(float *env,float *envend,dataptr dz)
+{
+
+#define NO_BRK		(0)
+#define TH_BRK		(1)
+#define L_BRK		(2)
+#define T_AND_L_BRK	(3)
+
+	int exit_status;
+	float  *p;
+	double x, toprange = 0.0, newrange, squeeze = 0.0;
+	double thistime = 0.0;
+	int    thistype;
+	double timestep = dz->outfile->window_size * MS_TO_SECS;
+	if(dz->brksize[ENV_THRESHOLD]) {
+		if(dz->brksize[ENV_LIMIT])
+			thistype = T_AND_L_BRK;
+		else
+			thistype = TH_BRK;
+	} else {
+		toprange = 1.0 - dz->param[ENV_THRESHOLD];
+		if(dz->brksize[ENV_LIMIT])
+			thistype = L_BRK;
+		else {
+			thistype = NO_BRK;
+			newrange = dz->param[ENV_LIMIT] - dz->param[ENV_THRESHOLD];
+			squeeze  = newrange/toprange;
+		}
+	}
+	p = env;
+	if(thistype == NO_BRK) {
+		while(p<envend) {
+			if(*p > dz->param[ENV_THRESHOLD]) {
+				x = (*p - dz->param[ENV_THRESHOLD]) * squeeze;
+				*p = (float)(dz->param[ENV_THRESHOLD] + x);
+			}
+			p++;
+		}
+	} else {
+		while(p<envend) {
+			switch(thistype) {
+			case(L_BRK):	
+				if((exit_status = read_value_from_brktable(thistime,ENV_LIMIT,dz))<0)
+					return(exit_status);
+				newrange = dz->param[ENV_LIMIT] - dz->param[ENV_THRESHOLD];
+				squeeze  = newrange/toprange;
+				break;
+			case(T_AND_L_BRK):	
+				if((exit_status = read_value_from_brktable(thistime,ENV_LIMIT,dz))<0)
+					return(exit_status);
+				/* fall thro */
+			case(TH_BRK):	
+				if((exit_status = read_value_from_brktable(thistime,ENV_THRESHOLD,dz))<0)
+					return(exit_status);
+				toprange = 1.0 - dz->param[ENV_THRESHOLD];
+				newrange = dz->param[ENV_LIMIT] - dz->param[ENV_THRESHOLD];
+				squeeze  = newrange/toprange;
+				break;
+			}
+			if(*p > dz->param[ENV_THRESHOLD]) {
+				x = (*p - dz->param[ENV_THRESHOLD]) * squeeze;
+				*p = (float)(dz->param[ENV_THRESHOLD] + x);
+			}
+			thistime += timestep;
+			p++;
+		}
+	}
+	return(FINISHED);
+}
+
+ /*************************** ENVKORRUG *************************/
+ 
+int envkorrug(float *env,float *envend,dataptr dz)
+{
+	int exit_status;
+ 	int upwards;
+	double thistime = 0.0;
+ 	float *p, *q;
+	double timestep = dz->outfile->window_size * MS_TO_SECS;
+ 	float *shadowenv;
+	size_t bytelen = (envend - env) * sizeof(float);
+	if((shadowenv = (float *)malloc(bytelen))==NULL) {
+		sprintf(errstr,"INSUFFICIENT MEMORY to create shadow envelope array.\n");
+		return(MEMORY_ERROR);
+	}
+	memset((char *)shadowenv,0,(size_t)bytelen);
+ 	p = env+1;
+ 	q = env;    
+ 	if (*p > *q)
+ 		upwards = TRUE;
+ 	else
+ 		upwards = FALSE;
+ 	while(p < envend) {
+		if((exit_status = read_values_from_all_existing_brktables(thistime,dz))<0)
+			return(exit_status);
+ 		if(upwards) {
+ 			if(*p <= *q) {
+ 				if(ispeak(env,envend,q,(int)dz->iparam[ENV_PKSRCHWIDTH]))
+					*(shadowenv + (q - env)) = 1.0f;	
+ 				upwards = FALSE;
+ 			}
+ 		} else {
+ 			if(*p > *q)
+ 				upwards = TRUE;
+ 		}
+		thistime += timestep;
+ 		p++;
+ 		q++;
+ 	}
+
+	thistime = 0.0;
+ 	p = env+1;
+ 	q = env;    
+ 	while(p < envend) {
+		if((exit_status = read_values_from_all_existing_brktables(thistime,dz))<0)
+			return(exit_status);
+ 		if(upwards) {
+ 			if(*p <= *q) {
+ 				upwards = FALSE;
+ 			}
+ 		} else {
+ 			if(*p > *q) {
+ 				if(istrough(env,envend,q,(int)dz->iparam[ENV_PKSRCHWIDTH]))
+ 					digout_trough(env,envend,shadowenv,(int)dz->iparam[ENV_TROFDEL],q);
+ 				upwards = TRUE;
+ 			}
+ 		}
+		thistime += timestep;
+ 		p++;
+ 		q++;
+ 	}
+	if(dz->process==ENV_WARPING) {
+ 		p = env;
+ 		while(p < envend) {
+	 		if(*p>0.0)
+ 				*p = 1.0f;	/* NB: NB: Therefore don't use REPLACE with corrugation, when WARPING !! */
+ 			p++;
+ 		}
+	}
+ 	free(shadowenv);
+ 	return(FINISHED);
+ }
+ 
+/*************************** ISTROUGH **********************************/
+ 
+int istrough(float *env,float *envend,float *q,int width)
+{
+ 	int up, down;
+ 	float *upq, *downq, *r;
+ 	if(width<2)
+ 		return(1);
+ 	down = up = width/2;   
+ 	if(EVEN(width))
+ 		down = up - 1;		/* set search p[arams above and below q */
+ 	downq = q - down;
+ 	upq   = q + up;
+ 	upq   = min(envend-1,upq);	/* allow for ends of envelope table */
+ 	downq = max(env,downq);
+ 	for(r = downq; r<=upq; r++) {
+ 		if(*q > *r)
+ 			return(FALSE);		
+ 	}
+ 	return(TRUE);			/* if r is minimum of all in trough, return 1 */
+ }
+ 
+/*************************** ISPEAK **********************************/
+ 
+int ispeak(float *env,float *envend,float *q,int width)
+{
+ 	int up, down;
+ 	float *upq, *downq, *r;
+ 	if(width<2)
+ 		return(TRUE);
+ 	down = up = width/2;   
+ 	if(EVEN(width))
+ 		down = up - 1;		/* set search params above and below q */
+ 	downq = q - down;
+ 	upq   = q + up;
+ 	upq   = min(envend-1,upq);	/* allow for ends of envelope table */
+ 	downq = max(env,downq);
+ 	for(r = downq; r<=upq; r++) {
+ 		if(*q < *r)
+ 			return(FALSE);		
+ 	}
+ 	return(TRUE);			/* if r is maximum of all in peak, return 1 */
+ }
+ 
+ /***************************** DIGOUT_TROUGH *********************************/
+ 
+void digout_trough(float *env,float *envend,float *shadowenv,int del,float *q)
+{
+ 	float *r, *upq, *downq;
+ 	int	down, up, herepos, lopos, hipos, thispos;
+ 	if(del<2) {
+ 		*q = 0.0f;	/* set single-sector trough to 0.0 */
+ 		return;
+ 	}
+ 	down = up = del/2;   
+ 	if(EVEN(del))
+ 		down = up - 1;				  /* set trof_delete limits above and below q */
+ 	downq = q - down;
+ 	upq   = q + up;
+ 	upq   = min(envend-1,upq); 				  /* allow for ends of envelope table */
+ 	downq = max(env,downq);
+
+	herepos = q-env;
+	lopos   = downq - env;				  /* find relative positions in env-table */
+	hipos   = upq - env;
+								/* search downwards for peaks set in shadow table */
+ 	for(r = shadowenv + herepos; r>= shadowenv + lopos; r--) {
+ 		if(*r>FLTERR) {
+			thispos = (r+1) - shadowenv;
+			downq   = env + thispos;/* & adjust downward delete-limit accordingly */
+ 			break;									   /* to avoid deleting peaks */
+ 		}
+ 	}							  /* search upwards for peaks set in shadow table */
+ 	for(r = shadowenv + herepos; r<=shadowenv + hipos; r++) {
+ 		if(*r>FLTERR) {		
+			thispos = (r-1) - shadowenv;
+			upq   = env + thispos;	/* and adjust upward delete-limit accordingly */
+ 			break;									   /* to avoid deleting peaks */
+ 		}
+ 	}
+ 	for(r = downq; r<=upq; r++)						 /* delete the defined trough */
+		 *r = 0.0f;
+ }
+
+/**************************** ENVTRIG *********************************/
+
+int envtrig(float **env,float **envend,dataptr dz)	/* NOTE THIS USES POINTERS TO env AND envend */
+{
+	int exit_status;
+	double *brk, *brkend;
+	if((exit_status = locate_and_size_triggers(*env,*envend,&brk,&brkend,dz))<0)
+		return(exit_status);
+	switch(dz->process) {
+	case(ENV_REPLOTTING):
+	case(ENV_RESHAPING):
+		exit_status = gen_trigger_envelope(&brk,&brkend,dz);
+		break;
+	case(ENV_WARPING):
+		exit_status = gen_reapplied_trigger_envelope(&brk,&brkend,dz);
+		break;
+	}		
+	if(exit_status < 0)
+		return(exit_status);
+	return convert_other_brktable_to_envtable(brk,brkend,env,envend,dz);
+}
+
+/**************************** LOCATE_AND_SIZE_TRIGGERS *******************************/
+
+int locate_and_size_triggers(float *env,float *envend,double **brk,double **brkend,dataptr dz)
+{
+	int exit_status;
+	float *p = env, *end;
+	double  *q, rise, mean, now;
+	double timestep = dz->outfile->window_size * MS_TO_SECS;
+	double envdur;
+	int   n, scan, arraysize = BIGARRAY;
+	int triggered = FALSE, k;
+	double maxrise, thistime = 0.0;
+	int look_ahead = 4;
+	if((*brk = (double *)malloc(arraysize * sizeof(double)))==NULL) {
+		sprintf(errstr,"INSUFFICIENT MEMORY to create trigger brktable.\n");
+		return(MEMORY_ERROR);
+	}
+	q = *brk;
+	*brkend = *brk + arraysize;
+	if((scan = (int)(dz->param[ENV_TRIGDUR]/timestep))<=0) {
+		sprintf(errstr,"scansize too small for envelope windows.\n");
+		return(GOAL_FAILED);
+	}
+	end = envend - scan - 1;
+	*q++ = 0.0;				
+	*q++ = 0.0;             		/*Store an initial brkpnt value of zero */
+	n = scan;
+	while(p<end) {
+		if((exit_status = read_values_from_all_existing_brktables(thistime,dz))<0)
+			return(exit_status);
+		maxrise = -DBL_MAX;
+		for(k=1;k<=scan;k++) {
+			rise = *(p+k) - *p;  	/* deduce max and min rise[fall] of envelope across scantime */
+			maxrise = max(rise,maxrise);
+		}
+		rise = maxrise;
+		mean = *p + (rise/2.0);		/* calc mean level of rising portion */
+		if(mean>dz->param[ENV_GATE] 	  /* deduce mean rate of rise[fall] and compare with triggering rate */
+		&& fabs(rise)>=dz->param[ENV_TRIGRISE]) {/* if triggering criteria met */
+			if(q+look_ahead >= *brkend) {							
+				if((exit_status = enlarge_brktable(brk,brkend,&q,&arraysize))<0)
+					return(exit_status);
+			}
+			now = n * timestep;
+			convert_to_on_triggers(now,timestep,rise,&triggered,&q);
+			p += scan;                               
+			n += scan;
+			thistime += timestep * scan;
+		} else {                                     
+			triggered = FALSE;
+			p++;
+			n++;
+			thistime += timestep;
+		}
+	}
+	envdur = (envend - env) * timestep; /* if end of new brktable not at orig end of envel.. extend */
+	if((exit_status = round_off_brktable(q,brk,brkend,envdur))<0)
+		return(exit_status);
+	return(FINISHED);
+}
+
+/******************************* GEN_TRIGGER_ENVELOPE ******************************/
+
+int gen_trigger_envelope(double **brk, double **brkend,dataptr dz)
+{
+	int exit_status;
+	int 	 n, brklen;
+	double   next_trigtime, this_trigtime, nuhere, last_outval = 0.0, trigval;
+	double   *q, *nubrkptr, *nubrk, *nubrkend;
+	double   *trigptr, *trigbrk, *trigbrkend;
+	int arraysize = BIGARRAY;
+	trigptr = trigbrk = *brk;
+	trigbrkend = *brkend;
+	if((nubrk = (double *)malloc(arraysize * sizeof(double)))==NULL) {
+		sprintf(errstr,"INSUFFICIENT MEMORY to create new envelope array.\n");
+		return(MEMORY_ERROR);
+	}
+	nubrkend = nubrk + arraysize;
+	nubrkptr = nubrk;
+	while(trigptr < trigbrkend) {
+		this_trigtime = *trigptr++;
+		trigval       = *trigptr++;
+		if(trigptr < trigbrkend)
+			next_trigtime = *trigptr;
+		else
+			next_trigtime = DBL_MAX;
+		if(flteq(trigval,0.0)) {		/* if the trigger table value is 0.0 put Zero in new table */
+			*nubrkptr++ = this_trigtime;
+			*nubrkptr++ = 0.0;
+		} else {						/* else */
+			if(trigval < last_outval)	/* If the new trigger value is less than current value held, */
+				trigval = last_outval;	/* set trig val to held value, (else, keep the new value).   */
+			q = dz->rampbrk;			/* start copying values from ramp table into new brkpnt table, */
+			n = 0;						/* until ramptable ends, OR we reach next brkpnt in trigger table */
+			while(n < dz->rampbrksize && (nuhere = this_trigtime + *q++)<next_trigtime) {  
+				*nubrkptr++ = nuhere;
+				last_outval = trigval  * (*q++);	/* Each rampval is scaled by size of current trigger */
+				*nubrkptr++ = last_outval;
+				n++;
+			}
+		}
+		if(nubrkptr>=(nubrkend-2)) {
+			if((exit_status = enlarge_brktable(&nubrk,&nubrkend,&nubrkptr,&arraysize))<0)
+				return(exit_status);
+		}
+	}
+	brkdeglitch(nubrk,&nubrkptr);		/* get rid of too fast amp rises or falls */
+	brklen = nubrkptr - nubrk;
+	free((char *)(*brk));
+	if((*brk=(double *)realloc((char *)nubrk,brklen * sizeof(double)))==NULL) {
+		sprintf(errstr,"INSUFFICIENT MEMORY to reallocate new envelope array.\n");
+		return(MEMORY_ERROR);
+	}
+	if((brklen/2) * 2 != brklen) {
+		sprintf(errstr,"Anomalous breaktable size in gen_trigger_envelope()\n");
+		return(PROGRAM_ERROR);
+	}
+	*brkend = *brk + brklen;
+	return(FINISHED);
+}
+
+/**************************** BRKDEGLITCH ****************************
+ * Check a breakpoint table for sudden glitches, and smooth them.
+ *
+ * (1) If the brktable has very sudden rise or fall, current time-point is moved forward a little.
+ * (2) If, as a result last time-points moved beyond original endtime, readjust to orig duration.
+ */
+
+void brkdeglitch(double *brk,double **brkend)
+{
+	double *p = brk, *here, *next;
+	double rise, risetime, slope, newtime;
+	double thistime, thisval, timeshift, timeratio;
+	double lasttime = *p++;
+	double lastval  = *p++;
+	double endtime  = *((*brkend)-2);
+	double timediff, valdiff, valstep;
+	double click = IS_CLICK;
+//	int cnt = 0;
+	while(p < *brkend) {
+		thistime = *p++;
+		thisval  = *p++;
+		rise =fabs(thisval-lastval);
+		if((slope = rise/(thistime-lasttime))>click) {	/* If the brktable has very sudden rise or fall */
+			risetime = rise/click;
+			here = p-2;
+			next = p;
+			newtime   = lasttime + risetime;			/* current time-point is moved forward a little */
+			timeshift = newtime - thistime;
+			while(next < *brkend) {
+				*here += timeshift;
+				if(*here >= *next) {
+					here += 2;
+					next += 2;								
+				} else
+					break;
+			}
+			if(next >= *brkend)
+				*here += timeshift;
+			thistime = newtime;
+		}
+		lasttime = thistime;
+		lastval  = thisval;
+	}
+	p = *brkend - 2;			  
+	if(flteq((double)*p,endtime)) {
+		*p = endtime;
+		*brkend = p + 2;
+	} else {
+		while(*p > endtime + FLTERR)	  /* if, as as a result of deglitches, endtime of table is moved forward */
+			p -= 2;						  /* Find the last point prior to the true endtime */
+		if(flteq((double)*p,endtime)) {	  /* and establish the correct time .. */
+			*p = endtime;
+			*brkend = p + 2;
+		} else {		   				  /* ... or the correct value, for that true endtime */
+			lasttime = *p;
+			lastval  = *(p+1);
+			thistime = *(p+2);
+			thisval  = *(p+3);
+			timediff = thistime - lasttime;
+			valdiff  = thisval - lastval;
+			timeratio= (endtime - lasttime)/timediff;
+			valstep  = valdiff * timeratio;
+			thisval  = lastval + valstep;
+			p += 2;
+			*p++ = endtime;
+			*p++ = thisval;
+			*brkend = p;
+		}
+	}
+	return;
+}
+    
+/********************************* ENVREPLACE *************************
+ *
+ *  NEEDED FOR all WARP, except KORRUGATION and TRIGGER
+ */
+
+int envreplace(float *env,float **envend,float *origenv,float *origend)
+{
+	float *p, *q;
+	double gate = MIN_FRACTION_OF_LEVEL; 	/* minimum non-zero value of envelope */
+	double maxval = 0.0;
+	p = origenv;
+	q = env;
+	if((origend - origenv) < (*envend - env)) {
+		while(p<origend) {
+			if(*p <= gate) {	/* if original envelope touches zero */
+				if(*q <=gate || q==env)	/* if new envelope touches zero */
+					*q = 0.0f;			/* OR start_of_file, set to zero */
+				else			/* else, retain previous value of envelope */
+					*q = *(q-1);
+			} else
+				*q = (float)((*q)/(*p));
+			maxval = max(*q,maxval);
+			q++;
+			p++;
+		} 
+	} else {
+		while(q<*envend) {
+			if(*p <= gate) {	/* if original envelope touches zero */
+				if(*q <=gate || q==env)	/* if new envelope touches zero */
+					*q = 0.0f;			/* OR start_of_file, set to zero */
+				else			/* else, retain previous value of envelope */
+					*q = *(q-1);
+			} else
+				*q = (float)((*q)/(*p));
+			maxval = max(*q,maxval);
+			q++;
+			p++;
+		}
+	}
+	*envend = q;
+	if(maxval<=gate) {
+		sprintf(errstr,"new envelope is effectively zero.\n");
+		return(GOAL_FAILED);
+	}
+	return(FINISHED);
+}
+
+/****************************** CONVERT_OTHER_BRKTABLE_TO_ENVTABLE *********************************/
+
+int convert_other_brktable_to_envtable(double *brk,double *brkend,float **env,float **envend,dataptr dz)
+{
+	int   n, envlen;
+	float  *q;
+	double here;
+	double timestep = dz->outfile->window_size * MS_TO_SECS;
+//	double inc = timestep;
+	double duration = *(brkend-2);
+	if(timestep <= 0.0) {
+		sprintf(errstr,"No window_size set: convert_other_brktable_to_envtable()\n");
+		return(PROGRAM_ERROR);
+	}
+	if(timestep < ENV_MIN_WSIZE * MS_TO_SECS) {
+		sprintf(errstr,"Invalid window_size: convert_other_brktable_to_envtable()\n");
+		return(PROGRAM_ERROR);
+	}
+	if(duration < timestep) {
+		sprintf(errstr,"Brktable duration less than window_size: Cannot proceed.\n");
+		return(DATA_ERROR);
+	}
+	envlen = (int)((duration/timestep) + 1.0);  /* round up */
+	envlen += MARGIN;                  		/* allow for errors in float-calculation */
+	if(brk==NULL) {
+		sprintf(errstr,"No existing brkpnt table. convert_brktable_to_envtable()\n");
+		return(PROGRAM_ERROR);
+	}
+	if(*env != NULL)
+		free(*env);
+	if((*env = (float *)malloc(envlen * sizeof(float)))==NULL) {
+		sprintf(errstr,"INSUFFICIENT MEMORY to create new envelope array.\n");
+		return(MEMORY_ERROR);
+	}
+	q = *env;
+	n = 0;
+	while(n<envlen) {
+		if((here = (double)n * timestep)>(duration+FLTERR))
+			break;
+		*q = read_a_val_from_brktable(brk,brkend,here);
+		q++;
+		n++;
+	}
+	envlen = n;
+	if((*env = (float *)realloc(*env,envlen * sizeof(float)))==NULL) {
+		sprintf(errstr,"INSUFFICIENT MEMORY to reallocate new envelope array.\n");
+		return(MEMORY_ERROR);
+	}
+	*envend = *env + envlen;
+	return(FINISHED);
+}
+
+/**************************** READ_A_VAL_FROM_BRKTABLE *****************************/
+
+float read_a_val_from_brktable(double *brk,double *brkend,double thistime)
+{
+    float  thisval;
+    double *p = brk, val;
+    double hival, loval, hiind, loind;
+	double firstval = *(brk+1);
+	double lastval  = *(brkend-1);
+	double lasttime = *(brkend-2);
+	if(thistime <= 0.0)
+		thisval = (float)firstval;
+	else if(thistime >= lasttime)
+		thisval = (float)lastval;
+	else { 
+		while(*(p)<thistime)
+			p += 2;
+		hival  = *(p+1);
+		hiind  = *p;
+		loval  = *(p-1);
+		loind  = *(p-2);
+		val    = (thistime - loind)/(hiind - loind);
+		val   *= (hival - loval);
+		val   += loval;
+		thisval  = (float)val;
+	}
+    return(thisval);
+}
+
+/**************************** ENLARGE_BRKTABLE *****************************/
+
+int enlarge_brktable(double **brk,double **brkend, double **q,int *arraysize)
+{
+	int offset = *q - *brk;
+	*arraysize += BIGARRAY;
+	if((*brk = (double *)realloc((*brk),(*arraysize) * sizeof(double)))==NULL) {
+		sprintf(errstr,"INSUFFICIENT MEMORY to enlarge brktable.\n");
+		return(MEMORY_ERROR);
+	}
+	*brkend = *brk + *arraysize;
+	*q = *brk + offset;
+	return(FINISHED);
+}
+
+/**************************** ROUND_OFF_BRKTABLE *****************************/
+
+int round_off_brktable(double *q,double **brk,double **brkend,double envdur)
+{
+	int brksize;
+	int vals_written = q - *brk;
+	double *endadr;
+	double *startadr = *brk;
+	double *nextadr  = *brk + 2;
+	double starttime = *startadr, nexttime = *nextadr;
+	(brksize = vals_written/2);
+	if((brksize = vals_written/2) * 2 != vals_written) {
+		sprintf(errstr,"Data pairing anomaly in round_off_brktable()\n");
+		return(PROGRAM_ERROR);
+	}
+	if(brksize > 1) {
+		if(flteq(nexttime,starttime)) {	/* Junk any redundant initial zero */
+			memmove((char *)startadr,(char *)nextadr,(brksize-1)*2*sizeof(double));
+			brksize--;
+		}
+	}
+	endadr = *brk + (brksize * 2);
+	if(*(endadr - 2) != envdur) {	  	/* IF lasttime != length of envelope */
+		if(flteq(*(endadr - 2),envdur))	/* If approx equal, reset to equal */
+			*(endadr - 2) = envdur;
+		else {							/* Else generate an endtime time-val pair */
+			brksize++;
+			if((*brk=(double *)realloc(*brk,(brksize*2)*sizeof(double)))==NULL) {
+				sprintf(errstr,"INSUFFICIENT MEMORY to reallocate brktable.\n");
+				return(MEMORY_ERROR);
+			}
+			endadr = *brk + (brksize * 2);
+			*(endadr-2) = envdur;		/* true end time gets */
+			*(endadr-1) = 0.0;			/* 0 endvalue		  */
+		}
+	}
+	if((*brk=(double *)realloc(*brk,(brksize*2)*sizeof(double)))==NULL) {
+		sprintf(errstr,"INSUFFICIENT MEMORY to reallocate brktable.\n");
+		return(MEMORY_ERROR);
+	}
+	*brkend = *brk + (brksize * 2);	
+	return(FINISHED);
+}
+
+/**************************** CONVERT_TO_ON_TRIGGERS *****************************/
+
+void convert_to_on_triggers(double now,double timestep,double rise,int *triggered,double **q)
+{
+	double *p = *q;
+	if(*triggered==FALSE) { 				/* If not already RISING-triggered */
+		if(!flteq(*(p-2),now-timestep)) {	/* If previous time-value was not too close to this one */
+			*p++ = now - timestep;			/* Write pre-time and 0.0 for start of rise */
+			*p++ = 0.0;
+		}
+		*p++ = now;	                    	/* Write time and rise-value for end of rise */
+		*p++ = rise;                    
+		*triggered = TRUE; 					/* Flag trigrise */
+	} else {                          		/* If already RISING-triggered  */
+		*(p-4)  = now - timestep;			/* readjust start-time of existing rise, from current time */
+		*(p-2)  = now;						/* readjust end-time of existing rise, from current time */
+		*(p-1) += rise;						/* readjust total rise value */
+	}
+	*q = p;
+}
+
+/******************************* GEN_REAPPLIED_TRIGGER_ENVELOPE ******************************/
+
+int gen_reapplied_trigger_envelope(double **brk, double **brkend,dataptr dz)
+{
+	int exit_status;
+	int 	 n, brklen;
+//	double   next_trigtime, this_trigtime, nuhere, last_outval = 0.0, trigval;
+	double   next_trigtime, this_trigtime, nuhere, trigval;
+	double   *q, *nubrkptr, *nubrk, *nubrkend;
+	double   *trigptr, *trigbrk, *trigbrkend;
+	int arraysize = BIGARRAY;
+	trigptr = trigbrk = *brk;
+	trigbrkend = *brkend;
+	if((nubrk = (double *)malloc(arraysize * sizeof(double)))==NULL) {
+		sprintf(errstr,"INSUFFICIENT MEMORY to create new envelope table.\n");
+		return(MEMORY_ERROR);
+	}
+	nubrkend = nubrk + arraysize;
+	nubrkptr = nubrk;
+	while(trigptr < trigbrkend) {
+		this_trigtime = *trigptr++;
+		trigval       = *trigptr++;
+		if(trigptr < trigbrkend)
+			next_trigtime = *trigptr;
+		else
+			next_trigtime = DBL_MAX;
+		if(flteq(trigval,0.0)) {		/* if the trigger table value is 0.0 put Zero in new table */
+			*nubrkptr++ = this_trigtime;
+			*nubrkptr++ = 0.0;
+		} else {						/* else */
+			q = dz->rampbrk;			/* start copying values from ramp table into new brkpnt table, */
+			n = 0;						/* until ramptable ends, OR we reach next brkpnt in trigger table */
+			while(n < dz->rampbrksize && (nuhere = this_trigtime + *q++)<next_trigtime) {  
+				*nubrkptr++ = nuhere;
+				*nubrkptr++ = *q++;
+				n++;
+			}
+		}
+		if(nubrkptr>=(nubrkend-2)) {
+			if((exit_status = enlarge_brktable(&nubrk,&nubrkend,&nubrkptr,&arraysize))<0)
+				return(exit_status);
+		}
+	}
+	brkdeglitch(nubrk,&nubrkptr);		/* get rid of too fast amp rises or falls */
+	brklen = nubrkptr - nubrk;
+	free((char *)(*brk));
+	if((*brk=(double *)realloc((char *)nubrk,brklen * sizeof(double)))==NULL) {
+		sprintf(errstr,"INSUFFICIENT MEMORY to reallocate new envelope table.\n");
+		return(MEMORY_ERROR);
+	}
+	if((brklen/2) * 2 != brklen) {
+		sprintf(errstr,"Anomalous breaktable size in gen_reapplied_trigger_envelope()\n");
+		return(PROGRAM_ERROR);
+	}
+	*brkend = *brk + brklen;
+	return(FINISHED);
+}
+
+/***************************** REALLOC_ENVCREATE_TABLES ****************************/
+
+int realloc_envcreate_tables(int tabsize,dataptr dz)
+{
+	if((dz->parray[ENV_CREATE_TIME] = 
+	(double *)realloc(dz->parray[ENV_CREATE_TIME],tabsize * sizeof(double)))==NULL
+	|| (dz->parray[ENV_CREATE_LEVL] = 
+	(double *)realloc(dz->parray[ENV_CREATE_LEVL],tabsize * sizeof(double)))==NULL) {
+		sprintf(errstr,"INSUFFICIENT MEMORY to reallocate level array.\n");
+		return(MEMORY_ERROR);
+	}
+	return(FINISHED);
+}
+
+/***************************** CREATE_ENVELOPE ****************************
+ *
+ * (1)	time_quantum has a minimum value, as this function can create a
+ *		brktable for conversion to an envfile.
+ * 1a)	Except in the case of ENV_ATTACK, which has very acute risetime!!
+ */
+
+int create_envelope(int *cnt,dataptr dz)
+{
+	int exit_status;
+	int falling = FALSE;
+	int n,m, k, base, newcnt;
+	double time_quantum, timestep, levelstep, attenator = 0.0;
+	double thisduration, ratio;
+//	double atten = 1.0/ATTEN;
+	if((dz->parray[ENV_CREATE_TIME] =  (double *)malloc(sizeof(double)))==NULL) {
+		sprintf(errstr,"INSUFFICIENT MEMORY to create times array.\n");
+		return(MEMORY_ERROR);
+	}
+	if((dz->parray[ENV_CREATE_LEVL] = (double *)malloc(sizeof(double)))==NULL) {
+		sprintf(errstr,"INSUFFICIENT MEMORY to create levels array.\n");
+		return(MEMORY_ERROR);
+	}
+	dz->parray[ENV_CREATE_TIME][0] = dz->parray[ENV_CREATE_INTIME][0];
+	dz->parray[ENV_CREATE_LEVL][0] = dz->parray[ENV_CREATE_INLEVEL][0];
+	*cnt = 1;
+	for(n=1;n<dz->itemcnt;n++) {
+		thisduration = dz->parray[ENV_CREATE_INTIME][n] - dz->parray[ENV_CREATE_INTIME][n-1];
+//TW UPDATE
+		if(dz->process == ENV_ATTACK || dz->process == ENV_DOVETAILING || dz->process == ENV_CURTAILING)
+			time_quantum = max(thisduration/(double)MINSPAN,2.0/dz->infile->srate);  	/* 1a */
+		else
+			time_quantum = max(thisduration/(double)MINSPAN,ENV_MIN_WSIZE * MS_TO_SECS);  /* 1 */
+		if((levelstep = dz->parray[ENV_CREATE_INLEVEL][n] - dz->parray[ENV_CREATE_INLEVEL][n-1]) <= 0.0)
+				falling = TRUE;
+			else
+				falling = FALSE;
+		switch(dz->iparray[ENV_SLOPETYPE][n]) {
+		case(ENVTYPE_LIN):
+			(*cnt)++;
+			if((exit_status = realloc_envcreate_tables(*cnt,dz))<0)
+				return(exit_status);
+			dz->parray[ENV_CREATE_TIME][*cnt - 1] = dz->parray[ENV_CREATE_INTIME][n];
+			dz->parray[ENV_CREATE_LEVL][*cnt - 1] = dz->parray[ENV_CREATE_INLEVEL][n];
+			break;
+		case(ENVTYPE_STEEP):
+		case(ENVTYPE_EXP):
+		case(ENVTYPE_DBL):
+			switch(dz->iparray[ENV_SLOPETYPE][n]) {
+			case(ENVTYPE_STEEP):	attenator = STEEP_ATTEN;	break;
+			case(ENVTYPE_EXP):		attenator = ATTENATOR;		break;
+			case(ENVTYPE_DBL):		attenator = ATTENATOR * 2;	break;
+			}
+			base = *cnt;
+			newcnt = (int)(thisduration/time_quantum);	/* TRUNCATE */
+			/* RWD 4:2002 NB: div/zero bug here when newcnt resolves to zero */
+			/* should this be flagged as a user error? */
+			if(newcnt==0)
+				newcnt = 1;
+			
+			timestep = thisduration/(double)newcnt;
+			*cnt += newcnt;
+			if((exit_status = realloc_envcreate_tables(*cnt,dz))<0)
+				return(exit_status);
+			for(m = 1,k = base;k < *cnt;k++,m++) {
+				dz->parray[ENV_CREATE_TIME][k] = dz->parray[ENV_CREATE_INTIME][n-1] + (m * timestep);
+				if(falling) {
+					ratio = 1.0 - ((m * timestep)/thisduration);
+					ratio = max(ratio,0.0);
+					ratio = pow(ratio,attenator);
+					dz->parray[ENV_CREATE_LEVL][k] = fabs(levelstep) * ratio;
+					dz->parray[ENV_CREATE_LEVL][k] += dz->parray[ENV_CREATE_INLEVEL][n];
+				}
+				else {
+					ratio = (m * timestep)/thisduration;
+					ratio = pow(ratio,attenator);
+					ratio = min(ratio,1.0);
+					dz->parray[ENV_CREATE_LEVL][k] = fabs(levelstep) * ratio;
+					dz->parray[ENV_CREATE_LEVL][k] += dz->parray[ENV_CREATE_INLEVEL][n-1];
+				}
+			}
+			dz->parray[ENV_CREATE_TIME][*cnt-1] = dz->parray[ENV_CREATE_INTIME][n];
+			break;
+		default:
+			sprintf(errstr,"Unknown case in create_envelope()\n");
+			return(PROGRAM_ERROR);			
+		}
+	}
+	return(FINISHED);
+}
+
+/******************************** ENVELOPE_TREMOL **********************************/
+
+int envelope_tremol(dataptr dz)
+{
+	int exit_status;
+	int m;
+	int n, k, st_sampsread, st_samps_processed;
+	double thistime, losin, hisin, frac, val;
+	double fsinpos = 0.0;
+	int	   sinpos;
+	int    chans = dz->infile->channels;
+	double inverse_srate = 1.0/(double)dz->infile->srate;
+	double tabsize_over_srate = (double)ENV_TREM_TABSIZE/(double)dz->infile->srate;
+	float *buf = dz->sampbuf[0];
+	double *sintab = dz->parray[ENV_SINETAB];
+	while(dz->samps_left > 0) {
+		st_samps_processed = dz->total_samps_read/chans;
+		if((exit_status = read_samps(buf,dz))<0)
+			return(exit_status);
+		st_sampsread = dz->ssampsread/chans; 
+		for(n=0; n < st_sampsread; n++) {
+			k = n * chans;
+			thistime = (double)st_samps_processed * inverse_srate;
+			if((exit_status = read_values_from_all_existing_brktables(thistime,dz))<0)
+				return(exit_status);
+			if(dz->brksize[ENV_TREM_FRQ] && dz->mode==ENV_TREM_LOG)
+				dz->param[ENV_TREM_FRQ] = pow(10,dz->param[ENV_TREM_FRQ]);
+			sinpos	 = (int)fsinpos;	/* TRUNCATE */
+			frac     = fsinpos - (double)sinpos;
+			losin    = sintab[sinpos];
+			hisin    = sintab[sinpos+1];
+			val		 = losin + ((hisin - losin) * frac);	/* interpd (normalised) sintable value */
+			val     *= dz->param[ENV_TREM_DEPTH];			/* adjusted for tremolo depth */
+			val     += (1.0 - dz->param[ENV_TREM_DEPTH]);	/* subtract from max: tremol superimposed on existing level */
+			val     *= dz->param[ENV_TREM_AMP];				/* multiply by overall signal gain (<= 1.0) */
+			fsinpos += (dz->param[ENV_TREM_FRQ] * tabsize_over_srate);	/* advance sintable float-pointer */
+			fsinpos  = fmod(fsinpos,(double)ENV_TREM_TABSIZE);			/* wrap at table-size */
+			for(m=0;m<chans;m++)
+				buf[k+m]   = (float)/*round*/(buf[k+m] * val);
+			st_samps_processed++;
+		}
+		if(dz->ssampsread > 0) {
+			if((exit_status = write_samps(buf,dz->ssampsread,dz))<0)
+				return(exit_status);
+		}
+	}
+	return(FINISHED);
+}
+
+
+/*************************** ENVPEAKCNT *************************/
+ 
+int envpeakcnt(float *env,float *envend,dataptr dz)
+{
+	int exit_status;
+ 	int upwards, peakkcnt = 0;
+	double thistime = 0.0;
+ 	float *p, *q;
+	double timestep = dz->outfile->window_size * MS_TO_SECS;
+ 	float *shadowenv;
+	size_t bytelen = (envend - env) * sizeof(float);
+	if((shadowenv = (float *)malloc(bytelen))==NULL) {
+		sprintf(errstr,"INSUFFICIENT MEMORY to create shadow envelope array.\n");
+		return(MEMORY_ERROR);
+	}
+	memset((char *)shadowenv,0,(size_t)bytelen);
+ 	p = env+1;
+ 	q = env;    
+ 	if (*p > *q)
+ 		upwards = TRUE;
+ 	else
+ 		upwards = FALSE;
+ 	while(p < envend) {
+		if((exit_status = read_values_from_all_existing_brktables(thistime,dz))<0)
+			return(exit_status);
+ 		if(upwards) {
+ 			if(*p <= *q) {
+ 				if(ispeak(env,envend,q,(int)dz->iparam[ENV_PKSRCHWIDTH]))
+					peakkcnt++;
+ 				upwards = FALSE;
+ 			}
+ 		} else {
+ 			if(*p > *q)
+ 				upwards = TRUE;
+ 		}
+		thistime += timestep;
+ 		p++;
+ 		q++;
+ 	}
+	fprintf(stdout,"INFO: Number of peaks = %d\n",peakkcnt);
+	fflush(stdout);
+ 	return(FINISHED);
+}
+ 

+ 333 - 0
dev/env/envimpos.c

@@ -0,0 +1,333 @@
+/*
+ * 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 <structures.h>
+#include <tkglobals.h>
+#include <globcon.h>
+#include <processno.h>
+#include <modeno.h>
+#include <arrays.h>
+#include <envel.h>
+#include <cdpmain.h>
+
+#include <sfsys.h>
+
+static void apply_envel_to_buffer(int samps_to_process,int envwindow_sampsize,int envcnt,
+								  int *cnt,float **envptr,double *step,float *thisval,
+								  float *nextval,int incr_cnt,int chans,dataptr dz);
+static void apply_env_to_window(int incr_cnt,double step, float startval,
+			int startsamp,int chans,int is_log,dataptr dz);
+static void step_gen(float *thisval,float *nextval,double *step,float **envptr,int *is_log,int incr_cnt);
+static int  reset_file_pos_and_counters(int fileno,dataptr dz);
+static void test_apply_env_to_window(int incr_cnt,double step,float startval,
+			int startsamp,int chans,int is_log,double *maxval,dataptr dz);
+static void test_apply_envel_to_buffer(int samps_to_process,int envwindow_sampsize,int envcnt,int *cnt,
+			float **envptr,double *step,float *thisval,float *nextval,int incr_cnt,int chans,
+			double *maxval,dataptr dz);
+static int  test_impose_envel_on_sndfile(float *env,int envcnt,int bufcnt,int fileno,double *maxval,dataptr dz);
+static void adjust_envelope(double adjuster,int envcnt,dataptr dz);
+
+/*************************** IMPOSE_ENVEL [APPLY_THE_ENV] *************************
+ *
+ * WE Assume that buffersizes have been recalcd etc by this stage,
+ * and that they were last-calculated for the CURRENT file!!
+ *
+ * envcnt MUST BE the TRUE length of the NEW envelope!!!
+ */
+
+int impose_envel_on_sndfile(float *env,int envcnt,int bufcnt,int fileno,dataptr dz)
+{
+	int	   exit_status;
+	int   n, cnt;
+	double maxval = 0.0;
+	int   envwindow_sampsize = dz->iparam[ENV_SAMP_WSIZE];
+	int    chans = dz->infile->channels;
+	int   incr_cnt = envwindow_sampsize/chans;
+	float  *envptr = env;
+	double step;
+	float  thisval = *envptr;	
+	float  nextval = *envptr;	
+	if((exit_status = reset_file_pos_and_counters(fileno,dz))<0)
+		return(exit_status);
+
+	if(sloom) {
+		fprintf(stdout,"INFO: Testing levels of new envelope.\n");
+		fflush(stdout);
+	}
+
+	if((exit_status = test_impose_envel_on_sndfile(env,envcnt,bufcnt,fileno,&maxval,dz))<0)
+		return(exit_status);
+	if(maxval > F_MAXSAMP)
+		adjust_envelope(F_MAXSAMP/maxval,envcnt,dz);
+	envptr  = env;
+	thisval = *envptr;
+	nextval = *envptr;
+	cnt = 0;
+	if((exit_status = reset_file_pos_and_counters(fileno,dz))<0)
+		return(exit_status);
+
+	if(sloom) {
+		fprintf(stdout,"INFO: Imposing new envelope on sound.\n");
+		fflush(stdout);
+	}
+	for(n = 0; n < bufcnt; n++)	{
+		if((exit_status = read_samps(dz->sampbuf[0],dz))<0)
+			return(exit_status);
+		apply_envel_to_buffer
+		(dz->ssampsread,envwindow_sampsize,envcnt,&cnt,&envptr,&step,&thisval,&nextval,incr_cnt,chans,dz);
+		if(dz->ssampsread > 0) {
+			if((exit_status = write_samps(dz->sampbuf[0],dz->ssampsread,dz))<0)
+				return(exit_status);
+		}
+	}
+	return(FINISHED);
+}
+
+/******************************* APPLY_ENVEL_TO_BUFFER [ENVAPPLY] ******************************
+ *
+ * Apply envelope to input soundfile, to produce output sound file.
+ *
+ * If envelope table runs out before sound, last value in table is held.
+ */
+
+void apply_envel_to_buffer(int samps_to_process,int envwindow_sampsize,int envcnt,
+int *cnt,float **envptr,double *step,float *thisval,float *nextval,int incr_cnt,
+int chans,dataptr dz)
+{
+	int is_log = FALSE;
+	int  startsamp = 0;
+	while(samps_to_process >= envwindow_sampsize) {
+		if(++(*cnt) < envcnt)
+			step_gen(thisval,nextval,step,envptr,&is_log,incr_cnt);
+		else {
+			*thisval = *nextval;
+			*step = 0.0;   /* retain last envelope value if we run out of values */
+			is_log = FALSE;
+		}
+		apply_env_to_window(incr_cnt,*step,*thisval,startsamp,chans,is_log,dz);
+		startsamp 		 += envwindow_sampsize;
+		samps_to_process -= envwindow_sampsize;
+	}	
+	if(samps_to_process) {					/* Handle any final short buffer */
+		if(++(*cnt) < envcnt)
+			step_gen(thisval,nextval,step,envptr,&is_log,incr_cnt);
+		else {
+			*thisval = *nextval;
+			*step = 0.0;   /* retain last envelope value if we run out of values */
+			is_log = FALSE;
+		}
+		incr_cnt = samps_to_process/chans;
+		apply_env_to_window(incr_cnt,*step,*thisval,startsamp,chans,is_log,dz);
+	}
+	return;
+}
+
+/************************ APPLY_ENV_TO_WINDOW [DO_THE_ENV] ***********************/
+
+void apply_env_to_window
+(int incr_cnt,double step, float startval, int startsamp,int chans,int is_log,dataptr dz)
+{
+	int i, offset, bufpos;
+	int chanpos;
+	double newval, multiplier, thisstep;
+	float *buf = dz->sampbuf[0];
+	if(is_log) {
+		for(i=0, offset = 0; i<incr_cnt; i++, offset += chans) {
+			thisstep    = ((double)i/(double)incr_cnt) * step;
+			thisstep    = pow(10,thisstep);
+			multiplier  = startval * thisstep;
+			for(chanpos=0; chanpos < chans; chanpos++) {
+				bufpos  	= startsamp + offset + chanpos;
+				newval    	= (double)(buf[bufpos] * multiplier);
+				newval      = min(newval,(double)F_MAXSAMP);
+				newval      = max(newval,(double)F_MINSAMP);	
+				buf[bufpos] = (float) /*round*/(newval);
+			}
+		}
+	} else {
+		for(i=0, offset = 0; i<incr_cnt; i++, offset += chans) {
+			for(chanpos=0; chanpos < chans; chanpos++) {
+				bufpos  	= startsamp + offset + chanpos;
+				newval    	= (double)buf[bufpos] * (startval + (step * (double)i));
+				newval      = min(newval,(double)F_MAXSAMP);
+				newval      = max(newval,(double)F_MINSAMP);	
+				buf[bufpos] = (float) /*round*/(newval);
+			}
+		}
+	}
+}
+
+/****************************** STEP_GEN ******************************
+ *
+ * Generates [stereo]-sample-wise step, for each window.
+ */
+
+#define STEP_LINEAR_LIMIT	(1.0)
+
+void step_gen(float *thisval,float *nextval,double *step,float **envptr,int *is_log,int incr_cnt)
+{   
+	double valstep, absstep;
+	*thisval = *nextval;
+	(*envptr)++;
+	*nextval = **envptr;
+	valstep = *nextval - *thisval; 
+	*step   = valstep/(double)incr_cnt;
+/* LOG INTERP FOR EXTREME CASES ONLY --> */
+	if((absstep = fabs(*step)) > STEP_LINEAR_LIMIT) {
+		*step   = log10((*nextval)/(*thisval));
+		*is_log = TRUE;
+	}
+/* <-- LOG INTERP FOR EXTREME CASES ONLY */
+	return;
+}
+	
+/**************************** RESET_FILE_POS_AND_COUNTERS *************************/
+
+int reset_file_pos_and_counters(int fileno,dataptr dz)
+{
+	if((sndseekEx(dz->ifd[fileno],0,0))<0) {					/* reset all file pointers and counters */
+		sprintf(errstr,"seek error: reset_file_pos_and_counters()\n");
+		return(SYSTEM_ERROR);
+	}
+	dz->total_samps_read = 0;
+	dz->samps_left = dz->insams[fileno];
+	return(FINISHED);
+}
+
+/*************************** TEST_IMPOSE_ENVEL *************************
+ *
+ * WE Assume that buffersizes have been recalcd etc by this stage,
+ * and that they were last-calculated for the CURRENT file!!
+ *
+ * envcnt MUST BE the TRUE length of the NEW envelope!!!
+ */
+
+int test_impose_envel_on_sndfile(float *env,int envcnt,int bufcnt,int fileno,double *maxval,dataptr dz)
+{
+	int	   exit_status;
+	int   n, cnt = 0;
+	int   envwindow_sampsize = dz->iparam[ENV_SAMP_WSIZE] ;
+	int    chans = dz->infile->channels;
+	int   incr_cnt = envwindow_sampsize/chans;
+	float  *envptr = env;
+	double step    = 0.0;
+	float  thisval = *envptr;	
+	float  nextval = *envptr;	
+
+	if((exit_status = reset_file_pos_and_counters(fileno,dz))<0)
+			return(exit_status);
+	for(n = 0; n < bufcnt; n++)	{
+		if((exit_status = read_samps(dz->sampbuf[0],dz))<0)
+			return(exit_status);
+		if(sloom)
+			display_virtual_time(dz->total_samps_read,dz);
+		test_apply_envel_to_buffer
+		(dz->ssampsread,envwindow_sampsize,envcnt,&cnt,&envptr,&step,&thisval,&nextval,incr_cnt,chans,maxval,dz);
+	}
+	return(FINISHED);
+}
+
+/******************************* TEST_APPLY_ENVEL_TO_BUFFER [ENVAPPLY] ******************************/
+
+void test_apply_envel_to_buffer(int samps_to_process,int envwindow_sampsize,int envcnt,int *cnt,float **envptr,
+double *step,float *thisval,float *nextval,int incr_cnt,int chans,
+double *maxval,dataptr dz)
+{
+	int is_log = FALSE;
+	int  startsamp = 0;
+	while(samps_to_process >= envwindow_sampsize) {
+		if(++(*cnt) < envcnt)
+			step_gen(thisval,nextval,step,envptr,&is_log,incr_cnt);
+		else {
+			*thisval = *nextval;
+			*step = 0.0;   /* retain last envelope value if we run out of values */
+			is_log = FALSE;
+		}
+		test_apply_env_to_window(incr_cnt,*step,*thisval,startsamp,chans,is_log,maxval,dz);
+		startsamp 		 += envwindow_sampsize;
+		samps_to_process -= envwindow_sampsize;
+	}	
+	if(samps_to_process) {					/* Handle any final short buffer */
+		if(++(*cnt) < envcnt)
+			step_gen(thisval,nextval,step,envptr,&is_log,incr_cnt);
+		else {
+			*thisval = *nextval;
+			*step = 0.0;   /* retain last envelope value if we run out of values */
+			is_log = FALSE;
+		}
+		incr_cnt = samps_to_process/chans;
+		test_apply_env_to_window(incr_cnt,*step,*thisval,startsamp,chans,is_log,maxval,dz);
+	}
+	return;
+}
+
+/************************ TEST_APPLY_ENV_TO_WINDOW [DO_THE_ENV] ***********************/
+
+void test_apply_env_to_window
+(int incr_cnt,double step, float startval,
+int startsamp, int chans,int is_log,double *maxval,dataptr dz)
+{
+	int i, offset, bufpos;
+	int chanpos;
+	double newval, multiplier, thisstep;
+	float *buf = dz->sampbuf[0];
+	if(is_log) {
+		for(i=0, offset = 0; i<incr_cnt; i++, offset += chans) {
+			
+			thisstep    = ((double)i/(double)incr_cnt) * step;
+			thisstep    = pow(10,thisstep);
+			multiplier  = startval * thisstep;
+			for(chanpos=0; chanpos < chans; chanpos++) {
+				bufpos  	= startsamp + offset + chanpos;
+				newval    	= (double)(buf[bufpos] * multiplier);
+				*maxval = max(*maxval,fabs(newval));
+			}
+		}
+	} else {
+		for(i=0, offset = 0; i<incr_cnt; i++, offset += chans) {
+			for(chanpos=0; chanpos < chans; chanpos++) {
+				bufpos  = startsamp + offset + chanpos;
+				newval  = (double)buf[bufpos] * (startval + (step * (double)i));
+				*maxval = max(*maxval,fabs(newval));
+			}
+		}
+	}
+}
+
+/************************ ADJUST_ENVELOPE ***********************/
+
+void adjust_envelope(double adjuster,int envcnt,dataptr dz)
+{
+	float *envptr = dz->env;
+	float *envend = envptr + envcnt;
+	while(envptr < envend) {
+		*envptr = (float)(*envptr * adjuster);
+		envptr++;
+	}
+}					   

+ 887 - 0
dev/env/envprepro.c

@@ -0,0 +1,887 @@
+/*
+ * 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 <structures.h>
+#include <tkglobals.h>
+#include <globcon.h>
+#include <processno.h>
+#include <modeno.h>
+#include <arrays.h>
+#include <envel.h>
+#include <cdpmain.h>
+
+#include <sfsys.h>
+#include <osbind.h>
+
+static int  create_initial_envelope_params(double infiledur,dataptr dz);
+static int  reallocate_initial_envelope_params(dataptr dz);
+static int  allocate_initial_envelope_params(dataptr dz);
+static int  find_and_test_attack_peak(dataptr dz);
+static int  find_attack_point(float *buf,int *attack_point_found,int *attack_point,dataptr dz);
+static int  find_attack_point_using_gate(float *buf,int *attack_point_found,int *attack_point,dataptr dz);
+static int  attack_point_definitively_found(int *n,float *buf,/*int*/double *attack_level,int *attack_point,
+				int previous_total_samps_read,dataptr dz);
+static int  level_is_too_high(float *buf,int abs_samppos,dataptr dz);
+static int  level_is_too_high_in_thisbuf(float *buf, double *gain, double tail_gainstep,int chans,
+				int n,int *too_high,dataptr dz);
+static int  go_to_search_start(dataptr dz);
+static int  go_to_max_sample(float *buf,int *attack_point_found,int *attack_point,dataptr dz);
+static int  find_local_maximum(float *buf,int *attack_point_found,int *attack_point,dataptr dz);
+static int  level_is_too_high_in_thisbuf2(float *buf, double *gain, double tail_gainstep,double maxgain,
+				int chans,int n,int *sampcnt,int abs_onset_len,int *too_high,dataptr dz);
+static int  level_is_too_high_in_onset(float *buf,int abs_samppos,double tail_gainstep,dataptr dz);
+static int  restore_buffers_and_file_to_original_condition(float *buf,int abs_samppos,dataptr dz);
+static int  level_is_too_high_in_tail(float *buf,int abs_samppos,double tail_gainstep,dataptr dz);
+static int  create_tremol_sintable(dataptr dz);
+static void convert_tremol_frq_to_log10(dataptr dz);
+
+/***************************** ENVEL_PREPROCESS ******************************/
+
+int envel_preprocess(dataptr dz)
+{
+	int  exit_status;
+	int filestsmplen;
+//TW UPDATES
+	double *d;
+	double maxsplen, minwidth;
+	int n;
+	double sec = (double)(ENV_FSECSIZE)/(double)(dz->infile->channels * dz->infile->srate);
+	switch(dz->process) {
+	case(ENV_WARPING):
+	case(ENV_RESHAPING):
+	case(ENV_REPLOTTING):
+		switch(dz->mode) {
+		case(ENV_NORMALISE):	case(ENV_REVERSE):		case(ENV_CEILING):
+		case(ENV_EXAGGERATING):	case(ENV_ATTENUATING):	case(ENV_FLATTENING):
+		case(ENV_TSTRETCHING):	case(ENV_CORRUGATING):	case(ENV_PEAKCNT):
+		case(ENV_LIFTING):		case(ENV_GATING):
+		case(ENV_DUCKED):		case(ENV_TRIGGERING):
+			break;
+		case(ENV_LIMITING):
+			if(!first_param_not_less_than_second(ENV_LIMIT,ENV_THRESHOLD,dz))
+				return(DATA_ERROR);
+			break;
+		case(ENV_INVERTING):
+			if(!first_param_greater_than_second(ENV_MIRROR,ENV_GATE,dz))
+				return(DATA_ERROR);
+			break;
+		case(ENV_EXPANDING):
+			if(!first_param_not_less_than_second(ENV_THRESHOLD,ENV_GATE,dz))
+				return(DATA_ERROR);
+			break;
+		default:
+			sprintf(errstr,"Unknown case: envwarp,reshape or replot: envelope_preprocess()\n");
+			return(PROGRAM_ERROR);
+		}
+		break;
+	case(ENV_CURTAILING):
+		switch(dz->mode) {
+		case(ENV_START_AND_END):	
+		case(ENV_START_AND_DUR):
+			switch(dz->iparam[ENV_TIMETYPE]) {
+			case(ENV_TIMETYPE_SMPS):
+				dz->param[ENV_STARTTIME] = (double)(round(dz->param[ENV_STARTTIME])/dz->infile->channels);
+				dz->param[ENV_ENDTIME]   = (double)(round(dz->param[ENV_ENDTIME])/dz->infile->channels);
+				/* fall thro */
+ 			case(ENV_TIMETYPE_STSMPS):
+				dz->param[ENV_STARTTIME] = dz->param[ENV_STARTTIME]/(double)dz->infile->srate;
+				dz->param[ENV_ENDTIME]   = dz->param[ENV_ENDTIME]/(double)dz->infile->srate;
+				break;
+ 			case(ENV_TIMETYPE_SECS):
+				break;
+			default:
+				sprintf(errstr,"Unknown case: ENV_CURTAILING: envelope_preprocess()\n");
+				return(PROGRAM_ERROR);
+			}
+			if(dz->param[ENV_STARTTIME] < 0.0 || dz->param[ENV_STARTTIME] >= dz->duration) {
+				sprintf(errstr,"Start of fade time : out of range.\n");
+				return(USER_ERROR);
+			}
+			if(dz->mode==ENV_START_AND_DUR) {	 /* "ENDTIME" is actually FADE DURATION */
+				if(dz->param[ENV_ENDTIME] < FLTERR) {
+					sprintf(errstr,"Negative or zero fade duration : impossible.\n");
+					return(USER_ERROR);
+				}
+				dz->param[ENV_ENDTIME] = dz->param[ENV_STARTTIME] + dz->param[ENV_ENDTIME];
+				if(dz->param[ENV_ENDTIME] > dz->duration + FLTERR) {
+					fprintf(stdout,"WARNING: Fade duration goes beyond file end: curtailing to file end.\n");
+					fflush(stdout);
+				}
+				if(dz->param[ENV_ENDTIME] > dz->duration-FLTERR) {
+					dz->param[ENV_ENDTIME] = dz->duration;
+				}
+			} else {
+				if(dz->param[ENV_STARTTIME] + sec >= dz->param[ENV_ENDTIME]) {
+					sprintf(errstr,"Fade times too close or reversed.\n");
+					return(USER_ERROR);
+				}
+			 	if(dz->param[ENV_ENDTIME] < 0.0) {
+					sprintf(errstr,"End-of-fade time : out of range.\n");
+					return(USER_ERROR);
+				} else if(dz->param[ENV_ENDTIME] > dz->duration) {
+					dz->param[ENV_ENDTIME] = dz->duration;
+					fprintf(stdout,"WARNING: End-of-fade beyond file end: defaulting to end of file.\n");
+					fflush(stdout);
+				}
+			}
+			break;
+		case(ENV_START_ONLY):
+			switch(dz->iparam[ENV_TIMETYPE]) {
+			case(ENV_TIMETYPE_SMPS):
+				dz->param[ENV_STARTTIME] = (double)(round(dz->param[ENV_STARTTIME])/dz->infile->channels);
+				/* fall thro */
+ 			case(ENV_TIMETYPE_STSMPS):
+				dz->param[ENV_STARTTIME] = dz->param[ENV_STARTTIME]/(double)dz->infile->srate;
+				break;
+ 			case(ENV_TIMETYPE_SECS):
+				break;
+			default:
+				sprintf(errstr,"Unknown case: ENV_CURTAILING: envelope_preprocess()\n");
+				return(PROGRAM_ERROR);
+			}
+			dz->param[ENV_ENDTIME] = dz->duration;
+		}
+		dz->itemcnt = 3;
+		if((exit_status = create_initial_envelope_params(dz->duration,dz))<0)
+			return(exit_status);
+		if((exit_status = establish_additional_brktable(dz))<0)
+			return(exit_status);
+		break;
+	case(ENV_DOVETAILING):
+		filestsmplen = dz->insams[0]/dz->infile->channels;
+		switch(dz->iparam[ENV_TIMETYPE]) {
+		case(ENV_TIMETYPE_SMPS):
+			dz->param[ENV_STARTTRIM] = 
+			(double)round(dz->param[ENV_STARTTRIM])/(double)(dz->infile->channels * dz->infile->srate);
+			dz->param[ENV_ENDTRIM]   = 
+			(double)round(dz->param[ENV_ENDTRIM])/(double)(dz->infile->channels * dz->infile->srate);
+			dz->param[ENV_ENDTRIM]   = dz->duration - dz->param[ENV_ENDTRIM];
+			break;
+		case(ENV_TIMETYPE_STSMPS):
+			dz->param[ENV_STARTTRIM] = (double)round(dz->param[ENV_STARTTRIM])/(double)dz->infile->srate;
+			dz->iparam[ENV_ENDTRIM]  = (int)round(dz->param[ENV_ENDTRIM]);
+			dz->iparam[ENV_ENDTRIM]  = (int)(filestsmplen - dz->iparam[ENV_ENDTRIM]);
+			dz->param[ENV_ENDTRIM]   = (double)dz->iparam[ENV_ENDTRIM]/(double)dz->infile->srate;
+			break;
+ 		case(ENV_TIMETYPE_SECS):
+			dz->param[ENV_ENDTRIM]   = dz->duration - dz->param[ENV_ENDTRIM];
+			break;
+		default:
+			sprintf(errstr,"Unknown case: ENV_DOVETAILING: envelope_preprocess()\n");
+			return(PROGRAM_ERROR);
+		}
+		if(dz->param[ENV_ENDTRIM] < 0.0) {
+			sprintf(errstr,"End Trim is too large.\n");
+			return(USER_ERROR);
+		}
+		if(dz->param[ENV_STARTTRIM] > dz->duration) {
+			sprintf(errstr,"Start Trim is too large.\n");
+			return(USER_ERROR);
+		}
+		if(dz->param[ENV_ENDTRIM] < dz->param[ENV_STARTTRIM]) {
+			sprintf(errstr,"Start and End Trims overlap: cannot proceed.\n");
+			return(USER_ERROR);
+		}
+		if(flteq(dz->param[ENV_ENDTRIM],dz->duration) && flteq(dz->param[ENV_STARTTRIM],0.0)) {
+			sprintf(errstr,"Start and End Trims are zero: no change in file.\n");
+			return(USER_ERROR);
+		}
+		if(flteq(dz->param[ENV_ENDTRIM],dz->duration) || flteq(dz->param[ENV_STARTTRIM],0.0))
+			dz->itemcnt = 3;
+		else
+			dz->itemcnt = 4;
+		if((exit_status = create_initial_envelope_params(dz->duration,dz))<0)
+			return(exit_status);
+		if((exit_status = establish_additional_brktable(dz))<0)
+			return(exit_status);
+		break;
+	case(ENV_SWELL):
+		dz->itemcnt = 3;
+		if((exit_status = create_initial_envelope_params(dz->duration,dz))<0)
+			return(exit_status);
+		if((exit_status = establish_additional_brktable(dz))<0)
+			return(exit_status);
+		break;
+	case(ENV_ATTACK):
+		dz->param[ENV_ATK_GATE] *= (double)F_MAXSAMP;		/* RWD actually redundant, but do it anyway */
+		if((exit_status = find_and_test_attack_peak(dz))<0)
+			return(exit_status);
+		dz->param[ENV_ATK_ONSET] *= MS_TO_SECS;
+		dz->param[ENV_ATK_TAIL]  *= MS_TO_SECS;
+		if(dz->iparam[ENV_ATK_ENVTYPE] == ENVTYPE_EXP)
+			dz->iparam[ENV_ATK_ENVTYPE] = ENVTYPE_STEEP;
+		dz->itemcnt = 5;
+		if((exit_status = create_initial_envelope_params(dz->duration,dz))<0)
+			return(exit_status);
+		if((exit_status = establish_additional_brktable(dz))<0)
+			return(exit_status);
+		break;
+	case(ENV_CREATE):
+		if(dz->mode==ENV_ENVFILE_OUT) {	
+			if(dz->extrabrkno>=0) {		  /* If a brktable passed in from framework */
+				if(dz->brk == NULL || dz->brk[dz->extrabrkno] == NULL) {	/* clear it */
+					sprintf(errstr,"Problem freeing inbrkfile-table: ENV_CREATE: envelope_preprocess()\n");
+					return(PROGRAM_ERROR);
+				} 
+				free(dz->brk[dz->extrabrkno]);
+			}								 		 /* allocate temporary brkpnt array */
+			if((exit_status = establish_additional_brktable(dz))<0)
+				return(exit_status);
+		}
+		break;	
+	case(ENV_EXTRACT):   case(ENV_IMPOSE): 	  	case(ENV_REPLACE):
+	case(ENV_ENVTOBRK):  case(ENV_ENVTODBBRK):	case(ENV_BRKTOENV):
+	case(ENV_DBBRKTOENV):case(ENV_DBBRKTOBRK):	case(ENV_BRKTODBBRK):
+//TW NEW CASE
+	case(ENV_PROPOR):
+		break;	
+	case(ENV_PLUCK):
+		if(dz->infile->channels!=MONO) {
+			sprintf(errstr,"This process only works with MONO files\n");
+			return(USER_ERROR);
+		}
+		initrand48();
+		break;	
+	case(ENV_TREMOL):
+		if(dz->brksize[ENV_TREM_FRQ] && dz->mode==ENV_TREM_LOG)
+			convert_tremol_frq_to_log10(dz);
+		return create_tremol_sintable(dz);
+		break;	
+	case(TIME_GRID):
+		dz->tempsize = dz->insams[0] * dz->iparam[GRID_COUNT];
+		if(dz->brksize[GRID_SPLEN] > 0) {
+			d = dz->brk[GRID_SPLEN] + 1;
+			for(n= 0;n < dz->brksize[GRID_SPLEN];n++) {
+				*d *= MS_TO_SECS;
+				d += 2;
+			}
+		} else
+			dz->param[GRID_SPLEN] *= MS_TO_SECS;
+		if(dz->brksize[GRID_WIDTH]) {
+			if((exit_status = get_minvalue_in_brktable(&minwidth,GRID_WIDTH,dz))<0)
+				return(exit_status);
+		} else
+			minwidth = dz->param[GRID_WIDTH];
+		if((exit_status = get_maxvalue(GRID_SPLEN,&maxsplen,dz))<0)
+			return(exit_status);
+		if(maxsplen >= minwidth) {
+			sprintf(errstr,"Maximum splicelen too large for minimum grid-width\n");
+			return(DATA_ERROR);
+		}
+		break;
+	default:
+		sprintf(errstr,"Unknown case: envelope_preprocess()\n");
+		return(PROGRAM_ERROR);
+	}
+	return(FINISHED);
+}
+
+/***************************** CREATE_INITIAL_ENVELOPE_PARAMS ******************************/
+
+int create_initial_envelope_params(double infiledur,dataptr dz)
+{
+	int exit_status, n, in_itemcnt;
+	double attack_start, attack_end;
+	if((exit_status = allocate_initial_envelope_params(dz))<0)
+		return(exit_status);
+	switch(dz->process) {
+	case(ENV_CURTAILING):
+		dz->parray[ENV_CREATE_INTIME][0]  = 0.0; 
+		dz->parray[ENV_CREATE_INLEVEL][0] = 1.0;
+		dz->iparray[ENV_SLOPETYPE][0]	  = ENVTYPE_LIN;
+
+		dz->parray[ENV_CREATE_INTIME][1]  = dz->param[ENV_STARTTIME]; 
+		dz->parray[ENV_CREATE_INLEVEL][1] = 1.0;
+		dz->iparray[ENV_SLOPETYPE][1]	  = ENVTYPE_LIN;
+
+		dz->parray[ENV_CREATE_INTIME][2]  = dz->param[ENV_ENDTIME]; 
+		dz->parray[ENV_CREATE_INLEVEL][2] = 0.0;
+		switch(dz->mode) {
+		case(ENV_START_AND_END):
+		case(ENV_START_AND_DUR):
+		case(ENV_START_ONLY):
+			dz->iparray[ENV_SLOPETYPE][2]	  = dz->iparam[ENV_ENVTYPE];
+			break;
+		default:
+			dz->iparray[ENV_SLOPETYPE][2]	  = ENVTYPE_DBL;
+			break;
+		}
+		break;
+	case(ENV_DOVETAILING):
+		n = 0;
+		if(flteq(dz->param[ENV_STARTTRIM],0.0)) {
+			dz->parray[ENV_CREATE_INTIME][n]  = 0.0; 
+			dz->parray[ENV_CREATE_INLEVEL][n] = 1.0;
+			dz->iparray[ENV_SLOPETYPE][n]	  = ENVTYPE_LIN;
+			n++;
+		} else {
+			dz->parray[ENV_CREATE_INTIME][n]  = 0.0; 
+			dz->parray[ENV_CREATE_INLEVEL][n] = 0.0;
+			dz->iparray[ENV_SLOPETYPE][n]	  = ENVTYPE_LIN;
+			n++;
+			dz->parray[ENV_CREATE_INTIME][n]  = dz->param[ENV_STARTTRIM]; 
+			dz->parray[ENV_CREATE_INLEVEL][n] = 1.0;
+			if(dz->mode==DOVE)
+				dz->iparray[ENV_SLOPETYPE][n]	  = dz->iparam[ENV_STARTTYPE];
+			else
+				dz->iparray[ENV_SLOPETYPE][n]	  = ENVTYPE_DBL;
+			n++;
+		}
+		if(flteq(dz->param[ENV_ENDTRIM],infiledur)) {
+			dz->parray[ENV_CREATE_INTIME][n]  = infiledur; 
+			dz->parray[ENV_CREATE_INLEVEL][n] = 1.0;
+			dz->iparray[ENV_SLOPETYPE][n]	  = ENVTYPE_LIN;
+		} else {
+			dz->parray[ENV_CREATE_INTIME][n]  = dz->param[ENV_ENDTRIM]; 
+			dz->parray[ENV_CREATE_INLEVEL][n] = 1.0;
+			dz->iparray[ENV_SLOPETYPE][n]	  = ENVTYPE_LIN;
+			n++;
+			dz->parray[ENV_CREATE_INTIME][n]  = infiledur; 
+			dz->parray[ENV_CREATE_INLEVEL][n] = 0.0;
+			if(dz->mode==DOVE)
+				dz->iparray[ENV_SLOPETYPE][n]	  = dz->iparam[ENV_ENDTYPE];
+			else
+				dz->iparray[ENV_SLOPETYPE][n]	  = ENVTYPE_DBL;
+		}
+		break;
+	case(ENV_SWELL):
+		dz->parray[ENV_CREATE_INTIME][0]  = 0.0; 
+		dz->parray[ENV_CREATE_INLEVEL][0] = 0.0;
+		dz->iparray[ENV_SLOPETYPE][0]	  = ENVTYPE_LIN;
+
+		dz->parray[ENV_CREATE_INTIME][1]  = dz->param[ENV_PEAKTIME]; 
+		dz->parray[ENV_CREATE_INLEVEL][1] = 1.0;
+		dz->iparray[ENV_SLOPETYPE][1]	  = dz->iparam[ENV_ENVTYPE];
+
+		dz->parray[ENV_CREATE_INTIME][2]  = infiledur; 
+		dz->parray[ENV_CREATE_INLEVEL][2] = 0.0;
+		dz->iparray[ENV_SLOPETYPE][2]	  = dz->iparam[ENV_ENVTYPE];
+		break;
+	case(ENV_ATTACK):
+		in_itemcnt = dz->itemcnt;
+		n = 0;
+		attack_start = max(0.0,dz->param[ENV_ATK_TIME] - dz->param[ENV_ATK_ONSET]);
+		attack_end   = min(infiledur,dz->param[ENV_ATK_TIME] + dz->param[ENV_ATK_TAIL]); 
+		if(dz->param[ENV_ATK_TIME] > 0.0) {
+			dz->parray[ENV_CREATE_INTIME][n]  = 0.0; 
+			dz->parray[ENV_CREATE_INLEVEL][n] = 1.0;
+			dz->iparray[ENV_SLOPETYPE][n]	  = ENVTYPE_LIN;
+			n++;
+			if(attack_start > 0.0) {
+				dz->parray[ENV_CREATE_INTIME][n]  = attack_start; 
+				dz->parray[ENV_CREATE_INLEVEL][n] = 1.0;
+				dz->iparray[ENV_SLOPETYPE][n]	  = ENVTYPE_LIN;
+				n++;
+			}
+			dz->parray[ENV_CREATE_INTIME][n]  = dz->param[ENV_ATK_TIME]; 
+			dz->parray[ENV_CREATE_INLEVEL][n] = dz->param[ENV_ATK_GAIN];
+			dz->iparray[ENV_SLOPETYPE][n]	  = dz->iparam[ENV_ATK_ENVTYPE];
+			n++;
+		} else {
+			dz->parray[ENV_CREATE_INTIME][n]  = 0.0; 
+			dz->parray[ENV_CREATE_INLEVEL][n] = dz->param[ENV_ATK_GAIN];
+			dz->iparray[ENV_SLOPETYPE][n]	  = ENVTYPE_LIN;
+			n++;
+		}
+		if(attack_end < infiledur) {
+			dz->parray[ENV_CREATE_INTIME][n]  = attack_end; 
+			dz->parray[ENV_CREATE_INLEVEL][n] = 1.0;
+			dz->iparray[ENV_SLOPETYPE][n]	  = dz->iparam[ENV_ATK_ENVTYPE];
+			n++;
+			dz->parray[ENV_CREATE_INTIME][n]  = infiledur; 
+			dz->parray[ENV_CREATE_INLEVEL][n] = 1.0;
+			dz->iparray[ENV_SLOPETYPE][n]	  = ENVTYPE_LIN;
+			n++;
+		} else {
+			dz->parray[ENV_CREATE_INTIME][3]  = infiledur; 
+			dz->parray[ENV_CREATE_INLEVEL][3] = 1.0;
+			dz->iparray[ENV_SLOPETYPE][3]	  = dz->iparam[ENV_ATK_ENVTYPE];
+		}
+		dz->itemcnt = n;
+		if((dz->itemcnt != in_itemcnt) && (exit_status = reallocate_initial_envelope_params(dz))<0)
+			return(exit_status);
+		break;
+	default:
+		sprintf(errstr,"Unknown case in create_initial_envelope_params()\n");
+		return(PROGRAM_ERROR);
+	}
+	return(FINISHED);
+}
+
+/***************************** REALLOCATE_INITIAL_ENVELOPE_PARAMS ******************************/
+
+int reallocate_initial_envelope_params(dataptr dz)
+{
+	if((dz->parray[ENV_CREATE_INLEVEL] = (double *)realloc
+	(dz->parray[ENV_CREATE_INLEVEL],dz->itemcnt * sizeof(double)))==NULL) {
+		sprintf(errstr,"INSUFFICIENT MEMORY to reallocate input level array.\n");
+		return(MEMORY_ERROR);
+	}
+	if((dz->parray[ENV_CREATE_INTIME]  = (double *)realloc
+	(dz->parray[ENV_CREATE_INTIME],dz->itemcnt * sizeof(double)))==NULL) {
+		sprintf(errstr,"INSUFFICIENT MEMORY to reallocate input time array.\n");
+		return(MEMORY_ERROR);
+	}
+	if((dz->iparray[ENV_SLOPETYPE]  = (int *)realloc
+	(dz->iparray[ENV_SLOPETYPE],dz->itemcnt * sizeof(int)))==NULL) {
+		sprintf(errstr,"INSUFFICIENT MEMORY to reallocate input slopetype array.\n");
+		return(MEMORY_ERROR);
+	}			
+	return(FINISHED);
+}
+
+/***************************** ALLOCATE_INITIAL_ENVELOPE_PARAMS ******************************/
+
+int allocate_initial_envelope_params(dataptr dz)
+{
+	if((dz->parray[ENV_CREATE_INLEVEL] = (double *)malloc(dz->itemcnt * sizeof(double)))==NULL) {
+		sprintf(errstr,"INSUFFICIENT MEMORY for input level array.\n");
+		return(MEMORY_ERROR);
+	}
+	if((dz->parray[ENV_CREATE_INTIME]  = (double *)malloc(dz->itemcnt * sizeof(double)))==NULL) {
+		sprintf(errstr,"INSUFFICIENT MEMORY for input time array.\n");
+		return(MEMORY_ERROR);
+	}
+	if((dz->iparray[ENV_SLOPETYPE]  = (int *)malloc(dz->itemcnt * sizeof(int)))==NULL) {
+		sprintf(errstr,"INSUFFICIENT MEMORY for input slopetype array.\n");
+		return(MEMORY_ERROR);
+	}
+	return(FINISHED);
+}
+
+/****************************** FIND_AND_TEST_ATTACK_PEAK *******************************/
+
+int find_and_test_attack_peak(dataptr dz)
+{
+	int  exit_status;
+	int  chans = dz->infile->channels;
+	int  attack_point_found = FALSE;
+	int attack_point=0, abs_samppos;
+	float *buf = dz->sampbuf[0];
+	if((exit_status = find_attack_point(buf,&attack_point_found,&attack_point,dz))<0)
+		return(exit_status);
+	if (!attack_point_found) {
+		sprintf(errstr,"Gate amplitude not exceeded.\n");
+		return(GOAL_FAILED);
+	}
+	if(dz->insams[0] - attack_point < 
+	   round((ENV_MIN_ATK_ONSET * MS_TO_SECS) * (double)(dz->infile->srate * chans))) {
+		sprintf(errstr,"Attack time too late in file to create a new attack.\n");
+		return(GOAL_FAILED);
+	}
+	abs_samppos = (attack_point/chans) * chans;
+	if((exit_status = restore_buffers_and_file_to_original_condition(buf,abs_samppos,dz))<0)
+		return(exit_status);
+	if(level_is_too_high(buf,abs_samppos,dz)) {
+		sprintf(errstr,"The attack may distort with this gain level.\n");
+		return(GOAL_FAILED);
+	}
+	if(dz->mode==ENV_ATK_XTIME)
+		dz->param[ENV_ATK_TIME] = dz->param[ENV_ATK_ATTIME];
+	else
+		dz->param[ENV_ATK_TIME] = (double)(attack_point/chans)/(double)(dz->infile->srate);
+	reset_filedata_counters(dz);
+	if(sndseekEx(dz->ifd[0],0,0)<0) {
+		sprintf(errstr,"sndseekEx failed: find_and_test_attack_peak()\n");
+		return(SYSTEM_ERROR);
+	}
+	return(FINISHED);
+}
+
+/****************************** FIND_ATTACK_POINT *******************************/
+
+int find_attack_point(float *buf,int *attack_point_found,int *attack_point,dataptr dz)
+{
+	int exit_status;
+//	int definitely_found = FALSE;
+	switch(dz->mode) {
+	case(ENV_ATK_GATED):		
+		return find_attack_point_using_gate(buf,attack_point_found,attack_point,dz);
+	case(ENV_ATK_TIMED):		
+		if((exit_status = go_to_search_start(dz))<0)
+			return(exit_status);
+		if((exit_status = find_local_maximum(buf,attack_point_found,attack_point,dz))<0)
+			return(exit_status);
+		break;
+	case(ENV_ATK_XTIME):
+		*attack_point = round(dz->param[ENV_ATK_ATTIME] * (double)dz->infile->srate) * dz->infile->channels;
+		*attack_point_found = TRUE;
+		break;
+	case(ENV_ATK_ATMAX):		
+		return go_to_max_sample(buf,attack_point_found,attack_point,dz);
+	default:
+		sprintf(errstr,"Unknown case in find_attack_point()\n");
+		return(PROGRAM_ERROR);
+	}
+	return(FINISHED);
+}
+
+/****************************** FIND_ATTACK_POINT_USING_GATE *******************************/
+
+int find_attack_point_using_gate(float *buf,int *attack_point_found,int *attack_point,dataptr dz)
+{
+	int exit_status;
+	int definitely_found = FALSE;
+	/*int*/double attack_level=0.0;
+	int previous_total_samps_read, n;
+	while(!definitely_found && (dz->samps_left > 0)) {
+		previous_total_samps_read = dz->total_samps_read;
+		if((exit_status = read_samps(buf,dz))<0)
+			return(exit_status);
+		n = 0;
+		while(n<dz->ssampsread) {
+			if(!(*attack_point_found)) {
+				/*RWD be a little efficient here... */
+				double fabsamp = fabs(buf[n]);
+				if(/*abs(buf[n])*/fabsamp > dz->param[ENV_ATK_GATE]) {
+					attack_level  = /* abs(buf[n])*/fabsamp;
+					*attack_point = previous_total_samps_read + n;
+					*attack_point_found = TRUE;
+				}
+			}
+			if(*attack_point_found) {
+				if((definitely_found = 
+				attack_point_definitively_found(&n,buf,&attack_level,attack_point,previous_total_samps_read,dz))==TRUE)
+					break;
+			} else
+				n++;
+		}
+	}
+	return(FINISHED);
+}
+
+/****************************** ATTACK_POINT_DEFINITIVELY_FOUND *******************************/
+
+int attack_point_definitively_found
+(int *n,float *buf,/*int*/double *attack_level,int *attack_point,int previous_total_samps_read,dataptr dz)
+{
+	/*int*/double thislevel;
+	while(*n < dz->ssampsread) {
+		thislevel = fabs(buf[*n]);
+		if(thislevel < *attack_level)
+			return TRUE;
+		else if(thislevel > *attack_level) {
+			*attack_level = thislevel;
+			*attack_point = previous_total_samps_read + *n;
+		}
+		(*n)++;
+	}
+	return(FALSE);
+}
+
+/****************************** LEVEL_IS_TOO_HIGH *******************************
+ *
+ * This is an overestimate of risk!!
+ */
+
+int level_is_too_high(float *buf,int abs_samppos,dataptr dz)
+{
+	int exit_status;
+//	int chans = dz->infile->channels;
+	int too_high = FALSE;
+	double tail_gainstep = dz->param[ENV_ATK_GAIN] - 1.0;
+	switch(dz->mode) {
+	case(ENV_ATK_ATMAX):
+		break;
+	case(ENV_ATK_TIMED):
+	case(ENV_ATK_XTIME):
+		if((exit_status = level_is_too_high_in_onset(buf,abs_samppos,tail_gainstep,dz))<0)
+			return(exit_status);
+  		if((too_high = exit_status)==TRUE)
+			break;
+		/* fall thro */
+	case(ENV_ATK_GATED):
+		if((exit_status = level_is_too_high_in_tail(buf,abs_samppos,tail_gainstep,dz))<0)
+			return(exit_status);
+		too_high = exit_status;
+		break;
+	default:
+		sprintf(errstr,"Unknown case in level_is_too_high()\n");
+		return(PROGRAM_ERROR);
+	}
+	return(too_high);
+}
+
+/****************************** LEVEL_IS_TOO_HIGH_IN_THISBUF *******************************/
+
+int level_is_too_high_in_thisbuf
+(float *buf, double *gain, double tail_gainstep,int chans,int n,int *too_high,dataptr dz)
+{
+	int m;
+	double thislevel;
+	while(n < dz->ssampsread) {
+		for(m=0;m<chans;m++) {
+			if((thislevel = (double) fabs(buf[n+m]) * (*gain)) > F_MAXSAMP) {
+				*too_high = TRUE;
+				return(FINISHED);
+			}
+		}
+		if((*gain -= tail_gainstep)<=1.0)
+			return(FINISHED);
+		n += chans;
+	}
+	return(CONTINUE);
+}
+
+/****************************** GO_TO_SEARCH_START *******************************/
+
+int go_to_search_start(dataptr dz)
+{
+	int seccnt;
+	int shsecsize = ENV_FSECSIZE;
+
+	double starttime = max(0.0,dz->param[ENV_ATK_ATTIME] - (ENV_ATK_SRCH * MS_TO_SECS));
+	int startsamp = round(starttime * (double)dz->infile->srate) * dz->infile->channels;
+	if(startsamp >= dz->insams[0]) {
+		sprintf(errstr,"Error in sample arithmetic: go_to_search_start()\n");
+		return(PROGRAM_ERROR);
+	}
+	seccnt = startsamp/shsecsize;	/* TRUNCATE */
+	startsamp = seccnt * shsecsize;
+
+	if(sndseekEx(dz->ifd[0],startsamp,0)<0) {
+		sprintf(errstr,"sndseekEx failed: go_to_search_start()\n");
+		return(SYSTEM_ERROR);
+	}
+	/*dz->total_bytes_read = startbyte;*/
+	dz->total_samps_read = startsamp;
+	dz->samps_left = dz->insams[0] - startsamp;
+	return(FINISHED);
+}
+
+/****************************** GO_TO_MAX_SAMPLE *******************************/
+
+int go_to_max_sample(float *buf,int *attack_point_found,int *attack_point,dataptr dz)
+{
+	int  exit_status;
+	int previous_total_samps_read = 0, n;
+	/*int*/double  thislevel;
+	/*int*/double  attack_level = -1.0;
+	*attack_point_found = TRUE;
+	while(dz->samps_left > 0) {
+		previous_total_samps_read = dz->total_samps_read;
+		if((exit_status = read_samps(dz->sampbuf[0],dz))<0)
+			return(exit_status);
+		n = 0;
+		while(n<dz->ssampsread) {
+			if((thislevel = fabs(buf[n])) > attack_level) {
+				attack_level = thislevel;
+				*attack_point = previous_total_samps_read + n;
+			}
+			n++;
+		}
+	}
+	return(FINISHED);
+}
+
+/****************************** FIND_LOCAL_MAXIMUM *******************************/
+
+int find_local_maximum(float *buf,int *attack_point_found,int *attack_point,dataptr dz)
+{
+	int exit_status;
+	/*int*/double thislevel;
+	int n, m = 0;
+	/*int*/double attack_level = -1.0;
+	int finished = FALSE;
+	int previous_total_samps_read;
+	int search_limit = round((ENV_ATK_SRCH * 2.0) * MS_TO_SECS * (double)dz->infile->srate);
+	search_limit *= dz->infile->channels;
+	if(dz->samps_left <=0) {
+		sprintf(errstr,"Error in buffer arithmetic: find_local_maximum()\n");
+		return(PROGRAM_ERROR);
+	}
+	while(!finished && (dz->samps_left > 0)) {
+		previous_total_samps_read = dz->total_samps_read;
+		if((exit_status = read_samps(dz->sampbuf[0],dz))<0)
+			return(exit_status);
+		n = 0;
+		while(n<dz->ssampsread) {
+			if((thislevel = fabs(buf[n])) > attack_level) {
+				attack_level = thislevel;
+				*attack_point = previous_total_samps_read + n;
+			}
+			n++;
+			if(++m >= search_limit) {
+				finished = TRUE;
+				break;
+			}
+		}
+	}
+	*attack_point_found = TRUE;
+	return(FINISHED);
+}
+
+/****************************** LEVEL_IS_TOO_HIGH_IN_THISBUF2 *******************************/
+
+int level_is_too_high_in_thisbuf2(float *buf, double *gain, double tail_gainstep,
+			double maxgain,int chans,int n,int *sampcnt,int abs_onset_len,int *too_high,dataptr dz)
+{
+	int m;
+	double thislevel;
+	while(!(*too_high) && (n < dz->ssampsread)) {
+		for(m=0;m<chans;m++) {
+			if((thislevel = (double) fabs(buf[n+m]) * (*gain)) > F_MAXSAMP) {
+				*too_high = TRUE;
+				break;
+			}
+		}
+		if((*gain += tail_gainstep)>=maxgain)
+			*gain = maxgain;
+		if((*sampcnt += chans) >= abs_onset_len)
+			return(FINISHED);
+		n += chans;
+		
+	}
+	return(CONTINUE);
+}
+
+/****************************** LEVEL_IS_TOO_HIGH_IN_ONSET *******************************/
+
+int level_is_too_high_in_onset(float *buf,int abs_samppos,double tail_gainstep,dataptr dz)
+{
+	int  exit_status;
+	int  too_high = FALSE;
+	int  chans = dz->infile->channels;
+	double gain = 1.0;
+	int this_bufpos;
+	int sampcnt = 0;
+	int go_back = round(dz->param[ENV_ATK_ONSET] * MS_TO_SECS * (double)dz->infile->srate) * chans;
+	int bakpos = max(0,abs_samppos - go_back);
+	int abs_onset_len = abs_samppos - bakpos;
+	int onset_len = abs_onset_len/chans;
+	int bakset = (bakpos/dz->buflen) * dz->buflen;
+	if(sndseekEx(dz->ifd[0],bakset,0)<0) {
+		sprintf(errstr,"sndseek failed in level_is_too_high_in_onset()\n");
+		return(SYSTEM_ERROR);
+	}
+	this_bufpos = bakpos%dz->buflen;
+
+	dz->total_samps_read = bakset;
+	dz->samps_left       = dz->insams[0] - dz->total_samps_read;
+
+	tail_gainstep /= (double)onset_len;
+	while(!too_high && (dz->samps_left > 0)) {
+		if((exit_status = read_samps(buf,dz))<0)
+			return(exit_status);
+		if(dz->ssampsread <= 0) {
+			sprintf(errstr,"read anomaly: level_is_too_high_in_onset()\n");
+			return(PROGRAM_ERROR);
+		}
+		if((exit_status = level_is_too_high_in_thisbuf2(buf,&gain,tail_gainstep,
+		dz->param[ENV_ATK_GAIN],chans,this_bufpos,&sampcnt,abs_onset_len,&too_high,dz))==FINISHED)
+			break;
+		this_bufpos = 0;
+	}
+	if((exit_status = restore_buffers_and_file_to_original_condition(buf,abs_samppos,dz))<0)
+		return(exit_status);
+	return(too_high);
+}
+
+/****************************** RESTORE_BUFFERS_AND_FILE_TO_ORIGINAL_CONDITION *******************************/
+
+int restore_buffers_and_file_to_original_condition(float *buf,int abs_samppos,dataptr dz)
+{
+	int exit_status;
+	int reset = (abs_samppos/dz->buflen) * dz->buflen;
+	if(sndseekEx(dz->ifd[0],reset,0)<0) {
+		sprintf(errstr,"sndseek failed in restore_buffers_and_file_to_original_condition()\n");
+		return(SYSTEM_ERROR);
+	}
+	if((exit_status = read_samps(buf,dz))<0)
+		return(exit_status);
+	if(dz->ssampsread <= 0) {
+		sprintf(errstr,"read anomaly: restore_buffers_and_file_to_original_condition()\n");
+		return(PROGRAM_ERROR);
+	}
+	dz->total_samps_read = reset + dz->ssampsread;	
+	dz->samps_left = dz->insams[0] - dz->total_samps_read;
+	return(FINISHED);
+}
+
+/****************************** LEVEL_IS_TOO_HIGH_IN_TAIL *******************************/
+
+int level_is_too_high_in_tail(float *buf,int abs_samppos,double tail_gainstep,dataptr dz)
+{
+	int    exit_status;
+	int    too_high = FALSE;
+	int	   chans = dz->infile->channels;
+	double gain = dz->param[ENV_ATK_GAIN];
+	int   tail_len = round((dz->param[ENV_ATK_TAIL] * MS_TO_SECS) * (double)dz->infile->srate);
+	int   buf_samppos = abs_samppos % dz->buflen;
+	tail_gainstep /= (double)tail_len;
+	if((exit_status = level_is_too_high_in_thisbuf
+	(buf,&gain,tail_gainstep,chans,buf_samppos,&too_high,dz))==FINISHED)
+		return(too_high);
+	while(dz->samps_left > 0) {
+		if((exit_status = read_samps(dz->sampbuf[0],dz))<0)
+			return(exit_status);
+		buf_samppos = 0;
+		if((exit_status = level_is_too_high_in_thisbuf
+		(buf,&gain,tail_gainstep,chans,buf_samppos,&too_high,dz))==FINISHED)
+			break;
+	}
+	return(too_high);
+}
+
+/************************** CREATE_TREMOL_SINTABLE ******************/
+
+int create_tremol_sintable(dataptr dz)
+{
+	int n;
+	if((dz->parray[ENV_SINETAB] = (double *)malloc((ENV_TREM_TABSIZE + 1) * sizeof(double)))==NULL) {
+		sprintf(errstr,"INSUFFICIENT MEMORY for sine table.\n");
+		return(MEMORY_ERROR);
+	}
+	for(n=0;n<ENV_TREM_TABSIZE;n++) {
+		dz->parray[ENV_SINETAB][n] = sin(PI * 2.0 * ((double)n/(double)ENV_TREM_TABSIZE));
+		dz->parray[ENV_SINETAB][n] += 1.0;
+		dz->parray[ENV_SINETAB][n] /= 2.0;
+	}
+	dz->parray[ENV_SINETAB][n] = 0.5; /* wrap around point */
+	return(FINISHED);
+}
+
+/************************** CONVERT_TREMOL_FRQ_TO_LOG10 ******************/
+
+void convert_tremol_frq_to_log10(dataptr dz)
+{
+	double *p, *pend;
+	double infiledur = (double)dz->insams[0]/(double)dz->infile->srate;
+	double effectively_zero =  1.0/infiledur;
+	p = dz->brk[ENV_TREM_FRQ];
+	pend = p + (dz->brksize[ENV_TREM_FRQ] * 2);
+	p++;
+	while(p < pend) {
+		if(*p <= effectively_zero)
+			*p = effectively_zero;
+		*p = log10(*p);
+		p += 2;
+	}
+}
+	    

+ 775 - 0
dev/env/envprocess.c

@@ -0,0 +1,775 @@
+/*
+ * 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 <structures.h>
+#include <tkglobals.h>
+#include <globcon.h>
+#include <processno.h>
+#include <modeno.h>
+#include <arrays.h>
+#include <envel.h>
+#include <cdpmain.h>
+
+#include <sfsys.h>
+#include <envlcon.h>
+
+#define MARGIN   	  (16)
+#define BASE_REDUCE   ENV_DEFAULT_DATAREDUCE
+
+static int  read_envel_from_envfile(float **env,float **envend,int fileno,dataptr dz);
+static int  envcopy(float *envel1,float *envend1,float **envel2,float **envend2);
+static int  convert_envelope_to_brkpnt_table(int envcnt,double window_size,double infiledur,dataptr dz);
+static int  convert_brktable_to_envtable(double window_size,float **env,float **envend,dataptr dz);
+static int  write_brkpnt_data_to_file(dataptr dz);
+static int  write_envel_to_envfile(float *env,float *envend,dataptr dz);
+static double *datareduce(double *q,double datareduction,int *bcnt,int paramno,dataptr dz);
+static int  rejig_buffering(dataptr dz);
+static int  adjust_last_val_of_brk(double *brk,double *brkend,int *datacnt,double endtime);
+static int  store_brkpnt_envelope(int cnt,dataptr dz);
+static int  read_value_from_brktable_from_brkpntfile(double thistime,float *thisval,dataptr dz);
+static int  convert_brkvals_db_to_gain(int paramno,dataptr dz);
+static int  convert_brkvals_gain_to_dB(int paramno,dataptr dz);
+static int  convert_normalised_gain_val_to_dB(double *val);
+
+/************************** PROCESS_ENVELOPE ************************/
+
+int process_envelope(dataptr dz)
+{
+	int exit_status;
+	int bufcnt, envcnt, cnt, other_envcnt;
+	switch(dz->process) {
+	case(ENV_CURTAILING):
+	case(ENV_DOVETAILING):
+	case(ENV_SWELL):
+	case(ENV_ATTACK):
+		if((exit_status = create_envelope(&cnt,dz))<0)
+			return(exit_status);
+		if((exit_status = store_brkpnt_envelope(cnt,dz))<0)
+			return(exit_status);
+		if((exit_status = apply_brkpnt_envelope(dz))<0)
+			return(exit_status);
+		break;
+	case(ENV_CREATE):
+		if((exit_status = create_envelope(&cnt,dz))<0)
+			return(exit_status);
+		if((exit_status = store_brkpnt_envelope(cnt,dz))<0)
+			return(exit_status);
+		switch(dz->mode) {
+		case(ENV_ENVFILE_OUT):
+			if((exit_status = convert_brktable_to_envtable(dz->param[ENV_WSIZE] * MS_TO_SECS,&dz->env,&dz->envend,dz))<0)
+				return(exit_status);
+			if((exit_status = write_envel_to_envfile(dz->env,dz->envend,dz))<0)
+				return(exit_status);
+			break;
+		case(ENV_BRKFILE_OUT):
+			if((exit_status = write_brkpnt_data_to_file(dz))<0)
+				return(exit_status);
+			break;
+		default:
+			sprintf(errstr,"Unknown case: ENV_CREATE in process_envelope()\n");
+			return(PROGRAM_ERROR);
+		}
+		break;	
+	case(ENV_EXTRACT):
+		if((exit_status = extract_env_from_sndfile(&bufcnt,&envcnt,&dz->env,&dz->envend,0,dz))<0)
+			return(exit_status);
+		switch(dz->mode) {
+		case(ENV_ENVFILE_OUT):
+			if((exit_status = write_envel_to_envfile(dz->env,dz->envend,dz))<0)
+				return(exit_status);
+			break;
+		case(ENV_BRKFILE_OUT):
+ 			if((exit_status = convert_envelope_to_brkpnt_table(envcnt,dz->outfile->window_size * MS_TO_SECS,dz->duration,dz))<0)
+				return(exit_status);
+			if((exit_status = write_brkpnt_data_to_file(dz))<0)
+				return(exit_status);
+			break;
+		default:
+			sprintf(errstr,"Unknown case: ENV_EXTRACT in process_envelope()\n");
+			return(PROGRAM_ERROR);
+		}
+		break;
+	case(ENV_ENVTOBRK):
+	case(ENV_ENVTODBBRK):
+		if((exit_status = read_envel_from_envfile(&dz->env,&dz->envend,0,dz))<0)
+			return(exit_status);
+		envcnt = dz->envend - dz->env;
+		if((exit_status = convert_envelope_to_brkpnt_table(envcnt,dz->infile->window_size * MS_TO_SECS,dz->duration,dz))<0)
+			return(exit_status);
+		if(dz->process==ENV_ENVTODBBRK) {
+			if((exit_status = convert_brkvals_gain_to_dB(dz->extrabrkno,dz))<0)
+				return(exit_status);
+		}
+		if((exit_status = write_brkpnt_data_to_file(dz))<0)
+			return(exit_status);
+		break;
+	case(ENV_BRKTODBBRK):
+		if((exit_status = convert_brkvals_gain_to_dB(dz->extrabrkno,dz))<0)
+			return(exit_status);
+		if((exit_status = write_brkpnt_data_to_file(dz))<0)
+			return(exit_status);								  
+		break;
+	case(ENV_DBBRKTOBRK):
+		if((exit_status = convert_brkvals_db_to_gain(dz->extrabrkno,dz))<0)
+			return(exit_status);
+		if((exit_status = write_brkpnt_data_to_file(dz))<0)
+			return(exit_status);
+		break;
+	case(ENV_DBBRKTOENV):
+		if((exit_status = convert_brkvals_db_to_gain(dz->extrabrkno,dz))<0)
+			return(exit_status);
+		/* fall thro */
+	case(ENV_BRKTOENV):
+		if((exit_status = convert_brktable_to_envtable(dz->param[ENV_WSIZE] * MS_TO_SECS,&dz->env,&dz->envend,dz))<0)
+			return(exit_status);
+		if((exit_status = write_envel_to_envfile(dz->env,dz->envend,dz))<0)
+			return(exit_status);
+		break;
+	case(ENV_WARPING):
+
+		if(sloom) {
+			fprintf(stdout,"INFO: Extracting envelope from input soundfile.\n");
+			fflush(stdout);
+		}
+		if((exit_status = extract_env_from_sndfile(&bufcnt,&envcnt,&dz->origenv,&dz->origend,0,dz))<0)
+			return(exit_status);
+		if((exit_status = envcopy(dz->origenv,dz->origend,&dz->env,&dz->envend))<0)
+			return(exit_status);
+		if((exit_status = envelope_warp(&dz->env,&dz->envend,dz))<0)
+			return(exit_status);
+		switch(dz->mode) {
+		case(ENV_CORRUGATING): 	/* generated envelope applied directly to source */
+		case(ENV_TRIGGERING):	/* generated envelope applied directly to source */
+		case(ENV_PEAKCNT):
+			break;
+		default:
+			if((exit_status = envreplace(dz->env,&dz->envend,dz->origenv,dz->origend))<0)
+				return(exit_status);
+			break;
+		}				
+		if(dz->mode == ENV_PEAKCNT)
+			return(FINISHED);
+		if((exit_status = impose_envel_on_sndfile(dz->env,envcnt,bufcnt,0,dz))<0)
+			return(exit_status);
+		break;
+	case(ENV_RESHAPING):
+		if((exit_status = read_envel_from_envfile(&dz->env,&dz->envend,0,dz))<0)
+			return(exit_status);
+		if((exit_status = envelope_warp(&dz->env,&dz->envend,dz))<0)
+			return(exit_status);
+		if((exit_status = write_envel_to_envfile(dz->env,dz->envend,dz))<0)
+			return(exit_status);
+		break;
+	case(ENV_REPLOTTING):
+		if((exit_status = convert_brktable_to_envtable(dz->param[ENV_WSIZE] * MS_TO_SECS,&dz->env,&dz->envend,dz))<0)
+			return(exit_status);
+		if((exit_status = envelope_warp(&dz->env,&dz->envend,dz))<0)
+			return(exit_status);
+		envcnt = dz->envend - dz->env;
+		if((exit_status = convert_envelope_to_brkpnt_table(envcnt,dz->param[ENV_WSIZE] * MS_TO_SECS,dz->duration,dz))<0)
+			return(exit_status);
+		if((exit_status = write_brkpnt_data_to_file(dz))<0)
+			return(exit_status);
+		break;
+//TW NEW CASE
+	case(ENV_PROPOR):
+		return apply_brkpnt_envelope(dz);
+	case(ENV_IMPOSE):
+		switch(dz->mode) {
+		case(ENV_BRKFILE_IN):
+		case(ENV_DB_BRKFILE_IN):
+			return apply_brkpnt_envelope(dz);
+		case(ENV_ENVFILE_IN):
+			exit_status = read_envel_from_envfile(&dz->env,&dz->envend,1,dz);
+			break;
+		case(ENV_SNDFILE_IN):
+
+			if(sloom) {
+				fprintf(stdout,"INFO: Extracting envelope from input soundfile.\n");
+				fflush(stdout);
+			}
+			if((exit_status = extract_env_from_sndfile(&bufcnt,&envcnt,&dz->env,&dz->envend,1,dz))<0)
+				return(exit_status);
+			exit_status = rejig_buffering(dz);	/* deals with file2 having different srate or channels */
+			reset_filedata_counters(dz);
+			break;
+		default:
+			sprintf(errstr,"Unknown case for ENV_IMPOSE: in process_envelope()\n");
+			return(PROGRAM_ERROR);
+		}
+		if(exit_status<0)
+			return(exit_status);
+		bufcnt = buffers_in_sndfile(/*dz->bigbufsize*/dz->buflen,0,dz);
+		envcnt = dz->envend - dz->env;
+		if((exit_status = impose_envel_on_sndfile(dz->env,envcnt,bufcnt,0,dz))<0)
+			return(exit_status);
+		break;
+	case(ENV_REPLACE):
+		switch(dz->mode) {
+		case(ENV_ENVFILE_IN):
+			exit_status = read_envel_from_envfile(&dz->env,&dz->envend,1,dz);
+			if(sloom) {
+				fprintf(stdout,"INFO: Extracting envelope from input soundfile.\n");
+				fflush(stdout);
+			}
+			break;
+		case(ENV_BRKFILE_IN):
+		case(ENV_DB_BRKFILE_IN):
+//			exit_status = convert_brktable_to_envtable(dz->param[ENV_WSIZE] * MS_TO_SECS,&dz->env,&dz->envend,dz);
+			exit_status = convert_brktable_to_envtable
+			((double)(dz->iparam[ENV_SAMP_WSIZE]/dz->infile->channels)/(double)dz->infile->srate,&dz->env,&dz->envend,dz);
+			if(sloom) {
+				fprintf(stdout,"INFO: Extracting envelope from input soundfile.\n");
+				fflush(stdout);
+			}
+			break;
+		case(ENV_SNDFILE_IN):
+			if(sloom) {
+				fprintf(stdout,"INFO: Extracting envelope from 1st input soundfile.\n");
+				fflush(stdout);
+			}
+			if((exit_status = extract_env_from_sndfile(&bufcnt,&envcnt,&dz->env,&dz->envend,1,dz))<0)
+				return(exit_status);
+			exit_status = rejig_buffering(dz);	/* deals with file2 having different srate or channels */
+			reset_filedata_counters(dz);
+			break;
+		default:
+			sprintf(errstr,"Unknown case for ENV_REPLACE: in process_envelope()\n");
+			return(PROGRAM_ERROR);
+		}
+		if(exit_status<0)
+			return(exit_status);
+		envcnt = dz->envend - dz->env;
+
+		if(sloom) {
+			fprintf(stdout,"INFO: Extracting envelope from 2nd input soundfile.\n");
+			fflush(stdout);
+		}
+		if((exit_status = extract_env_from_sndfile(&bufcnt,&other_envcnt,&dz->origenv,&dz->origend,0,dz))<0)
+			return(exit_status);
+		if((exit_status = envreplace(dz->env,&dz->envend,dz->origenv,dz->origend))<0)
+			return(exit_status);
+		if((exit_status = impose_envel_on_sndfile(dz->env,envcnt,bufcnt,0,dz))<0)
+			return(exit_status);
+		break;
+	case(ENV_PLUCK):
+		if((exit_status = envelope_pluck(dz))<0)
+			return(exit_status);
+		break;
+	case(ENV_TREMOL):
+		if((exit_status = envelope_tremol(dz))<0)
+			return(exit_status);
+		break;
+	default:
+		sprintf(errstr,"Unknown case in process_envelope()\n");
+		return(PROGRAM_ERROR);
+	}
+	return FINISHED;
+}
+
+/**************************** REJIG_BUFFERING ******************************
+ *
+ * recreates buffering to deal with 1ST file, once 2ND file has been dealt with!!
+ */
+
+int rejig_buffering(dataptr dz)
+{
+	int exit_status;
+	if(dz->otherfile->srate    != dz->infile->srate
+	|| dz->otherfile->channels != dz->infile->channels) {
+		if((exit_status = generate_samp_windowsize(dz->infile,dz)) < 0)
+			return(exit_status);			
+		free(dz->bigbuf);
+		if((exit_status = create_sndbufs_for_envel(dz)) < 0)
+			return(exit_status);
+	}
+	return(FINISHED);
+}
+
+/*************************** READ_ENVEL_FROM_ENVFILE **************************/
+
+int read_envel_from_envfile(float **env,float **envend,int fileno,dataptr dz)
+{
+	int samps_read /*, samps_to_read, secs_to_read*/;
+	int envlen = dz->insams[fileno];
+#ifdef NOTDEF
+	if(((secs_to_read = dz->infilesize[fileno]/SECSIZE)*SECSIZE)!=dz->infilesize[fileno])
+		secs_to_read++;
+	bytes_to_read = secs_to_read * SECSIZE;	
+#endif
+	if((*env = (float *)malloc(/*bytes_to_read*/envlen * sizeof(float)))==NULL) {
+		sprintf(errstr,"INSUFFICIENT MEMORY for envelope array.\n");
+		return(MEMORY_ERROR);
+	}
+	if((samps_read = fgetfbufEx(*env, envlen,dz->ifd[fileno],0)) < 0) {
+		sprintf(errstr,"Can't read samples from input envelfile\n");
+		return(SYSTEM_ERROR);
+	}
+#ifdef NOTDEF
+	if((*env = (float *)realloc(*env,dz->insams[fileno]))==NULL) {
+		sprintf(errstr,"INSUFFICIENT MEMORY to reallocate envelope array.\n");
+		return(MEMORY_ERROR);
+	}
+#endif
+	*envend = *env + envlen;
+	return(FINISHED);
+}
+
+/*************************** ENVCOPY [ENVMOVE] *****************************
+ * moves envelope from array env1 to array pointed to by env2.
+ * returns the end+1 address of env2 array.
+ */
+
+int envcopy(float *envel1,float *envend1,float **envel2,float **envend2)
+{
+	float *p, *q;
+	int tabsize = envend1 - envel1;
+	if(*envel2 != NULL)
+		free(*envel2);
+	if((*envel2 = (float *)malloc(tabsize * sizeof(float)))==NULL) {
+		sprintf(errstr,"INSUFFICIENT MEMORY to copy envelope array.\n");
+		return(MEMORY_ERROR);
+	}
+	p = envel1;
+	q = *envel2;
+	while(p<envend1)
+		*q++ = *p++;
+	*envend2 = q;
+	return(FINISHED);
+}
+
+/****************************** CONVERT_ENVELOPE_TO_BRKPNT_TABLE [ENVTOBRK]*********************************
+ *
+ * window_size is in seconds.
+ */
+
+int convert_envelope_to_brkpnt_table(int envcnt,double window_size,double infiledur,dataptr dz)
+{
+	int exit_status;
+	double *q;
+	float  *p = dz->env;
+	double inc = window_size, lasttime, thisreduce = BASE_REDUCE;
+	int bcnt, n, final_size;
+	int paramno = dz->extrabrkno;
+	int add_last_val = FALSE;
+	int orig_bcnt;
+
+	if(window_size <= 0.0) {
+		sprintf(errstr,"No window_size set: convert_envelope_to_brkpnt_table()\n");
+		return(PROGRAM_ERROR);
+	}
+	if(paramno < 0) {
+		sprintf(errstr,"extrabuf not set up: convert_envelope_to_brkpnt_table()\n");
+		return(PROGRAM_ERROR);
+	}
+	if(dz->brk[paramno]!=NULL)
+		free(dz->brk[paramno]);
+	if((dz->brk[paramno] = (double *)malloc(envcnt * sizeof(double) * 2))==NULL) {
+		sprintf(errstr,"INSUFFICIENT MEMORY to convert envelope to brkpnt table.\n");
+		return(MEMORY_ERROR);
+	}
+
+	q = dz->brk[paramno];
+	for(n=0;n<envcnt;n++) {
+		*q++ = (double)n * inc;
+		*q++ = (double)*p++;
+	}
+	bcnt = envcnt * 2;
+	while(bcnt >= 6 && thisreduce < dz->param[ENV_DATAREDUCE]) {	/* RWD improvement --> */
+		q = dz->brk[paramno] + 4;								/* incremental datareduction */
+		orig_bcnt = bcnt;
+		for(n=4;n<orig_bcnt;n+=2) {									
+			q += 2;												
+			q = datareduce(q,thisreduce,&bcnt,paramno,dz);						
+		}															
+		thisreduce += BASE_REDUCE;								
+	}															
+	if(bcnt >= 6) {												
+		q = dz->brk[paramno] + 4;								
+		orig_bcnt = bcnt;
+		for(n=4;n<orig_bcnt;n+=2) {									
+			q += 2;												
+			q = datareduce(q,dz->param[ENV_DATAREDUCE],&bcnt,paramno,dz);		
+		}														
+	}
+	n = bcnt;
+	if(ODD(n)) {
+		sprintf(errstr,"convert_envelope_to_brkpnt_table(): Problem of event pairing.\n");
+		return(PROGRAM_ERROR);
+	}
+	lasttime = *(q-2);
+	final_size = n;
+	if(flteq(lasttime,infiledur)) {
+		*(q-2) = infiledur;
+		final_size = n;
+	} else if(lasttime < infiledur) {
+		final_size = n+2;
+		add_last_val = TRUE;
+	} else {
+ 		if(q-4 >= dz->brk[paramno]) {
+			if((exit_status = adjust_last_val_of_brk(dz->brk[paramno],q,&final_size,infiledur))<0)
+				return(exit_status);
+		}
+	} 				
+	if((dz->brk[paramno] = (double *)realloc(dz->brk[paramno],final_size * sizeof(double)))==NULL) {
+		sprintf(errstr,"INSUFFICIENT MEMORY to reallocate new brkpnt table.\n");
+		return(MEMORY_ERROR);
+	}
+	if(add_last_val) {
+		*(dz->brk[paramno] + final_size - 2) = infiledur;
+		*(dz->brk[paramno] + final_size - 1) = *(dz->brk[paramno] + final_size - 3);
+	}
+	dz->brkptr[paramno]  = dz->brk[paramno];
+	dz->brksize[paramno] = final_size/2;
+	return(FINISHED);
+}
+    
+/***************************** DATAREDUCE **********************
+ * Reduce data on passing from envelope to brkpnt representation.
+ *
+ * Take last 3 points, and if middle point has (approx) same value as
+ * a point derived by interpolating between first and last points, then
+ * ommit midpoint from brkpnt representation.
+ */
+
+double *datareduce(double *q,double datareduction,int *bcnt,int paramno,dataptr dz)
+{
+	double *p   = q-6, *midpair = q-4, *endpair = q-2, *tabend;
+	double startime = *p++;
+	double startval = sqrt(*p++);	/* RWD improvement: in power case, take sqrt */
+	double midtime  = *p++;
+	double midval   = sqrt(*p++);
+	double endtime  = *p++;
+	double endval   = sqrt(*p);
+	double valrange     = endval - startval;
+	double midtimeratio = (midtime-startime)/(endtime-startime);
+	double guessval     = (valrange * midtimeratio) + startval;
+	if(fabs(guessval - midval) < datareduction) {
+		tabend = dz->brk[paramno] + (*bcnt);
+		while (endpair < tabend) {		
+			*midpair++ = *endpair++;
+		}
+		(*bcnt) -= 2;
+		q -= 2;
+	}
+	return(q);
+}
+
+/****************************** CONVERT_BRKTABLE_TO_ENVTABLE [BRKTOENV] *********************************
+ * convert brkpnt table to envelope table 
+ *
+ * Assume envelope space has already beem mallocd().
+ *
+ * window_size is in SECS.
+ */
+
+int convert_brktable_to_envtable(double window_size,float **env,float **envend,dataptr dz)
+{
+	int exit_status;
+	int   n, envlen;
+	float  *q;
+	double here = 0.0;
+	double inc = window_size;
+	int    paramno = dz->extrabrkno;
+	double duration;
+
+	if(paramno < 0) {
+		sprintf(errstr,"extrabuf not set up: convert_brktable_to_envtable()\n");
+		return(PROGRAM_ERROR);
+	}
+	duration = *(dz->brk[paramno] + ((dz->brksize[paramno]-1)*2));
+	if(window_size <= 0.0) {
+		sprintf(errstr,"No window_size set: convert_brktable_to_envtable()\n");
+		return(PROGRAM_ERROR);
+	}
+	if(inc < ENV_MIN_WSIZE * MS_TO_SECS) {
+		sprintf(errstr,"Invalid window_size: convert_brktable_to_envtable()\n");
+		return(PROGRAM_ERROR);
+	}
+	if(duration < inc) {
+		sprintf(errstr,"Brktable duration less than window_size: Cannot proceed.\n");
+		return(DATA_ERROR);
+	}
+	envlen = (int)((duration/inc) + 1.0);  /* round up */
+	envlen += MARGIN;                  		/* allow for errors in float-calculation */
+	if(dz->brk[paramno]==NULL) {
+		sprintf(errstr,"No existing brkpnt table. convert_brktable_to_envtable()\n");
+		return(PROGRAM_ERROR);
+	}
+	if(dz->brksize[paramno]<2) {
+		sprintf(errstr,"Brkpnt table length invalid: convert_brktable_to_envtable()\n");
+		return(PROGRAM_ERROR);
+	}
+	if(*env != NULL)
+		free(*env);
+	if((*env = (float *)malloc(envlen * sizeof(float)))==NULL) {
+		sprintf(errstr,"INSUFFICIENT MEMORY for envelope array.\n");
+		return(MEMORY_ERROR);
+	}
+	q = *env;
+	n = 0;
+	while(n<envlen) {
+		if((here = (double)n * inc)>(duration+FLTERR))
+			break;
+		if((exit_status = read_value_from_brktable_from_brkpntfile(here,q,dz))<0)
+			return(exit_status);
+		q++;
+		n++;
+	}
+	if(here<duration) {
+		sprintf(errstr,"Not all of brkpnt table transferred: convert_brktable_to_envtable()\n");
+		return(PROGRAM_ERROR);
+	}
+	envlen = n;
+	if((*env = (float *)realloc(*env,envlen * sizeof(float)))==NULL) {
+		sprintf(errstr,"INSUFFICIENT MEMORY to reallocate envelope array.\n");
+		return(MEMORY_ERROR);
+	}
+	*envend = *env + envlen;
+	return(FINISHED);
+}
+
+/*************************** WRITE_BRKPNT_DATA_TO_FILE [FPUT_BRK] *****************************/
+
+int write_brkpnt_data_to_file(dataptr dz)
+{   
+	double *p;
+	int n, cnt;
+	int paramno = dz->extrabrkno;
+	if(paramno < 0) {
+		sprintf(errstr,"extrabrkno not set: write_brkpnt_data_to_file()\n");
+		return(PROGRAM_ERROR);
+	}
+	p = dz->brk[paramno];
+	cnt = dz->brksize[paramno];
+	for(n=0;n<cnt;n++) {
+		if((fprintf(dz->fp,"%lf\t%lf\n",*p,*(p+1)))<2) {
+			sprintf(errstr,"fput_brk(): Problem writing brkpnt data to file.\n");
+			return(PROGRAM_ERROR);
+		}
+		p += 2;
+	}
+/*
+	if(fclose(dz->fp)<0)  {
+		fprintf(stdout,"WARNING: Failure to close brkpnt data output file.\n");
+		fflush(stdout);
+	}
+*/
+	return(FINISHED);
+}
+
+/*************************** WRITE_ENVEL_TO_ENVFILE ***************************/
+
+int write_envel_to_envfile(float *env,float *envend,dataptr dz)
+{
+	int envlen = envend - env;
+	int samps_to_write = envlen  /* * sizeof(float)*/;
+	int exit_status;
+#ifdef NOTDEF
+	int pseudo_bytes_to_write;
+	int secs_to_write = bytes_to_write/SECSIZE;
+	int bytes_written;
+	if((secs_to_write * SECSIZE)!=bytes_to_write)
+		secs_to_write++;
+	pseudo_bytes_to_write = secs_to_write * SECSIZE;
+#else
+	int samps_written;
+#endif
+	if(samps_to_write > 0) {
+		if((exit_status = write_samps_no_report(env,samps_to_write,&samps_written,dz))<0)
+			return(SYSTEM_ERROR);
+		else if(samps_written  == 0) {
+			sprintf(errstr,"No data written to output envelfile.\n");
+			return(SYSTEM_ERROR);
+		}
+	}
+	return(FINISHED);
+}
+
+/*************************** ADJUST_LAST_VAL_OF_BRK ***************************/
+
+int adjust_last_val_of_brk(double *brk,double *brkend,int *datacnt,double endtime)
+{
+	double *q = brkend - 4;
+	double penulttime, penultval, lasttime, lastval, timeratio, valdiff;
+	while(*q > endtime+FLTERR) {
+		q -= 2;
+		if(q < brk) {
+			sprintf(errstr,"Cannot adjust last brkval: adjust_last_val_of_brk()\n");
+			return(PROGRAM_ERROR);
+		}
+	}
+	if(flteq(*q,endtime)) {
+		*q = endtime;
+		q += 2;
+		*datacnt = (q - brk)/2;
+	} else {
+		penulttime   = *(q);
+		penultval    = *(q+1);
+		lasttime     = *(q+2);
+		lastval      = *(q+3);
+		timeratio    = (endtime - penulttime)/(lasttime - penulttime);
+		valdiff      = timeratio * (lastval - penultval);
+		*(q+2) = lasttime;
+		*(q+3) = penultval + valdiff;
+		q += 4;
+		*datacnt = (q - brk)/2;
+	}
+	return(FINISHED);
+}
+
+/***************************** STORE_BRKPNT_ENVELOPE *****************************/
+
+int store_brkpnt_envelope(int cnt,dataptr dz)
+{
+	int paramno = dz->extrabrkno;
+	int n;
+	double *p;																			  
+	if(paramno < 0) {
+		sprintf(errstr,"extrabrkno not established: store_brkpnt_envelope()\n");
+		return(PROGRAM_ERROR);
+	}
+	if(dz->brk[paramno]!=NULL) {
+		sprintf(errstr,"extrabrktable already exists: store_brkpnt_envelope()\n");
+		return(PROGRAM_ERROR);
+	}
+	if((dz->brk[paramno] = (double *)malloc(cnt * 2 * sizeof(double)))==NULL) {
+		sprintf(errstr,"INSUFFICIENT MEMORY for brkpnt envelope array.\n");
+		return(MEMORY_ERROR);
+	}
+	p = dz->brk[paramno];
+	for(n=0;n<cnt;n++) {
+		*p++ = dz->parray[ENV_CREATE_TIME][n];
+		*p++ = dz->parray[ENV_CREATE_LEVL][n];
+	}
+	dz->brksize[paramno] = cnt;
+	dz->brkptr[paramno]  = dz->brk[paramno];
+	free(dz->parray[ENV_CREATE_TIME]);
+	free(dz->parray[ENV_CREATE_LEVL]);
+	dz->parray[ENV_CREATE_TIME] = (double *)0;
+	dz->parray[ENV_CREATE_LEVL] = (double *)0;
+	return(FINISHED);
+}
+
+/**************************** READ_VALUE_FROM_BRKTABLE_FROM_BRKPNTFILE *****************************/
+
+int read_value_from_brktable_from_brkpntfile(double thistime,float *thisval,dataptr dz)
+{
+    double *endpair, *p, val;
+    double hival, loval, hiind, loind;
+	int paramno = dz->extrabrkno;
+    if(!dz->brkinit[paramno]) {
+		dz->brkptr[paramno]   = dz->brk[paramno];
+		dz->firstval[paramno] = *(dz->brk[paramno]+1);
+		endpair                 = dz->brk[paramno] + ((dz->brksize[paramno]-1)*2);
+		dz->lastind[paramno]  = *endpair;
+		dz->lastval[paramno]  = *(endpair+1);
+ 		dz->brkinit[paramno] = 1;
+    }
+	p = dz->brkptr[paramno];
+	if(thistime <= *(dz->brk[paramno])) {
+		*thisval = (float)dz->firstval[paramno];
+		return(FINISHED);
+	} else if(thistime >= dz->lastind[paramno]) {
+		*thisval = (float)dz->lastval[paramno];
+		return(FINISHED);
+	} 
+	if(thistime > *p) {
+		while(*p < thistime)
+			p += 2;
+	} else {
+		while(*p >= thistime)
+			p -= 2;
+		p += 2;
+	}
+	hival  = *(p+1);
+	hiind  = *p;
+	loval  = *(p-1);
+	loind  = *(p-2);
+	val    = (thistime - loind)/(hiind - loind);
+	val   *= (hival - loval);
+	val   += loval;
+	*thisval  = (float)val;
+ 	dz->brkptr[paramno] = p;
+    return(FINISHED);
+}
+
+/******************************** CONVERT_BRKVALS_DB_TO_GAIN *************************/
+
+int convert_brkvals_db_to_gain(int paramno,dataptr dz)
+{
+	int exit_status;
+	double *p = dz->brk[paramno];
+	double *pend = p + (dz->brksize[paramno] * 2);
+	p++;
+	while(p < pend) {
+		if((exit_status = convert_dB_at_or_below_zero_to_gain(p))<0)
+			return(exit_status);
+		p += 2;
+	}
+	return(FINISHED);
+}
+
+/******************************** CONVERT_BRKVALS_GAIN_TO_DB *************************/
+
+int convert_brkvals_gain_to_dB(int paramno,dataptr dz)
+{
+	int exit_status;
+	double *p = dz->brk[paramno];
+	double *pend = p + (dz->brksize[paramno] * 2);
+	p++;
+	while(p < pend) {
+		if((exit_status = convert_normalised_gain_val_to_dB(p))<0)
+			return(exit_status);
+		p += 2;
+	}
+	return(FINISHED);
+}
+
+/**************************** CONVERT_NORMALISED_GAIN_VAL_TO_DB ********************************/
+
+int convert_normalised_gain_val_to_dB(double *val)
+{
+	double thisval = *val;
+	double mingain = 1.0/pow(10,(-MIN_DB_ON_16_BIT/20.0));
+	if(thisval > 1.0 || thisval < 0.0) {
+		sprintf(errstr,"convert_normalised_gain_vals_to_dB() received non-normalised gain\n");
+		return(PROGRAM_ERROR);
+	}
+	if(thisval <= mingain)
+		*val = MIN_DB_ON_16_BIT;
+	else {
+		thisval  = 1.0/thisval;
+		thisval  = log10(thisval);
+		thisval *= 20.0;
+		thisval  = -thisval;
+		*val = thisval;
+	}
+	return(FINISHED);
+}

+ 131 - 0
dev/env/envxtract.c

@@ -0,0 +1,131 @@
+/*
+ * 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 <structures.h>
+#include <tkglobals.h>
+#include <globcon.h>
+#include <processno.h>
+#include <modeno.h>
+#include <arrays.h>
+#include <envel.h>
+#include <cdpmain.h>
+
+#include <sfsys.h>
+
+static void getenv_of_buffer
+			(int samps_to_process,int envwindow_sampsize,double convertor,float **envptr,float *buffer);
+static double  getmaxsamp(int startsamp, int cnt,float *buffer);
+
+/******************************** EXTRACT_ENV_FROM_SNDFILE [GETENV] *****************************
+ *
+ * NB THIS ALWAYS GETS ENVELOPE FROM sampbuf[0] !!!
+ */
+
+int extract_env_from_sndfile(int *bufcnt,int *envcnt,float **env,float **envend,int fileno,dataptr dz)
+{
+	int n;
+	double convertor = 1.0/F_ABSMAXSAMP;
+	float *envptr;
+	int envwindow_sampsize = dz->iparam[ENV_SAMP_WSIZE];
+	float *buffer = dz->sampbuf[0];
+	*bufcnt = buffers_in_sndfile(dz->buflen,fileno,dz);
+	*envcnt = windows_in_sndfile(fileno,dz);
+	if((*env=(float *)malloc((*envcnt+20) * sizeof(float)))==NULL) {
+		sprintf(errstr,"INSUFFICIENT MEMORY for envelope array.\n");
+		return(MEMORY_ERROR);
+	}
+	envptr = *env;
+	for(n = 0; n < *bufcnt; n++)	{
+		if((dz->ssampsread = fgetfbufEx(dz->sampbuf[0], dz->buflen,dz->ifd[fileno],0)) < 0) {
+			sprintf(errstr,"Can't read samples from soundfile: extract_env_from_sndfile()\n");
+			return(SYSTEM_ERROR);
+		}
+		if(sloom)
+			display_virtual_time(dz->total_samps_read,dz);		
+		getenv_of_buffer(dz->ssampsread,envwindow_sampsize,convertor,&envptr,buffer);
+	}
+	*envend = envptr;
+	return(FINISHED);
+}
+
+/************************* GETENV_OF_BUFFER [READENV] *******************************/
+
+void getenv_of_buffer(int samps_to_process,int envwindow_sampsize,double convertor,float **envptr,float *buffer)
+{
+	int  start_samp = 0;
+	float *env = *envptr;
+	while(samps_to_process >= envwindow_sampsize) {
+		*env++       = (float) (getmaxsamp(start_samp,envwindow_sampsize,buffer) * convertor);
+		start_samp  += envwindow_sampsize;
+		samps_to_process -= envwindow_sampsize;
+	}
+	if(samps_to_process)	/* Handle any final short buffer */
+		*env++ = (float)(getmaxsamp(start_samp,samps_to_process,buffer) * convertor);
+	*envptr = env;
+}
+
+/****************************** BUFFERS_IN_SNDFILE [BUFFER_CNT] ******************************/
+
+int buffers_in_sndfile(int buffer_size,int fileno,dataptr dz)
+{
+	int bufcnt;
+	if(((bufcnt = dz->insams[fileno]/buffer_size)*buffer_size)!=dz->insams[0])
+		bufcnt++;
+	return(bufcnt);
+}
+
+/****************************** WINDOWS_IN_SNDFILE [GET_ENVSIZE] ******************************
+ *
+ * Find samp-length of soundfiles, number of whole buffers this corresponds
+ * to (bufcnt) and number of whole sectors reamining (nsec).
+ */
+
+int windows_in_sndfile(int fileno,dataptr dz)
+{
+	int envsize, winsize = dz->iparam[ENV_SAMP_WSIZE];
+	if(((envsize = dz->insams[fileno]/winsize) * winsize)!=dz->insams[fileno])
+		envsize++;
+	return(envsize);
+}
+
+/*************************** GETMAXSAMP ******************************
+ *
+ * REVERTED TO FINDING largest sample in window, rather than POWER.
+ */
+
+/*int*/double getmaxsamp(int startsamp, int sampcnt,float *buffer)
+{
+	int  i, endsamp = startsamp + sampcnt;
+	double thisval, thismaxsamp = 0.0;
+	for(i = startsamp; i<endsamp; i++) {
+		if((thisval =  fabs(buffer[i]))>thismaxsamp)		   
+			thismaxsamp = thisval;
+	}
+	return thismaxsamp;
+}

+ 254 - 0
dev/env/main.c

@@ -0,0 +1,254 @@
+/*
+ * 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 <envel.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 <string.h>
+
+
+char errstr[2400];
+
+#define EXCEPTION -10
+
+/*extern*/ int	sloom = 0;
+/* TW May 2001 */
+/*extern*/ int sloombatch = 0;	/*TW may 2001 */
+	
+/*extern*/ int anal_infiles = 0;
+/*extern*/ int is_converted_to_stereo = -1;
+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);
+		}
+					  /* GET PRE_DATA, ALLOCATE THE APPLICATION, CHECK FOR EXTRA INFILES */
+		cmdline    = argv;
+		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!=ENV_CREATE && dz->process!=ENVSYN) {
+		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->process!=ENV_CREATE && dz->process!=ENVSYN) {
+		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(dz->mode == ENV_PEAKCNT)
+		dz->process_type = OTHER_PROCESS;
+
+	if((exit_status = complete_output(dz))<0) {
+		print_messages_and_close_sndfiles(exit_status,is_launched,dz);
+		return(FAILED);
+	}
+	if(dz->mode == ENV_PEAKCNT && exit_status == FINISHED)
+		exit_status = EXCEPTION;
+
+	exit_status = print_messages_and_close_sndfiles(FINISHED,is_launched,dz);
+	free(dz);
+	return(SUCCEEDED);
+}
+

+ 475 - 0
dev/env/pluck.c

@@ -0,0 +1,475 @@
+/*
+ * 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 <globcon.h>
+#include <processno.h>
+#include <modeno.h>
+#include <arrays.h>
+#include <filetype.h>
+#include <envel.h>
+#include <cdpmain.h>
+
+#include <sfsys.h>
+#include <osbind.h>
+
+
+static int  do_wrap(int samps_to_wrap,dataptr dz);
+static int  read_rest_of_file(int initial_bufsize,dataptr dz);
+static int  pluck(dataptr dz);
+static int envsyn_env(int *phase,int cyclestart,int *cycle_end,double one_less_trof,dataptr dz);
+
+static int  	envsyn_troffed(int cyclestart,int *cyclend,double one_less_trof,int *phase,dataptr dz);
+static int 		envsyn_userdef(int cyclestart,int *cyclend,int *phase,dataptr dz);
+static int  	envsyn_rising( int cyclestart,int *cyclend,double one_less_trof,int *phase,dataptr dz);
+static int  	envsyn_falling(int cyclestart,int *cyclend,double one_less_trof,int *phase,dataptr dz);
+
+static double	do_firsthalf_trof(int k,int cyclehlf,double one_less_trof,dataptr dz);
+static double	do_lasthalf_trof(int k,int cyclehlf,double one_less_trof,dataptr dz);
+static double	do_rising(int k,int cyclelen,double one_less_trof,dataptr dz);
+static double	do_falling(int k,int cyclelen,double one_less_trof,dataptr dz);
+
+static int		read_from_user_envelope(double *env_val,double table_index,int init,dataptr dz);
+
+/****************************** ENVELOPE_PLUCK *************************/
+
+int envelope_pluck(dataptr dz)
+{
+	
+	int exit_status;
+	int initial_bufsize;
+	int first_read_offset = dz->sampbuf[PLK_INITBUF] - dz->bigbuf;
+	dz->buflen -= first_read_offset;			/* size of buffer from where first read takes place */
+	if((exit_status = read_samps(dz->sampbuf[PLK_INITBUF],dz))<0)
+		return(exit_status);		
+	initial_bufsize = dz->buflen;
+    if((exit_status = pluck(dz))<0)
+		return(exit_status);		
+	dz->buflen = dz->iparam[ENV_PLK_OBUFLEN];		/* size of buffer for subsequent reads */
+    return read_rest_of_file(initial_bufsize,dz);
+}
+
+/**************************** PLUCK ******************************
+ *
+ * (1)  goalbufend is the last sample of the cycle in the input file buffer from which we will
+ *      derive the pluck attack. We read it backwards, from this LAST sample.
+ * (2)  The outplukptr points to the position in the output buffer where we
+ *      are WRITING pluck-form wavecycles. We write these BKWDS
+ *		from here to start of dz->sampbuf[PLK_OUTBUF].
+ * (3)	Set goalbufptr to start(i.e. end!!) of goalbuf.
+ * (4)	Inverse_index is a BACKWARDS count of the samples in the pluck.
+ * (5)	For each wavecycle of Pluck attack..
+ * (6) 	For each sample in wavecycle....
+ * (7) 	Noiselevel is directly proportional to distance (bkwds) into pluck.
+ * (8)	Then reduced via exponential curve.
+ * (9)	Becoming this fraction of the maximum amplitude.
+ * (10)	Noise input itself is a random value in range +- this noiselevel value.
+ * (11) Reinitialise goalbufptr for eack wavecycle.
+ * (13a)By the time we reach the start of the pluck, signal will cause#
+ *		spurious foldover when added to orig signal: but this will simply make
+ *		it more like noise!!
+ * (12)	Calculate sample length of initial risetime.
+ * (13)	Finally, envelope start of pluck!!
+ */
+
+int pluck(dataptr dz)
+{
+	int   n, m, inverse_index;
+	float  *goalbufend, *goalbufptr, *outplukptr;
+	double noise_level;
+	/*int*/double   thisnoise;
+    int   startup;
+	int   pluklen = dz->iparam[ENV_PLK_CYCLEN] * dz->iparam[ENV_PLK_WAVELEN];
+	if((goalbufend = dz->sampbuf[PLK_PLUKEND] + dz->iparam[ENV_PLK_WAVELEN] - 1) >=dz->sampbuf[PLK_BUFEND]) {
+		sprintf(errstr,"End of goal pluck_cycle falls outside buffer: Insufficient memory to proceed.\n");  
+		return(GOAL_FAILED);												/* 1 */
+	}	
+	if((outplukptr = dz->sampbuf[PLK_PLUKEND]  - 1) < dz->bigbuf) {			/* 2 */
+		sprintf(errstr,"Buffer accounting problem.\n");  
+		return(PROGRAM_ERROR);
+	}	
+	goalbufptr = goalbufend;												/* 3 */
+	inverse_index = 0;														/* 4 */
+	for(n=0;n<dz->iparam[ENV_PLK_CYCLEN];n++) {								/* 5 */
+		for(m=0;m<dz->iparam[ENV_PLK_WAVELEN];m++) {						/* 6 */
+			noise_level = (double)inverse_index/(double)pluklen; 			/* 7 */
+			noise_level = pow(noise_level,dz->param[ENV_PLK_DECAY]);		/* 8 */
+			noise_level = noise_level * (double)F_MAXSAMP;					/* 9 */
+			thisnoise   = /*round*/ (((drand48() * 2.0) - 1.0) * noise_level);	/* 10 */
+			*outplukptr = (float)((*goalbufptr) + thisnoise);
+			outplukptr--;
+			goalbufptr--;
+			inverse_index++;
+		}
+		goalbufptr = goalbufend;											/* 11 */
+	}
+    startup = round(ENV_PLK_ONSET_TIME * MS_TO_SECS * (double)dz->infile->srate); /* 12 */
+	startup = min(startup,dz->iparam[ENV_PLK_CYCLEN] * dz->iparam[ENV_PLK_WAVELEN]);
+	for(n=0;n<startup;n++) {
+		outplukptr++;														/* 13 */
+		*outplukptr = (float) /*round */(*outplukptr * (double)n/(double)startup);
+	}	
+	return(FINISHED);
+}
+
+/*********************** READ_REST_OF_FILE ************************
+ *
+ * (1)	If the input buffer was NOT filled, then we must be at end of file: so write data and return.
+ * (2)	Samples to write is those read,
+ *		MINUS the length of initial replaced segment (dz->iparam[ENV_PLK-STSAMP])
+ *		PLUS  the added initial segment (dz->iparam[ENV_PLK_OWRAPLEN]).
+ *	 ELSE
+ * (3)	Write a standard buffer_full, from start of obuf_preflow (where pluck has been constructed).
+ * (4)  This leaves, [ENV_PLK_OWRAPLEN] samples in end of dz->sampbuf[PLK_OUTBUF],
+ *      SO   samps_to_wrap = [ENV_PLK_OWRAPLEN];
+ * (6)  Do the wrap-around.
+ * (8)  Whilst ever there is something in wrap-around part of buffer...
+ * (10)	Try to read more samples (may get full-buff, part-buf 
+ *		or zero if file already exhausted).
+ * (11)	Total samps to write is the wrapped samps plus those just read.
+ * (12) If this leaves no samps to wrap (i.e. buffer is NOT full, therefore FILE must be exhausted), 
+ *		write all these samps to out and quit.
+ * (13)	ELSE, write a bufferfull and do another wrap-around.
+ */
+
+int read_rest_of_file(int initial_bufsize,dataptr dz)
+{
+	int  exit_status;
+	int samps_to_write, samps_to_wrap;
+	int pluklen = dz->iparam[ENV_PLK_CYCLEN] * dz->iparam[ENV_PLK_WAVELEN];
+
+	if(dz->ssampsread < (int)(initial_bufsize)) {										/* 1 */
+		if((samps_to_write = dz->ssampsread - dz->iparam[ENV_PLK_ENDSAMP] + pluklen)>0) { /* 2 */
+			if((exit_status = write_samps(dz->sampbuf[PLK_OUTBUF],samps_to_write,dz))<0)
+				return(exit_status);
+		}
+	} else {
+		if((exit_status = write_samps(dz->sampbuf[PLK_OUTBUF],dz->buflen,dz))<0)			/* 3 */
+			return(exit_status);
+		samps_to_wrap = dz->iparam[ENV_PLK_OWRAPLEN];													/* 4 */
+		if((exit_status = do_wrap(samps_to_wrap,dz))<0)													/* 6 */
+			return(exit_status);
+		while(samps_to_wrap > 0) {																		/* 8 */
+			if((exit_status = read_samps(dz->sampbuf[PLK_INBUF],dz))<0)							/* 10 */
+				return(exit_status);
+			samps_to_write = samps_to_wrap + dz->ssampsread;        									/* 11 */
+			if((samps_to_wrap = samps_to_write - dz->buflen) <= 0) {									/* 12 */
+				if(samps_to_write > 0) {
+					if((exit_status = write_samps(dz->sampbuf[PLK_OUTBUF],samps_to_write,dz))<0)
+						return(exit_status);
+				}
+			} else {
+				if((exit_status = write_samps(dz->sampbuf[PLK_OUTBUF],dz->buflen,dz))<0)	/* 13 */
+					return(exit_status);
+				if((exit_status = do_wrap(samps_to_wrap,dz))<0)														
+					return(exit_status);
+			}
+		}
+	}						
+	return(FINISHED);
+}
+
+/*********************** DO_WRAP ************************/
+
+int do_wrap(int samps_to_wrap,dataptr dz) 
+{
+	memmove((char *)dz->sampbuf[PLK_OUTBUF],(char *)dz->sampbuf[PLK_OBUFWRAP],(samps_to_wrap)*sizeof(float));
+	return(FINISHED);
+}
+
+/************************** ENVSYN **************************/
+
+int envsyn(dataptr dz)
+{
+	int exit_status;
+	int current_pos = 0, cyclelen, cycle_end, done = 0;
+	int phase, initial_phase;
+	double thistime = 0.0, one_less_trof;
+	int samps_needed;
+
+	dz->param[ENVSYN_WSIZE] *= MS_TO_SECS;
+	samps_needed = (int)floor((dz->param[ENVSYN_DUR]/ dz->param[ENVSYN_WSIZE]) + 1);
+	dz->tempsize = samps_needed  * sizeof(float);
+	if((exit_status = read_values_from_all_existing_brktables(thistime,dz)) < 0)
+		return(exit_status);
+	one_less_trof = 1.0 - dz->param[ENVSYN_TROF];
+	cyclelen = (int)round(dz->param[ENVSYN_CYCLEN]/dz->param[ENVSYN_WSIZE]);
+	cycle_end = cyclelen;
+	phase  = (int)round((double)cyclelen * dz->param[ENVSYN_STARTPHASE]);
+	initial_phase = phase;
+	for (;;) {
+		if(cyclelen < 2) {
+			sprintf(errstr,"ENVELOPE DURATION TOO SHORT FOR WINDOWSIZE at time %lf\n",
+			(dz->total_samps_written + current_pos) * dz->param[ENV_WSIZE]);
+			return(DATA_ERROR);
+		}
+		if((exit_status = envsyn_env(&phase,current_pos,&cycle_end,one_less_trof,dz))< 0)
+			return(exit_status);
+		if((done += cyclelen) >= samps_needed + initial_phase)
+			break;
+		thistime += dz->param[ENVSYN_CYCLEN];
+		if((exit_status = read_values_from_all_existing_brktables(thistime,dz)) < 0)
+			return(exit_status);
+		one_less_trof = 1.0 - dz->param[ENVSYN_TROF];
+		cyclelen = (int)round(dz->param[ENVSYN_CYCLEN]/dz->param[ENVSYN_WSIZE]);
+		current_pos = cycle_end;
+		cycle_end = current_pos + cyclelen;
+	}
+	if(cycle_end > 0) {
+		if((exit_status = write_samps(dz->flbufptr[0],cycle_end,dz))<0)
+			return(exit_status);
+	}
+	return(FINISHED);
+}
+
+/************************** ENVSYN_ENV **************************/
+
+int envsyn_env(int *phase,int cyclestart,int *cycle_end,double one_less_trof,dataptr dz)
+{
+	switch(dz->mode) {
+	case(ENVSYN_TROFFED):	return envsyn_troffed(cyclestart,cycle_end,one_less_trof,phase,dz);
+	case(ENVSYN_USERDEF):	return envsyn_userdef(cyclestart,cycle_end,phase,dz);
+	case(ENVSYN_RISING):   	return envsyn_rising(cyclestart,cycle_end,one_less_trof,phase,dz);
+	case(ENVSYN_FALLING):  	return envsyn_falling(cyclestart,cycle_end,one_less_trof,phase,dz);
+	default:
+		sprintf(errstr,"Unknown case: envsyn_env()\n");
+		return(PROGRAM_ERROR);
+	}
+	return(CONTINUE);
+}
+
+/************************** ENVSYN_TROFFED *******************************/
+
+int envsyn_troffed(int cyclestart,int *cyclend,double one_less_trof,int *phase,dataptr dz)
+{
+	int exit_status;
+	register int k = 0, j = cyclestart;
+	int cyclelen = *cyclend - cyclestart;
+	int cyclehlf = cyclelen/2;
+	int cyclemid = cyclestart + cyclehlf;
+	float *b = dz->flbufptr[0];
+	if(*phase > 0) {
+		if(*phase >= cyclehlf) {
+			cyclemid = -1;
+			k = (*phase - cyclehlf);
+		} else {
+			cyclemid -= *phase;
+			k = *phase;
+		}
+		(*cyclend) -= *phase;
+		*phase = 0;
+	}
+	while(j<cyclemid) {
+		b[j] = (float)do_firsthalf_trof(k,cyclehlf,one_less_trof,dz);
+		k++;
+		j++;
+		if(j >= dz->buflen) {
+			if((exit_status = write_samps(b,dz->buflen,dz))<0)
+				return(exit_status);
+			j = 0;
+			*cyclend -= dz->buflen;
+		}
+	}
+	if(cyclemid >= 0)
+		k = 0;
+	cyclehlf = cyclelen - cyclehlf;
+	while(j < *cyclend) {
+		b[j] = (float)do_lasthalf_trof(k,cyclehlf,one_less_trof,dz);
+		k++;
+		j++;
+		if(j >= dz->buflen) {
+			if((exit_status = write_samps(b,dz->buflen,dz))<0)
+				return(exit_status);
+			j = 0;
+			*cyclend -= dz->buflen;
+		}
+	}
+	return(FINISHED);
+}
+
+/*************************** ENVSYN_USERDEF ***************************/
+
+int envsyn_userdef(int cyclestart,int *cyclend,int *phase,dataptr dz)
+{
+	int exit_status;
+	register int k = 0, j = cyclestart;
+	int cyclelen = *cyclend - cyclestart;
+	double index;
+	double z;
+	int init = 1;
+	float *b = dz->flbufptr[0];
+	if(*phase > 0) {
+		k = *phase;
+		(*cyclend) -= *phase;
+		*phase = 0;
+	}
+	while(j<*cyclend) {
+		index = (double)k/(double)cyclelen;
+		if((exit_status = read_from_user_envelope(&z,index,init,dz))<0)
+			return(exit_status);
+		b[j]  = (float)z;
+		k++;
+		j++;
+		if(j >= dz->buflen) {
+			if((exit_status = write_samps(b,dz->buflen,dz))<0)
+				return(exit_status);
+			j = 0;
+			*cyclend -= dz->buflen;
+		}
+		init = 0;
+	}
+	return(FINISHED);
+}
+
+/*************************** ENVSYN_RISING ***********************/
+
+int envsyn_rising(int cyclestart,int *cyclend,double one_less_trof,int *phase,dataptr dz)
+{
+	int exit_status;
+	register int k = 0, j = cyclestart;
+	int cyclelen = *cyclend - cyclestart;
+	float *b = dz->flbufptr[0];
+	
+	if(*phase > 0) {
+		k = *phase;
+		(*cyclend) -= *phase;
+		*phase = 0;
+	}
+	while(j<*cyclend) {
+		b[j] = (float)do_rising(k,cyclelen - 1,one_less_trof,dz);
+		k++;								 
+		j++;
+		if(j >= dz->buflen) {
+			if((exit_status = write_samps(b,dz->buflen,dz))<0)
+				return(exit_status);
+			j = 0;
+			*cyclend -= dz->buflen;
+		}
+	}
+	return(FINISHED);
+}
+
+/********************** ENVSYN_FALLING *************************/
+
+int envsyn_falling(int cyclestart,int *cyclend,double one_less_trof,int *phase,dataptr dz)
+{
+	int exit_status;
+	register int k = 0, j = cyclestart;
+	int cyclelen = *cyclend - cyclestart;
+	float *b = dz->flbufptr[0];
+	if(*phase > 0) {
+		k = *phase;
+		(*cyclend) -= *phase;
+		*phase = 0;
+	}
+	while(j<*cyclend) {
+		b[j] = (float)do_falling(k,cyclelen - 1,one_less_trof,dz);
+		k++;
+		j++;
+		if(j >= dz->buflen) {
+			if((exit_status = write_samps(b,dz->buflen,dz))<0)
+				return(exit_status);
+			j = 0;
+			*cyclend -= dz->buflen;
+		}
+	}
+	return(FINISHED);
+}
+
+/******************* DO_FIRSTHALF_TROF **************************/
+
+double do_firsthalf_trof(int k,int cyclehlf,double one_less_trof,dataptr dz)
+{
+	double z = 1.0 - ((double)k/(double)cyclehlf);
+	z = (pow(z,dz->param[ENVSYN_EXPON]) * one_less_trof) + dz->param[ENVSYN_TROF];
+	return (z);
+}
+
+/******************* DO_LASTHALF_TROF **************************/
+
+double do_lasthalf_trof(int k,int cyclehlf,double one_less_trof,dataptr dz)
+{
+	double z = (double)k/(double)cyclehlf;
+	z    = (pow(z,dz->param[ENVSYN_EXPON]) * one_less_trof) + dz->param[ENVSYN_TROF];
+	return(z);
+}
+
+/************************ DO_RISING_TROFFED *******************************/
+
+double do_rising(int k,int cyclelen,double one_less_trof,dataptr dz)
+{
+	double z = (double)k/(double)cyclelen;
+	z  = pow(z,dz->param[ENVSYN_EXPON]);
+	z *= one_less_trof;
+	z += dz->param[ENVSYN_TROF];
+	return(z);
+}
+
+/************************ DO_FALLING_TROFFED *******************************/
+
+double do_falling(int k,int cyclelen,double one_less_trof,dataptr dz)
+{
+	double z;
+	z = 1.0 - ((double)k/(double)cyclelen);
+	z = (pow(z,dz->param[ENVSYN_EXPON]) * one_less_trof) + dz->param[ENVSYN_TROF];
+	return z;
+}
+
+/************************ READ_FROM_USER_ENVELOPE *******************************/
+
+int read_from_user_envelope(double *env_val,double table_index,int init,dataptr dz)
+{
+	double *p;
+	double hi_env, lo_env, hi_index, lo_index;
+	double env;
+	if(init)
+		dz->ptr[ENVSYN_ENV] = dz->parray[ENVSYN_ENV];
+	p = dz->ptr[ENVSYN_ENV];
+	while(table_index > *p) {
+		if((p += 2) >= dz->ptr[ENVSYN_ENVEND]) {
+			sprintf(errstr,"Problem reading user envelope data: read_from_user_envelope()\n");
+			return(PROGRAM_ERROR);
+		}
+	}
+	if(p != dz->parray[ENVSYN_ENV]) {
+		hi_env   = *(p+1);
+		hi_index = *p;
+		lo_env   = *(p-1);
+		lo_index = *(p-2);
+		env      = (double)((table_index - lo_index)/(hi_index - lo_index));
+		env     *= (double)(hi_env - lo_env);
+		env     += (double)lo_env;
+	} else
+		env = *(p+1);
+	dz->ptr[ENVSYN_ENV] = p;
+	*env_val = env;
+	return(FINISHED);
+}

+ 20 - 0
dev/extend/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(extend main.c ap_extend.c drunk.c extprepro.c iterate.c zigzag.c)
+
+target_link_libraries(extend cdp2k sfsys ${EXTRA_LIBRARIES})
+
+my_install(extend)
+

+ 1704 - 0
dev/extend/ap_extend.c

@@ -0,0 +1,1704 @@
+/*
+ * 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
+ *
+ */
+/* RWD 14 Dec 2020 fix typos in usage msgs */
+
+
+/* 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 <extend.h>
+#include <processno.h>
+#include <modeno.h>
+#include <globcon.h>
+#include <logic.h>
+#include <filetype.h>
+#include <mixxcon.h>
+#include <flags.h>
+#include <speccon.h>
+#include <arrays.h>
+#include <special.h>
+#include <formants.h>
+#include <sfsys.h>
+#include <osbind.h>
+#include <srates.h>
+#include <graicon.h>
+#include <limits.h>
+#include <float.h>
+
+#if defined unix || defined __GNUC__
+#define round(x) lround((x))
+#endif
+
+#ifndef HUGE
+#define HUGE 3.40282347e+38F
+#endif
+
+static int read_sequence(char *filename,dataptr dz);
+static int read_sequence2(char *filename,dataptr dz);
+static int sequencer_preprocess(dataptr dz);
+static int sequencer2_preprocess(dataptr dz);
+static int create_btob_bufs(dataptr dz);
+static int check_btob_consistency(dataptr dz);
+static int create_doublets_bufs(dataptr dz);
+static int doublets_preprocess(dataptr dz);
+#define SAMPLE_T short
+
+/********************************************************************************************/
+/********************************** FORMERLY IN pconsistency.c ******************************/
+/********************************************************************************************/
+
+static int  check_zigzag_consistency(dataptr dz);
+static int  check_loop_consistency(dataptr dz);
+static int  calc_params(int *repetitions,int *outsamps,int filelen,int lsfield,
+				int startsamp,int stepsamps,int loopsamps);
+static int  check_scramble_consistency(dataptr dz);
+static int  check_drunk_consistency(dataptr dz);
+static int  cloktik_vals_OK(double lo_limit,dataptr dz);
+
+static int read_atstream(char *filename,dataptr dz);
+static int create_accbufs(dataptr dz);
+static int create_seqbufs(dataptr dz);
+static int create_seqbufs2(dataptr dz);
+
+/********************************************************************************************/
+/********************************** FORMERLY IN specialin.c *********************************/
+/********************************************************************************************/
+
+static int  read_ziginfo(char *filename,dataptr dz);
+/*static int getmaxlong(void);*/
+
+/***************************************************************************************/
+/****************************** 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(ZIGZAG):				dz->extra_bufcnt = 1;	dz->bufcnt = 3;		break;
+	case(LOOP):					dz->extra_bufcnt = 1;	dz->bufcnt = 2;		break;
+	case(SCRAMBLE):				dz->extra_bufcnt = 1;	dz->bufcnt = 2;		break;
+	case(ITERATE):				dz->extra_bufcnt = 0;	dz->bufcnt = 3;		break;
+	case(ITERATE_EXTEND):		dz->extra_bufcnt = 0;	dz->bufcnt = 4;		break;
+	case(DRUNKWALK):			dz->extra_bufcnt = 0;	dz->bufcnt = 3;		break;
+	case(ACC_STREAM):			dz->extra_bufcnt = 1;	dz->bufcnt = 1;		break;
+	case(SEQUENCER2):			dz->extra_bufcnt = 0;	dz->bufcnt = 0;		break;
+	case(SEQUENCER):			dz->extra_bufcnt = 0;	dz->bufcnt = 4;		break;
+	case(BAKTOBAK):				dz->extra_bufcnt = 0;	dz->bufcnt = 3;		break;
+	case(DOUBLETS):				dz->extra_bufcnt = 0;	dz->bufcnt = 3;		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_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(ZIGZAG):	dz->array_cnt = 1; dz->iarray_cnt = 0; dz->larray_cnt = 1; dz->ptr_cnt = 0;	dz->fptr_cnt = 0; break;
+	case(LOOP):		dz->array_cnt = 1; dz->iarray_cnt = 1; dz->larray_cnt = 1; dz->ptr_cnt = 0;	dz->fptr_cnt = 0; break;
+	case(SCRAMBLE):	dz->array_cnt = 1; dz->iarray_cnt = 2; dz->larray_cnt = 3; dz->ptr_cnt = 0;	dz->fptr_cnt = 0; break;
+	case(ITERATE_EXTEND):
+	case(ITERATE):	dz->array_cnt = 0; dz->iarray_cnt = 0; dz->larray_cnt = 0; dz->ptr_cnt = 0;	dz->fptr_cnt = 0; break;
+	case(DRUNKWALK): dz->array_cnt = 1; dz->iarray_cnt = 0; dz->larray_cnt = 0; dz->ptr_cnt = 0;	dz->fptr_cnt = 0; break;
+	case(ACC_STREAM): dz->array_cnt = 0; dz->iarray_cnt = 0; dz->larray_cnt = 1; dz->ptr_cnt = 0;	dz->fptr_cnt = 0; break;
+	case(SEQUENCER2): dz->array_cnt = 2; dz->iarray_cnt = 0; dz->larray_cnt = 1; dz->ptr_cnt = 0;	dz->fptr_cnt = 0; break;
+	case(SEQUENCER): dz->array_cnt = 2; dz->iarray_cnt = 0; dz->larray_cnt = 0; dz->ptr_cnt = 0;	dz->fptr_cnt = 0; break;
+	case(BAKTOBAK): dz->array_cnt = 0; dz->iarray_cnt = 0; dz->larray_cnt = 0; dz->ptr_cnt = 0;	dz->fptr_cnt = 0; break;
+	case(DOUBLETS): dz->array_cnt = 0; 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(ZIGZAG):		setup_process_logic(SNDFILES_ONLY,		  	UNEQUAL_SNDFILE,	SNDFILE_OUT,	dz);	break;
+	case(LOOP):  		setup_process_logic(SNDFILES_ONLY,		  	UNEQUAL_SNDFILE,	SNDFILE_OUT,	dz);	break;
+	case(SCRAMBLE):		setup_process_logic(SNDFILES_ONLY,		  	UNEQUAL_SNDFILE,	SNDFILE_OUT,	dz);	break;
+	case(ITERATE_EXTEND):
+	case(ITERATE):		setup_process_logic(SNDFILES_ONLY,		  	UNEQUAL_SNDFILE,	SNDFILE_OUT,	dz);	break;
+	case(DRUNKWALK):	setup_process_logic(SNDFILES_ONLY,		  	UNEQUAL_SNDFILE,	SNDFILE_OUT,	dz);	break;
+	case(ACC_STREAM):	setup_process_logic(SNDFILES_ONLY,		  	UNEQUAL_SNDFILE,	SNDFILE_OUT,	dz);	break;
+	case(SEQUENCER):	setup_process_logic(SNDFILES_ONLY,		  	UNEQUAL_SNDFILE,	SNDFILE_OUT,	dz);	break;
+	case(SEQUENCER2):	setup_process_logic(MANY_SNDFILES,		  	UNEQUAL_SNDFILE,	SNDFILE_OUT,	dz);	break;
+	case(BAKTOBAK):		setup_process_logic(SNDFILES_ONLY,		  	UNEQUAL_SNDFILE,	SNDFILE_OUT,	dz);	break;
+	case(DOUBLETS):		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) {
+	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(ZIGZAG):
+	switch(mode) {
+		case(ZIGZAG_SELF):
+				      	exit_status = set_internalparam_data("iiii"  ,ap);			break;
+		case(ZIGZAG_USER):	/* 1st 2,dummy variables for non-used maxzig & seed */	
+		   			  	exit_status = set_internalparam_data("diiiii",ap);			break;
+		default:
+			sprintf(errstr,"Unknown mode for zigzag: set_legal_internalparam_structure()\n");
+			return(PROGRAM_ERROR);
+		}
+		break;
+	case(LOOP):      	exit_status = set_internalparam_data("iiiii" ,ap);			break;
+	case(SCRAMBLE):    	exit_status = set_internalparam_data("iiiiii",ap);			break;
+	case(ITERATE_EXTEND):
+	case(ITERATE):    	exit_status = set_internalparam_data("diiii", ap);			break;
+	case(DRUNKWALK):    exit_status = set_internalparam_data("iiiiiii",ap);			break;
+	case(ACC_STREAM):	exit_status = set_internalparam_data("",ap);				break;
+	case(SEQUENCER2):
+	case(SEQUENCER):	exit_status = set_internalparam_data("",ap);				break;
+	case(BAKTOBAK):		exit_status = set_internalparam_data("",ap);				break;
+	case(DOUBLETS):		exit_status = set_internalparam_data("i",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)	   
+{
+	/*int exit_status = FINISHED;*/
+	aplptr ap = dz->application;
+
+	switch(ap->special_data) {
+	case(ZIGDATA):				return read_ziginfo(str,dz);
+	case(ATTACK_STREAM):		return read_atstream(str,dz);
+	case(SEQUENCER_VALUES):		return read_sequence(str,dz);
+	case(SEQUENCER2_VALUES):	return read_sequence2(str,dz);
+	default:
+		sprintf(errstr,"Unknown special_data type: read_special_data()\n");
+		return(PROGRAM_ERROR);
+	}
+	return(FINISHED);	/* NOTREACHED */
+}
+
+/***************************** READ_ZIGINFO ***************************/
+
+int read_ziginfo(char *filename,dataptr dz)
+{
+	FILE   *fp;
+	double  p;
+	char  temp[200], *q;
+	int  arraysize = BIGARRAY, sampcnt;
+	int maxlong = /*getmaxlong()*/0x7fffffff;
+	dz->itemcnt = 0;
+	if((fp = fopen(filename,"r"))==NULL) {
+		sprintf(errstr,"Can't open text file %s to read.\n",filename);
+		return(DATA_ERROR);
+	}
+	if((dz->lparray[ZIGZAG_TIMES] = (int *)malloc(arraysize * sizeof(int)))==NULL) {
+		sprintf(errstr,"INSUFFICIENT MEMORY to store zigzag times.\n");
+		return(MEMORY_ERROR);
+	}
+	while(fgets(temp,200,fp)!=NULL) {
+		q = temp;
+		if(*q == ';')	//	Allow comments in file
+			continue;
+		while(get_float_from_within_string(&q,&p)){
+			if(p < 0.0) {
+				sprintf(errstr,"Invalid zigzag time, less than zero\n");
+				return(DATA_ERROR);
+			}
+			if((sampcnt = round(p * (double)dz->infile->srate) * dz->infile->channels) < 0) /* overflow */
+				dz->lparray[ZIGZAG_TIMES][dz->itemcnt] = (maxlong/dz->infile->channels) * dz->infile->channels;
+			else
+				dz->lparray[ZIGZAG_TIMES][dz->itemcnt] = sampcnt;
+ 			if(++dz->itemcnt >= arraysize) {
+				arraysize += BIGARRAY;
+				if((dz->lparray[ZIGZAG_TIMES] = 
+				(int *)realloc((char *)dz->lparray[ZIGZAG_TIMES],arraysize*sizeof(int)))==NULL) {
+					sprintf(errstr,"INSUFFICIENT MEMORY to reallocate zigzag times.\n");
+					return(MEMORY_ERROR);
+				}
+			}
+		}
+	}	    
+	if(!dz->itemcnt) {
+		sprintf(errstr,"No data in file %s\n",filename);
+		return(DATA_ERROR);
+	}
+	if((dz->lparray[ZIGZAG_TIMES] =
+	(int *)realloc((char *)dz->lparray[ZIGZAG_TIMES],dz->itemcnt * sizeof(int)))==NULL) {
+		sprintf(errstr,"INSUFFICIENT MEMORY to reallocate zigzag times.\n");
+		return(MEMORY_ERROR);
+	}
+	if(fclose(fp)<0) {
+		fprintf(stdout,"WARNING: Failed to close input textfile %s.\n",filename);
+		fflush(stdout);
+	}
+	if(dz->itemcnt < 2) {
+		sprintf(errstr,"Not enough zig information found in file %s\n",filename);
+		return(DATA_ERROR);
+	}
+	return(FINISHED);
+}
+
+/***************************** READ_ATSTREAM ***************************/
+
+int read_atstream(char *filename,dataptr dz)
+{
+	FILE   *fp;
+	double  p;
+	char  temp[200], *q;
+	int  arraysize = BIGARRAY, sampcnt;
+	aplptr ap = dz->application;
+	dz->itemcnt = 0;
+	ap->min_special *= (double)(dz->infile->srate * dz->infile->channels);
+	ap->max_special *= (double)(dz->infile->srate * dz->infile->channels);
+	if((fp = fopen(filename,"r"))==NULL) {
+		sprintf(errstr,"Can't open text file %s to read.\n",filename);
+		return(DATA_ERROR);
+	}
+	if((dz->lparray[0] = (int *)malloc(arraysize * sizeof(int)))==NULL) {
+		sprintf(errstr,"INSUFFICIENT MEMORY to store entry times.\n");
+		return(MEMORY_ERROR);
+	}
+	while(fgets(temp,200,fp)!=NULL) {
+		q = temp;
+		if(*q == ';')	//	Allow comments in file
+			continue;
+		while(get_float_from_within_string(&q,&p)){
+			if(p < 0.0) {
+				sprintf(errstr,"Invalid entry time, less than zero\n");
+				return(DATA_ERROR);
+			}
+			sampcnt = round(p * (double)dz->infile->srate) * dz->infile->channels;
+			if (sampcnt  < ap->min_special || sampcnt > ap->max_special) {
+				sprintf(errstr,"Entry time value (%lf) out of range.\n",p);
+				return(MEMORY_ERROR);
+			}
+			dz->lparray[0][dz->itemcnt] = sampcnt;
+ 			if(++dz->itemcnt >= arraysize) {
+				arraysize += BIGARRAY;
+				if((dz->lparray[0] = 
+				(int *)realloc((char *)dz->lparray[0],arraysize*sizeof(int)))==NULL) {
+					sprintf(errstr,"INSUFFICIENT MEMORY to reallocate entry times.\n");
+					return(MEMORY_ERROR);
+				}
+			}
+		}
+	}	    
+	if(!dz->itemcnt) {
+		sprintf(errstr,"No data in file %s\n",filename);
+		return(DATA_ERROR);
+	}
+	if((dz->lparray[0] =
+	(int *)realloc((char *)dz->lparray[0],dz->itemcnt * sizeof(int)))==NULL) {
+		sprintf(errstr,"INSUFFICIENT MEMORY to reallocate entry times.\n");
+		return(MEMORY_ERROR);
+	}
+	if(fclose(fp)<0) {
+		fprintf(stdout,"WARNING: Failed to close input textfile %s.\n",filename);
+		fflush(stdout);
+	}
+	return(FINISHED);
+}
+
+/***** GONE TO TK ************************ GETMAXLONG ***************************/
+#ifdef NOTDEF
+int getmaxlong(void)
+{
+	int k, maxlong = sizeof(int) * CHARBITSIZE;	/* bitsize, say 32 			 */
+	maxlong--;										/* say 31 					 */
+	k = 1;
+	k <<= maxlong-1;								/* 2^30 					 */
+	maxlong = k;									
+	maxlong += (k-1);								/* 2^30 + 2^30 -1 = 2^31 - 1 */
+	return(maxlong);
+}
+#endif
+/********************************************************************************************/
+/********************************** FORMERLY IN preprocess.c ********************************/
+/********************************************************************************************/
+
+
+/****************************** PARAM_PREPROCESS *********************************/
+
+int param_preprocess(dataptr dz)	
+{
+	switch(dz->process) {
+	case(ZIGZAG):		return zigzag_preprocess(dz);
+	case(LOOP):			return loop_preprocess(dz);
+	case(SCRAMBLE):		return scramble_preprocess(dz);
+	case(ITERATE_EXTEND):
+	case(ITERATE):		return iterate_preprocess(dz);
+	case(DRUNKWALK):   	return drunk_preprocess(dz);
+	case(ACC_STREAM):   return FINISHED;
+	case(SEQUENCER):    return sequencer_preprocess(dz);
+	case(SEQUENCER2):   return sequencer2_preprocess(dz);
+	case(BAKTOBAK):     return FINISHED;
+	case(DOUBLETS):     return doublets_preprocess(dz);
+	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;
+
+	switch(dz->process) {
+	case(ZIGZAG):
+	case(LOOP):
+	case(SCRAMBLE):
+		if((exit_status = zigzag(dz))<0)
+			return(exit_status);
+		break;
+	case(ITERATE_EXTEND):
+	case(ITERATE):
+		if((exit_status = do_iteration(dz))<0)
+			return(exit_status);
+		break;
+	case(DRUNKWALK):
+		if((exit_status = do_drunken_walk(dz))<0)
+			return(exit_status);
+		break;
+	case(ACC_STREAM):
+		if((exit_status = accent_stream(dz))<0)
+			return(exit_status);
+		break;
+	case(SEQUENCER):
+		if((exit_status = do_sequence(dz))<0)
+			return(exit_status);
+		break;
+	case(SEQUENCER2):
+		if((exit_status = do_sequence2(dz))<0)
+			return(exit_status);
+		break;
+	case(BAKTOBAK):
+		if((exit_status = do_btob(dz))<0)
+			return(exit_status);
+		break;
+	case(DOUBLETS):
+		if((exit_status = do_doubling(dz))<0)
+			return(exit_status);
+		break;
+	default:
+		sprintf(errstr,"Unknown case in process_file()\n");
+		return(PROGRAM_ERROR);
+	}
+	return(FINISHED);
+}
+
+/********************************************************************************************/
+/********************************** 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(ZIGZAG):		return check_zigzag_consistency(dz);
+	case(LOOP):			return check_loop_consistency(dz);
+	case(SCRAMBLE):		return check_scramble_consistency(dz);
+	case(DRUNKWALK):	return check_drunk_consistency(dz);
+	case(BAKTOBAK):		return check_btob_consistency(dz);
+	}
+	return(FINISHED);
+}
+
+/********************************** CHECK_ZIGZAG_CONSISTENCY **********************************/
+
+int check_zigzag_consistency(dataptr dz)
+{
+	double diff;
+	if(dz->mode==ZIGZAG_SELF) {
+		if(dz->param[ZIGZAG_MAX] <= dz->param[ZIGZAG_MIN]) {
+			sprintf(errstr,"maximum zig duration <= minimum zig duration\n");
+			return(DATA_ERROR);
+		}
+		if(dz->param[ZIGZAG_MIN] < (((dz->param[ZIGZAG_SPLEN] * 2) + ZIG_MIN_UNSPLICED) * MS_TO_SECS)) {
+			sprintf(errstr,"minimum ziglength must be > %.3lf: cannot proceed\n",
+			((dz->param[ZIGZAG_SPLEN] * 2) + ZIG_MIN_UNSPLICED) * MS_TO_SECS);
+			return(DATA_ERROR);
+		}
+		diff = dz->param[ZIGZAG_END] - dz->param[ZIGZAG_START];
+		if(diff<=0.0) {
+			sprintf(errstr,"Zig start and end times incompatible.\n");
+			return(DATA_ERROR);
+		}
+		if(round(diff/dz->param[ZIGZAG_MIN])<1) {
+			sprintf(errstr,"Zigzagging sector too short for zig-zag minlength specified.\n");
+			return(DATA_ERROR);
+		}
+	}
+	return(FINISHED);
+}
+
+/********************************** CHECK_LOOP_CONSISTENCY **********************************/
+
+int check_loop_consistency(dataptr dz)
+{
+	int exit_status;
+	int outsamps, loopsamps, lsfield, end_partloop = 0, filelen_needed;
+	int filelen = dz->insams[0];
+	int stepsamps = dz->infile->channels * (int) (dz->infile->srate * dz->param[LOOP_STEP] * MS_TO_SECS);
+	int startsamp = dz->infile->channels * (int) (dz->infile->srate * dz->param[LOOP_START]);
+	loopsamps = dz->infile->channels * round((double)dz->infile->srate * dz->param[LOOP_LEN] * MS_TO_SECS);
+	lsfield   = dz->infile->channels * round((double)dz->infile->srate * dz->param[LOOP_SRCHF] * MS_TO_SECS);	/* default to 0 */
+	if(dz->mode==LOOP_ALL) {
+		if((exit_status = calc_params((int *)&dz->iparam[LOOP_REPETS],&outsamps,filelen,lsfield,startsamp,stepsamps,loopsamps))<0)
+			return(exit_status);
+	} else {
+		switch(dz->mode) {
+		case(LOOP_RPTS):	
+			dz->iparam[ZIG_RUNSTOEND] = TRUE;
+			outsamps = ((dz->iparam[LOOP_REPETS] * loopsamps)/dz->infile->channels) * dz->infile->channels;
+			end_partloop = 0;
+			break;
+		case(LOOP_OUTLEN):	
+			outsamps = dz->infile->channels * round(dz->infile->srate * dz->param[LOOP_OUTDUR]);
+			outsamps -= startsamp + lsfield;
+			if((dz->iparam[LOOP_REPETS] = (int)(outsamps / loopsamps))<=0) {
+				sprintf(errstr,"Infile too short to do this looping operation.\n");
+				return(GOAL_FAILED);
+			}
+			end_partloop = outsamps - (dz->iparam[LOOP_REPETS] * loopsamps);
+			break;
+		}
+		filelen_needed = startsamp + lsfield + (dz->iparam[LOOP_REPETS] * stepsamps) + end_partloop;
+		if(filelen > filelen_needed)
+			dz->iparam[ZIG_RUNSTOEND] = FALSE;
+		else {
+			if((exit_status = calc_params((int *)&dz->iparam[LOOP_REPETS],&outsamps,filelen,lsfield,startsamp,stepsamps,loopsamps))<0)
+				return(exit_status);
+			switch(dz->mode) {
+			case(LOOP_RPTS):
+				fprintf(stdout,"WARNING: filelength too short for job : Curtailing to %d repetitions\n",
+				dz->iparam[LOOP_REPETS]); 
+				break;
+			case(LOOP_OUTLEN):
+				sprintf(errstr,"WARNING: filelength too short for job: Curtailing to ");
+				if(lsfield>0)
+					strcat(errstr,"approx ");
+				fprintf(stdout,"%s%lf secs\n",errstr,
+					(double)(outsamps + startsamp)/(double)(dz->infile->srate * dz->infile->channels)); 
+				break;
+			}
+			fflush(stdout);
+			dz->iparam[ZIG_RUNSTOEND] = TRUE;
+		}		
+	}
+ 	return(FINISHED);
+}
+
+/********************************** CALC_PARAMS **********************************/
+
+int calc_params(int *repetitions,int *outsamps,int filelen,int lsfield,int startsamp,int stepsamps,int loopsamps)
+{										 	
+	int  part_repet = 0;
+	int end_partloop;
+	int loopable_len = filelen - lsfield - startsamp;
+	if((loopable_len -= loopsamps)<0) { 	/* subtract final complete loop */
+		if(lsfield > 0)
+			sprintf(errstr,"Infile too short to attempt this looping operation.\n");
+		else
+			sprintf(errstr,"Infile too short to do this looping operation.\n");
+		return(GOAL_FAILED);
+	}
+	*repetitions = loopable_len/stepsamps;	/* TRUNCATE: no of complete steps in remaining filelen */
+	if((end_partloop = loopable_len - ((*repetitions) * stepsamps))>0)
+		part_repet = 1;						/* Final curtailed repetition which hits end of data */
+	(*repetitions)++;						/* add in final loop, subtracted at start */
+	if((*repetitions) + part_repet<=1) {
+		sprintf(errstr,"Infile too short to do this looping operation.\n");
+		return(GOAL_FAILED);
+	}
+	*outsamps = ((*repetitions) * loopsamps) + end_partloop;
+	return(FINISHED);
+}
+
+/********************************** CHECK_SCRAMBLE_CONSISTENCY **********************************/
+
+int check_scramble_consistency(dataptr dz)
+{
+	int chunkcnt;
+	switch(dz->mode) {
+	case(SCRAMBLE_RAND):
+		if(dz->param[SCRAMBLE_MAX] < dz->param[SCRAMBLE_MIN]) {
+			sprintf(errstr,"maxseglen is less than minseglen\n");
+			return(USER_ERROR);
+		}
+		if(dz->param[SCRAMBLE_SPLEN] * MS_TO_SECS * 2.0 > dz->param[SCRAMBLE_MIN]) {
+			sprintf(errstr,"Splicelen is too long for minseglen\n");
+			return(USER_ERROR);
+		}
+		if(dz->param[SCRAMBLE_DUR] < dz->param[SCRAMBLE_MAX]) {
+			sprintf(errstr,"Output duration is less than maxseglen\n");
+			return(USER_ERROR);
+		}
+		break;
+	case(SCRAMBLE_SHRED):
+		chunkcnt =  /* truncate */
+		dz->insams[0]/round(dz->param[SCRAMBLE_LEN] * dz->infile->srate * dz->infile->channels);
+		if(dz->param[SCRAMBLE_SCAT] > (double)chunkcnt) {
+			sprintf(errstr,"scatter cannot be greater than infilesize/chunklen (rounded DOWN).\n");
+			return(USER_ERROR);
+		}
+		break;
+	default:
+		sprintf(errstr,"Unknown case: check_scramble_consistency()\n");
+		return(PROGRAM_ERROR);
+	}
+	return(FINISHED);
+}
+
+/***************************** CHECK_DRUNK_CONSISTENCY *************************/
+
+int check_drunk_consistency(dataptr dz)
+{
+	int exit_status;
+	dz->iparam[DRNK_SPLICELEN] = (int)round(dz->param[DRNK_SPLICELEN] * MS_TO_SECS * (double)dz->infile->srate);
+
+	if((exit_status = convert_time_and_vals_to_samplecnts(DRNK_CLOKTIK,dz))<0)
+		return(exit_status);
+	if(!cloktik_vals_OK((double)(dz->iparam[DRNK_SPLICELEN] * 2),dz)) {
+		sprintf(errstr,"(minimum) clock value <= splicelen * 2 [%.1lf MS]: cannot proceed.\n",
+		dz->param[DRNK_SPLICELEN]*2.0);
+		return(DATA_ERROR);
+	}
+	return(FINISHED);
+}
+
+/************************* CLOKTIK_VALS_OK *********************/
+
+int cloktik_vals_OK(double lo_limit,dataptr dz)
+{
+	double *p, *pend;
+	if(dz->brksize[DRNK_CLOKTIK]) {
+		p    = dz->brk[DRNK_CLOKTIK] + 1;
+		pend = dz->brk[DRNK_CLOKTIK] + (dz->brksize[DRNK_CLOKTIK] * 2);
+		while(p < pend) {
+			if(*p <= lo_limit)
+				return(FALSE);
+			p += 2;
+		}
+	} else {
+		if((double)dz->iparam[DRNK_CLOKTIK] <= lo_limit)
+			return(FALSE);
+	}		
+	return(TRUE);
+}
+
+/********************************************************************************************/
+/********************************** FORMERLY IN buffers.c ***********************************/
+/********************************************************************************************/
+
+/**************************** ALLOCATE_LARGE_BUFFERS ******************************/
+
+int allocate_large_buffers(dataptr dz)
+{
+	switch(dz->process) {
+	case(ZIGZAG):		case(LOOP):			case(SCRAMBLE):			
+		return create_sndbufs(dz);
+
+	case(ITERATE):		case(DRUNKWALK):	case(ITERATE_EXTEND):		
+		return FINISHED;	/* buffers allocated after param-preprocessing */
+	case(ACC_STREAM):		
+		return create_accbufs(dz);
+	case(SEQUENCER):		
+		return create_seqbufs(dz);
+	case(SEQUENCER2):		
+		return create_seqbufs2(dz);
+	case(BAKTOBAK):		
+		return create_btob_bufs(dz);
+	case(DOUBLETS):		
+		return create_doublets_bufs(dz);
+	default:
+		sprintf(errstr,"Unknown program no. in allocate_large_buffers()\n");
+		return(PROGRAM_ERROR);
+	}
+	return(FINISHED);	/* NOTREACHED */
+}
+
+/*************************** CREATE_ITERBUFS **************************
+ *
+ * (1)	Create extra spaces for interpolation guard points at end of infile.
+ *
+ * (2) 	Allow for any cumulative addition errors in interpolation.
+ *
+ * (3)	Output buffer must be at least as big as the overflow buffer.
+ *	Output buffer must be big enough for the whole of any possible
+ *	data overflow (in overflow_size buff) to be copied back into it.
+ *	This is because the overflow buffer is ZEROED after such a copy
+ *	and if a 2nd copy of the overflow back into the main buffer
+ *	were necessary , we would be copying zeroes rather than true data.
+ *
+ *
+ *		true buffer	    			overflow
+ *  |-----------------------------|------------------------------------------|
+ *			    worst			  ^					    					 ^
+ *		    possible case		  ^					    					 ^
+ *		                 	      ^----->-delayed by maxdelay_size to ->-----^
+ *			         			  ^<-restored by -buffer_size into truebuf-<-^
+ *  |<-------- BUFFER_SIZE------->
+ *
+ */
+
+int create_iterbufs(double maxpscat,dataptr dz)
+{
+	size_t bigbufsize;
+    int seccnt;
+	double k;
+	int extra_space, infile_space, orig_infile_space = 0, big_buffer_size;
+	int overflowsize /*, seccnt*/;
+
+	int framesize = F_SECSIZE * sizeof(float) * dz->infile->channels;
+/* MULTICHAN 2009 --> */
+	int chans = dz->infile->channels;
+/* <-- MULTICHAN 2009 */
+
+	size_t bigchunk, min_bufsize;
+	if(dz->process == ITERATE) {
+		infile_space = dz->insams[0];
+		if(dz->vflag[IS_ITER_PSCAT]) {
+			infile_space += dz->infile->channels;			/* 1 */
+			k = pow(2.0,maxpscat * OCTAVES_PER_SEMITONE);
+			overflowsize = (round((double)(dz->insams[0]/chans) * k) * chans) + 1;
+			overflowsize += ITER_SAFETY; 						/* 2 */	
+		} else
+			overflowsize = dz->insams[0];
+		if((seccnt = infile_space/F_SECSIZE) * F_SECSIZE < infile_space)
+			seccnt++;
+		infile_space = F_SECSIZE * seccnt;
+	} else {	//	dz->process = ITERATE_EXTEND;
+		dz->rampbrksize = dz->iparam[CHUNKEND] - dz->iparam[CHUNKSTART];
+		orig_infile_space = dz->rampbrksize;
+		infile_space = orig_infile_space;
+		if(dz->param[ITER_PSCAT] > 0.0) {
+			infile_space += dz->infile->channels;			/* 1 */
+			if((seccnt = infile_space/F_SECSIZE) * F_SECSIZE < infile_space)
+				seccnt++;
+			infile_space = F_SECSIZE * seccnt;
+			k = pow(2.0,maxpscat * OCTAVES_PER_SEMITONE);
+			overflowsize = (round((double)(orig_infile_space/chans) * k) * chans) + 1;
+			overflowsize += ITER_SAFETY; 						/* 2 */	
+		} else
+			overflowsize = orig_infile_space;
+	}
+
+	extra_space = infile_space + overflowsize;
+	if(dz->process == ITERATE_EXTEND)
+		extra_space += infile_space;
+	min_bufsize = (extra_space * sizeof(float)) + framesize;
+	if(dz->process == ITERATE) {
+		bigchunk = (size_t)Malloc(-1);
+		if(bigchunk < min_bufsize)
+			bigbufsize = framesize;
+		else {
+			bigbufsize = bigchunk - extra_space*sizeof(float);
+			bigbufsize = (bigbufsize/framesize) * framesize;
+		}
+		dz->buflen     = (int)(bigbufsize/sizeof(float));
+		big_buffer_size = dz->buflen + extra_space;
+	} else {
+		dz->buflen = max(ITERATE_EXTEND_BUFSIZE,infile_space);
+		big_buffer_size = (dz->buflen * 2) + overflowsize + infile_space;
+	}
+	if((dz->bigbuf = (float *)Malloc(big_buffer_size * sizeof(float)))==NULL) {
+		sprintf(errstr, "INSUFFICIENT MEMORY to create sound buffers.\n");
+		return(MEMORY_ERROR);
+	}
+	dz->sbufptr[0] = dz->sampbuf[0] = dz->bigbuf;
+	if(dz->process == ITERATE) {
+		dz->sbufptr[1] = dz->sampbuf[1] = dz->sampbuf[0] + infile_space;
+		dz->sbufptr[2] = dz->sampbuf[2] = dz->sampbuf[1] + dz->buflen;
+		dz->sbufptr[3] = dz->sampbuf[3] = dz->sampbuf[2] + overflowsize;
+		memset((char *)dz->sampbuf[0],0,(size_t)(infile_space * sizeof(float)));
+		memset((char *)dz->sampbuf[1],0,(size_t)(dz->buflen * sizeof(float)));
+		memset((char *)dz->sampbuf[2],0,(size_t)(overflowsize * sizeof(float)));
+	} else {
+		dz->sbufptr[1] = dz->sampbuf[1] = dz->sampbuf[0] + dz->buflen;
+		dz->sbufptr[2] = dz->sampbuf[2] = dz->sampbuf[1] + dz->buflen;
+		dz->sbufptr[3] = dz->sampbuf[3] = dz->sampbuf[2] + overflowsize;
+		memset((char *)dz->sampbuf[0],0,(size_t)(dz->buflen * sizeof(float)));
+		memset((char *)dz->sampbuf[1],0,(size_t)(dz->buflen * sizeof(float)));
+		memset((char *)dz->sampbuf[2],0,(size_t)(overflowsize * sizeof(float)));
+		memset((char *)dz->sampbuf[3],0,(size_t)infile_space * sizeof(float));
+	}
+	return(FINISHED);
+}
+
+/*************************** CREATE_SEQBUFS **************************
+ *
+ * (0)	 Buffer for input
+ * (1-2) Buffers for output, both >= largest transpos size of input
+ * (3) 	 Buffer for transpos, >= largest transpos size of input.
+ */
+
+int create_seqbufs(dataptr dz)
+{
+	double *d, mintranspos;
+	int transposbufsize, seccnt, infile_space = dz->insams[0] + dz->infile->channels, total_bufsize;
+	unsigned int limit;
+	int bigbufsize;
+/* MULTICHAN 2009 --> */
+	int chans = dz->infile->channels;
+/* <-- MULTICHAN 2009 */
+	d = dz->parray[0] + 1;
+	mintranspos = HUGE;
+	while(d < dz->parray[1]) {
+		if(*d < mintranspos)
+			mintranspos = *d;
+		d += 3;
+	}
+	limit = (unsigned int)floor((INT_MAX - 64) * mintranspos);
+	if((unsigned int)(dz->insams[0] * sizeof(float)) >= limit) {
+		sprintf(errstr, "INSUFFICIENT MEMORY to create sound buffers (A).\n");
+		return(MEMORY_ERROR);
+	}
+/* MULTICHAN 2009 --> */
+//	transposbufsize = (int)round(dz->insams[0]/mintranspos) + 64; /* 64 = safety margin */
+	transposbufsize = ((int)round((dz->insams[0]/chans)/mintranspos) * chans) + 64; /* 64 = safety margin */
+	if((seccnt = infile_space/F_SECSIZE) * F_SECSIZE < infile_space)
+		seccnt++;
+	if((infile_space = F_SECSIZE * seccnt) < 0) {
+		sprintf(errstr, "INSUFFICIENT MEMORY to create sound buffers (B).\n");
+		return(MEMORY_ERROR);
+	}
+	if((seccnt = transposbufsize/F_SECSIZE) * F_SECSIZE < transposbufsize)
+		seccnt++;
+	if((transposbufsize = F_SECSIZE * seccnt) < 0) {
+		sprintf(errstr, "INSUFFICIENT MEMORY to create sound buffers (C).\n");
+		return(MEMORY_ERROR);
+	}
+	bigbufsize = transposbufsize * sizeof(float);	
+	if((unsigned int)bigbufsize >= (INT_MAX - (infile_space * sizeof(float)))/3) {
+		sprintf(errstr, "INSUFFICIENT MEMORY to create sound buffers (D).\n");
+		return(MEMORY_ERROR);
+	}
+	total_bufsize = (infile_space * sizeof(float)) + (3 * bigbufsize);
+
+	if((dz->bigbuf = (float *)Malloc(total_bufsize))==NULL) {
+		sprintf(errstr, "INSUFFICIENT MEMORY to create sound buffers (E).\n");
+		return(MEMORY_ERROR);
+	}
+	dz->buflen     = bigbufsize/sizeof(float);
+	dz->sbufptr[0] = dz->sampbuf[0] = dz->bigbuf;
+	dz->sbufptr[1] = dz->sampbuf[1] = dz->sampbuf[0] + infile_space;
+	dz->sbufptr[2] = dz->sampbuf[2] = dz->sampbuf[1] + dz->buflen;
+	dz->sbufptr[3] = dz->sampbuf[3] = dz->sampbuf[2] + dz->buflen;
+	memset((char *)dz->sampbuf[0],0,(size_t)infile_space * sizeof(float));
+	memset((char *)dz->sampbuf[1],0,(size_t)dz->buflen * sizeof(float));
+	memset((char *)dz->sampbuf[2],0,(size_t)dz->buflen * sizeof(float));
+	memset((char *)dz->sampbuf[3],0,(size_t)dz->buflen * sizeof(float));
+	return(FINISHED);
+}
+
+/*************************** CREATE_SEQBUFS2 **************************
+ *
+ * (0)	 Buffer for input
+ * (1-2) Buffers for output, both >= largest transpos size of input
+ * (3) 	 Buffer for transpos, >= largest transpos size of input.
+ */
+ 
+int create_seqbufs2(dataptr dz)
+{
+	double *d, mintranspos;
+	int transposbufsize, seccnt;
+	int total_memory_space = 0;
+	int maxlen, k;
+	int n;
+/* MULTICHAN 2009 --> */
+	int chans = dz->infile->channels;
+/* <-- MULTICHAN 2009 */
+
+	if((dz->sampbuf = (float **)malloc(sizeof(float *) * (dz->infilecnt + 4)))==NULL) {
+		sprintf(errstr,"INSUFFICIENT MEMORY establishing sample buffers.\n");
+		return(MEMORY_ERROR);
+	}
+	if((dz->sbufptr = (float **)malloc(sizeof(float *) * (dz->infilecnt + 4)))==NULL) {
+		sprintf(errstr,"INSUFFICIENT MEMORY establishing sample buffer pointers.\n");
+		return(MEMORY_ERROR);
+	}
+	for(n = 0;n <(dz->infilecnt + 3); n++)
+		dz->sampbuf[n] = dz->sbufptr[n] = (float *)0;
+	dz->sampbuf[n] = (float *)0;
+
+	if((dz->lparray[0] = (int *)malloc((dz->infilecnt+1) * sizeof(int)))==NULL) {
+		sprintf(errstr, "INSUFFICIENT MEMORY to start creation of sound buffer.\n");
+		return(MEMORY_ERROR);
+	}
+	d = dz->parray[0] + 2;
+	mintranspos = DBL_MAX;
+	while(d < dz->parray[1]) {
+		if(*d < mintranspos)
+			mintranspos = *d;
+		d += 5;
+	}
+	maxlen = 0;
+	for(n=0;n<dz->infilecnt;n++) {
+		if(dz->insams[n] > maxlen)
+			maxlen = dz->insams[n];
+		if((seccnt = dz->insams[n]/F_SECSIZE) * F_SECSIZE < dz->insams[n])
+			seccnt++;
+		if((k = F_SECSIZE * seccnt) < 0) {
+			sprintf(errstr, "INSUFFICIENT MEMORY to create sound buffer for infile %d.\n",n+1);
+			return(MEMORY_ERROR);
+		}
+		total_memory_space += k;
+		if(n > 0)  {
+			if(total_memory_space < 0) {
+				sprintf(errstr, "INSUFFICIENT MEMORY to create sound buffers for infiles 1 - %d.\n",n+1);
+				return(MEMORY_ERROR);
+			}
+		}
+		dz->lparray[0][n] = k;
+	}
+
+/* MULTICHAN 2009 --> */
+//	transposbufsize = (int)ceil((double)maxlen/(double)mintranspos) + 64; /* 64 = safety margin */
+	transposbufsize = ((int)ceil((double)(maxlen/chans)/(double)mintranspos) * chans) + 64; /* 64 = safety margin */
+	if((seccnt = transposbufsize/F_SECSIZE) * F_SECSIZE < transposbufsize)
+		seccnt++;
+	if((transposbufsize = F_SECSIZE * seccnt) < 0) {
+		sprintf(errstr, "INSUFFICIENT MEMORY to create transposition buffer.\n");
+		return(MEMORY_ERROR);
+	}
+	dz->lparray[0][n] = transposbufsize;
+	total_memory_space += transposbufsize;	/* outputbuf */
+	if(total_memory_space < 0) {
+		sprintf(errstr, "INSUFFICIENT MEMORY to create output buffer.\n");
+		return(MEMORY_ERROR);
+	}
+	total_memory_space += transposbufsize;	/* overflowbuf */
+	if(total_memory_space < 0) {
+		sprintf(errstr, "INSUFFICIENT MEMORY to create overflow buffer.\n");
+		return(MEMORY_ERROR);
+	}
+	total_memory_space += transposbufsize;	/* transposbuf */
+	if(total_memory_space < 0) {
+		sprintf(errstr, "INSUFFICIENT MEMORY to create transposition buffer.\n");
+		return(MEMORY_ERROR);
+	}
+	if((dz->bigbuf = (float *)Malloc(total_memory_space * sizeof(float)))==NULL) {
+		sprintf(errstr, "INSUFFICIENT MEMORY to create sound buffers (E).\n");
+		return(MEMORY_ERROR);
+	}
+	dz->sbufptr[0] = dz->sampbuf[0] = dz->bigbuf;
+	for(n=1;n<=dz->infilecnt;n++)
+		dz->sbufptr[n] = dz->sampbuf[n] = dz->sampbuf[n-1] + (dz->lparray[0][n-1]);
+	dz->sbufptr[n] = dz->sampbuf[n] = dz->sampbuf[n-1] + (transposbufsize);
+	n++;
+	dz->sbufptr[n] = dz->sampbuf[n] = dz->sampbuf[n-1] + (transposbufsize);
+	memset((char *)dz->bigbuf,0,(size_t)total_memory_space * sizeof(float));
+	return(FINISHED);
+}
+
+/*************************** CREATE_BUFFER **************************/
+
+int create_drunk_buffers(dataptr dz)
+{
+	size_t bigbufsize;
+    int seccnt;
+	int exit_status;
+	int maxoverflow/*, seccnt*/;
+	size_t bigchunk, min_bufsize;
+	double maxclok, maxrand;
+	int chans = dz->infile->channels;
+	int standardbuf_cnt, n;
+//TW old buffer protocol for now + allow channel rounding
+	int framesize = F_SECSIZE * sizeof(float) * dz->infile->channels;
+
+	if((exit_status = get_maxvalue(DRNK_CLOKTIK,&maxclok,dz))<0)
+		return(exit_status);
+	if((exit_status = get_maxvalue(DRNK_CLOKRND,&maxrand,dz))<0)
+		return(exit_status);
+	maxoverflow  = round((double)maxclok * (1.0 + maxrand)) * chans;
+	maxoverflow += 2 * (dz->iparam[DRNK_SPLICELEN] * chans);
+
+//TW retaining old buffer-protocol for now
+	maxoverflow += F_SECSIZE;	/* safety */
+	if(((seccnt = maxoverflow/F_SECSIZE)*F_SECSIZE)!=maxoverflow) {
+		seccnt++;
+		maxoverflow = seccnt * F_SECSIZE;
+	}
+	standardbuf_cnt = dz->bufcnt - 1;
+//TW CHANGED
+	min_bufsize = standardbuf_cnt * framesize;
+	bigchunk = (size_t) Malloc(-1);
+	if(bigchunk < min_bufsize)
+		bigbufsize = framesize;
+	else {
+		bigchunk /= standardbuf_cnt;
+//TW retaining old buffer-protocol for now + channel rounding, for RWD
+		bigbufsize = (bigchunk/framesize) * framesize;
+	}
+	dz->buflen = (int) (bigbufsize/sizeof(float));
+
+	if((dz->bigbuf = (float *)malloc((size_t)(((dz->buflen * standardbuf_cnt) + maxoverflow) * sizeof(float)))) == NULL) {
+		sprintf(errstr,"INSUFFICIENT MEMORY to create sound buffers.\n");
+		return(MEMORY_ERROR);
+	}
+	for(n=0;n<standardbuf_cnt;n++)
+		dz->sbufptr[n] = dz->sampbuf[n] = dz->bigbuf + (dz->buflen * n);
+	dz->sampbuf[standardbuf_cnt] = dz->bigbuf + (dz->buflen * standardbuf_cnt);
+	dz->sampbuf[dz->bufcnt]      = dz->sampbuf[standardbuf_cnt] + maxoverflow;
+	return(FINISHED);
+}
+
+/*************************** CREATE_DOUBLETS_BUFS **************************/
+
+int create_doublets_bufs(dataptr dz)
+{
+	int shsecsize = F_SECSIZE * sizeof(float);
+	int n, exit_status;
+	double brkmax;
+	size_t segbuflen, bigbufsize;
+	if(dz->sbufptr == 0 || dz->sampbuf==0) {
+		sprintf(errstr,"buffer pointers not allocated: create_sndbufs()\n");
+		return(PROGRAM_ERROR);
+	}
+	if(dz->brksize[SEG_DUR] > 0) {
+		if((exit_status = get_maxvalue_in_brktable(&brkmax,SEG_DUR,dz))<0)
+			return(exit_status);
+	} else
+		brkmax = dz->param[SEG_DUR];
+	segbuflen = round((brkmax * dz->infile->srate) + 1.0) * dz->infile->channels * sizeof(float);
+
+	bigbufsize = (size_t) Malloc(-1) - segbuflen;
+	bigbufsize /= (dz->bufcnt - 1);
+	if((bigbufsize  = (bigbufsize/shsecsize) * shsecsize)<=0)
+		bigbufsize  = shsecsize;
+	dz->buflen = bigbufsize/sizeof(float);
+	if((dz->bigbuf = (float *)malloc((size_t)((bigbufsize * (dz->bufcnt - 1)) + segbuflen))) == NULL) {
+		sprintf(errstr,"INSUFFICIENT MEMORY to create sound buffers.\n");
+		return(PROGRAM_ERROR);
+	}
+	for(n=0;n<dz->bufcnt;n++)
+		dz->sbufptr[n] = dz->sampbuf[n] = dz->bigbuf + (dz->buflen * n);
+	dz->iparam[SEGLEN] = segbuflen/sizeof(float);
+	dz->sampbuf[n] = dz->bigbuf + (dz->buflen * (dz->bufcnt -1)) + dz->iparam[SEGLEN];
+	return(FINISHED);
+}
+
+/********************************************************************************************/
+/********************************** FORMERLY IN cmdline.c ***********************************/
+/********************************************************************************************/
+
+int get_process_no(char *prog_identifier_from_cmdline,dataptr dz)
+{
+	if     (!strcmp(prog_identifier_from_cmdline,"zigzag"))   		dz->process = ZIGZAG;
+	else if(!strcmp(prog_identifier_from_cmdline,"loop"))     		dz->process = LOOP;
+	else if(!strcmp(prog_identifier_from_cmdline,"scramble")) 		dz->process = SCRAMBLE;
+	else if(!strcmp(prog_identifier_from_cmdline,"iterate"))  		dz->process = ITERATE;
+	else if(!strcmp(prog_identifier_from_cmdline,"freeze"))  		dz->process = ITERATE_EXTEND;
+	else if(!strcmp(prog_identifier_from_cmdline,"drunk"))    		dz->process = DRUNKWALK;
+	else if(!strcmp(prog_identifier_from_cmdline,"sequence"))    	dz->process = SEQUENCER;
+	else if(!strcmp(prog_identifier_from_cmdline,"sequence2"))    	dz->process = SEQUENCER2;
+	else if(!strcmp(prog_identifier_from_cmdline,"baktobak"))    	dz->process = BAKTOBAK;
+	else if(!strcmp(prog_identifier_from_cmdline,"doublets"))    	dz->process = DOUBLETS;
+	else if(!strcmp(prog_identifier_from_cmdline,"repetitions"))    dz->process = ACC_STREAM;
+	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,
+	"\nUSAGE: extend NAME (mode) infile outfile parameters: \n"
+	"\n"
+	"where NAME can be any one of\n"
+	"\n"
+  	"zigzag loop iterate freeze scramble drunk sequence sequence2 baktobak doublets\n"
+  	"repetitions\n"
+	"\n"
+	"Type 'extend zigzag' for more info on zigzag option.. ETC.\n");
+	return(USAGE_ONLY);
+}
+
+/******************************** USAGE2 ********************************/
+
+int usage2(char *str)
+{
+	if(!strcmp(str,"zigzag")) {		
+	    fprintf(stdout,
+		"USAGE: extend zigzag 1 infile outfile start end dur minzig\n"
+		"\t[-ssplicelen] [-mmaxzig] [-rseed]\n\n"
+		"OR:    extend zigzag 2 infile outfile timefile [-ssplicelen]\n\n"
+	    "READ BACK AND FORTH INSIDE SOUNDFILE.\n\n"
+		"MODES\n"
+		"1:	random zigzags: starts at file start, ends at file end.\n"
+		"2: zigzagging follows times supplied by user.\n"
+		"start:     together with...\n"
+		"end:       define interval in which times zigzag.\n"
+		"dur:       is total duration of output sound required.\n"
+		"minzig:    is min acceptable time between successive zigzag timepoints.\n"
+		"splicelen: in MILLIsecs (Default 25ms).\n"
+		"maxzig:    is max acceptable time between successive zigzag timepoints\n"
+		"seed:      number to generate a replicable random sequence. (>0)\n"
+		"           entering same number on next program run, generates same sequence.\n"
+		"           (Default: (0) random sequence is different every time).\n"
+		"timefile:  text file containing sequence of times to zigzag between.\n"
+		"           Each step-between-times must be > (3 * splicelen).\n"
+		"           zigsteps moving in the same (time-)direction will be concatenated.\n");
+	} else if(!strcmp(str,"loop")) {		
+	    fprintf(stdout,
+		"USAGE:\n"
+		"extend loop 1 infile outfile     start len    step  [-wsplen] [-sscat] [-b]\n"
+		"extend loop 2 infile outfile dur start len [-lstep] [-wsplen] [-sscat] [-b]\n"
+		"extend loop 3 infile outfile cnt start len [-lstep] [-wsplen] [-sscat] [-b]\n\n"
+	    "LOOP INSIDE SOUNDFILE.\n\n"
+		"MODES\n"
+		"1: Loop advances in soundfile until soundfile is exhausted.\n"
+		"2: Specify outfile duration (shortened if looping reaches end of infile).\n"
+		"3: Specify number of loop repeats (reduced if looping reaches end of infile).\n\n"
+		"start:   time in infile at which looping process begins.\n"
+		"dur:     duration of outfile required.\n"
+		"cnt:     number of loop repeats required.\n"
+		"len:     length of looped segment (MILLIsecs).\n"
+		"step:    advance in infile from one loopstart to next (MILLIsecs).\n"
+		"         NB: Can be ZERO in modes 2 and 3, but NOT in mode 1.\n"
+		"splen:   length of splice in MILLIsecs (Default 25ms).\n"
+		"scat:    make step advance irregular, within timeframe given by 'scat'.\n"
+		"b:       play from beginning of infile (even if looping doesn't begin there).\n");
+	} else if(!strcmp(str,"scramble")) {		
+	    fprintf(stdout,
+		"USAGE:\n"
+		"extend scramble 1 infile outfile minseglen maxseglen outdur\n"
+		"                               [-wsplen] [-sseed] [-b] [-e]\n"
+		"extend scramble 2 infile outfile seglen    scatter   outdur\n"
+		"                             [-wsplen] [-sseed] [-b] [-e]\n\n"
+		"MODES:-\n"
+	    "1) CUT RANDOM CHUNKS FROM FILE, AND SPLICE END TO END.\n"
+	    "1) CUT FILE INTO RANDOM CHUNKS AND REARRANGE. REPEAT DIFFERENTLY..ETC\n\n"
+		"minseglen: minimum chunksize to cut.\n"
+		"maxseglen: maximum chunksize to cut. (> minseglen)\n"
+		"seglen:    average chunksize to cut.\n"
+		"scatter:   Randomisation of chunk lengths. (>= 0)\n"
+		"           (cannot be greater than infilesize/chunklen (rounded DOWN))\n"
+		"outdur:    duration of outfile required (> maxseglen).\n"
+		"splen:     length of splice in MILLIsecs (Default 25ms).\n"
+		"seed:      the same seed-number will produce identical output on rerun\n"
+		"           (Default: (0) random sequence is different every time).\n"
+		"b:         force start of outfile to be beginning of infile.\n"
+		"e:         force end of outfile to be end of infile.\n");
+	} else if(!strcmp(str,"iterate")) {		
+	    fprintf(stdout,
+		"ITERATE AN INPUT SOUND IN A FLUID MANNER\n\n"
+		"USAGE: extend iterate 1 infil outfil outduration\n"
+		"     [-ddelay] [-rrand] [-ppshift] [-aampcut] [-ffade] [-ggain] [-sseed]\n"
+		"OR:    extend iterate 2 infil outfil repetitions\n"
+		"     [-ddelay] [-rrand] [-ppshift] [-aampcut] [-ffade] [-ggain] [-sseed]\n\n"
+		"delay   (average) delay between iterations. Default: infile duration.\n"
+		"rand    delaytime-randomisation: Range 0 - 1: Default 0\n"
+		"pshift  max of random pitchshift of each iter: Range 0 - %.0lf semitones\n"
+		"        e.g.  2.5 =  2.5 semitones up or down.\n"
+		"ampcut  max of random amp-reduction on each iter: Range 0-1: default 0\n"
+		"fade    (average) amplitude fade between iters (Range 0 - 1: default 0)\n"
+		"gain    Overall Gain: Range 0 - 1:\n"
+		"        special val 0 (default), gives best guess for no distortion.\n"
+		"seed	 the same seed-number will produce identical output on rerun,\n"
+		"        (Default: (0) random sequence is different every time).\n",ITER_MAXPSHIFT);
+	} else if(!strcmp(str,"freeze")) {		
+	    fprintf(stdout,
+		"FREEZE A SEGMENT OF A SOUND BY ITERATION IN A FLUID MANNER\n\n"
+		"USAGE: extend freeze 1 infil outfil outduration\n"
+		"     delay rand pshift ampcut start_of_freeze end gain [-sseed]\n"
+		"OR:    extend freeze 2 infil outfil repetitions\n"
+		"     delay rand pshift ampcut starttime_of_freeze endtime gain [-sseed]\n"
+		"delay   (average) delay between iterations: <= length of frozen segment.\n"
+		"rand    delaytime-randomisation: Range 0 - 1\n"
+		"pshift  max of random pitchshift of each iter: Range 0 - %.0lf semitones\n"
+		"        e.g.  2.5 =  2.5 semitones up or down.\n"
+		"ampcut  max of random amp-reduction on each iter: Range 0-1\n"
+		"start_of_freeze    Time where frozen segment begins in original sound.\n"
+		"end                Time where frozen segment ends in original sound.\n"
+		"gain				Adjustment to gain of frozen segment (range 0.25 to 4).\n"
+		"seed	 the same seed-number will produce identical output on rerun,\n"
+		"        (Default: (0) random sequence is different every time).\n",ITER_MAXPSHIFT);
+	} else if(!strcmp(str,"drunk")) {		
+	    fprintf(stdout,
+		"SPLICE SEGMENTS OF SRCFILE END-TO-END: START-TIMES (IN SRCFILE) OF SEGS,CHOSEN\n"
+		"BY 'DRUNKEN-WALK' THROUGH SRCFILE:   IN MODE 2, SRCFILE PLAYS SOBERLY AT HOLDS\n\n"
+		"USAGES:\n"
+		"extend drunk 1 infile outfile outdur locus ambitus step clock\n"
+        "       [-ssplicelen] [-cclokrand] [-ooverlap] [-rseed]\n\n"
+		"extend drunk 2 infile outfile outdur locus ambitus step clock mindrnk maxdrnk\n"
+		"       [-ssplicelen] [-cclokrand] [-ooverlap] [-rseed] [-llosober] [-hhisober]\n\n"
+		"OUTDUR    Total (minimum) duration of output file (secs)\n"
+		"LOCUS     Time in src around which drunkwalk happens.(secs) CAN MOVE THRO SRC.\n"
+		"AMBITUS   (half)width of region from within which sound-segments read.(secs).\n"
+		"STEP      Max length of (random) step between segment-reads (>%.3lf secs).\n"
+        "          (always falls WITHIN ambitus: automatically adjusted where too large)\n"
+		"CLOCK     Time between segment reads = seg duration (> SPLICELEN * 2).(secs).\n"
+		"MINDRNK   Min no. cloktiks between sober plays (1 - %.0lf: Default %.0lf)\n"
+		"MAXDRNK   Max no. cloktiks between sober plays (1 - %.0lf: Default %.0lf)\n"
+		"SPLICELEN in MILLIsecs (default %.0lfms).\n"
+		"CLOKRAND  Randomisation of clock-ticks. (Range : 0-1: default 0)\n"
+		"OVERLAP   Mutual overlap of segments in output. (Range 0 to %.4lf: default 0)\n"
+		"SEED      Any set value gives REPRODUCIBLE output.\n"
+		"LOSOBER   Min duration of sober plays (secs) (Range: >0 - infiledur+)\n"
+		"          If >= infiledur (default): sober plays all go to end of src\n"
+		"HISOBER   Max duration of sober plays (secs) (Range: >0 - infiledur+)\n\n"
+		"all params EXCEPT outdur, splicelen and seed, may vary through time.\n",
+		DRNK_GRAIN,MAX_DRNKTIK,DEFAULT_MIN_DRNKTIK,MAX_DRNKTIK,DEFAULT_MAX_DRNKTIK,DRNK_SPLICE,DRNK_MAX_OVERLAP);
+	} else if(!strcmp(str,"sequence")) {		
+	    fprintf(stdout,
+    	"PRODUCE SEQUENCE OF INPUT SOUND PLAYED AT TRANSPOSITIONS & TIMES SPECIFIED.\n"
+		"USAGE:  extend sequence infile outfile sequence-file attenuation\n\n"
+		"SEQUENCE-FILE  contains output-time, semitone-transposition, loudness triples.\n"
+		"               (one for each event in the sequence)\n"
+		"               where loudness is a loudness multiplier\n"
+		"ATTENUATION    overall attenuation on source, should output overload.\n");
+	} else if(!strcmp(str,"sequence2")) {		
+	    fprintf(stdout,
+    	"PRODUCE SEQUENCE OF SEVERAL SOUNDS PLAYED AT TRANSPOSITIONS & TIMES SPECIFIED.\n"
+		"USAGE:  extend sequence2 inf1 inf2 [inf3....] outfile sequence-file attenuation [-ssplice]\n"
+		"        (Input files must all have same number of channels).\n"
+		"SEQUENCE-FILE  1st line has (possibly notional) midi-pitch of each input snd.\n"
+		"               All other lines have 5 values...\n"
+		"               input-sound-number, output-time, midi-pitch, loudness, duration\n"
+		"               (one for each event in the sequence)\n"
+		"               Loudness is a loudness multiplier (value 0-1).\n"
+		"               Duration val can curtail length of event, but cannot extend it.\n"
+		"               (Max event length = (transposed) duration of sound chosen).\n"
+		"ATTENUATION    overall attenuation on output.\n"
+		"SPLICE         length, in mS, of splice to cutoff samples at correct duration, if necessary.\n");
+	} else if(!strcmp(str,"baktobak")) {		
+	    fprintf(stdout,
+    	"JOIN A TIME-REVERSED COPY OF THE SOUND, TO A NORMAL COPY, IN THAT ORDER.\n"
+		"USAGE:  extend baktobak infile outfile join_time splice-length\n\n"
+		"JOIN TIME     Time in src file where join-cut is to be made.\n"
+		"SPLICE LENGTH (MS) Length of the splice, in milliseconds.\n");
+
+	} else if(!strcmp(str,"doublets")) {		
+	    fprintf(stdout,
+    	"SPLICE SOURCE INTO SEGMENTS, REPEATING EACH.\n"
+		"USAGE:  extend doublets infile outfile segdur repets [-s]\n\n"
+		"SEGDUR       Duration of segments (can vary through time).\n"
+		"REPETS       Number of times each segment repeated.\n"
+		"-s           Outfile tries to stay 'synced' to infile.\n");
+	} else if(!strcmp(str,"repetitions")) {		
+	    fprintf(stdout,
+    	"REPEAT SOURCE AT GIVEN TIMES.\n"
+		"USAGE:  extend repetitions infile outfile timesfile level\n\n"
+		"TIMESFILE   Textfile of times (in secs) at which source plays.\n"
+		"LEVEL       Level of output (range 0-1): can vary over time.\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);
+}
+
+/******************************** 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);
+}
+
+/******************************** CREATE_ACCBUFS ********************************/
+
+int create_accbufs(dataptr dz)
+{
+	size_t bigbufsize;
+	int /*seccnt,*/ effective_size;
+#ifdef NOTDEF
+	if(((seccnt = dz->infilesize[0]/SECSIZE) * SECSIZE) < dz->infilesize[0])
+		seccnt++;
+	effective_size = seccnt * SECSIZE;
+#else
+	effective_size = dz->insams[0];
+#endif
+	if(dz->sbufptr == 0 || dz->sampbuf==0 || dz->extrabuf==0) {
+		sprintf(errstr,"buffer pointers not allocated: create_accbufs()\n");
+		return(PROGRAM_ERROR);
+	}
+	if((dz->extrabuf[0] = (float *)malloc((size_t)(effective_size * sizeof(float)))) == NULL) {
+		sprintf(errstr,"INSUFFICIENT MEMORY to store input sound: Process works with short sounds only.\n");
+		return(PROGRAM_ERROR);
+	}
+	bigbufsize = (size_t) Malloc(-1);
+#ifdef NOTDEF
+	if((dz->bigbufsize  = (dz->bigbufsize/SECSIZE) * SECSIZE)<=0)
+		dz->bigbufsize  = SECSIZE;
+#endif
+	dz->buflen = (int)(bigbufsize/sizeof(float));
+
+	/*RWD*/
+	dz->buflen = (dz->buflen / dz->infile->channels) * dz->infile->channels;
+
+	if((dz->bigbuf = (float *)malloc((size_t)(sizeof(float)*(dz->buflen + effective_size)))) == NULL) {
+		sprintf(errstr,"INSUFFICIENT MEMORY to create sound buffers.\n");
+		return(PROGRAM_ERROR);
+	}
+	dz->sbufptr[0] = dz->sampbuf[0] = dz->bigbuf;
+	return(FINISHED);
+}
+
+//TW NEW FUNCTIONS
+/********************************* READ_SEQUENCE ***************************/
+
+#define IS_SEQ_TIME (0)
+#define IS_SEQ_PICH (1)
+#define IS_SEQ_LEVL (2)
+
+int read_sequence(char *filename,dataptr dz)
+{
+	FILE *fp;
+	char temp[200], *p;
+	double val;
+	int itemcnt = 0;
+	int data_type = 0;
+//	double max_transpos = GR_MAX_TRANSPOS * SEMITONES_PER_OCTAVE;
+	double last_time = -1.0;
+	if((fp = fopen(filename,"r"))==NULL) {
+		sprintf(errstr,"Cannot open file %s to read data.\n",filename);
+		return(DATA_ERROR);
+	}
+	while(fgets(temp,200,fp)!=NULL) {
+		p = temp;
+		if(*p == ';')	//	Allow comments in file
+			continue;
+		while(get_float_from_within_string(&p,&val)) {
+			switch(data_type) {
+			case(IS_SEQ_TIME):
+				if(last_time < 0.0) {
+					if(val < 0.0) {
+						sprintf(errstr,"First Time (%lf) less than zero\n",val);
+						return(DATA_ERROR);
+					}
+				} else {
+					if(val < last_time) {
+						sprintf(errstr,"Times do not increase at (%lf): OR data not grouped as time-transpos-level\n",val);
+						return(DATA_ERROR);
+					}
+				}
+				last_time = val;
+				break;
+			case(IS_SEQ_PICH):
+				if(val < dz->application->min_special || val > dz->application->max_special) {
+					sprintf(errstr,"Pitch-ratio (%lf) out of range (%lf - %lf): OR data not grouped as time-transpos-level\n",
+					val,dz->application->min_special,dz->application->max_special);
+					return(DATA_ERROR);
+				}
+				val = pow(2.0,val/SEMITONES_PER_OCTAVE);
+				break;
+			case(IS_SEQ_LEVL):
+				if(val < 0.0) {
+					sprintf(errstr,"Level (%lf) is less than zero: OR data not grouped as time-transpos-level\n",val);
+					return(DATA_ERROR);
+				}
+				break;
+			}
+			data_type++;
+			data_type = data_type % 3;
+			if(!itemcnt)
+				dz->parray[0] = (double *)malloc((itemcnt+1)*sizeof(double));
+			else
+				dz->parray[0] =(double *)realloc((char *)dz->parray[0],(itemcnt+1)*sizeof(double));
+			dz->parray[0][itemcnt] = val;
+			itemcnt++;
+		}
+	}
+	if(itemcnt==0) {
+		sprintf(errstr,"No data in file '%s'.\n",filename);
+		return(DATA_ERROR);
+	}
+	if((itemcnt/3)*3 != itemcnt) {
+		sprintf(errstr,"Time, Pitch and Level values not grouped correctly.\n");
+		return(DATA_ERROR);
+	}
+	dz->parray[1] = dz->parray[0] + itemcnt;
+	if(fclose(fp)<0) {
+		fprintf(stdout,"WARNING: Failed to close input textfile %s.\n",filename);
+		fflush(stdout);
+	}
+	return(FINISHED);
+}
+
+/********************************* SEQUENCER_PREPROCESS ***************************/
+
+int sequencer_preprocess(dataptr dz)
+{
+	int chans = dz->infile->channels;
+	double last_time     = *(dz->parray[1] - 3);
+	double last_transpos = *(dz->parray[1] - 2);
+	dz->tempsize =  (int)round(last_time * dz->infile->srate) * chans;
+	dz->tempsize += (int)round((dz->insams[0]/chans)/last_transpos) * chans;
+	return(FINISHED);
+}
+
+/********************************* CREATE_BTOB_BUFS ***************************/
+
+int create_btob_bufs(dataptr dz)
+{
+	int seccnt;
+	size_t total_bufsize, bigbufsize;
+	int fsecbytesize = F_SECSIZE * sizeof(float);
+	bigbufsize = (size_t) Malloc(-1);
+	seccnt = bigbufsize/(2 * fsecbytesize);
+	if(seccnt * (2 *fsecbytesize) < bigbufsize)
+		seccnt++;
+	bigbufsize = seccnt * fsecbytesize;
+	dz->buflen = (int)(bigbufsize/sizeof(float));
+	total_bufsize = ((dz->buflen * 2) + dz->iparam[BTOB_SPLEN]) * sizeof(float);
+	if((dz->bigbuf = (float *)Malloc(total_bufsize)) == 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;
+	dz->sampbuf[2] = dz->sampbuf[1] + dz->buflen;
+	memset((char *)dz->bigbuf,0,total_bufsize);
+	return(FINISHED);
+}
+
+/********************************* CHECK_BTOB_CONSISTENCY ***************************/
+
+int check_btob_consistency(dataptr dz)
+{
+	dz->param[BTOB_SPLEN] *= MS_TO_SECS;
+	if(dz->param[BTOB_SPLEN]/2.0 >= dz->param[BTOB_CUT]) {
+		sprintf(errstr,"Cut point (%lf secs)is too near to start of file for the splicelength (%lf secs) demanded.\n",
+			dz->param[BTOB_CUT],dz->param[BTOB_SPLEN]);
+		return(DATA_ERROR);
+	}
+	if(!EVEN(dz->iparam[BTOB_SPLEN] = (int)round(dz->param[BTOB_SPLEN] * dz->infile->srate)))
+		dz->iparam[BTOB_SPLEN]--;
+	dz->iparam[BTOB_SPLEN] *= dz->infile->channels;
+	dz->iparam[BTOB_CUT] = (int)round(dz->param[BTOB_CUT] * dz->infile->srate) * dz->infile->channels;
+	dz->tempsize = ((dz->insams[0] - dz->iparam[BTOB_CUT]) * 2) + (dz->iparam[BTOB_SPLEN]/2);
+	return(FINISHED);
+}
+
+/********************************* DOUBLETS_PREPROCESS ***************************/
+
+int doublets_preprocess(dataptr dz)
+{
+	int file_samplen;
+	double duration;
+	file_samplen = dz->insams[0]/dz->infile->channels;
+	duration= (double)file_samplen/(double)dz->infile->srate;
+	if(duration < SPLICEDUR * 2) {
+		sprintf(errstr,"Input file is too short for this process.\n");
+		return(DATA_ERROR);
+	}
+	return FINISHED;
+}
+
+/********************************* READ_SEQUENCE2 ***************************/
+
+#define IS_SEQ2_INS  (0)
+#define IS_SEQ2_TIME (1)
+#define IS_SEQ2_PICH (2)
+#define IS_SEQ2_LEVL (3)
+#define IS_SEQ2_DUR  (4)
+
+int read_sequence2(char *filename,dataptr dz)
+{
+	FILE *fp;
+	char temp[200], *p;
+	double val;
+	double *inpitches;
+	int ival = 0;
+	int itemcnt = 0, gotpitches = 0;
+	int arraysize = 0;
+	int data_type = 0, linecnt;
+	double last_time = -1.0;
+	double splicelen = 2.0 * MS_TO_SECS;
+	if((fp = fopen(filename,"r"))==NULL) {
+		sprintf(errstr,"Cannot open file %s to read data.\n",filename);
+		return(DATA_ERROR);
+	}
+	while(fgets(temp,200,fp)!=NULL) {
+		p = temp;
+		if(*p == ';')	//	Allow comments in file
+			continue;
+		while(get_float_from_within_string(&p,&val)) {
+			arraysize++;
+		}
+	}
+	if(arraysize==0) {
+		sprintf(errstr,"No data in file '%s'.\n",filename);
+		return(DATA_ERROR);
+	}
+	arraysize -= dz->infilecnt;
+	if((arraysize/5)*5 != arraysize) {
+		sprintf(errstr,"Sound-number, Time, Pitch, Level, Duration vals not grouped correctly: or sound-pitches listed incorrectly\n");
+		return(DATA_ERROR);
+	}
+	if((inpitches = (double *)malloc((dz->infilecnt)*sizeof(double)))==NULL) {
+		sprintf(errstr,"Cannot allocate memory to store input sound pitches.\n");
+		return(MEMORY_ERROR);
+	}
+	if((dz->parray[0] = (double *)malloc((arraysize)*sizeof(double)))==NULL) {
+		sprintf(errstr,"Cnnot allocate memory to store sequence data\n");
+		return(MEMORY_ERROR);
+	}
+	fseek(fp,0,0);
+	linecnt = 1;
+	gotpitches = 0;
+	while(fgets(temp,200,fp)!=NULL) {
+		p = temp;
+		if(*p == ';')	//	Allow comments in file
+			continue;
+		while(get_float_from_within_string(&p,&val)) {
+			if(gotpitches < dz->infilecnt) {			/* GET PITCHES OF INPUT SOUND */
+				if(val < dz->application->min_special || val > dz->application->max_special) {
+					sprintf(errstr,"Pitch of sound %d (%lf) on first line of sequence data is out of range\n",
+					gotpitches+1,val/*, dz->application->min_special,dz->application->max_special*/);
+					return(DATA_ERROR);
+				}
+				inpitches[gotpitches++] = miditohz(val);
+				continue;
+			}
+			switch(data_type) {
+			case(IS_SEQ2_INS):
+				ival = (int)round(val);
+				if(val != (double)ival || ival < 1 || ival > dz->infilecnt) {
+					sprintf(errstr,"Instrument number (1st item) at line %d does  not correspond to any input file\n",linecnt);
+					return(DATA_ERROR);
+				}
+				ival--;
+				val = (double)ival;
+				break;
+			case(IS_SEQ2_TIME):
+				if(last_time < 0.0) {
+					if(val < 0.0) {
+						sprintf(errstr,"First Time (%lf) less than zero\n",val);
+						return(DATA_ERROR);
+					}
+				} else {
+					if(val < last_time) {
+						sprintf(errstr,"Times do not increase at (%lf) AT LINE %d: OR data not grouped as time-transpos-level\n",val,linecnt);
+						return(DATA_ERROR);
+					}
+				}
+				last_time = val;
+				break;
+			case(IS_SEQ2_PICH):
+				if(val < dz->application->min_special || val > dz->application->max_special) {
+					sprintf(errstr,"Pitch (%lf) (2nd item) on line %d out of range (%lf - %lf): OR data not grouped as sound-time-pitch-level\n",
+					val,linecnt, dz->application->min_special,dz->application->max_special);
+					return(DATA_ERROR);
+				}
+				val = miditohz(val);
+				val = val/inpitches[ival];	/* convert pitch to transposition */
+				break;
+			case(IS_SEQ2_LEVL):
+				if(val < 0.0) {
+					sprintf(errstr,"Level (%lf) is less than zero at line %d: OR data not grouped as sound-time-pitch-level\n",val,linecnt);
+					return(DATA_ERROR);
+				}
+				break;
+			case(IS_SEQ2_DUR):
+				if(val <= splicelen) {
+					sprintf(errstr,"Duration (%lf) at line %d is too short for splicelen (2 ms)\n",val,linecnt);
+					return(DATA_ERROR);
+				}
+				break;
+			}
+			data_type++;
+			data_type = data_type % 5;
+			dz->parray[0][itemcnt] = val;
+			itemcnt++;
+		}
+		linecnt++;
+	}
+	dz->parray[1] = dz->parray[0] + itemcnt;
+	if(fclose(fp)<0) {
+		fprintf(stdout,"WARNING: Failed to close input textfile %s.\n",filename);
+		fflush(stdout);
+	}
+	return(FINISHED);
+}
+
+/********************************* SEQUENCER2_PREPROCESS ***************************/
+
+int sequencer2_preprocess(dataptr dz)
+{
+	int chans = dz->infile->channels;
+	int    last_ins      = (int)round(*(dz->parray[1] - 5));
+	double last_time     = *(dz->parray[1] - 4);
+	double last_transpos = *(dz->parray[1] - 3);
+	int   last_dur      = (int)round(*(dz->parray[1] - 1) * dz->infile->srate) * chans;
+	int lastdur = (int)round((dz->insams[last_ins]/chans)/last_transpos) * chans;
+	lastdur = min(lastdur,last_dur);
+	dz->tempsize =  (int)round(last_time * dz->infile->srate) * chans;
+	dz->tempsize += lastdur;
+	return(FINISHED);
+}
+

+ 613 - 0
dev/extend/drunk.c

@@ -0,0 +1,613 @@
+/*
+ * 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 <string.h>
+#include <structures.h>
+#include <tkglobals.h>
+#include <globcon.h>
+#include <processno.h>
+#include <modeno.h>
+#include <arrays.h>
+#include <extend.h>
+#include <cdpmain.h>
+#include <sfsys.h>
+#include <osbind.h>
+
+
+int  drunk(int here,int *obufpos,int *thisbuf,int thisdur,double pregain,int *endwrite,int outbufspace,dataptr dz);
+int  do_pause(int here,int *obufpos,int *endwrite,int *thisbuf,int thisdur,double pregain,int outbufspace,dataptr dz);
+int  get_thisdur(int *thisdur,int *goalpcnt,int *pcnt,dataptr dz);
+int  get_pos_and_dur_for_pause(int *here,int *thisdur,int *thisbuf,int *ibufpos,double pregain,dataptr dz);
+int  get_pos(int *here,int thisdur,dataptr dz);
+void do_pregain(double pregain,dataptr dz);
+int  is_paus(int *goalpcnt,int *pcnt,dataptr dz);
+int  convert_time_to_samplecnts(int paramno,dataptr dz);
+int  convert_sec_steps_to_grain_steps(dataptr dz);
+int  adjust_bufs(int here,int *ibufpos,int *thisbuf,double pregain,dataptr dz);
+int  do_intermediate_write(int *endwrite,int *obufpos,dataptr dz);
+int  make_drnk_splicetab(dataptr dz);
+void setup_paus_params(dataptr dz);
+int  get_maxvalue(int paramno,double *maxval,dataptr dz);
+double get_pregain(dataptr dz);
+int  do_start_splice(int chans,float *obuf,int *obufpos,float *ibuf,int *ibufpos,int *thisbuf,double pregain,
+		int *endwrite,int outbufspace,dataptr dz);
+int  do_end_splice(int chans,float *obuf,int *obufpos,float *ibuf,int *ibufpos,int *thisbuf,double pregain,dataptr dz);
+int  bounce_off_file_end_if_necessary(int *here,int thisdur,int chans,int splicelen,dataptr dz);
+int  get_pausdur(int *here,int splicelen,int chans,int *thisdur,dataptr dz);
+int get_step(int chans,dataptr dz);
+int get_new_pos(int here,int ambitus,int locus,int step);
+int get_new_locus_pos(int here,int ambitus,int locus,int step);
+
+/*************************** DO_DRUNKEN_WALK *************************/
+
+int do_drunken_walk(dataptr dz)
+{
+	int exit_status;
+	int here = 0, ibufpos, obufpos = 0, samps_processed = 0;
+	double outsamptime;
+	double  pregain = 1.0;
+	int thisdur, endwrite = 0;
+	int thisbuf;
+	int is_a_pause;
+	int goalpcnt = -1;	/* total events needed before pause: initialisation value -1 */
+	int pcnt = 0;		/* count of events since last pause: initial val 0 > -1 */
+	int chans = dz->infile->channels;
+	int finished = FALSE;
+	int outbufspace = dz->sampbuf[3] - dz->sampbuf[1];
+
+	display_virtual_time(0,dz);
+	if((exit_status = read_samps(dz->sampbuf[0],dz))<0)
+		return(exit_status);
+	if(dz->vflag[IS_DRNK_OVERLAP]) {
+		pregain = get_pregain(dz);
+		do_pregain(pregain,dz);
+	}
+	while(samps_processed < dz->iparam[DRNK_TOTALDUR]) {
+		outsamptime  = (double)((obufpos + dz->total_samps_written)/chans);
+		if((exit_status = read_values_from_all_existing_brktables(outsamptime,dz))<0)
+			return(exit_status);
+		while((is_a_pause = get_thisdur(&thisdur,&goalpcnt,&pcnt,dz))==TRUE) {
+			setup_paus_params(dz);
+			if((exit_status = get_pos_and_dur_for_pause(&here,&thisdur,&thisbuf,&ibufpos,pregain,dz))<0)
+				return(exit_status);
+			if((exit_status = do_pause(ibufpos,&obufpos,&endwrite,&thisbuf,thisdur,pregain,outbufspace,dz))<0)
+				return(exit_status);
+			if((samps_processed = dz->total_samps_written + endwrite) >= dz->iparam[DRNK_TOTALDUR]) {
+				finished = TRUE;
+				break;
+			}
+			outsamptime  = (double)((obufpos + dz->total_samps_written)/chans);
+			if((exit_status = read_values_from_all_existing_brktables(outsamptime,dz))<0)
+				return(exit_status);
+		}
+		if(finished)
+			break;
+		if((exit_status = get_pos(&here,thisdur,dz))<0)
+			return(exit_status);
+		if((exit_status = adjust_bufs(here,&ibufpos,&thisbuf,pregain,dz))<0)
+			return(exit_status);
+		if((exit_status = drunk(ibufpos,&obufpos,&thisbuf,thisdur,pregain,&endwrite,outbufspace,dz))<0)
+			return(exit_status);
+		if(obufpos >= dz->buflen) {
+			if((exit_status = do_intermediate_write(&endwrite,&obufpos,dz))<0)
+				return(exit_status);
+		}
+		samps_processed = dz->total_samps_written + endwrite;
+	}
+	if(endwrite > 0) {
+		if((exit_status = write_samps(dz->sampbuf[1],endwrite,dz))<0)
+			return(exit_status);
+	}
+	display_virtual_time(dz->total_samps_written,dz);
+	return(FINISHED);
+}
+
+/**************************** DRUNK **************************/
+
+int drunk(int ibufpos,int *obufpos,int *thisbuf,int thisdur,double pregain,int *endwrite,int outbufspace,dataptr dz)
+{
+	int exit_status;
+	int n, overlap, copyblk;
+	int  chans = dz->infile->channels;
+	int splicelen = dz->iparam[DRNK_SPLICELEN] * chans;
+	int outbpos;
+	float *ibuf = dz->sampbuf[0], *thisin;
+	float *obuf = dz->sampbuf[1];
+	int available_insamps;
+	if((exit_status = do_start_splice(chans,obuf,obufpos,ibuf,&ibufpos,thisbuf,pregain,endwrite,outbufspace,dz))<0)
+		return(exit_status);
+	outbpos = *obufpos;
+	copyblk = thisdur - splicelen;
+	available_insamps  = dz->ssampsread - ibufpos;
+	while(available_insamps < copyblk) {
+		thisin  = ibuf+ibufpos;
+		for(n=0;n<available_insamps;n++) {
+			if(outbpos >= outbufspace) {
+				*endwrite = outbpos;
+				if((exit_status = do_intermediate_write(endwrite,&outbpos,dz))<0)
+					return(exit_status);
+			}
+			obuf[outbpos++] += thisin[n];
+		}
+		if((exit_status = read_samps(dz->sampbuf[0],dz))<0)
+			return(exit_status);
+		if(dz->vflag[IS_DRNK_OVERLAP])
+			do_pregain(pregain,dz);			 
+		(*thisbuf)++;
+		ibufpos  = 0;
+		copyblk -= available_insamps;
+		available_insamps = dz->ssampsread;
+	}			
+	if(copyblk > 0) {
+		thisin  = ibuf+ibufpos;
+		for(n=0;n<copyblk;n++) {
+			if(outbpos >= outbufspace) {
+				*endwrite = outbpos;
+				if((exit_status = do_intermediate_write(endwrite,&outbpos,dz))<0)
+					return(exit_status);
+			}
+			obuf[outbpos++] += thisin[n];	
+		}
+		ibufpos += copyblk;
+	}
+	if((exit_status = do_end_splice(chans,obuf,&outbpos,ibuf,&ibufpos,thisbuf,pregain,dz))<0)
+		return(exit_status);
+	*endwrite = outbpos;
+	outbpos -= splicelen;
+	if(dz->vflag[IS_DRNK_OVERLAP]) {
+		overlap = round((double)(thisdur/chans) * dz->param[DRNK_OVERLAP]) * chans; 
+		outbpos  -= overlap;
+	}
+	*obufpos = outbpos;
+	return(FINISHED);
+} 
+
+/**************************** DO_PAUSE **************************/
+
+int do_pause(int ibufpos,int *obufpos,int *endwrite,int *thisbuf,int thisdur,double pregain,
+	int outbufspace,dataptr dz)
+{
+	int exit_status;
+	int n, copyblk, write_block;
+	int outbpos;
+	int  chans = dz->infile->channels;
+	int splicelen = dz->iparam[DRNK_SPLICELEN] * chans;
+	float *ibuf = dz->sampbuf[0], *thisin;
+	float *obuf = dz->sampbuf[1], *thisout;
+	int available_insamps, available_outspace;
+/* ?? */
+	if((exit_status = do_start_splice(chans,obuf,obufpos,ibuf,&ibufpos,thisbuf,pregain,endwrite,outbufspace,dz))<0)
+		return(exit_status);
+	outbpos = *obufpos;
+	copyblk = thisdur - splicelen;
+	write_block = dz->sampbuf[3] - dz->sampbuf[1]; /* writeable block = outbuf + overflow */
+	available_outspace = write_block - outbpos;
+	available_insamps  = dz->ssampsread - ibufpos;
+	while(copyblk >= available_outspace) {
+		while(available_insamps <= available_outspace) {
+			thisout = obuf+outbpos;
+			thisin  = ibuf+ibufpos;
+			for(n=0;n<available_insamps;n++)
+				thisout[n] += thisin[n];	
+			if((exit_status = read_samps(dz->sampbuf[0],dz))<0)
+				return(exit_status);
+			if(dz->vflag[IS_DRNK_OVERLAP])
+				do_pregain(pregain,dz);
+			(*thisbuf)++;
+			ibufpos     		= 0;
+			outbpos   		   += available_insamps;
+			copyblk 		   -= available_insamps;
+			available_outspace -= available_insamps;
+			available_insamps   = dz->ssampsread;			
+		}
+		if(available_outspace > 0) {
+			thisout = obuf+outbpos;
+			thisin  = ibuf+ibufpos;
+			for(n=0;n<available_outspace;n++)
+				thisout[n] += thisin[n];	
+			ibufpos  		  += available_outspace;
+			outbpos 		  += available_outspace;
+			copyblk 		  -= available_outspace;
+			available_insamps  = dz->ssampsread - ibufpos;			
+		}
+		if(write_block > 0) {
+			if((exit_status = write_samps(dz->sampbuf[1],write_block,dz))<0)
+				return(exit_status);
+		}
+		display_virtual_time(dz->total_samps_written,dz);
+		memset((char *)dz->sampbuf[1],0,write_block * sizeof(float));
+		write_block = dz->sampbuf[2] - dz->sampbuf[1];	/* change writeable block to outbuf only */
+		outbpos = 0;
+		available_outspace = dz->buflen;
+	}
+	while(available_insamps < copyblk) {
+		thisout = obuf+outbpos;
+		thisin  = ibuf+ibufpos;
+		for(n=0;n<available_insamps;n++)
+			thisout[n] += thisin[n];	
+		if((exit_status = read_samps(dz->sampbuf[0],dz))<0)
+			return(exit_status);
+		if(dz->vflag[IS_DRNK_OVERLAP])
+			do_pregain(pregain,dz);
+		(*thisbuf)++;
+		ibufpos  = 0;
+		outbpos += available_insamps;
+		copyblk -= available_insamps;
+		available_insamps = dz->ssampsread;			
+	}
+	if(copyblk > 0) {
+		thisout = obuf+outbpos;
+		thisin  = ibuf+ibufpos;
+		for(n=0;n<copyblk;n++)
+			thisout[n] += thisin[n];	
+		ibufpos += copyblk;
+		outbpos += copyblk;
+	}
+	if((exit_status = do_end_splice(chans,obuf,&outbpos,ibuf,&ibufpos,thisbuf,pregain,dz))<0)
+		return(exit_status);
+	*endwrite = outbpos;
+	outbpos -= splicelen;
+	if(outbpos >= dz->buflen) {	/* if we're now beyond outbuf end: do bufwrite & copyback */
+		if((exit_status = do_intermediate_write(endwrite,&outbpos,dz))<0)
+			return(exit_status);
+	}
+	*obufpos = outbpos;
+	return FINISHED;
+} 
+
+/***************************** GET_THISDUR *******************************/
+
+int get_thisdur(int *thisdur,int *goalpcnt,int *pcnt,dataptr dz)
+{
+	double randv;
+	if(dz->mode==HAS_SOBER_MOMENTS && is_paus(goalpcnt,pcnt,dz))
+		return TRUE;
+	randv  = drand48() * dz->param[DRNK_CLOKRND];
+	if((*thisdur = round((double)dz->iparam[DRNK_CLOKTIK] * (1.0 + randv)))<dz->iparam[DRNK_SPLICELEN])
+		*thisdur = round((double)dz->iparam[DRNK_CLOKTIK] * (1.0 - randv));
+	*thisdur *= dz->infile->channels;
+	return FALSE;
+}
+
+/***************************** GET_POS_AND_DUR_FOR_PAUSE *******************************/
+
+int get_pos_and_dur_for_pause(int *here,int *thisdur,int *thisbuf,int *ibufpos,double pregain,dataptr dz)
+{										   
+	int exit_status;
+	int step;
+	int chans = dz->infile->channels;
+	int ambitus   = dz->iparam[DRNK_AMBITUS]   * chans;
+	int locus     = dz->iparam[DRNK_LOCUS] 	* chans;
+	int splicelen = dz->iparam[DRNK_SPLICELEN] * chans;
+
+	if(ambitus>0 && (step = get_step(chans,dz))!=0)
+		*here = get_new_pos(*here,ambitus,locus,step);
+
+	if((exit_status = get_pausdur(here,splicelen,chans,thisdur,dz))<0)
+		return(exit_status);
+	
+	return adjust_bufs(*here,ibufpos,thisbuf,pregain,dz);
+}
+
+/***************************** GET_POS *******************************/
+
+int get_pos(int *here,int thisdur,dataptr dz)
+{										   
+	int step = 0;
+	int  chans = dz->infile->channels;
+	int ambitus   = dz->iparam[DRNK_AMBITUS]   * chans;
+	int locus 	   = dz->iparam[DRNK_LOCUS] 	* chans;
+	int splicelen = dz->iparam[DRNK_SPLICELEN] * chans;
+
+	if(ambitus > 0 && (step = get_step(chans,dz))!=0)
+		*here = get_new_pos(*here,ambitus,locus,step);
+	else if(dz->iparam[DRNK_LAST_LOCUS] != dz->iparam[DRNK_LOCUS])
+		*here = get_new_locus_pos(*here,ambitus,locus,step);
+	dz->iparam[DRNK_LAST_LOCUS] = dz->iparam[DRNK_LOCUS];
+	return bounce_off_file_end_if_necessary(here,thisdur,chans,splicelen,dz);
+}
+
+/*************************** PREGAIN ****************************
+ *
+ * Allows for effect of overlapping segments.
+ */
+
+void do_pregain(double pregain,dataptr dz)
+{
+	int i;
+	double j;
+	float *iptr = dz->sampbuf[0];
+	for(i=0;i<dz->ssampsread;i++) {
+		j = (*iptr) * pregain;
+		*iptr++ = (float) /*round*/j; 
+	}
+}
+
+/******************************* IS_PAUS *******************************/
+
+int is_paus(int *goalpcnt,int *pcnt,dataptr dz)
+{
+	if(*goalpcnt < 0) {								/* if 1st time */
+		setup_paus_params(dz);
+		*goalpcnt  = round(drand48() * (double)dz->iparam[DRNK_DRNKTIK_RANG]);
+		*goalpcnt += dz->iparam[DRNK_MIN_DRNKTIK];
+	} else if((*pcnt)++ >= *goalpcnt) {				/* if counted enough events to insert pause  */
+		setup_paus_params(dz);
+		*goalpcnt  = round(drand48() * (double)dz->iparam[DRNK_DRNKTIK_RANG]);
+		*goalpcnt += dz->iparam[DRNK_MIN_DRNKTIK];
+		*pcnt = 0;									/* Reset event counter to zero    */
+		return TRUE;								/* Flag that pz has been returned */
+	}
+	return FALSE;									/* ELSE Flag no pz on this occasion */
+}
+
+/************************* ADJUST_BUFS *********************/
+
+int adjust_bufs(int here,int *ibufpos,int *thisbuf,double pregain,dataptr dz)
+{
+	int exit_status;
+	int nextbuf = here/dz->buflen;
+	if(nextbuf != *thisbuf) {
+		if((sndseekEx(dz->ifd[0],nextbuf * dz->buflen,0))<0) {
+			sprintf(errstr,"seek error in adjust_bufs()\n");
+			return(SYSTEM_ERROR);
+		}
+		if((exit_status = read_samps(dz->sampbuf[0],dz))<0)
+			return(exit_status);
+		if(dz->vflag[IS_DRNK_OVERLAP])
+			do_pregain(pregain,dz);
+	}			
+	*ibufpos = here % dz->buflen;
+	if(*ibufpos >= dz->ssampsread) {
+		sprintf(errstr,"Buffer accounting problem: adjust_bufs()\n"); 
+		return(PROGRAM_ERROR);
+	}
+	*thisbuf = nextbuf;
+	return FINISHED;
+}
+
+/************************* DO_INTERMEDIATE_WRITE *********************/
+
+int do_intermediate_write(int *endwrite,int *obufpos,dataptr dz)
+{
+	int exit_status;
+	int samps_to_move   = *endwrite - dz->buflen;
+	int samps_available = dz->sampbuf[3] - dz->sampbuf[1];
+	if((exit_status = write_samps(dz->sampbuf[1],dz->buflen,dz))<0)
+		return(exit_status);
+	display_virtual_time(dz->total_samps_written,dz);
+	memmove((char *)dz->sampbuf[1],(char *)dz->sampbuf[2],(size_t)(samps_to_move* sizeof(float)));
+	memset((char *)(dz->sampbuf[1] + samps_to_move),0,(size_t)((samps_available - samps_to_move)*sizeof(float)));
+	*endwrite -= dz->buflen;
+	*obufpos -= dz->buflen;
+	return(FINISHED);
+}
+
+/************************* SETUP_PAUS_PARAMS *********************/
+
+void setup_paus_params(dataptr dz)
+{
+	int tempval;
+
+    if(dz->iparam[DRNK_MIN_DRNKTIK] > dz->iparam[DRNK_MAX_DRNKTIK]) {
+		tempval      				 = dz->iparam[DRNK_MIN_DRNKTIK];
+		dz->iparam[DRNK_MIN_DRNKTIK] = dz->iparam[DRNK_MAX_DRNKTIK];
+		dz->iparam[DRNK_MAX_DRNKTIK] = tempval;
+    }
+    dz->iparam[DRNK_DRNKTIK_RANG] = (int)(dz->iparam[DRNK_MAX_DRNKTIK] - dz->iparam[DRNK_MIN_DRNKTIK]);
+
+	if(dz->param[DRNK_MIN_PAUS] >= dz->insams[0])
+		dz->iparam[DRNK_MAXHOLD] = TRUE;
+	else {
+		dz->iparam[DRNK_MAXHOLD] = FALSE;
+		if(dz->iparam[DRNK_MIN_PAUS] > dz->iparam[DRNK_MAX_PAUS]) {
+			tempval					  = dz->iparam[DRNK_MIN_PAUS];
+			dz->iparam[DRNK_MIN_PAUS] = dz->iparam[DRNK_MAX_PAUS];
+			dz->iparam[DRNK_MAX_PAUS] = tempval;
+		}
+		dz->iparam[DRNK_PAUS_RANG] = (int)(dz->iparam[DRNK_MAX_PAUS] - dz->iparam[DRNK_MIN_PAUS]);
+	}
+}
+
+/************************* GET_PREGAIN *********************/
+			 
+double get_pregain(dataptr dz)
+{
+	double val;
+	val = 1.0 - dz->param[DRNK_MAX_OVLAP];		/* e.g. 3/4+ -> 1/4 || .76 -> .24 */
+	val = 1.0/val;								/* i.e  1/4  -> 4   || .24 -> 4+  */
+	val += 1.0;									/* i.e. 4    -> 5   || 4+  -> 5+  */	
+//TW UPDATE
+//	return val;
+	return 1.0/val;
+}
+
+/*************************** DO_START_SPLICE **************************/
+
+int do_start_splice(int chans,float *obuf,int *obufpos,float *ibuf,int *ibufpos,int *thisbuf,
+	double pregain,int *endwrite,int outbufspace,dataptr dz) 
+{
+	int exit_status;
+	int n;
+	int m;
+	int outbpos = *obufpos;
+	int inbpos  = *ibufpos;
+	for(n=0;n<dz->iparam[DRNK_SPLICELEN];n++) {
+		for(m=0;m<chans;m++) {			
+			if(outbpos >= outbufspace) {
+				*endwrite = outbpos;
+				if((exit_status = do_intermediate_write(endwrite,&outbpos,dz))<0)
+					return(exit_status);
+			}
+			obuf[outbpos++] += (float)/*round*/((double)ibuf[inbpos++] * dz->parray[DRNK_SPLICETAB][n]); 
+		}
+		if(inbpos >= dz->ssampsread) {
+			if((exit_status = read_samps(dz->sampbuf[0],dz))<0)
+				return(exit_status);
+			if(dz->vflag[IS_DRNK_OVERLAP])
+				do_pregain(pregain,dz);
+			inbpos = 0;
+			(*thisbuf)++;
+		}
+	}
+	*obufpos = outbpos;
+	*ibufpos = inbpos;
+	return(FINISHED);
+}
+
+
+/*************************** DO_END_SPLICE **************************/
+
+int do_end_splice(int chans,float *obuf,int *obufpos,float *ibuf,int *ibufpos,int *thisbuf,double pregain,dataptr dz) 
+{
+	int exit_status;
+	int n;
+	int m;
+	int outbpos = *obufpos;
+	int inbpos  = *ibufpos;
+	for(n=dz->iparam[DRNK_SPLICELEN]-1;n>=0;n--) {
+		for(m=0;m<chans;m++)			
+			obuf[outbpos++] += (float)/*round*/((double)ibuf[inbpos++] * dz->parray[DRNK_SPLICETAB][n]); 
+		if(inbpos >= dz->ssampsread) {
+			if((exit_status = read_samps(dz->sampbuf[0],dz))<0)
+				return(exit_status);
+			if(dz->vflag[IS_DRNK_OVERLAP])
+				do_pregain(pregain,dz);
+			inbpos = 0;
+			(*thisbuf)++;			
+		}
+	}
+	*obufpos = outbpos;
+	*ibufpos = inbpos;
+	return(FINISHED);
+}
+
+/*************************** GET_NEW_POS **************************/
+
+int get_new_pos(int here,int ambitus,int locus,int step)
+{
+	int current_stray = here - locus; 					/* distance frm start available seg (locus) to current pos*/
+	int new_stray = current_stray + step;			 	/* new_stray = distance from locus */
+	int otherstray, newstep;
+	if(new_stray > ambitus || new_stray < -ambitus ) {	/* if new_stray greater than ambitus */
+		otherstray = current_stray - step;
+		if(otherstray >= 0 && otherstray <= ambitus)
+			here = locus + otherstray;					/* try reversing step */
+		else if(otherstray <0 && otherstray >= -ambitus)
+			here = locus + otherstray;						
+		else {												
+			newstep = abs(new_stray) % ambitus;			/* otherwise take modulus */
+			if(step >= 0)
+				here = locus + newstep;
+			else
+				here = locus - newstep;
+		}
+	} else
+		here += step;
+	if(here<0) 											/* Bounce off start of buffer if ness */
+		here = -here;
+	return(here);
+}
+
+/*************************** GET_NEW_LOCUS_POS **************************/
+
+int get_new_locus_pos(int here,int ambitus,int locus,int step)
+{
+	int current_stray = here - locus; 					/* distance frm start available seg (locus) to current pos*/
+	int new_stray = current_stray + step;			 	/* new_stray = distance from locus */
+	if(new_stray > ambitus || new_stray < -ambitus)		/* if new_stray greater than ambitus */
+		here = locus + step;
+	else
+		here += step;
+	if(here<0) 											/* Bounce off start of buffer if ness */
+		here = -here;
+	return(here);
+}
+
+/*************************** GET_STEP **************************/
+
+int get_step(int chans,dataptr dz)
+{
+	int step;
+	double dstep  = (drand48() * 2.0) - 1.0;	/* range +1 to -1 */
+	dstep *= dz->param[DRNK_GSTEP];		/* range +gstep to -gstep */
+	step   = round(dstep);				/* Current stepsize in mintime-grains */	 			
+	step  *= dz->iparam[DRNK_LGRAIN];	/* Current stepsize in samples 		  */
+	step  *= chans;
+	return step;
+}
+
+/*************************** GET_PAUSDUR **************************/
+
+int get_pausdur(int *here,int splicelen,int chans,int *thisdur,dataptr dz)
+{
+	int this_pause;
+	int max_pause = dz->insams[0] - *here - splicelen;
+	if(EVEN(chans) && ODD(max_pause)) {
+		sprintf(errstr,"Stereo anomaly at file end: get_pausdur()\n");
+		return(PROGRAM_ERROR);
+	}
+	if(max_pause < 0) {
+		sprintf(errstr,"Negative pause duration: get_pausdur()\n");
+		return(PROGRAM_ERROR);
+	}
+	if(dz->iparam[DRNK_MAXHOLD])
+		*thisdur = max_pause;
+	else {
+		this_pause  = round(drand48() * dz->iparam[DRNK_PAUS_RANG]); /* gen pause dur between */
+		this_pause += dz->iparam[DRNK_MIN_PAUS]; 			    	 /* given limits */
+		this_pause *= chans;
+		*thisdur  = min(this_pause,max_pause);    	    			 /* but not >endoffile */
+	}										   				  
+	return(FINISHED);
+}
+
+/*************************** BOUNCE_OFF_FILE_END_IF_NECESSARY **************************/
+//TW MY CURRENT CODE AGREES WITH THIS, so removed #ifdef
+int bounce_off_file_end_if_necessary(int *here,int thisdur,int chans,int splicelen,dataptr dz)
+{
+	int diff, initial_diff, needed;
+	initial_diff = abs(dz->insams[0] - *here);	/* Ensure enough room to read final segment and splice */
+	if(EVEN(chans) && ODD(initial_diff)) {
+		sprintf(errstr,"Stereo anomaly at file end: bounce_off_file_end_if_necessary()\n");
+		return(PROGRAM_ERROR);
+	}
+	if((needed = thisdur + splicelen) > dz->insams[0]) {
+		sprintf(errstr,"Segment duration exceeds size of sound\n");
+		return(DATA_ERROR);
+	}
+	while((diff = dz->insams[0] - *here) < needed) {
+		*here -= initial_diff; 		   			/* Bounce off end of buffer if ness */
+		if(*here < 0 || initial_diff == 0) {	/* But, if it bounces off BOTH ends !! */
+			*here = (dz->insams[0] - needed)/dz->infile->channels;
+			*here = (int)round(*here * drand48()) * dz->infile->channels;
+		}
+	}
+	return(FINISHED);
+}
+

+ 58 - 0
dev/extend/drunkfix.c

@@ -0,0 +1,58 @@
+/*
+ * 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
+ *
+ */
+
+
+
+/*************************** BOUNCE_OFF_FILE_END_IF_NECESSARY 
+**************************/
+
+int bounce_off_file_end_if_necessary(int *here,int thisdur,int chans,int 
+splicelen,dataptr dz)
+{
+	int diff, initial_diff, needed;
+	initial_diff = abs(dz->insams[0] - *here);	/* Ensure enough room to read 
+final segment and splice */
+	if(EVEN(chans) && ODD(initial_diff)) {
+		sprintf(errstr,"Stereo anomaly at file end: 
+bounce_off_file_end_if_necessary()\n");
+		return(PROGRAM_ERROR);
+	}
+	if((needed = thisdur + splicelen) > dz->sampbuf[0]) {
+		sprintf(errstr,"Segement duration exceeds size of sound\n");
+		return(DATA_ERROR);
+	}
+	while((diff = dz->insams[0] - *here) < needed) {
+		*here -= initial_diff; 		   			/* Bounce off end of buffer if ness */
+		if(*here < 0) {					   		/* But, if it bounces off BOTH ends !! */
+			*here = (dz->insams[0] - needed)/dz->infile->channels;
+			*here = (int)round(*here * drand48()) * dz->infile->channels;
+/*
+			sprintf(errstr,"Anomaly in bounce_off_file_end_if_necessary()\n");
+			return(PROGRAM_ERROR);
+*/
+		}
+	}
+	return(FINISHED);
+}
+

+ 1394 - 0
dev/extend/extprepro.c

@@ -0,0 +1,1394 @@
+/*
+ * 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 <string.h>
+#include <structures.h>
+#include <tkglobals.h>
+#include <globcon.h>
+#include <processno.h>
+#include <modeno.h>
+#include <arrays.h>
+#include <extend.h>
+#include <sfsys.h>
+#include <osbind.h>
+
+#if defined  unix || defined __GNUC__
+#define round(x) lround((x))
+#else
+#define round(x) cdp_round((x))
+#endif
+
+#define RANDSET     (32)  /* reduce no.of segs to small finite no, so start and end seg have chance to be chosen */
+#define FORWARDS    (1)
+#define BACKWARDS   (-1)
+
+static int  setup_zigzag_splice(int paramno,dataptr dz);
+static int  make_zigsplice(int paramno,dataptr dz);
+static int  create_zigzag_splicebuffer(dataptr dz);
+static int  generate_zigzag_table(dataptr dz);
+static int  sort_zigs(dataptr dz);
+static int  eliminate_n_steps(int *this_zigtime,int *next_zigtime,int **ziglistend,int *cnt,dataptr dz);
+static int  eliminate_step(int *next_zigtime,int **ziglistend,int *cnt,dataptr dz);
+static int  insert_extra_zig
+                (int direction,int **this_zigtime,int **next_zigtime,int **ziglistend,int len,dataptr dz);
+static int  split_up_steps_too_large_for_buffer(dataptr dz);
+static int  update_and_check_ziglist_params(int **next_zigtime,int **this_zigtime,int *ziglistend,int direction);
+static int  generate_loop_table(dataptr dz);
+static int  sort_loops(dataptr dz);
+static int  insert_extra_loop_element
+                (int direction,int **this_zigtime,int **next_zigtime,int **ziglistend,int len,dataptr dz);
+static int  generate_scramble_table(dataptr dz);
+static int  scramble_rand(int arraysize,dataptr dz);
+static int  preprocess_scramble_shred(dataptr dz);
+static int  scramble_shred(int arraysize,dataptr dz);
+static int  get_basis_lengths(int chunkcnt,int worklen,int *unit_len, int *endlen,
+                      int *scatgrpcnt, int *endscat, int *range, int *endrange, dataptr dz);
+static int  normal_scat(int unit_len,int endlen,int chunkcnt_less_one,dataptr dz);
+static int  heavy_scat(int scatgrpcnt,int range,int endscat,int endrange,dataptr dz);
+static void permute_chunks(int chunkcnt,dataptr dz);
+static void insert(int n,int t,int chunkcnt,dataptr dz);
+static void prefix(int n,int chunkcnt,dataptr dz);
+static void shuflup(int k,int chunkcnt,dataptr dz);
+static int  ptr_sort(int end,dataptr dz);
+static int  get_maxvalue_of_rand(double *maxrand,dataptr dz);
+static int  get_maxvalue_of_pscat(double *maxpscat,dataptr dz);
+static int  get_minvalue_of_delay(double *mindelay,dataptr dz);
+static void reverse_fadevals(dataptr dz);
+static void set_default_gain(int mindelay_samps,dataptr dz);
+static void set_default_delays(dataptr dz);
+static void setup_iter_process_type(int is_unity_gain,dataptr dz);
+static int  make_drnk_splicetab(dataptr dz);
+static int  convert_sec_steps_to_grain_steps(dataptr dz);
+
+/***************************** ZIGZAG_PREPROCESS ******************************/
+
+int zigzag_preprocess(dataptr dz)
+{
+    int exit_status;
+    int n = 0;
+    if(dz->mode == ZIGZAG_SELF)
+        initialise_random_sequence(IS_ZIG_RSEED,ZIGZAG_RSEED,dz);
+    if((exit_status = setup_zigzag_splice(ZIGZAG_SPLEN,dz))<0)
+        return(exit_status);
+    if(dz->insams[0] <= dz->iparam[ZIG_SPLSAMPS] * dz->infile->channels * 2) {
+        sprintf(errstr,"Infile too short for splices.\n");
+        return(DATA_ERROR);
+    }
+    if(dz->mode == ZIGZAG_SELF) {
+        if((exit_status = generate_zigzag_table(dz))<0)
+            return(exit_status);
+    }
+    if((exit_status = sort_zigs(dz))<0)
+        return(exit_status);
+    if(sloom) {
+        dz->tempsize = 0L;
+        for(n=1;n<dz->itemcnt;n++)
+            /*RWD treat tempszie as in samps */
+            dz->tempsize += abs(dz->lparray[ZIGZAG_TIMES][n] - dz->lparray[ZIGZAG_TIMES][n-1]);
+    }
+    return(FINISHED);
+}
+
+/*********************** SETUP_ZIGZAG_SPLICE ***************************/
+
+int setup_zigzag_splice(int paramno,dataptr dz)
+{
+    int exit_status;
+    if((exit_status = make_zigsplice(paramno,dz))<0)
+        return(exit_status);
+    return create_zigzag_splicebuffer(dz);
+}
+
+/*********************** MAKE_ZIGSPLICE ***************************/
+
+int make_zigsplice(int paramno,dataptr dz)
+{
+    int n;
+    int framesize = dz->infile->channels;
+    
+
+    dz->iparam[ZIG_SPLICECNT] = (int)round(dz->param[paramno] * MS_TO_SECS * dz->infile->srate);
+    dz->iparam[ZIG_SPLSAMPS]  = dz->iparam[ZIG_SPLICECNT] * framesize;
+    if(dz->iparam[ZIG_SPLSAMPS] >= dz->buflen) {
+        sprintf(errstr,"Splicelength too long for available memory.\n");
+        return(GOAL_FAILED);
+    }
+    if((dz->parray[ZIGZAG_SPLICE] = (double *)malloc(dz->iparam[ZIG_SPLICECNT] * sizeof(double)))==NULL) {
+        sprintf(errstr,"INSUFFICIENT MEMORY to make splicer buffer.\n");
+        return(MEMORY_ERROR);
+    }
+    for(n=0;n<dz->iparam[ZIG_SPLICECNT];n++)
+        dz->parray[ZIGZAG_SPLICE][n] = (double)n/(double)dz->iparam[ZIG_SPLICECNT];
+    return(FINISHED);
+}
+
+/*********************** CREATE_ZIGZAG_SPLICEBUFFER ***************************/
+
+int create_zigzag_splicebuffer(dataptr dz)
+{
+    if(dz->extrabuf == (float **)0) {
+        sprintf(errstr,"extrabuf has not been created: create_zigzag_splicebuffer()\n");
+        return(PROGRAM_ERROR);
+    }
+
+    if((dz->extrabuf[ZIGZAG_SPLBUF] = (float *)malloc(sizeof(float) * dz->iparam[ZIG_SPLSAMPS]))==NULL) {
+        sprintf(errstr,"INSUFFICIENT MEMORY to make splicing buffer.\n");
+        return(MEMORY_ERROR);
+    }
+    memset((char *)dz->extrabuf[ZIGZAG_SPLBUF],0,sizeof(float) * dz->iparam[ZIG_SPLSAMPS]);
+    return(FINISHED);
+}
+
+/***************************** GENERATE_ZIGZAG_TABLE ***************************/
+
+int generate_zigzag_table(dataptr dz)
+{
+    int    OK;
+    int   arraysize = BIGARRAY;
+    double infiledur = (double)(dz->insams[0]/dz->infile->channels)/(double)(dz->infile->srate);
+    double totaltime = dz->param[ZIGZAG_START];
+    double goaltime  = dz->param[ZIGZAG_DUR] - (infiledur - dz->param[ZIGZAG_END]);
+    double diff, randlen = 0.0, here  = dz->param[ZIGZAG_START];
+    int direction = FORWARDS;
+    if((dz->lparray[ZIGZAG_TIMES] = (int *)malloc(arraysize * sizeof(int)))==NULL) {
+        sprintf(errstr,"INSUFFICIENT MEMORY to store times.\n");
+        return(MEMORY_ERROR);
+    }
+    dz->lparray[ZIGZAG_TIMES][0] = 0;
+    dz->itemcnt = 1;
+    do {
+        OK = TRUE;
+        switch(direction) {
+        case(FORWARDS):
+            diff = min(dz->param[ZIGZAG_MAX],dz->param[ZIGZAG_END] - here);
+            if(diff<=dz->param[ZIGZAG_MIN])
+                OK = FALSE;
+            else {
+                randlen = drand48();                        /* generate segment length at random */
+                randlen *= (diff - dz->param[ZIGZAG_MIN]);  /* scale it to range required */
+                randlen += dz->param[ZIGZAG_MIN];           /* and add mindur */
+                here = (here + randlen);
+            }
+            break;
+        case(BACKWARDS):
+            diff = min(dz->param[ZIGZAG_MAX],here - dz->param[ZIGZAG_START]);
+            if(diff<=dz->param[ZIGZAG_MIN])
+                OK = FALSE;
+            else {
+                randlen = drand48();                        /* generate segment length at random */
+                randlen *= (diff - dz->param[ZIGZAG_MIN]);  /* scale it to range required */
+                randlen += dz->param[ZIGZAG_MIN];           /* and add mindur */
+                here = (here - randlen);
+            }
+            break;
+        }
+        direction = -direction; /* invert time-direction */
+        if(!OK)
+            continue;
+        totaltime += randlen;
+        dz->lparray[ZIGZAG_TIMES][dz->itemcnt] = round(here * (double)dz->infile->srate) * dz->infile->channels;
+        if(++dz->itemcnt >= arraysize) {
+            arraysize += BIGARRAY;
+            if((dz->lparray[ZIGZAG_TIMES] = 
+            (int *)realloc((char *)dz->lparray[ZIGZAG_TIMES],arraysize*sizeof(int)))==NULL) {
+                sprintf(errstr,"INSUFFICIENT MEMORY to reallocate times store.\n");
+                return(MEMORY_ERROR);
+            }
+        }
+    } while(totaltime<goaltime);
+    dz->lparray[ZIGZAG_TIMES][dz->itemcnt] = dz->insams[0];
+    dz->itemcnt++;
+    if(dz->itemcnt < arraysize) {
+        if((dz->lparray[ZIGZAG_TIMES] = 
+        (int *)realloc((char *)dz->lparray[ZIGZAG_TIMES],dz->itemcnt*sizeof(int)))==NULL) {
+            sprintf(errstr,"INSUFFICIENT MEMORY to reallocate times store.\n");
+            return(MEMORY_ERROR);
+        }
+    }
+    return(FINISHED);
+}
+
+/****************************** SORT_ZIGS ************************************/
+
+int sort_zigs(dataptr dz)
+{
+    int exit_status;
+    int zigsize;
+    int safety = round(ZIG_MIN_UNSPLICED * MS_TO_SECS * (double)dz->infile->srate) * dz->infile->channels;
+    int cnt = 0, firstime = TRUE, direction, previous_direction = FORWARDS;
+    int *this_zigtime = dz->lparray[ZIGZAG_TIMES];
+    int *next_zigtime = dz->lparray[ZIGZAG_TIMES] + 1;
+    int *ziglistend = dz->lparray[ZIGZAG_TIMES] + dz->itemcnt;
+    int minzig = (dz->iparam[ZIG_SPLSAMPS] * 2) + safety;
+    int file_samplen = dz->insams[0];
+    double convert_to_time = 1.0/(double)dz->infile->channels/(double)dz->infile->srate;
+    if(minzig > (dz->buflen/2)-1) {
+        sprintf(errstr,"splicelen too long to work with available memory\n"
+        "Longest splicelen available %ld msecs.\n",
+round((double)(((((dz->buflen/2)-1) - safety)/2)/(double)dz->infile->channels/(double)dz->infile->srate) * SECS_TO_MS)-1);
+        return(GOAL_FAILED);
+    }
+    if(*this_zigtime < 0 || *this_zigtime > file_samplen) {
+        sprintf(errstr,"Invalid 1st zigtime %lf\n",(*this_zigtime) * convert_to_time);
+        return(DATA_ERROR);
+    }
+    if(*(ziglistend-1) >= file_samplen) {
+        *(ziglistend-1) = file_samplen;
+        dz->iparam[ZIG_RUNSTOEND] = 1;
+    } else
+        dz->iparam[ZIG_RUNSTOEND] = 0;
+    while(next_zigtime < ziglistend - dz->iparam[ZIG_RUNSTOEND]) {
+        if(*next_zigtime < 0 || *next_zigtime > file_samplen) {
+            sprintf(errstr,"Invalid zigtime %lf\n",(*next_zigtime) * convert_to_time);
+            return(DATA_ERROR);
+        }
+        while((zigsize = abs(*next_zigtime - *this_zigtime)) < minzig) {
+            if(++next_zigtime == ziglistend - dz->iparam[ZIG_RUNSTOEND])
+                break;
+        }
+        if(next_zigtime - this_zigtime > 1) {
+            if(dz->mode == ZIGZAG_USER) {
+                sprintf(errstr,"Some zigs too short to use with specified splicelen.\n");
+                return(DATA_ERROR);
+            }
+            eliminate_n_steps(this_zigtime,next_zigtime,&ziglistend,&cnt,dz);
+            next_zigtime = this_zigtime + 1;
+        }
+        if(*next_zigtime > *this_zigtime)
+            direction = FORWARDS;
+        else
+            direction = BACKWARDS;
+        if(!firstime && (direction == previous_direction)) {
+            if((exit_status = eliminate_step(next_zigtime,&ziglistend,&cnt,dz))<0)
+                return(exit_status);
+            continue;
+        }
+        previous_direction = direction;
+        firstime = FALSE;
+        this_zigtime++;
+        next_zigtime++;
+    }
+    if(cnt>0) {
+        fprintf(stdout,"WARNING: %d steps eliminated (too small relative to spliclength\n",cnt);
+//TW : CAN'T SPLIT LINES SENT TO SLOOM - 'WARNING' is a flag to SLOOM - possibly my error, since updated
+        fprintf(stdout,"WARNING: or moving in same direction as previous step)\n");
+        fflush(stdout);
+        if((dz->lparray[ZIGZAG_TIMES] =
+        (int *)realloc((char *)dz->lparray[ZIGZAG_TIMES],dz->itemcnt * sizeof(int)))==NULL) {
+            sprintf(errstr,"INSUFFICIENT MEMORY to reallocate times store.\n");
+            return(MEMORY_ERROR);
+        }
+    }
+    if(dz->iparam[ZIG_RUNSTOEND]) {
+        if(*(ziglistend-1) - *(ziglistend-2) < dz->iparam[ZIG_SPLSAMPS] + safety) {
+            sprintf(errstr,"Final zig too short for splicelen.\n");
+            return(GOAL_FAILED);
+        }
+    }
+    return split_up_steps_too_large_for_buffer(dz);
+}
+
+/**************************** ELIMINATE_N_STEPS ***************************/
+
+int eliminate_n_steps(int *this_zigtime,int *next_zigtime,int **ziglistend,int *cnt,dataptr dz)
+{
+    int *here  = this_zigtime + 1;
+    int *there = next_zigtime;
+    int elimination_cnt = next_zigtime - this_zigtime - 1;
+    while(there < *ziglistend) {
+        *here = *there;
+        here++;
+        there++;
+    }
+    if((dz->itemcnt -= elimination_cnt) < 2) {
+        sprintf(errstr,"All zigsteps either too small for splices: or moving in same direction.\n");
+        return(DATA_ERROR);
+    }
+    *ziglistend -= elimination_cnt;
+    (*cnt) += elimination_cnt;
+    return(FINISHED);
+}
+
+/***************************** ELIMINATE_STEP ***************************/
+
+int eliminate_step(int *next_zigtime,int **ziglistend,int *cnt,dataptr dz)
+{
+    int *here = next_zigtime;
+
+    while(here < *ziglistend) {
+        *(here-1) = *here;
+        here++;
+    }
+    if(--dz->itemcnt < 2) {
+        sprintf(errstr,"All zigsteps either too small for splices: or moving in same direction.\n");
+        return(DATA_ERROR);
+    }
+    (*ziglistend)--;
+    (*cnt)++;
+    return(FINISHED);
+}
+
+/***************************** INSERT_EXTRA_ZIG ***************************/
+
+int insert_extra_zig(int direction,int **this_zigtime,int **next_zigtime,int **ziglistend,int len,dataptr dz)
+{
+    int *here;
+    int zthis = *this_zigtime - dz->lparray[ZIGZAG_TIMES];
+    int znext = *next_zigtime - dz->lparray[ZIGZAG_TIMES];
+    dz->itemcnt++;
+    if((dz->lparray[ZIGZAG_TIMES] =
+    (int *)realloc((char *)dz->lparray[ZIGZAG_TIMES],dz->itemcnt * sizeof(int)))==NULL) {
+        sprintf(errstr,"INSUFFICIENT MEMORY to reallocate times store.\n");
+        return(MEMORY_ERROR);
+    }
+    *this_zigtime = dz->lparray[ZIGZAG_TIMES] + zthis;
+    *next_zigtime = dz->lparray[ZIGZAG_TIMES] + znext;
+    *ziglistend  =  dz->lparray[ZIGZAG_TIMES] + dz->itemcnt;
+    here = *ziglistend - 1;
+    while(here > *next_zigtime) {
+        *here = *(here-1);
+        here--;
+    }
+    switch(direction) {
+    case(FORWARDS):
+        *here = **this_zigtime + len;       
+        break;
+    case(BACKWARDS):    
+        *here = **this_zigtime - len;       
+        break;
+    }
+    if(*here < 0.0 || (int)*here > dz->insams[0]) {
+        sprintf(errstr,"Error in logic of sample arithmetic: insert_extra_zig()\n");
+        return(PROGRAM_ERROR);
+    }
+    return(FINISHED);
+}
+
+/**************************** SPLIT_UP_STEPS_TOO_LARGE_FOR_BUFFER ***************************/
+
+int split_up_steps_too_large_for_buffer(dataptr dz)
+{
+    int zigsize;
+    int direction, n, longbufs, shortbufs;
+    int safety = round(ZIG_MIN_UNSPLICED * MS_TO_SECS * (double)dz->infile->srate) * dz->infile->channels;
+    int minzig = (dz->iparam[ZIG_SPLSAMPS] * 2) + safety;
+    int *this_zigtime = dz->lparray[ZIGZAG_TIMES];
+    int *next_zigtime = this_zigtime + 1;
+    int *ziglistend = dz->lparray[ZIGZAG_TIMES] + dz->itemcnt;
+    int max_effective_length = dz->buflen - F_SECSIZE;
+    int pre_endbuflen, endbuflen;
+    while(next_zigtime < ziglistend) {
+        zigsize = *next_zigtime - *this_zigtime;
+        if(zigsize > 0.0)
+            direction = FORWARDS;
+        else
+            direction = BACKWARDS;
+        zigsize = abs(zigsize);
+
+        if((longbufs = zigsize/max_effective_length) > 0) { /* TRUNCATE */
+            shortbufs    = -1;
+            pre_endbuflen =  0;
+            while((endbuflen = zigsize%max_effective_length) > 0 && endbuflen < minzig) {
+                longbufs--;             
+                if(longbufs<0) {
+                    sprintf(errstr,"splicelen is too long for available memory.\n");
+                    return(GOAL_FAILED);
+                }
+                shortbufs++;
+                pre_endbuflen  = max_effective_length + endbuflen - minzig;
+                if(pre_endbuflen > minzig)
+                    break;
+                zigsize -= minzig;
+            }
+            for(n = 0; n < longbufs;n++) {
+                insert_extra_zig(direction,&this_zigtime,&next_zigtime,&ziglistend,max_effective_length,dz);
+                update_and_check_ziglist_params(&next_zigtime,&this_zigtime,ziglistend,direction);
+            }
+            if(pre_endbuflen > 0) {
+                insert_extra_zig(direction,&this_zigtime,&next_zigtime,&ziglistend,pre_endbuflen,dz);
+                update_and_check_ziglist_params(&next_zigtime,&this_zigtime,ziglistend,direction);
+            }
+            if(shortbufs > 0) {
+                for(n = 0; n < shortbufs; n++) {
+                    insert_extra_zig(direction,&this_zigtime,&next_zigtime,&ziglistend,minzig,dz);
+                    update_and_check_ziglist_params(&next_zigtime,&this_zigtime,ziglistend,direction);
+                }
+            }
+        }
+        next_zigtime++;
+        this_zigtime++;
+    }   
+    return(FINISHED);
+}
+
+/***************************** UPDATE_AND_CHECK_ZIGLIST_PARAMS ***************************/
+
+int update_and_check_ziglist_params(int **next_zigtime,int **this_zigtime,int *ziglistend,int direction)
+{       
+    int zigsize;
+    (*next_zigtime)++;
+    (*this_zigtime)++;
+    if(*this_zigtime >= ziglistend - 1) {
+        sprintf(errstr,"Error in counting logic: update_and_check_ziglist_params()\n");
+        return(PROGRAM_ERROR);
+    }
+    zigsize = **next_zigtime - **this_zigtime;
+    if((zigsize > 0.0 && direction != FORWARDS)
+    || (zigsize < 0.0 && direction != BACKWARDS)) {
+        sprintf(errstr,"Error in counting logic(2): update_and_check_ziglist_params()\n");
+        return(PROGRAM_ERROR);
+    }
+    return(FINISHED);
+}
+
+/*********************** LOOP_PREPROCESS ***************************/
+
+int loop_preprocess(dataptr dz)
+{
+    int exit_status;
+    initrand48();
+    if(dz->param[LOOP_LEN] <= dz->param[LOOP_SPLEN] * 2) {
+        sprintf(errstr,"Loop length too short for splices.\n");
+        return(DATA_ERROR);
+    }
+    if((exit_status = setup_zigzag_splice(LOOP_SPLEN,dz))<0)
+        return(exit_status);
+    if(dz->insams[0] <= dz->iparam[ZIG_SPLSAMPS] * 2) {
+        sprintf(errstr,"Infile too short for splices.\n");
+        return(DATA_ERROR);
+    }
+    if((exit_status = generate_loop_table(dz))<0)
+        return(exit_status);
+    return sort_loops(dz);
+}
+
+/***************************** GENERATE_LOOP_TABLE ***************************/
+
+int generate_loop_table(dataptr dz)
+{
+    int searchsamps, tmpstart;
+    unsigned int file_endsamp = dz->insams[0];
+    int   i, arraysize = BIGARRAY;
+    int   startsamp = dz->infile->channels * (int) (dz->infile->srate * dz->param[LOOP_START]);
+    int   looplen   = dz->infile->channels * (int) (dz->infile->srate * dz->param[LOOP_LEN]   * MS_TO_SECS);
+    int   stepsamps = dz->infile->channels * (int) (dz->infile->srate * dz->param[LOOP_STEP]  * MS_TO_SECS);
+    int   lsfield   = dz->infile->channels * (int) (dz->infile->srate * dz->param[LOOP_SRCHF] * MS_TO_SECS);
+    int   samplen, excess, totallen, endsamp, n;
+
+/* NEW APR 16 --> */
+    looplen += dz->iparam[ZIG_SPLSAMPS]; /* allow for splice overlaps in calcs */
+
+    dz->itemcnt = 0;
+    if((dz->lparray[ZIGZAG_TIMES] = (int *)malloc(arraysize * sizeof(int)))==NULL) {
+        sprintf(errstr,"INSUFFICIENT MEMORY to store times.\n");
+        return(MEMORY_ERROR);
+    }
+    if((dz->iparray[ZIGZAG_PLAY]  = (int  *)malloc(arraysize * sizeof(int )))==NULL) {
+        sprintf(errstr,"INSUFFICIENT MEMORY to store section markers.\n");
+        return(MEMORY_ERROR);
+    }
+    searchsamps = 0;
+    tmpstart = startsamp;
+    for(i = 0; i < dz->iparam[LOOP_REPETS] ;i++) {
+        if(dz->itemcnt + 2 > arraysize) {
+            arraysize  += BIGARRAY;
+            if((dz->lparray[ZIGZAG_TIMES] = (int *)realloc(dz->lparray[ZIGZAG_TIMES],arraysize * sizeof(int)))==NULL) {
+                sprintf(errstr,"INSUFFICIENT MEMORY to reallocate times.\n");
+                return(MEMORY_ERROR);
+            }
+            if((dz->iparray[ZIGZAG_PLAY]  = (int  *)realloc(dz->iparray[ZIGZAG_PLAY],arraysize * sizeof(int)))==NULL) {
+                sprintf(errstr,"INSUFFICIENT MEMORY to reallocate markers.\n");
+                return(MEMORY_ERROR);
+            }
+        }
+        dz->iparray[ZIGZAG_PLAY][dz->itemcnt]  = TRUE;
+        if(i==0 && dz->vflag[IS_KEEP_START])
+            dz->lparray[ZIGZAG_TIMES][dz->itemcnt] = 0;
+        else
+            dz->lparray[ZIGZAG_TIMES][dz->itemcnt] = tmpstart;
+        dz->itemcnt++;
+        dz->iparray[ZIGZAG_PLAY][dz->itemcnt]  = FALSE;
+        if((unsigned int)(dz->lparray[ZIGZAG_TIMES][dz->itemcnt] = tmpstart + looplen) >= file_endsamp) {
+            dz->iparam[ZIG_RUNSTOEND] = TRUE;
+            dz->itemcnt++;
+            break;
+        }           
+        dz->itemcnt++;
+        startsamp += stepsamps;
+        if(lsfield)
+            searchsamps = round((double) lsfield * drand48());
+        tmpstart = (startsamp + searchsamps);
+    }
+    if(dz->iparam[ZIG_RUNSTOEND])
+        dz->lparray[ZIGZAG_TIMES][dz->itemcnt-1] = file_endsamp;    /* Force read to end */
+    else if(dz->mode==LOOP_OUTLEN) {
+        samplen = dz->infile->channels * round(dz->infile->srate * dz->param[LOOP_OUTDUR]);
+        totallen = 0;                                               /* Force to correct outlen */
+        for(n=1;n<dz->itemcnt;n+=2)
+            totallen += dz->lparray[ZIGZAG_TIMES][n] - dz->lparray[ZIGZAG_TIMES][n-1] - dz->iparam[ZIG_SPLSAMPS];
+        if((excess = samplen - totallen) > 0) {
+            endsamp = min(dz->lparray[ZIGZAG_TIMES][dz->itemcnt-1] + excess,(int)file_endsamp);
+            dz->lparray[ZIGZAG_TIMES][dz->itemcnt-1] = endsamp;
+            if(endsamp == (int)file_endsamp)
+                dz->iparam[ZIG_RUNSTOEND] = TRUE;
+        }
+    }
+    if((dz->lparray[ZIGZAG_TIMES] = (int *)realloc(dz->lparray[ZIGZAG_TIMES],dz->itemcnt * sizeof(int)))==NULL) {
+        sprintf(errstr,"INSUFFICIENT MEMORY to reallocate times.\n");
+        return(MEMORY_ERROR);
+    }
+    if((dz->iparray[ZIGZAG_PLAY]  = (int  *)realloc(dz->iparray[ZIGZAG_PLAY], dz->itemcnt * sizeof(int )))==NULL) {
+        sprintf(errstr,"INSUFFICIENT MEMORY to reallocate markers.\n");
+        return(MEMORY_ERROR);
+    }
+    return(FINISHED);
+}
+
+/****************************** SORT_LOOPS ************************************/
+
+int sort_loops(dataptr dz)
+{
+    int zigsize;
+    int direction, n, longbufs, shortbufs;
+    int safety = round(ZIG_MIN_UNSPLICED * MS_TO_SECS * (double)dz->infile->srate) * dz->infile->channels;
+    int minzig = (dz->iparam[ZIG_SPLSAMPS] * 2) + safety;
+    int *this_zigtime = dz->lparray[ZIGZAG_TIMES];
+    int *next_zigtime = this_zigtime + 1;
+    int *ziglistend = dz->lparray[ZIGZAG_TIMES] + dz->itemcnt;
+    int max_effective_length = dz->buflen - F_SECSIZE;
+    int pre_endbuflen, endbuflen;
+    int m = 0;
+
+    while(next_zigtime < ziglistend) {
+        zigsize = *next_zigtime - *this_zigtime;
+        if(zigsize > 0.0)
+            direction = FORWARDS;
+        else
+            direction = BACKWARDS;
+        zigsize = abs(zigsize);
+
+        if((longbufs = zigsize/max_effective_length) > 0) { /* TRUNCATE */
+            shortbufs     = -1;
+            pre_endbuflen =  0;
+            while((endbuflen = zigsize%max_effective_length) > 0 && endbuflen < minzig) {
+                longbufs--;             
+                if(longbufs<0) {
+                    sprintf(errstr,"splicelen is too long for available memory.\n");
+                    return(GOAL_FAILED);
+                }
+                shortbufs++;
+                pre_endbuflen  = max_effective_length + endbuflen - minzig;
+                if(pre_endbuflen > minzig)
+                    break;
+                zigsize -= minzig;
+            }
+            for(n = 0; n < longbufs;n++) {
+                insert_extra_loop_element(direction,&this_zigtime,&next_zigtime,&ziglistend,max_effective_length,dz);
+                update_and_check_ziglist_params(&next_zigtime,&this_zigtime,ziglistend,direction);
+            }
+            if(pre_endbuflen > 0) {
+                insert_extra_loop_element(direction,&this_zigtime,&next_zigtime,&ziglistend,pre_endbuflen,dz);
+                update_and_check_ziglist_params(&next_zigtime,&this_zigtime,ziglistend,direction);
+            }
+            if(shortbufs > 0) {
+                for(n = 0; n < shortbufs; n++) {
+                    insert_extra_loop_element(direction,&this_zigtime,&next_zigtime,&ziglistend,minzig,dz);
+                    update_and_check_ziglist_params(&next_zigtime,&this_zigtime,ziglistend,direction);
+                }
+            }
+        }
+        next_zigtime++;
+        this_zigtime++;
+    }
+    if(sloom) {
+        dz->tempsize = 0L;
+        for(n=0,m=1;m<dz->itemcnt;n++,m++) {
+            if(dz->iparray[ZIGZAG_PLAY][n])
+                dz->tempsize += abs(dz->lparray[ZIGZAG_TIMES][m] - dz->lparray[ZIGZAG_TIMES][n]);
+        }                    /* abs for SAFETY: should be unnecessary as all plays should be forwards!! */
+    }
+    return(FINISHED);
+}
+
+/***************************** INSERT_EXTRA_LOOP_ELEMENT ***************************/
+
+int insert_extra_loop_element(int direction,int **this_zigtime,int **next_zigtime,int **ziglistend,int len,dataptr dz)
+{
+    int *here;
+    int  *there, *playlistend, *nextplaytime;
+    int zthis = *this_zigtime - dz->lparray[ZIGZAG_TIMES];
+    int znext = *next_zigtime - dz->lparray[ZIGZAG_TIMES];
+    dz->itemcnt++;
+    if((dz->lparray[ZIGZAG_TIMES] =
+    (int *)realloc(dz->lparray[ZIGZAG_TIMES],dz->itemcnt * sizeof(int)))==NULL) {
+        sprintf(errstr,"INSUFFICIENT MEMORY to insert extra loop time.\n");
+        return(MEMORY_ERROR);
+    }
+    if((dz->iparray[ZIGZAG_PLAY] =
+    (int  *)realloc(dz->iparray[ZIGZAG_PLAY], dz->itemcnt * sizeof(int )))==NULL) {
+        sprintf(errstr,"INSUFFICIENT MEMORY to insert extra loopmarker.\n");
+        return(MEMORY_ERROR);
+    }
+    *this_zigtime = dz->lparray[ZIGZAG_TIMES] + zthis;
+    *next_zigtime = dz->lparray[ZIGZAG_TIMES] + znext;
+    *ziglistend   = dz->lparray[ZIGZAG_TIMES] + dz->itemcnt;
+    here = *ziglistend - 1;
+    while(here > *next_zigtime) {
+        *here = *(here-1);
+        here--;
+    }
+    nextplaytime = dz->iparray[ZIGZAG_PLAY] + (*next_zigtime - dz->lparray[ZIGZAG_TIMES]);
+    playlistend =  dz->iparray[ZIGZAG_PLAY] + dz->itemcnt;
+    there = playlistend - 1;
+    while(there > nextplaytime) {
+        *there = *(there-1);
+        there--;
+    }
+    switch(dz->process) {
+    case(LOOP): /* COMMENT: this old LOOPcode may be unnecessary, as SCRAMBLE version may be OK for both */
+        switch(direction) {
+        case(FORWARDS):     *here = **this_zigtime + len;       *there = TRUE;      break;
+        case(BACKWARDS):    *here = **this_zigtime - len;       *there = FALSE;     break;
+        }
+        break;
+    case(SCRAMBLE):
+        switch(direction) {
+        case(FORWARDS):     *here = **this_zigtime + len;       break;
+        case(BACKWARDS):    *here = **this_zigtime - len;       break;
+        }
+        *there = *(there-1);
+        break;
+    }
+//  if(*here < 0.0 || (unsigned int)*here > dz->insams[0]) {
+    if(*here < 0.0 || (int)*here > dz->insams[0]) {
+        sprintf(errstr,"Error in logic of sample arithmetic: insert_extra_loop_element()\n");
+        return(PROGRAM_ERROR);
+    }
+    return(FINISHED);
+}
+
+/***************************** SCRAMBLE_PREPROCESS ***************************/
+
+int scramble_preprocess(dataptr dz)
+{
+    int exit_status;
+    initialise_random_sequence(IS_SCRAMBLE_RSEED,SCRAMBLE_SEED,dz);
+    if((exit_status = setup_zigzag_splice(SCRAMBLE_SPLEN,dz))<0)
+        return(exit_status);
+    if(dz->insams[0] <= dz->iparam[ZIG_SPLSAMPS] * dz->infile->channels * 2) {
+        sprintf(errstr,"Infile too short for splices.\n");
+        return(DATA_ERROR);
+    }
+    if((exit_status = generate_scramble_table(dz))<0)
+        return(exit_status);
+    return sort_loops(dz);
+}
+
+/***************************** GENERATE_SCRAMBLE_TABLE **************************/
+
+int generate_scramble_table(dataptr dz)
+{
+    int exit_status;
+    int arraysize = BIGARRAY;
+    if((dz->lparray[ZIGZAG_TIMES] = (int *)malloc(arraysize*sizeof(int)))==NULL) {
+        sprintf(errstr,"INSUFFICIENT MEMORY for times store.\n");
+        return(MEMORY_ERROR);
+    }
+    if((dz->iparray[ZIGZAG_PLAY] = (int  *)malloc(arraysize * sizeof(int )))==NULL) {
+        sprintf(errstr,"INSUFFICIENT MEMORY for markers store.\n");
+        return(MEMORY_ERROR);
+    }
+    switch(dz->mode) {
+    case(SCRAMBLE_RAND):
+        exit_status =  scramble_rand(arraysize,dz);
+        break;
+    case(SCRAMBLE_SHRED):   
+        if((exit_status = preprocess_scramble_shred(dz))<0)
+            return(exit_status);
+        exit_status =  scramble_shred(arraysize,dz);
+        break;
+    default:
+        sprintf(errstr,"Unknown mode in generate_scramble_table()\n");
+        return(PROGRAM_ERROR);
+    }
+    if(dz->vflag[IS_SCR_KEEP_START])
+        dz->lparray[ZIGZAG_TIMES][0] = 0;
+    if(dz->vflag[IS_SCR_KEEP_END])
+        dz->lparray[ZIGZAG_TIMES][dz->itemcnt-1] = dz->insams[0];
+    return(exit_status);
+}
+
+/***************************** SCRAMBLE_RAND **************************/
+
+int scramble_rand(int arraysize,dataptr dz)
+{
+    int lenrange = round((dz->param[SCRAMBLE_MAX] - dz->param[SCRAMBLE_MIN]) * dz->infile->srate);
+    int minlen   = round(dz->param[SCRAMBLE_MIN] * dz->infile->srate);
+    int infilelen = dz->insams[0];
+    int thislen, outlen = 0, effective_range, thispos;
+    int  finished = 0, zz;
+    double thisfrac;
+    dz->iparam[SCRAMBLE_OUTLEN] = round(dz->param[SCRAMBLE_DUR] * dz->infile->srate) * dz->infile->channels;
+    dz->itemcnt = 0;
+    while(!finished) {
+        if(dz->itemcnt + 2 >= arraysize) {
+            arraysize += BIGARRAY;
+            if((dz->lparray[ZIGZAG_TIMES] =(int *)realloc(dz->lparray[ZIGZAG_TIMES],arraysize*sizeof(int)))==NULL) {
+                sprintf(errstr,"INSUFFICIENT MEMORY to reallocate times store.\n");
+                return(MEMORY_ERROR);
+            }
+            if((dz->iparray[ZIGZAG_PLAY] = (int  *)realloc(dz->iparray[ZIGZAG_PLAY], arraysize*sizeof(int )))==NULL) {
+                sprintf(errstr,"INSUFFICIENT MEMORY to reallocate markers store.\n");
+                return(MEMORY_ERROR);
+            }
+        }
+        thislen  = (round(drand48() * lenrange) + minlen) * dz->infile->channels;
+        effective_range = infilelen - dz->iparam[ZIG_SPLSAMPS] - thislen;
+        zz =  round(drand48() * RANDSET);
+        thisfrac = (double)zz/(double)RANDSET;
+        thispos =  round(thisfrac * effective_range);
+        if(ODD(thispos))
+            thispos--;
+        dz->lparray[ZIGZAG_TIMES][dz->itemcnt]  = thispos;
+        dz->iparray[ZIGZAG_PLAY][dz->itemcnt++] = TRUE;
+        dz->lparray[ZIGZAG_TIMES][dz->itemcnt]  = thispos + thislen + dz->iparam[ZIG_SPLSAMPS];
+        dz->iparray[ZIGZAG_PLAY][dz->itemcnt++] = FALSE;
+        if((outlen += thislen) >= dz->iparam[SCRAMBLE_OUTLEN])
+            finished = 1;
+    }
+    if((dz->lparray[ZIGZAG_TIMES] = (int *)realloc(dz->lparray[ZIGZAG_TIMES],dz->itemcnt * sizeof(int)))==NULL) {
+        sprintf(errstr,"INSUFFICIENT MEMORY to reallocate times store.\n");
+        return(MEMORY_ERROR);
+    }
+    if((dz->iparray[ZIGZAG_PLAY] = (int  *)realloc(dz->iparray[ZIGZAG_PLAY], dz->itemcnt * sizeof(int )))==NULL) {
+        sprintf(errstr,"INSUFFICIENT MEMORY to reallocate markers store.\n");
+        return(MEMORY_ERROR);
+    }
+    return(FINISHED);
+}
+
+/***************************** PREPROCESS_SCRAMBLE_SHRED **************************/
+
+int preprocess_scramble_shred(dataptr dz)
+{
+//  double infiledur;
+    int chunksamps;
+
+    //infiledur = (double)(dz->insams[0]/dz->infile->channels)/(double)(dz->infile->srate);
+    chunksamps = round(dz->param[SCRAMBLE_LEN] * dz->infile->srate) * dz->infile->channels;
+    dz->iparam[SCRAMBLE_CHCNT]   = dz->insams[0]/chunksamps;    /* truncate */
+    if(dz->iparam[SCRAMBLE_CHCNT]<2) {
+        sprintf(errstr,"Too long chunklen not trapped earlier.\n");
+        return(PROGRAM_ERROR);
+    }
+    dz->iparam[SCRAMBLE_OUTLEN] = round(dz->param[SCRAMBLE_DUR] * dz->infile->srate) * dz->infile->channels;
+
+    if((dz->lparray[SCRAMBLE_CHUNKPTR] = (int *)malloc(dz->iparam[SCRAMBLE_CHCNT] * sizeof(int)))==NULL) {
+        sprintf(errstr,"INSUFFICIENT MEMORY to store scramble chunk pointers.\n");
+        return(MEMORY_ERROR);
+    }
+    if((dz->lparray[SCRAMBLE_CHUNKLEN] = (int *)malloc(dz->iparam[SCRAMBLE_CHCNT] * sizeof(int)))==NULL) {
+        sprintf(errstr,"INSUFFICIENT MEMORY to store scramble chunk lengths.\n");
+        return(MEMORY_ERROR);
+    }
+    if((dz->iparray[SCRAMBLE_PERM]    = (int  *)malloc(dz->iparam[SCRAMBLE_CHCNT] * sizeof(int )))==NULL) {
+        sprintf(errstr,"INSUFFICIENT MEMORY to store scramble permutation.\n");
+        return(MEMORY_ERROR);
+    }
+    return(FINISHED);
+}
+
+/******************************* SCRAMBLE_SHRED ***************************/
+
+int scramble_shred(int arraysize,dataptr dz)
+{
+    int n, exit_status;
+    int finished = 0;
+    int chunkcnt = dz->iparam[SCRAMBLE_CHCNT];
+    int worklen  = dz->insams[0];
+    int total_len = 0;
+    int chunkcnt_less_one = chunkcnt - 1;
+    int unit_len, endlen, scatgrpcnt=0, endscat=0, range=0, endrange=0;
+    int *perm = dz->iparray[SCRAMBLE_PERM];
+    dz->itemcnt = 0;
+    if((exit_status = get_basis_lengths(chunkcnt,worklen,&unit_len,&endlen,&scatgrpcnt,&endscat,&range,&endrange,dz))<0)
+        return(exit_status);
+    while(!finished)  {
+        if(dz->iparam[SCRAMBLE_SCAT]) { 
+            if((exit_status = heavy_scat(scatgrpcnt,range,endscat,endrange,dz))<0)
+                return(exit_status);
+        } else   {
+            if((exit_status = normal_scat(unit_len,endlen,chunkcnt_less_one,dz))<0)
+                return(exit_status);
+        }
+        for(n=0;n<chunkcnt_less_one;n++)            /* 2 */
+            dz->lparray[SCRAMBLE_CHUNKLEN][n] = dz->lparray[SCRAMBLE_CHUNKPTR][n+1] - dz->lparray[SCRAMBLE_CHUNKPTR][n];
+        dz->lparray[SCRAMBLE_CHUNKLEN][n]     = worklen - dz->lparray[SCRAMBLE_CHUNKPTR][n];        /* 2A */
+        permute_chunks(chunkcnt,dz);                            /* 3 */
+        for(n=0;n < chunkcnt; n++) { 
+            if(dz->itemcnt + 2 >= arraysize) {
+                arraysize += BIGARRAY;
+                if((dz->lparray[ZIGZAG_TIMES] =(int *)realloc(dz->lparray[ZIGZAG_TIMES],arraysize*sizeof(int)))==NULL) {
+                    sprintf(errstr,"INSUFFICIENT MEMORY to reallocate times store.\n");
+                    return(MEMORY_ERROR);
+                }
+                if((dz->iparray[ZIGZAG_PLAY] = (int  *)realloc(dz->iparray[ZIGZAG_PLAY], arraysize*sizeof(int )))==NULL) {
+                    sprintf(errstr,"INSUFFICIENT MEMORY to reallocate markers store.\n");
+                    return(MEMORY_ERROR);
+                }
+            }
+            dz->lparray[ZIGZAG_TIMES][dz->itemcnt]   = dz->lparray[SCRAMBLE_CHUNKPTR][perm[n]];
+            dz->iparray[ZIGZAG_PLAY][dz->itemcnt]    = TRUE;
+            dz->lparray[ZIGZAG_TIMES][dz->itemcnt+1] = dz->lparray[ZIGZAG_TIMES][dz->itemcnt] + dz->lparray[SCRAMBLE_CHUNKLEN][perm[n]];
+/* APR 1998 */
+            dz->lparray[ZIGZAG_TIMES][dz->itemcnt+1] += dz->iparam[ZIG_SPLSAMPS];
+            if(dz->lparray[ZIGZAG_TIMES][dz->itemcnt+1] > worklen) {
+                dz->lparray[ZIGZAG_TIMES][dz->itemcnt+1] = worklen;
+                dz->lparray[ZIGZAG_TIMES][dz->itemcnt]   = worklen - dz->lparray[SCRAMBLE_CHUNKLEN][perm[n]];
+            }
+/* APR 1998 */
+            dz->iparray[ZIGZAG_PLAY][dz->itemcnt+1]  = FALSE;
+            if((total_len += dz->lparray[SCRAMBLE_CHUNKLEN][perm[n]]) > dz->iparam[SCRAMBLE_OUTLEN]) {
+                finished = 1;
+                break;
+            }
+            dz->itemcnt += 2;
+        }
+    }
+    if((dz->lparray[ZIGZAG_TIMES] = (int *)realloc(dz->lparray[ZIGZAG_TIMES],dz->itemcnt * sizeof(int)))==NULL) {
+        sprintf(errstr,"INSUFFICIENT MEMORY to reallocate times store.\n");
+        return(MEMORY_ERROR);
+    }
+    if((dz->iparray[ZIGZAG_PLAY] = (int  *)realloc(dz->iparray[ZIGZAG_PLAY], dz->itemcnt * sizeof(int )))==NULL) {
+        sprintf(errstr,"INSUFFICIENT MEMORY to reallocate markers store.\n");
+        return(MEMORY_ERROR);
+    }
+    return(FINISHED);
+}
+
+/*********************** GET_BASIS_LENGTHS ***********************/
+
+int get_basis_lengths(int chunkcnt,int worklen,int *unit_len, int *endlen,
+                      int *scatgrpcnt, int *endscat, int *range, int *endrange, dataptr dz)
+{
+    int excess;
+    *unit_len = (int)round(worklen/chunkcnt);
+    if(ODD(*unit_len))   
+        (*unit_len)--;       /* Allow for stereo case */
+    excess   = worklen - ((*unit_len) * chunkcnt);
+    if(ODD(excess) && dz->infile->channels==2) {
+        sprintf(errstr,"Problem in buffer accounting: get_basis_lengths()\n");
+        return(PROGRAM_ERROR);
+    }
+    *endlen  = *unit_len  + excess;
+    if(dz->param[SCRAMBLE_SCAT] >= 1.0) {
+        dz->iparam[SCRAMBLE_SCAT] = round(dz->param[SCRAMBLE_SCAT]);
+        *scatgrpcnt = (int)(chunkcnt/dz->iparam[SCRAMBLE_SCAT]);
+        *endscat    = (int)(chunkcnt - ((*scatgrpcnt) * dz->iparam[SCRAMBLE_SCAT]));
+        *range      = (*unit_len) * dz->iparam[SCRAMBLE_SCAT];
+        *endrange   = ((*endscat - 1) * (*unit_len)) + *endlen;
+    } else {
+        dz->iparam[SCRAMBLE_SCAT] = 0;
+    }
+    return(FINISHED);
+}
+
+/************************** NORMAL_SCAT *******************************/
+
+int normal_scat(int unit_len,int endlen,int chunkcnt_less_one,dataptr dz)
+{
+    double this_scatter;
+    int n;
+    int new_chunklen, total_len = unit_len;     
+    for(n=1;n<chunkcnt_less_one;n++) {          
+        this_scatter  = (drand48() - 0.5) * dz->param[SCRAMBLE_SCAT];   /* range +- .5 reduced by  *scatter */
+        new_chunklen = (int)(this_scatter * (double)unit_len);
+        if(ODD(new_chunklen))   
+            new_chunklen--;                             /* in case stereo?? */
+        dz->lparray[SCRAMBLE_CHUNKPTR][n] = total_len + new_chunklen;           /* position chunk-pointer */
+        total_len  += unit_len;                         /* step to next BASE position */
+    }
+    this_scatter  = (drand48() - 0.5) * dz->param[SCRAMBLE_SCAT];       /* as final chunk may be unique length */
+    if(this_scatter<0.0) {                              /* if scatter is -ve, scatter is frac of penultimate length */
+        new_chunklen   = (int)(this_scatter * (double)unit_len);
+        if(ODD(new_chunklen))   
+            new_chunklen--;
+        dz->lparray[SCRAMBLE_CHUNKPTR][n] = total_len - new_chunklen;
+    } else {                                            /* else, scatter is frac of final length */
+        new_chunklen   = (int)(this_scatter * (double)endlen);
+        if(ODD(new_chunklen))   
+            new_chunklen--;
+        dz->lparray[SCRAMBLE_CHUNKPTR][n] = total_len + new_chunklen;
+    }
+    return(FINISHED);
+}
+
+/*********************** 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.
+ */
+
+int heavy_scat(int scatgrpcnt,int range,int endscat,int endrange,dataptr dz)
+{
+    int thiss = 0, that, start, n, m, OK;           /* 1 */
+    int startptr = 0;                               /* 2 */
+    int minlen = (dz->iparam[ZIG_SPLSAMPS] * 2);
+    int filend = dz->insams[0];
+    int first = 1;                                  /* 3 */
+/* TW OCT 1997 */   
+    int latest_ptr = 0;
+    dz->lparray[SCRAMBLE_CHUNKPTR][thiss++] = 0;
+/* TW OCT 1997 */   
+    for(n=0;n<scatgrpcnt;n++) {                     /* 4 */
+        start = thiss;                              /* 5 */
+        for(m=first;m<dz->iparam[SCRAMBLE_SCAT];m++) {                  /* 6 */
+            do {                                    /* 7 */
+                OK = 1;                 
+                dz->lparray[SCRAMBLE_CHUNKPTR][thiss] = (int)(drand48()*range);     /* TRUNCATE */
+                dz->lparray[SCRAMBLE_CHUNKPTR][thiss] += startptr;      /* 8 */
+                if(ODD(dz->lparray[SCRAMBLE_CHUNKPTR][thiss]))   
+                    dz->lparray[SCRAMBLE_CHUNKPTR][thiss]--;    
+/* TW OCT 1997 -->*/
+                if(abs(dz->lparray[SCRAMBLE_CHUNKPTR][thiss] - latest_ptr)< minlen) {
+                    OK = 0;
+                    continue;
+                }
+                for(that=start; that<thiss; that++) {
+                    if(abs(dz->lparray[SCRAMBLE_CHUNKPTR][thiss] - dz->lparray[SCRAMBLE_CHUNKPTR][that])<minlen
+                    || abs(filend - abs(dz->lparray[SCRAMBLE_CHUNKPTR][thiss]))< minlen) {
+/* TW OCT 1997 */
+                        OK = 0;                     /* 9 */
+                        break;
+                    }
+                }
+            } while(!OK);                           /* 10 */
+            thiss++;                                /* 11 */
+        }
+/* TW OCT 1997 --> */   
+        for(m=0;m<thiss;m++) {
+            if(dz->lparray[SCRAMBLE_CHUNKPTR][m] > latest_ptr)
+                latest_ptr = dz->lparray[SCRAMBLE_CHUNKPTR][m];
+        }
+/* TW OCT 1997 */   
+        startptr += range;                          /* 12 */
+        first = 0;                                  /* 13 */
+    }
+
+    if(endscat) {                                   /* 14 */
+        start = thiss;
+        for(m=0;m<endscat;m++) {
+            do {
+                OK = 1;
+                dz->lparray[SCRAMBLE_CHUNKPTR][thiss] = (int)(drand48() * endrange);      /* TRUNCATE */
+                dz->lparray[SCRAMBLE_CHUNKPTR][thiss] += startptr;
+                if(ODD(dz->lparray[SCRAMBLE_CHUNKPTR][thiss]))   
+                    dz->lparray[SCRAMBLE_CHUNKPTR][thiss]--;    
+/* TW OCT 1997 */
+                if(abs(dz->lparray[SCRAMBLE_CHUNKPTR][thiss] - latest_ptr)< minlen) {
+                    OK = 0;
+                    continue;
+                }
+/* TW OCT 1997 */
+                for(that=start; that<thiss; that++) {
+                    if(abs(dz->lparray[SCRAMBLE_CHUNKPTR][thiss] - dz->lparray[SCRAMBLE_CHUNKPTR][that])< minlen 
+/* TW OCT 1997 */
+                    || abs(filend - abs(dz->lparray[SCRAMBLE_CHUNKPTR][thiss]))< minlen) {
+/* TW OCT 1997 */
+                        OK = 0;
+                        break;
+                    }
+                }
+            } while(!OK);
+            thiss++;
+        }
+    }
+    return ptr_sort(thiss,dz);
+}
+
+/*************************** PERMUTE_CHUNKS ***************************/
+
+void permute_chunks(int chunkcnt,dataptr dz)
+{
+    int n, t;
+    for(n=0;n<chunkcnt;n++) {
+        t = (int)(drand48() * (double)(n+1));    /* TRUNCATE */
+        if(t==n)
+            prefix(n,chunkcnt,dz);
+        else
+            insert(n,t,chunkcnt,dz);
+    }
+}
+
+/****************************** INSERT ****************************/
+
+void insert(int n,int t,int chunkcnt,dataptr dz)
+{
+    shuflup(t+1,chunkcnt,dz);
+    dz->iparray[SCRAMBLE_PERM][t+1] = n;
+}
+
+/****************************** PREFIX ****************************/
+
+void prefix(int n,int chunkcnt,dataptr dz)
+{
+    shuflup(0,chunkcnt,dz);
+    dz->iparray[SCRAMBLE_PERM][0] = n;
+}
+
+/****************************** SHUFLUP ****************************/
+
+void shuflup(int k,int chunkcnt,dataptr dz)
+{
+    int n;
+    int *i;
+    int z = chunkcnt-1;
+    i = &(dz->iparray[SCRAMBLE_PERM][z]);
+    for(n = z; n > k; n--) {
+        *i = *(i-1);
+        i--;
+    }
+}
+
+/************************** PTR_SORT ***************************/
+
+int ptr_sort(int end,dataptr dz)
+{
+    int i,j;
+    int a;
+    for(j=1;j<end;j++) {
+        a = dz->lparray[SCRAMBLE_CHUNKPTR][j];
+        i = j-1;
+        while(i >= 0 && dz->lparray[SCRAMBLE_CHUNKPTR][i] > a) {
+            dz->lparray[SCRAMBLE_CHUNKPTR][i+1]=dz->lparray[SCRAMBLE_CHUNKPTR][i];
+            i--;
+        }
+        dz->lparray[SCRAMBLE_CHUNKPTR][i+1] = a;
+    }
+    return(FINISHED);
+}    
+
+/**************************** ITERATE_PREPROCESS ******************************/
+
+int iterate_preprocess(dataptr dz)
+{
+    int exit_status;
+    double maxrand, maxpscat, mindelay, temp;
+    int is_unity_gain = FALSE;
+    int mindelay_samps;
+    if(dz->process == ITERATE_EXTEND) {
+        if(dz->iparam[ITER_RRSEED] > 0)
+            srand((int)dz->iparam[ITER_RRSEED]);
+        else
+            initrand48();
+    } else {
+        if(dz->iparam[ITER_RSEED] > 0)
+            srand((int)dz->iparam[ITER_RSEED]);
+        else
+            initrand48();
+    }
+    if((exit_status = get_maxvalue_of_rand(&maxrand,dz))<0)
+            return(exit_status);
+    if((exit_status = get_maxvalue_of_pscat(&maxpscat,dz))<0)
+            return(exit_status);
+    if((exit_status = get_minvalue_of_delay(&mindelay,dz))<0)
+            return(exit_status);
+    mindelay_samps = round(mindelay * (double)dz->infile->srate);
+    if(dz->process == ITERATE_EXTEND) {
+        dz->iparam[CHUNKSTART] = (int)round(dz->param[CHUNKSTART] * dz->infile->srate) * dz->infile->channels;
+        dz->iparam[CHUNKEND]   = (int)round(dz->param[CHUNKEND]   * dz->infile->srate) * dz->infile->channels;
+        if(dz->param[CHUNKSTART] > dz->param[CHUNKEND]) {
+            temp = dz->param[CHUNKSTART];
+            dz->param[CHUNKSTART] = dz->param[CHUNKEND];
+            dz->param[CHUNKEND] = temp;
+        }
+        if(dz->iparam[CHUNKEND] - dz->iparam[CHUNKSTART] <= ITX_SPLICELEN * dz->infile->channels * 2) {
+            sprintf(errstr,"FROZEN SEGMENT (%d samples) TOO SHORT FOR SPLICING (needs %d samples)\n",
+                dz->iparam[CHUNKEND] - dz->iparam[CHUNKSTART],ITX_SPLICELEN * dz->infile->channels * 2);
+            return(DATA_ERROR);
+        }
+        if(dz->iparam[CHUNKEND] - dz->iparam[CHUNKSTART] < mindelay_samps * dz->infile->channels) {
+            sprintf(errstr,"FROZEN SEGMENT (%d samples) TOO SHORT FOR (MINIMUM) DELAY TIME SPECIFIED (%d samples)\n",
+                dz->iparam[CHUNKEND] - dz->iparam[CHUNKSTART],mindelay_samps * dz->infile->channels);
+            return(DATA_ERROR);
+        }
+    }
+    if((dz->process != ITERATE_EXTEND) && (dz->param[ITER_GAIN]==DEFAULT_ITER_GAIN))
+        set_default_gain(mindelay_samps,dz);
+    set_default_delays(dz);
+    if (dz->process == ITERATE_EXTEND) {
+        dz->param[ITER_SSTEP] = 1.0; /* 1st sound is exact copy of orig */
+    } else {
+        reverse_fadevals(dz);
+        dz->param[ITER_STEP] = 1.0; /* 1st sound is exact copy of orig */
+    }
+    if((dz->process != ITERATE_EXTEND) && flteq(dz->param[ITER_GAIN],1.0))
+        is_unity_gain = TRUE;
+    setup_iter_process_type(is_unity_gain,dz);
+    return create_iterbufs(maxpscat,dz);
+}
+
+/*************************** GET_MAXVALUE_OF_RAND ****************************/
+
+int get_maxvalue_of_rand(double *maxrand,dataptr dz)
+{
+    int exit_status;
+    if(dz->brksize[ITER_RANDOM]) {
+        if((exit_status = get_maxvalue_in_brktable(maxrand,ITER_RANDOM,dz))<0)
+            return(exit_status);
+    } else
+        *maxrand = dz->param[ITER_RANDOM];
+    return(FINISHED);
+}
+
+/************************* GET_MAXVALUE_OF_PSCAT ****************************/
+
+int get_maxvalue_of_pscat(double *maxpscat,dataptr dz)
+{
+    int exit_status;
+    if(dz->brksize[ITER_PSCAT]) {
+        if((exit_status = get_maxvalue_in_brktable(maxpscat,ITER_PSCAT,dz))<0)
+            return(exit_status);
+    } else
+        *maxpscat = dz->param[ITER_PSCAT];
+    return(FINISHED);
+}
+
+/************************* GET_MINVALUE_OF_DELAY ****************************/
+
+int get_minvalue_of_delay(double *mindelay,dataptr dz)
+{
+    int exit_status;
+    if(dz->brksize[ITER_DELAY]) {
+        if((exit_status = get_minvalue_in_brktable(mindelay,ITER_DELAY,dz))<0)
+            return(exit_status);
+    } else
+        *mindelay = dz->param[ITER_DELAY];
+    return(FINISHED);
+}
+
+/************************* REVERSE_FADEVALS ****************************/
+
+void reverse_fadevals(dataptr dz)
+{
+    double *p, *pend;
+
+    if(dz->brksize[ITER_FADE]==0)
+        dz->param[ITER_FADE] = 1.0 - dz->param[ITER_FADE];
+    else {
+        p    = dz->brk[ITER_FADE] + 1;
+        pend = dz->brk[ITER_FADE] + (dz->brksize[ITER_FADE] * 2);
+        while(p < pend) {
+            *p = 1.0 - *p;
+            p += 2;
+        }
+    }
+}
+
+/************************** SET_DEFAULT_GAIN ****************************/
+
+void set_default_gain(int mindelay_samps,dataptr dz)
+{
+    int inmsampsize;
+    int maxoverlay_cnt;
+    inmsampsize = dz->insams[0]/dz->infile->channels;
+    maxoverlay_cnt = round(((double)inmsampsize/(double)mindelay_samps)+1.0);
+    if(dz->vflag[IS_ITER_RAND])
+        maxoverlay_cnt++;
+    dz->param[ITER_GAIN]   = 1.0/(double)maxoverlay_cnt;
+}
+
+/*********************** SET_DEFAULT_DELAYS ****************************/
+
+void set_default_delays(dataptr dz)
+{
+    if(dz->process==ITERATE_EXTEND) {
+        if(!dz->brksize[ITER_DELAY])
+            dz->iparam[ITER_MSAMPDEL] = round(dz->param[ITER_DELAY] * (double)dz->infile->srate);
+        return;
+    }
+    if(dz->vflag[IS_ITER_DELAY]) {
+        if(!dz->brksize[ITER_DELAY])
+            dz->iparam[ITER_MSAMPDEL] = round(dz->param[ITER_DELAY] * (double)dz->infile->srate);
+    } else
+        dz->iparam[ITER_MSAMPDEL] = dz->insams[0]/dz->infile->channels; /* default */
+}
+
+/********************* SETUP_ITER_PROCESS_TYPE ********************************/
+
+void setup_iter_process_type(int is_unity_gain,dataptr dz)
+{
+    if(dz->process==ITERATE_EXTEND) {
+        if(dz->param[ITER_PSCAT] > 0.0) {
+            if(dz->infile->channels>1)
+                dz->iparam[ITER_PROCESS] = ST_INTP_SHIFT;
+            else
+                dz->iparam[ITER_PROCESS] = MN_INTP_SHIFT;
+        } else {
+            if(dz->infile->channels>1)
+                dz->iparam[ITER_PROCESS] = STEREO;
+            else
+                dz->iparam[ITER_PROCESS] = MONO;
+        }
+        if(flteq(dz->param[ITER_ASCAT],0.0)) {
+            dz->iparam[ITER_PROCESS] += FIXED_AMP;
+        }
+        return;
+    }
+    dz->iparam[ITER_DO_SCALE] = TRUE;
+    if(dz->vflag[IS_ITER_PSCAT]) {
+        if(dz->infile->channels>1)
+            dz->iparam[ITER_PROCESS] = ST_INTP_SHIFT;
+        else
+            dz->iparam[ITER_PROCESS] = MN_INTP_SHIFT;
+    } else {
+        if(dz->infile->channels>1)
+            dz->iparam[ITER_PROCESS] = STEREO;
+        else
+            dz->iparam[ITER_PROCESS] = MONO;
+    }
+    if(!dz->vflag[IS_ITER_ASCAT]) {
+        if(is_unity_gain)
+            dz->iparam[ITER_DO_SCALE] = FALSE;
+        dz->iparam[ITER_PROCESS] += FIXED_AMP;
+    }
+}
+
+/***************************** DRUNK_PREPROCESS *************************
+ *
+ * Splicelen & cloktiks have been converted to SAMPLES in pconsistency.c
+ */
+
+int drunk_preprocess(dataptr dz)
+{
+    int exit_status;
+    dz->iparam[DRNK_LAST_LOCUS] = -1;
+    initialise_random_sequence(IS_DRNK_RSEED,DRNK_RSEED,dz);
+    if((exit_status = create_drunk_buffers(dz))<0)  /* 1 */
+        return(exit_status);
+    if((exit_status = make_drnk_splicetab(dz))<0)
+        return(exit_status);
+    if(dz->insams[0] <= dz->iparam[DRNK_SPLICELEN] * dz->infile->channels * 2) {
+        sprintf(errstr,"Infile too short for splices.\n");
+        return(DATA_ERROR);
+    }
+    dz->iparam[DRNK_LGRAIN] = round((double)dz->infile->srate * DRNK_GRAIN); 
+
+    dz->iparam[DRNK_TOTALDUR]  = round(dz->param[DRNK_TOTALDUR] * (double)(dz->infile->srate * dz->infile->channels));
+    if((exit_status = convert_time_and_vals_to_samplecnts(DRNK_LOCUS,dz))<0)
+        return(exit_status);
+    if((exit_status = convert_time_and_vals_to_samplecnts(DRNK_AMBITUS,dz))<0)
+        return(exit_status);
+    if((exit_status = convert_time_to_samplecnts(DRNK_CLOKRND,dz))<0)
+        return(exit_status);
+    if((exit_status = convert_time_to_samplecnts(DRNK_OVERLAP,dz))<0)
+        return(exit_status);
+    if((exit_status = get_maxvalue(DRNK_OVERLAP,&dz->param[DRNK_MAX_OVLAP],dz))<0)
+        return(exit_status);
+    if((exit_status = convert_time_to_samplecnts(DRNK_GSTEP,dz))<0)
+        return(exit_status);
+    if((exit_status = convert_sec_steps_to_grain_steps(dz))<0)
+        return(exit_status);
+    if(dz->mode==HAS_SOBER_MOMENTS) {
+        if((exit_status = convert_time_and_vals_to_samplecnts(DRNK_MIN_PAUS,dz))<0)
+            return(exit_status);
+        if((exit_status = convert_time_and_vals_to_samplecnts(DRNK_MAX_PAUS,dz))<0)
+            return(exit_status);
+        if((exit_status = convert_time_to_samplecnts(DRNK_MIN_DRNKTIK,dz))<0)
+            return(exit_status);
+        if((exit_status = convert_time_to_samplecnts(DRNK_MAX_DRNKTIK,dz))<0)
+            return(exit_status);
+    }
+    return(FINISHED);
+}
+
+/********************** MAKE_DRNK_SPLICETAB *********************/
+
+int make_drnk_splicetab(dataptr dz)
+{
+    int n;
+    if((dz->parray[DRNK_SPLICETAB] = (double *)malloc(dz->iparam[DRNK_SPLICELEN] * sizeof(double)))==NULL) {
+        sprintf(errstr,"INSUFFICIENT MEMORY to make splicetable.\n");
+        return(MEMORY_ERROR);
+    } 
+    for(n=0;n<dz->iparam[DRNK_SPLICELEN];n++)
+        dz->parray[DRNK_SPLICETAB][n] = (double)n/(double)dz->iparam[DRNK_SPLICELEN];
+    return(FINISHED);
+ }
+
+/************************* CONVERT_SEC_STEPS_TO_GRAIN_STEPS *********************/
+
+int convert_sec_steps_to_grain_steps(dataptr dz)
+{
+    double *p, *pend;
+    int lval;
+    if(dz->iparam[DRNK_LGRAIN]<=0) {
+        sprintf(errstr,"Invalid DRNK_LGRAIN val: convert_sec_steps_to_grain_steps()\n");
+        return(PROGRAM_ERROR);
+    }
+    if(dz->brksize[DRNK_GSTEP]) {
+        p    = dz->brk[DRNK_GSTEP] + 1;
+        pend = dz->brk[DRNK_GSTEP] + (dz->brksize[DRNK_GSTEP] * 2);
+        while(p < pend) {
+            lval = round(*p * (double)dz->infile->srate);
+            lval = (lval+(dz->iparam[DRNK_LGRAIN]/2))/dz->iparam[DRNK_LGRAIN];
+            *p   = (double)lval;
+            p += 2;
+        }
+    } else {
+        dz->iparam[DRNK_GSTEP] = round(dz->param[DRNK_GSTEP] * (double)dz->infile->srate);
+        dz->iparam[DRNK_GSTEP] = (dz->iparam[DRNK_GSTEP]+(dz->iparam[DRNK_LGRAIN]/2))/dz->iparam[DRNK_LGRAIN];
+        dz->param[DRNK_GSTEP]  = (double)dz->iparam[DRNK_GSTEP];
+    }
+    return(FINISHED);
+}

+ 2548 - 0
dev/extend/iterate.c

@@ -0,0 +1,2548 @@
+/*
+ * 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 <globcon.h>
+#include <processno.h>
+#include <modeno.h>
+#include <arrays.h>
+#include <extend.h>
+#include <cdpmain.h>
+#include <sfsys.h>
+#include <osbind.h>
+#include <limits.h>
+
+
+
+static int  read_the_input_snd(dataptr dz);
+static int  new_read_the_input_snd(int samplen,int wrap,dataptr dz);
+static void scale_input(dataptr dz);
+static int get_next_writestart(int write_start,dataptr dz);
+
+//TW UPDATED ALL THESE FUNCTIONS
+//HAVE DONE FLOAT CONVERSIONS HERE
+static int iterate(int cnt,int pass,double *gain,double *pshift,
+				int write_end,int local_write_start,int inmsampsize,double level,double *maxsamp,int pstep,int iterating,dataptr dz);
+static int iter(int cnt,int passno, double *gain,int local_write_start,int inmsampsize,double level,double *maxsamp,int iterating,dataptr dz);
+static int iter_stereo(int cnt,int passno, double *gain,int local_write_start,int inmsampsize,double level,double *maxsamp,int iterating,dataptr dz);
+static int iter_shift_interp(int cnt,int passno, double *gain,double *pshift,int local_write_start,int inmsampsize,double level,double *maxsamp,int pstep,int iterating,dataptr dz);
+static int iter_shift_interp_stereo(int cnt,int passno, double *gain,double *pshift,int local_write_start,int inmsampsize,double level,double *maxsamp,int pstep,int iterating,dataptr dz);
+static int fixa_iter(int cnt,int passno,double *gain,int local_write_start,int inmsampsize,double level,double *maxsamp,int iterating,dataptr dz);
+static int fixa_iter_stereo(int cnt,int passno,double *gain,int local_write_start,int inmsampsize,double level,double *maxsamp,int iterating,dataptr dz);
+static int fixa_iter_shift_interp(int cnt,int passno,double *gain,double *pshift,int local_write_start,int inmsampsize,double level,double *maxsamp,int pstep,int iterating,dataptr dz);
+static int fixa_iter_shift_interp_stereo(int cnt,int passno,double *gain,double *pshift,int local_write_start,int inmsampsize,double level,double *maxsamp,int pstep,int iterating,dataptr dz);
+
+static int new_iterate(int cnt,int pass,double *gain,double *pshift,
+				int write_end,int local_write_start,int inmsampsize,double level,int pstep,int iterating,dataptr dz);
+static int new_iter(int cnt,int passno, double *gain,int local_write_start,int inmsampsize,double level,int iterating,dataptr dz);
+static int new_iter_stereo(int cnt,int passno, double *gain,int local_write_start,int inmsampsize,double level,int iterating,dataptr dz);
+static int new_iter_shift_interp(int cnt,int passno, double *gain,double *pshift,int local_write_start,int inmsampsize,double level,int pstep,int iterating,dataptr dz);
+static int new_iter_shift_interp_stereo(int cnt,int passno, double *gain,double *pshift,int local_write_start,int inmsampsize,double level,int pstep,int iterating,dataptr dz);
+static int new_fixa_iter(int cnt,int passno,double *gain,int local_write_start,int inmsampsize,double level,int iterating,dataptr dz);
+static int new_fixa_iter_stereo(int cnt,int passno,double *gain,int local_write_start,int inmsampsize,double level,int iterating,dataptr dz);
+static int new_fixa_iter_shift_interp(int cnt,int passno,double *gain,double *pshift,int local_write_start,int inmsampsize,double level,int pstep,int iterating,dataptr dz);
+static int new_fixa_iter_shift_interp_stereo(int cnt,int passno,double *gain,double *pshift,int local_write_start,int inmsampsize,double level,int pstep,int iterating,dataptr dz);
+
+static double get_gain(dataptr dz);
+static double get_pshift(dataptr dz);
+static void do_endsplice(float *buf,int dur,int splicelen,double spliceincr,int chans);
+static int do_iteration_extend(dataptr dz);
+
+/****************************** DO_ITERATION *************************
+ *
+ * (1) First event is always copy of original.
+ */
+
+//TW COMPLETELY UPDATED FUNCTION : (flt-converted)
+#define ACCEPTABLE_LEVEL 0.75
+
+int do_iteration(dataptr dz)
+{
+	int    exit_status, iterating;
+	int   write_end, tail, cnt, arraysize = BIGARRAY;
+	float *tailend;
+	int    bufs_written, finished;
+	double level, thistime;
+	int   out_sampdur = 0, inmsampsize;
+	int   write_start, local_write_start;
+	double one_over_sr = 1.0/(double)dz->infile->srate, maxsamp = 0.0;
+	int    passno, is_penult = 0, pstep;
+	int   k;
+	double *gain, *pshift, gaingain = -1.0;
+	int   *wstart /*,  chunkmsamps = 0, chunksampsize = 0 */ ;
+	float	*orig_inbuf = dz->sampbuf[0];
+
+	if(dz->process == ITERATE_EXTEND)
+		return do_iteration_extend(dz);
+	pstep = ITER_STEP;
+	iterating = 1;
+	if ((gain = (double *)malloc(arraysize * sizeof(double)))==NULL) {
+		sprintf(errstr,"Insufficient memory to store gain values\n");
+		return(MEMORY_ERROR);
+	}
+	if ((pshift = (double *)malloc(arraysize * sizeof(double)))==NULL) {
+		sprintf(errstr,"Insufficient memory to store pitch shift values\n");
+		return(MEMORY_ERROR);
+	}
+	if ((wstart = (int *)malloc(arraysize * sizeof(int)))==NULL) {
+		sprintf(errstr,"Insufficient memory to store pitch shift values\n");
+		return(MEMORY_ERROR);
+	}
+/*
+	if(dz->process == ITERATE_EXTEND) {
+		chunksampsize = dz->iparam[CHUNKEND] - dz->iparam[CHUNKSTART]; 
+		chunkmsamps = chunksampsize/dz->infile->channels; 
+	}
+*/
+	if(dz->mode==ITERATE_DUR)
+		out_sampdur  = round(dz->param[ITER_DUR] * (double)dz->infile->srate) * dz->infile->channels;
+	if(sloom) {
+		switch(dz->mode) {
+		case(ITERATE_DUR):		
+			dz->tempsize = out_sampdur;		
+			break;
+		case(ITERATE_REPEATS):	
+			dz->tempsize = dz->insams[0] * (dz->iparam[ITER_REPEATS]+1);	/* approx */
+			break; 
+		}
+	}
+	for(passno=0;passno<2;passno++) {
+		is_penult = 0;
+		cnt = 0;
+		bufs_written = 0;
+		write_start = 0;
+		maxsamp = 0.0;
+		memset((char *)dz->sampbuf[1],0,dz->buflen * sizeof(float));
+		level = dz->param[ITER_FADE];
+		sndseekEx(dz->ifd[0],0L,0);
+		display_virtual_time(0L,dz);
+		fflush(stdout);
+		dz->sampbuf[0] = orig_inbuf;
+		if(passno > 0) {
+			print_outmessage_flush("Second pass, for greater level\n");
+			dz->tempsize = dz->total_samps_written;
+			dz->total_samps_written = 0;
+			memset((char *)dz->sampbuf[0],0,(dz->sampbuf[3] - dz->sampbuf[0]) * sizeof(float));
+		}
+		if((exit_status = read_the_input_snd(dz))<0)
+			return(exit_status);
+		if(dz->iparam[ITER_DO_SCALE])								
+			scale_input(dz);
+		inmsampsize = dz->insams[0]/dz->infile->channels;	/* no. of 'stereo'-samps to process */
+		/* 1 */
+		local_write_start = 0;
+		switch(dz->iparam[ITER_PROCESS]) {
+		case(MONO):		      		
+			iter(0,passno,gain,local_write_start,inmsampsize,level,&maxsamp,iterating,dz);		
+			break;
+		case(STEREO):	      		
+			iter_stereo(0,passno,gain,local_write_start,inmsampsize,level,&maxsamp,iterating,dz);			 		
+			break;
+		case(MN_INTP_SHIFT):      	
+			iter_shift_interp(0,passno,gain,pshift,local_write_start,inmsampsize,level,&maxsamp,pstep,iterating,dz);	 		
+			break;
+		case(ST_INTP_SHIFT):      	
+			iter_shift_interp_stereo(0,passno,gain,pshift,local_write_start,inmsampsize,level,&maxsamp,pstep,iterating,dz);		
+			break;
+		case(FIXA_MONO):	      	
+			fixa_iter(0,passno,gain,local_write_start,inmsampsize,level,&maxsamp,iterating,dz);			 		
+			break;
+		case(FIXA_STEREO):	      	
+			fixa_iter_stereo(0,passno,gain,local_write_start,inmsampsize,level,&maxsamp,iterating,dz);		 		
+			break;
+		case(FIXA_MN_INTP_SHIFT): 	
+			fixa_iter_shift_interp(0,passno,gain,pshift,local_write_start,inmsampsize,level,&maxsamp,pstep,iterating,dz); 		
+			break;
+		case(FIXA_ST_INTP_SHIFT): 	
+			fixa_iter_shift_interp_stereo(0,passno,gain,pshift,local_write_start,inmsampsize,level,&maxsamp,pstep,iterating,dz); 
+			break;
+		}
+		write_end   = dz->insams[0];
+		thistime = 0.0;
+		if((exit_status = read_values_from_all_existing_brktables(thistime,dz))<0)
+			return(exit_status);
+		if(dz->brksize[ITER_DELAY])
+			dz->iparam[ITER_MSAMPDEL] = round(dz->param[ITER_DELAY] * (double)dz->infile->srate);
+		if(passno==0)
+			wstart[cnt] = get_next_writestart(write_start,dz);
+		write_start = wstart[cnt];
+		local_write_start = write_start;
+		finished = FALSE;
+		for(;;) {
+			switch(dz->mode) {
+			case(ITERATE_DUR):
+				if(write_start >= out_sampdur)
+					finished = TRUE;
+				break;
+			case(ITERATE_REPEATS):
+				if(cnt >= dz->iparam[ITER_REPEATS])
+					finished = TRUE;
+				break;
+			}
+			if(finished)
+				break;
+			while(local_write_start >= dz->buflen) {
+				if(passno > 0) {
+					if((exit_status = write_samps(dz->sampbuf[1],dz->buflen,dz))<0)
+						return(exit_status);
+				}
+				bufs_written++;
+				tail = write_end - dz->buflen;
+				memset((char *)dz->sampbuf[1],0,dz->buflen * sizeof(float));
+				if(tail > 0) {
+					memmove((char *)dz->sampbuf[1],(char *)dz->sampbuf[2],tail * sizeof(float));
+					tailend = dz->sampbuf[1] + tail;
+				} else
+					tailend = dz->sampbuf[2];
+				memset((char *)tailend,0,(dz->sampbuf[3] - tailend) * sizeof(float));
+				local_write_start -= dz->buflen;
+				write_end         -= dz->buflen;
+			}
+			cnt++;
+			if((passno == 0) && (cnt >= arraysize)) {
+				arraysize += BIGARRAY;
+				if ((gain = (double *)realloc((char *)gain,arraysize * sizeof(double)))==NULL) {
+					sprintf(errstr,"Insufficient memory to store gain values (2)\n");
+					return(MEMORY_ERROR);
+				}
+				if ((pshift = (double *)realloc((char *)pshift,arraysize * sizeof(double)))==NULL) {
+					sprintf(errstr,"Insufficient memory to store gain values (2)\n");
+					return(MEMORY_ERROR);
+				}
+				if ((wstart = (int *)realloc((char *)wstart,arraysize * sizeof(int)))==NULL) {
+					sprintf(errstr,"Insufficient memory to store gain values (2)\n");
+					return(MEMORY_ERROR);
+				}
+			}
+			thistime = ((dz->buflen * bufs_written) + local_write_start) * one_over_sr;
+			
+			if((exit_status = read_values_from_all_existing_brktables(thistime,dz))<0)
+				return(exit_status);
+			if(is_penult) {
+				dz->param[ITER_PSCAT] = 0.0;
+				dz->param[ITER_ASCAT] = 0.0;
+			}
+			if(dz->brksize[ITER_DELAY])
+				dz->iparam[ITER_MSAMPDEL] = round(dz->param[ITER_DELAY] * (double)dz->infile->srate);
+			write_end = iterate(cnt,passno,gain,pshift,write_end,local_write_start,inmsampsize,level,&maxsamp,pstep,iterating,dz);
+			level *= dz->param[ITER_FADE];
+			if(passno==0)
+				wstart[cnt] = get_next_writestart(write_start,dz);
+			write_start = wstart[cnt];
+			local_write_start = write_start - (bufs_written * dz->buflen);
+		}
+		if(passno > 0) {
+			if(write_end > 0) {
+				if((exit_status = write_samps(dz->sampbuf[1],write_end,dz))<0)
+					return(exit_status);
+			}
+		} else {
+			if(maxsamp <= 0.0) {
+				sprintf(errstr,"No significant signal level found");
+				return(DATA_ERROR);
+			}
+			if(maxsamp < ACCEPTABLE_LEVEL || maxsamp > 0.99)
+				gaingain = ACCEPTABLE_LEVEL/maxsamp;
+			else
+				gaingain = 1.0;
+			switch(dz->iparam[ITER_PROCESS]) {
+			case(MONO):		      		
+			case(STEREO):	      		
+			case(MN_INTP_SHIFT):      	
+			case(ST_INTP_SHIFT):      	
+				for(k=0;k<=cnt;k++)
+					gain[k] *= gaingain;
+				break;
+			case(FIXA_MONO):	      	
+			case(FIXA_STEREO):	      	
+			case(FIXA_MN_INTP_SHIFT): 	
+			case(FIXA_ST_INTP_SHIFT): 	
+				for(k=0;k<=cnt;k++)
+					gain[k] = gaingain;
+				break;
+			}
+		}
+	}
+	return FINISHED;
+}
+
+/****************************** DO_ITERATION_EXTEND **************************/
+
+//2012 TW COMPLETELY UPDATED FUNCTION : (Better iterate-extend)
+
+int do_iteration_extend(dataptr dz)
+{
+	int    exit_status, iterating;
+	int   write_end, tail, cnt, arraysize = BIGARRAY, remnant = 0;
+	float *tailend;
+	int    bufs_written, finished, units = 0;
+	int   twoseccnt = dz->infile->srate * 2;
+	double level, thistime, localmax=0.0;
+	int   out_sampdur = 0, inmsampsize;
+	int   write_start, local_write_start;
+	double srate = (double)dz->infile->srate, one_over_sr = 1.0/srate, maxsamp = 0.0;
+	int    passno, is_penult = 0, pstep;
+	int   k, orig_sampdel = 0, ii, jj, kk, n;
+	double *gain, *pshift, gaingain = -1.0;
+	int   *wstart, /* chunkmsamps = 0, */ chunksampsize = 0;
+	int splicelen = ITX_SPLICELEN;
+	double spliceincr = 1.0/(double)ITX_SPLICELEN, splicer;
+	float *ibuf = dz->sampbuf[0], *obuf = dz->sampbuf[1], *ovflw = dz->sampbuf[2], *chunkbuf = dz->sampbuf[3];
+	int chans = dz->infile->channels;
+
+	pstep = ITER_SSTEP;
+	iterating = 0;
+	if ((gain = (double *)malloc(arraysize * sizeof(double)))==NULL) {
+		sprintf(errstr,"Insufficient memory to store gain values\n");
+		return(MEMORY_ERROR);
+	}
+	if ((pshift = (double *)malloc(arraysize * sizeof(double)))==NULL) {
+		sprintf(errstr,"Insufficient memory to store pitch shift values\n");
+		return(MEMORY_ERROR);
+	}
+	if ((wstart = (int *)malloc(arraysize * sizeof(int)))==NULL) {
+		sprintf(errstr,"Insufficient memory to store pitch shift values\n");
+		return(MEMORY_ERROR);
+	}
+	chunksampsize = dz->iparam[CHUNKEND] - dz->iparam[CHUNKSTART];
+	/* chunkmsamps = chunksampsize/chans; */
+	if(dz->mode==ITERATE_DUR)
+		out_sampdur  = round(dz->param[ITER_DUR] * srate) * chans;
+	if(sloom) {
+		switch(dz->mode) {
+		case(ITERATE_DUR):		
+			dz->tempsize = out_sampdur;		
+			break;
+		case(ITERATE_REPEATS):	
+			dz->tempsize = dz->insams[0] + (chunksampsize * dz->iparam[ITER_REPEATS]);	/* approx */
+			break; 
+		}
+	}
+	if(dz->mode == ITERATE_DUR)
+		out_sampdur -= dz->insams[0] - dz->iparam[CHUNKEND];
+	for(passno=0;passno<2;passno++) {
+		is_penult = 0;
+		cnt = 0;
+		bufs_written = 0;
+		write_start = 0;
+		maxsamp = 0.0;
+		memset((char *)obuf,0,dz->buflen * sizeof(float));
+		level = 1.0;
+		localmax = 0.0;
+		if(passno > 0) {
+			print_outmessage_flush("Second pass, for correct level\n");
+			memset((char *)ibuf,0,(chunkbuf - ibuf) * sizeof(float));
+		}
+		sndseekEx(dz->ifd[0],0L,0);
+		reset_filedata_counters(dz);
+		display_virtual_time(0L,dz);
+		fflush(stdout);
+
+		if(passno == 0) {
+			sndseekEx(dz->ifd[0],dz->iparam[CHUNKSTART],0);
+			dz->total_samps_read = dz->iparam[CHUNKSTART];
+			dz->samps_left = dz->insams[0] - dz->total_samps_read;
+			dz->total_samps_written = dz->iparam[CHUNKSTART]; //For accountancy for local_write_start
+			/* Make bakup copy of chunk to iterate, with splice at start */
+			if((exit_status = new_read_the_input_snd(dz->buflen,0,dz))<0)
+				return(exit_status);
+			for(jj = 0; jj < chunksampsize;jj++)
+				localmax = max(localmax,fabs(ibuf[jj]));
+			if(localmax <= 0.0) {
+				sprintf(errstr,"No significant signal found in frozen segment");
+				return(DATA_ERROR);
+			}
+			memcpy((char *)chunkbuf,(char *)ibuf,(chunksampsize * sizeof(float)));
+			jj = 0;
+			splicer = 0.0;
+			for(kk = 0; kk < splicelen; kk++) {
+				for(ii=0; ii <chans;ii++) {
+					chunkbuf[jj] = (float)(chunkbuf[jj] * splicer);
+					jj++;
+				}
+				splicer += spliceincr;
+			}
+		} else {
+			if(dz->iparam[CHUNKSTART] == 0) {
+				if((exit_status = new_read_the_input_snd(chunksampsize,1,dz))<0)
+					return(exit_status);
+			} else {
+				while(dz->total_samps_read < dz->iparam[CHUNKSTART]) {
+					if((exit_status = new_read_the_input_snd(dz->buflen,0,dz))<0)
+						return(exit_status);
+					if(dz->total_samps_read < dz->iparam[CHUNKSTART]) {
+						for(ii =0; ii < dz->buflen;ii++)
+							ibuf[ii] = (float)(ibuf[ii] * gaingain);
+						if((exit_status = write_samps(ibuf,dz->buflen,dz))<0)
+							return(exit_status);
+						write_end = dz->total_samps_written;
+					} else {
+						remnant = dz->iparam[CHUNKSTART] - (dz->total_samps_read - dz->ssampsread);
+						if(remnant > 0) {
+							for(ii =0; ii < remnant;ii++)
+								ibuf[ii] = (float)(ibuf[ii] * gaingain);
+							if((exit_status = write_samps(ibuf,remnant,dz))<0)
+								return(exit_status);
+						}
+						memset((char *)ibuf,0,dz->buflen * sizeof(float));
+						write_end = dz->total_samps_written;
+						sndseekEx(dz->ifd[0],dz->iparam[CHUNKSTART],0);
+						dz->total_samps_read = dz->iparam[CHUNKSTART];
+						dz->samps_left = dz->insams[0] - dz->total_samps_read;
+						if((exit_status = new_read_the_input_snd(chunksampsize,1,dz))<0)
+							return(exit_status);
+					}
+				}
+			}
+		}
+		/*Put splice on END of iterated chunk in TRUE buffer */
+		jj = chunksampsize + chans - 1;
+		for(ii=0; ii <chans;ii++) {
+			ibuf[jj] = (float)0;		/* These are the wrap-around points */
+			jj--;
+		}
+		splicer = 0.0;
+		for(kk = 0; kk < splicelen; kk++) {
+			for(ii=0; ii <chans;ii++) {
+				ibuf[jj] = (float)(ibuf[jj] * splicer);
+				jj--;
+			}
+			splicer += spliceincr;
+		}
+		inmsampsize = chunksampsize/chans;
+		// copy this at its original level to output buffer (because it must match level of immediately previous sound)
+		jj = 0;
+		for(ii=0; ii < inmsampsize; ii++) {
+			kk = ii*chans;
+			for(n=0;n<chans;n++) {
+				if(passno == 0)
+					obuf[jj] = ibuf[kk];	//	Copy at original level, as this is start of iterated chunk, to be level-assessed
+				else
+					obuf[jj] = (float)(ibuf[kk] * gaingain);
+				jj++;
+				kk++;
+			}
+		}
+		iterating = 1;
+		
+		write_end  = dz->total_samps_written + chunksampsize;
+		thistime   = (double)((dz->total_samps_read - chunksampsize)/chans)/srate;
+		jj = 0;		/* Put splice on START of iterated chunk */
+		splicer = 0.0;
+		for(kk = 0; kk < splicelen; kk++) {
+			for(ii=0; ii <chans;ii++) {
+				ibuf[jj] = (float)(ibuf[jj] * splicer);
+				jj++;
+			}
+			splicer += spliceincr;
+		}
+		if((exit_status = read_values_from_all_existing_brktables(thistime,dz))<0)
+			return(exit_status);
+		if(dz->process == ITERATE_EXTEND) {
+			orig_sampdel = round(dz->param[ITER_DELAY] * srate);
+			dz->iparam[ITER_MSAMPDEL] = dz->iparam[CHUNKSTART]/chans + orig_sampdel;
+			dz->iparam[ITER_MSAMPDEL] -= ITX_SPLICELEN * 2;
+		}
+		if(passno==0)
+			wstart[cnt] = dz->iparam[ITER_MSAMPDEL] * chans;
+
+		write_start = wstart[cnt];
+		local_write_start = write_start - dz->iparam[CHUNKSTART];
+		finished = FALSE;
+		for(;;) {
+			if(is_penult) {			/* If previously got to end, break */
+				/* If last repeat, get orig material, with splice at start */
+				memcpy((char *)ibuf,(char *)chunkbuf,chunksampsize * sizeof(float));
+				for(jj = 0, k = local_write_start; jj < chunksampsize; jj++,k++) {			//	Write the final iteration
+					if(k >= dz->buflen) {
+						if(passno == 0) {
+							for(ii =0; ii < dz->buflen;ii++)
+								maxsamp = max(maxsamp,fabs(obuf[ii]));
+						} else {
+							for(ii =0; ii < dz->buflen;ii++)
+								obuf[ii] = (float)(obuf[ii] * gaingain);
+							if((exit_status = write_samps(obuf,dz->buflen,dz))<0)
+								return(exit_status);
+						}
+						bufs_written++;
+						tail = write_end - dz->buflen;
+						memset((char *)obuf,0,dz->buflen * sizeof(float));
+						if(tail > 0) {
+							memmove((char *)obuf,(char *)ovflw,tail * sizeof(float));
+							tailend = obuf + tail;
+						} else
+							tailend = ovflw;
+						memset((char *)tailend,0,(chunkbuf - tailend) * sizeof(float));
+						local_write_start -= dz->buflen;
+						write_end         -= dz->buflen;
+						k = 0;
+					}
+					obuf[k] = (float)(obuf[k] + ibuf[jj]);
+				}
+				while(dz->samps_left > 0) {
+					if((exit_status = new_read_the_input_snd(dz->buflen,0,dz))<0)
+						return(exit_status);
+					for(jj = 0; jj < dz->ssampsread; jj++,k++) {
+						if(k >= dz->buflen) {
+							if(passno == 0) {
+								if(write_end > 0) {
+									for(ii =0; ii < min(dz->buflen,write_end);ii++)
+										maxsamp = max(maxsamp,fabs(obuf[ii]));
+								}
+							} else {
+								for(ii =0; ii < dz->buflen;ii++)
+									obuf[ii] = (float)(obuf[ii] * gaingain);
+								if((exit_status = write_samps(obuf,dz->buflen,dz))<0)
+									return(exit_status);
+							}
+							bufs_written++;
+							tail = write_end - dz->buflen;
+							memset((char *)obuf,0,dz->buflen * sizeof(float));
+							if(tail > 0) {
+								memmove((char *)obuf,(char *)ovflw,tail * sizeof(float));
+								tailend = obuf + tail;
+							} else
+								tailend = ovflw;
+							memset((char *)tailend,0,(chunkbuf - tailend) * sizeof(float));
+							local_write_start -= dz->buflen;
+							write_end         -= dz->buflen;
+							k = 0;
+						}
+						obuf[k] = ibuf[jj];
+					}
+				}
+				write_end = max(k,write_end);
+				finished = 1;
+				break;
+			}
+			if(cnt==0) {
+				if(!dz->brksize[ITER_DELAY])
+					dz->iparam[ITER_MSAMPDEL]= orig_sampdel;
+			}
+			/* Zet to normal iteration delay  for 2nd Iteration: */
+			iterating = 1;
+			
+			switch(dz->mode) {
+			case(ITERATE_DUR):
+				if(write_start >= out_sampdur)
+					is_penult = 1;
+				break;
+			case(ITERATE_REPEATS):
+				if(cnt >= dz->iparam[ITER_REPEATS] - 1)
+					is_penult = 1;
+				break;
+			}
+			if(finished)
+				break;
+			while(local_write_start >= dz->buflen) {
+				if(passno > 0) {
+					for(ii = 0;ii < dz->buflen;ii++)
+						obuf[ii] = (float)(obuf[ii] * gaingain);
+					if((exit_status = write_samps(obuf,dz->buflen,dz))<0)
+						return(exit_status);
+				} else {
+					for(ii=0;ii<dz->buflen;ii++)
+						maxsamp = max(maxsamp,fabs(obuf[ii]));
+					dz->total_samps_written += dz->buflen; // Accountancy for local_write_start
+					if(sloom) {
+						if(dz->total_samps_written > twoseccnt * units) {
+							fprintf(stdout,"Processed %d secs\n",units * 10);
+							fflush(stdout);
+							units++;
+						}
+					}
+				}
+				bufs_written++;
+				tail = write_end - dz->buflen;
+				memset((char *)obuf,0,dz->buflen * sizeof(float));
+				if(tail > 0) {
+					memmove((char *)obuf,(char *)ovflw,tail * sizeof(float));
+					tailend = obuf + tail;
+				} else
+					tailend = ovflw;
+				memset((char *)tailend,0,(chunkbuf - tailend) * sizeof(float));
+				local_write_start -= dz->buflen;
+				write_end         -= dz->buflen;
+			}
+			cnt++;
+			if((passno == 0) && (cnt >= arraysize)) {
+				arraysize += BIGARRAY;
+				if ((gain = (double *)realloc((char *)gain,arraysize * sizeof(double)))==NULL) {
+					sprintf(errstr,"Insufficient memory to store gain values (2)\n");
+					return(MEMORY_ERROR);
+				}
+				if ((pshift = (double *)realloc((char *)pshift,arraysize * sizeof(double)))==NULL) {
+					sprintf(errstr,"Insufficient memory to store gain values (2)\n");
+					return(MEMORY_ERROR);
+				}
+				if ((wstart = (int *)realloc((char *)wstart,arraysize * sizeof(int)))==NULL) {
+					sprintf(errstr,"Insufficient memory to store gain values (2)\n");
+					return(MEMORY_ERROR);
+				}
+			}
+			thistime = ((dz->buflen * bufs_written) + local_write_start) * one_over_sr;
+			
+			if((exit_status = read_values_from_all_existing_brktables(thistime,dz))<0)
+				return(exit_status);
+			if(is_penult) {
+				dz->param[ITER_PSCAT] = 0.0;
+				dz->param[ITER_ASCAT] = 0.0;
+				continue;				//	We will write the final segment at original level, as part of tail of sound: no iteration pass here
+			}
+			if(dz->brksize[ITER_DELAY])
+				dz->iparam[ITER_MSAMPDEL] = round(dz->param[ITER_DELAY] * srate);
+			write_end = new_iterate(cnt,passno,gain,pshift,write_end,local_write_start,inmsampsize,level,pstep,iterating,dz);
+			if(passno==0)
+				wstart[cnt] = get_next_writestart(write_start,dz);
+			write_start = wstart[cnt];
+			local_write_start = write_start - dz->total_samps_written;
+		}
+		if(passno > 0) {
+			if(write_end > 0) {
+				for(ii =0; ii < write_end;ii++)
+					obuf[ii] = (float)(obuf[ii] * gaingain);
+				if((exit_status = write_samps(obuf,write_end,dz))<0)
+					return(exit_status);
+			}
+		} else {
+			if(write_end > 0) {
+				for(ii =0; ii < write_end;ii++)
+					maxsamp = max(maxsamp,fabs(obuf[ii]));
+			}
+			gaingain = (localmax/maxsamp) * dz->param[ITER_LGAIN];
+		}
+	}
+	return FINISHED;
+}
+
+/*************************** READ_THE_INPUT_SND **************************/
+
+int read_the_input_snd(dataptr dz)
+{
+	int samps, k, samps_read;
+	int n;
+	if((samps_read = fgetfbufEx(dz->sampbuf[0], dz->insams[0]/* + SECSIZE*/,dz->ifd[0],0)) <= 0) {
+		sprintf(errstr,"Can't read bytes from input soundfile\n");
+		if(samps_read<0)
+			return(SYSTEM_ERROR);
+		return(DATA_ERROR);
+	}
+	if(samps_read!=dz->insams[0]) {
+		sprintf(errstr, "Failed to read all of source file. read_the_input_snd()\n");
+		return(PROGRAM_ERROR);
+	}
+	samps = samps_read / dz->infile->channels;
+
+	if(dz->vflag[IS_ITER_PSCAT]) {
+		k = samps * dz->infile->channels;
+		for(n=0;n<dz->infile->channels;n++) {
+			dz->sampbuf[0][k] = (float)0;
+			k++;		/* GUARD POINTS FOR INTERPOLATION */
+		}
+	}
+	return(FINISHED);
+}
+
+/*************************** NEW_READ_THE_INPUT_SND **************************/
+
+int new_read_the_input_snd(int samplen,int wrap,dataptr dz)
+{
+	int samps, k, samps_read;
+	int n;
+	if((samps_read = fgetfbufEx(dz->sampbuf[0], samplen/* + SECSIZE*/,dz->ifd[0],0)) <= 0) {
+		sprintf(errstr,"Can't read bytes from input soundfile\n");
+		if(samps_read<0)
+			return(SYSTEM_ERROR);
+		return(DATA_ERROR);
+	}
+	dz->total_samps_read += samps_read;
+	dz->samps_left -= samps_read;
+	dz->ssampsread = samps_read;
+	if(wrap) {
+		if(samps_read!=samplen) {
+			sprintf(errstr, "Failed to all of the input sound. new_read_the_input_snd()\n");
+			return(PROGRAM_ERROR);
+		}
+		samps = samps_read / dz->infile->channels;
+		if(dz->param[ITER_PSCAT] > 0.0) {
+			k = samps * dz->infile->channels;
+			for(n=0;n<dz->infile->channels;n++) {
+				dz->sampbuf[0][k] = (float)0;
+				k++;		/* GUARD POINTS FOR INTERPOLATION */
+			}
+		}
+	}
+	return(FINISHED);
+}
+
+/******************************* SCALE_INPUT ****************************/
+
+void scale_input(dataptr dz)
+{
+	int n;
+	int end = dz->insams[0];
+	if(dz->iparam[ITER_PROCESS]!=FIXA_MONO && dz->iparam[ITER_PROCESS]!=FIXA_STEREO)
+		end = dz->insams[0] + dz->infile->channels;	/* ALLOW FOR GUARD POINTS */
+	for(n=0; n < end; n++)
+		dz->sampbuf[0][n] = (float)(dz->sampbuf[0][n] * dz->param[ITER_GAIN]);
+}
+
+/*************************** GET_NEXT_WRITESTART ****************************/
+
+int get_next_writestart(int write_start,dataptr dz)
+{
+	int this_step;
+	double d;  
+	int mwrite_start = write_start/dz->infile->channels;
+	if((dz->process == ITERATE_EXTEND && dz->param[ITER_RANDOM] > 0.0) 
+	|| (dz->process != ITERATE_EXTEND && dz->vflag[IS_ITER_RAND])) {
+		d = ((drand48() * 2.0) - 1.0) * dz->param[ITER_RANDOM];
+		d += 1.0;
+		this_step = (int)round((double)dz->iparam[ITER_MSAMPDEL] * d);
+		mwrite_start += this_step;
+	} else
+		mwrite_start += dz->iparam[ITER_MSAMPDEL];
+	write_start = mwrite_start * dz->infile->channels;
+	return(write_start);
+}    
+
+/******************************* ITERATE *****************************/
+
+//TW COMPLETELY UPDATED FUNCTION : (flt-converted)
+int new_iterate
+(int cnt,int pass,double *gain,double *pshift,int write_end,int local_write_start,
+	int inmsampsize,double level,int pstep,int iterating,dataptr dz)
+{
+	int wr_end = 0;
+	switch(dz->iparam[ITER_PROCESS]) {
+	case(MONO):		      		
+		wr_end = new_iter(cnt,pass,gain,local_write_start,inmsampsize,level,iterating,dz);							
+		break;
+	case(STEREO):	      		
+		wr_end = new_iter_stereo(cnt,pass,gain,local_write_start,inmsampsize,level,iterating,dz);			 		
+		break;
+	case(MN_INTP_SHIFT):      	
+		wr_end = new_iter_shift_interp(cnt,pass,gain,pshift,local_write_start,inmsampsize,level,pstep,iterating,dz);				
+		break;
+	case(ST_INTP_SHIFT):      	
+		wr_end = new_iter_shift_interp_stereo(cnt,pass,gain,pshift,local_write_start,inmsampsize,level,pstep,iterating,dz);		
+		break;
+	case(FIXA_MONO):	      	
+		wr_end = new_fixa_iter(cnt,pass,gain,local_write_start,inmsampsize,level,iterating,dz);			 			
+		break;
+	case(FIXA_STEREO):	      	
+		wr_end = new_fixa_iter_stereo(cnt,pass,gain,local_write_start,inmsampsize,level,iterating,dz);		 		
+		break;
+	case(FIXA_MN_INTP_SHIFT): 	
+		wr_end = new_fixa_iter_shift_interp(cnt,pass,gain,pshift,local_write_start,inmsampsize,level,pstep,iterating,dz); 		
+		break;
+	case(FIXA_ST_INTP_SHIFT): 	
+		wr_end = new_fixa_iter_shift_interp_stereo(cnt,pass,gain,pshift,local_write_start,inmsampsize,level,pstep,iterating,dz); 
+		break;
+	}
+	return max(wr_end,write_end);
+}
+
+/**************************** ITER ***************************/
+
+//TW COMPLETELY UPDATED FUNCTION : (flt-converted)
+int new_iter(int cnt,int passno, double *gain,int local_write_start,int inmsampsize,double level,int iterating,dataptr dz)
+{
+	register int i, j = local_write_start;
+	float *outbuf = dz->sampbuf[1];
+	float *inbuf  = dz->sampbuf[0];
+	double z;
+	double thisgain;
+	if(passno == 0) {
+		gain[cnt] = get_gain(dz);
+		thisgain = gain[cnt];
+
+		if(dz->process != ITERATE_EXTEND && dz->vflag[IS_ITER_FADE]) {
+			for(i=0; i < inmsampsize; i++) {
+				z = outbuf[j] + (inbuf[i] * thisgain * level);
+				outbuf[j++] = (float)z;
+			}
+		} else {
+			for(i=0; i < inmsampsize; i++) {
+				if(iterating)
+					z = outbuf[j] + (inbuf[i] * thisgain);
+				else
+					z = outbuf[j] + inbuf[i];
+				outbuf[j++] = (float)z;
+			}
+		}
+	} else {
+		thisgain = gain[cnt];
+
+		if(dz->process != ITERATE_EXTEND && dz->vflag[IS_ITER_FADE]) {
+			for(i=0; i < inmsampsize; i++) {
+				z = outbuf[j] + (inbuf[i] * thisgain * level);
+				outbuf[j++] = (float)z;
+			}
+		} else {
+			for(i=0; i < inmsampsize; i++) {
+			if(iterating)
+				z = outbuf[j] + (inbuf[i] * thisgain);
+			else
+				z = outbuf[j] + inbuf[i];
+				outbuf[j++] = (float)z;
+			}
+		}
+	}
+	return(j);
+}
+
+/**************************** ITER_STEREO ***************************/
+
+//TW COMPLETELY UPDATED FUNCTION : (flt-converted)
+int new_iter_stereo(int cnt,int passno, double *gain,int local_write_start,int inmsampsize,double level,int iterating,dataptr dz)
+{
+	register int i, j = local_write_start, k;
+	int n;
+	float *outbuf = dz->sampbuf[1];
+	float *inbuf  = dz->sampbuf[0];
+	double z;
+	double thisgain;
+	if(passno == 0) {
+		gain[cnt] = get_gain(dz);
+		thisgain = gain[cnt];
+
+		if(dz->process != ITERATE_EXTEND && dz->vflag[IS_ITER_FADE]) {
+			for(i=0; i < inmsampsize; i++) {
+				k = i*dz->infile->channels;
+				for(n=0;n<dz->infile->channels;n++) {
+					z = outbuf[j] + (inbuf[k++] * thisgain * level);
+					outbuf[j++]  = (float)z;
+				}
+			}
+		} else {
+			for(i=0; i < inmsampsize; i++) {
+				k = i*dz->infile->channels;
+				for(n=0;n<dz->infile->channels;n++) {
+					if(iterating)
+						z = outbuf[j] + (inbuf[k++] * thisgain);
+					else 
+						z = outbuf[j] + inbuf[k++];
+					outbuf[j++]  = (float)z;
+				}
+			}
+		}
+	} else {
+		thisgain = gain[cnt];
+
+		if(dz->process != ITERATE_EXTEND && dz->vflag[IS_ITER_FADE]) {
+			for(i=0; i < inmsampsize; i++) {
+				k = i*dz->infile->channels;
+				for(n=0;n<dz->infile->channels;n++) {
+					z = outbuf[j] + (inbuf[k++] * thisgain * level);
+					outbuf[j++]  = (float)z;
+				}
+			}
+		} else {
+			for(i=0; i < inmsampsize; i++) {
+				k = i*dz->infile->channels;
+				for(n=0;n<dz->infile->channels;n++) {
+					if(iterating)
+						z = outbuf[j] + (inbuf[k++] * thisgain);
+					else 
+						z = outbuf[j] + inbuf[k++];
+					outbuf[j++]  = (float)z;
+				}
+			}
+		}
+	}
+	return(j);
+}
+
+/**************************** ITER_SHIFT_INTERP ***************************/
+
+//TW COMPLETELY UPDATED FUNCTION : (flt-converted)
+int new_iter_shift_interp(int cnt,int passno, double *gain,double *pshift,int local_write_start,
+		int inmsampsize,double level,int pstep,int iterating,dataptr dz)
+{
+	register int i = 0, j = local_write_start;
+	double d = 0.0, part = 0.0;
+	float val, nextval, diff;
+	float *outbuf = dz->sampbuf[1];
+	float *inbuf  = dz->sampbuf[0];
+	double z;
+	double thisgain;
+	if(passno == 0) {
+		gain[cnt] = get_gain(dz);
+		thisgain = gain[cnt];
+		if(dz->process != ITERATE_EXTEND && dz->vflag[IS_ITER_FADE]) {
+			while(i < inmsampsize) {
+				val     = inbuf[i++];
+				nextval = inbuf[i];
+				diff    = nextval - val;
+				z = val + ((double)diff * part);
+				z = (z * thisgain * level);
+				z += outbuf[j];
+				outbuf[j++] = (float)z;
+				d      += dz->param[pstep];
+				i      = (int)d; 			/* TRUNCATE */
+				part   = d - (double)i; 
+			}
+		} else {
+			while(i < inmsampsize) {
+				val     = inbuf[i++];
+				nextval = inbuf[i];
+				diff    = nextval - val;
+				z = val + ((double)diff * part);
+				if(iterating)
+					z = (z * thisgain);
+				z += outbuf[j];
+				outbuf[j++] = (float)z;
+				d      += dz->param[pstep];
+				i      = (int)d; 			/* TRUNCATE */
+				part   = d - (double)i; 
+			}
+		}
+		pshift[cnt] = get_pshift(dz);
+		dz->param[pstep] = pshift[cnt];
+	} else {
+		thisgain = gain[cnt];
+		if(dz->process != ITERATE_EXTEND && dz->vflag[IS_ITER_FADE]) {
+			while(i < inmsampsize) {
+				val     = inbuf[i++];
+				nextval = inbuf[i];
+				diff    = nextval - val;
+				z = val + ((double)diff * part);
+				z = (z * thisgain * level);
+				z += outbuf[j];
+				outbuf[j++] = (float)z;
+				d      += dz->param[pstep];
+				i      = (int)d; 			/* TRUNCATE */
+				part   = d - (double)i; 
+			}
+		} else {
+			while(i < inmsampsize) {
+				val     = inbuf[i++];
+				nextval = inbuf[i];
+				diff    = nextval - val;
+				z = val + ((double)diff * part);
+				if(iterating)
+					z = (z * thisgain);
+				z += outbuf[j];
+				outbuf[j++] = (float)z;
+				d      += dz->param[pstep];
+				i      = (int)d; 			/* TRUNCATE */
+				part   = d - (double)i; 
+			}
+		}
+		dz->param[pstep] = pshift[cnt];
+	}
+	return(j);
+}
+
+/*********************** ITER_SHIFT_INTERP_STEREO *************************/
+
+//TW COMPLETELY UPDATED FUNCTION : (flt-converted)
+int new_iter_shift_interp_stereo(int cnt,int passno, double *gain,double *pshift,int local_write_start,
+		int inmsampsize,double level,int pstep,int iterating,dataptr dz)
+{
+	register int i = 0, j = local_write_start, k;
+	int n;
+	double d = 0.0, part = 0.0;
+	float val, nextval, diff;
+	float *outbuf = dz->sampbuf[1];
+	float *inbuf  = dz->sampbuf[0];
+	double z;
+	double thisgain;
+	if(passno == 0) {
+		gain[cnt] = get_gain(dz);
+		thisgain = gain[cnt];
+
+		if(dz->process != ITERATE_EXTEND && dz->vflag[IS_ITER_FADE]) {
+			while(i < inmsampsize) {
+				k = i*dz->infile->channels;
+				for(n=0;n<dz->infile->channels;n++) {
+					val     = inbuf[k];
+					nextval = inbuf[k+dz->infile->channels];
+					diff    = nextval - val;
+					z = val + ((double)diff * part);
+					z = (z * thisgain * level);
+					z += outbuf[j];
+					outbuf[j++] = (float)z;
+					k++;
+				}
+				d   += dz->param[pstep];
+				i    = (int)d; 			/* TRUNCATE */
+				part = d - (double)i; 
+			}
+		} else {
+			while(i < inmsampsize) {
+				k = i*dz->infile->channels;
+				for(n=0;n<dz->infile->channels;n++) {
+					val     = inbuf[k];
+					nextval = inbuf[k+dz->infile->channels];
+					diff    = nextval - val;
+					z = val + ((double)diff * part);
+					if(iterating)
+						z = (z * thisgain);
+					z += outbuf[j];
+					outbuf[j++] = (float)z;
+					k++;
+				}
+				d   += dz->param[pstep];
+				i    = (int)d; 			/* TRUNCATE */
+				part = d - (double)i; 
+			}
+		}
+		pshift[cnt] = get_pshift(dz);
+		dz->param[pstep] = pshift[cnt];
+	} else {
+		thisgain = gain[cnt];
+
+		if(dz->process != ITERATE_EXTEND && dz->vflag[IS_ITER_FADE]) {
+			while(i < inmsampsize) {
+				k = i*dz->infile->channels;
+				for(n=0;n<dz->infile->channels;n++) {
+					val     = inbuf[k];
+					nextval = inbuf[k+dz->infile->channels];
+					diff    = nextval - val;
+					z = val + ((double)diff * part);
+					z = (z * thisgain * level);
+					z += outbuf[j];
+					outbuf[j++] = (float)z;
+					k++;
+				}
+				d   += dz->param[pstep];
+				i    = (int)d; 			/* TRUNCATE */
+				part = d - (double)i; 
+			}
+		} else {
+			while(i < inmsampsize) {
+				k = i*dz->infile->channels;
+				for(n=0;n<dz->infile->channels;n++) {
+					val     = inbuf[k];
+					nextval = inbuf[k+dz->infile->channels];
+					diff    = nextval - val;
+					z = val + ((double)diff * part);
+					if(iterating)
+						z = (z * thisgain);
+					z += outbuf[j];
+					outbuf[j++] = (float)z;
+					k++;
+				}
+				d   += dz->param[pstep];
+				i    = (int)d; 			/* TRUNCATE */
+				part = d - (double)i; 
+			}
+		}
+		dz->param[pstep] = pshift[cnt];
+	}
+	return(j);
+}
+
+/**************************** FIXA_ITER ***************************/
+
+//TW COMPLETELY UPDATED FUNCTION : (flt-converted)
+int new_fixa_iter(int cnt,int passno,double *gain,int local_write_start,int inmsampsize,double level,int iterating,dataptr dz)
+{
+	register int i, j = local_write_start;
+	float *outbuf = dz->sampbuf[1];
+	float *inbuf  = dz->sampbuf[0];
+	double z;
+
+	if(passno ==0) {
+		if(dz->process != ITERATE_EXTEND && dz->vflag[IS_ITER_FADE]) {
+			for(i=0; i < inmsampsize; i++) {
+				z = outbuf[j] + (inbuf[i] * level);
+				outbuf[j]  = (float)z;
+				j++;
+			}
+		} else {
+			for(i=0; i < inmsampsize; i++) {
+				z = outbuf[j] + inbuf[i];
+				outbuf[j]  = (float)z;
+				j++;
+			}
+		}
+	} else {
+		if(dz->process != ITERATE_EXTEND && dz->vflag[IS_ITER_FADE]) {
+			for(i=0; i < inmsampsize; i++) {
+				z = outbuf[j] + (inbuf[i] * level * gain[cnt]);
+				outbuf[j]  = (float)z;
+				j++;
+			}
+		} else if(dz->process == ITERATE_EXTEND) {
+			for(i=0; i < inmsampsize; i++) {
+				z = outbuf[j] + inbuf[i];
+				outbuf[j]  = (float)z;
+				j++;
+			}
+		} else {
+			for(i=0; i < inmsampsize; i++) {
+				if(iterating)
+					z = outbuf[j] + (inbuf[i] * gain[cnt]);
+				else
+					z = outbuf[j] + inbuf[i];
+				outbuf[j]  = (float)z;
+				j++;
+			}
+		}
+	}
+	return(j);
+}
+
+/**************************** FIXA_ITER_STEREO ***************************/
+
+//TW COMPLETELY UPDATED FUNCTION : (flt-converted)
+int new_fixa_iter_stereo(int cnt,int passno,double *gain,int local_write_start,int inmsampsize,double level,int iterating,dataptr dz)
+{
+	register int i, j = local_write_start, k;
+	int n;
+	float *outbuf = dz->sampbuf[1];
+	float *inbuf  = dz->sampbuf[0];
+	double z;
+
+	if(passno == 0) {
+		if(dz->process != ITERATE_EXTEND && dz->vflag[IS_ITER_FADE]) {
+			for(i=0; i < inmsampsize; i++) {
+				k = i*dz->infile->channels;
+				for(n=0;n<dz->infile->channels;n++) {
+					z = outbuf[j] + (inbuf[k++] * level);
+					outbuf[j]  = (float)z;
+					j++;
+				}
+			}
+		} else {
+			for(i=0; i < inmsampsize; i++) {
+				k = i*dz->infile->channels;
+				for(n=0;n<dz->infile->channels;n++) {
+					z = outbuf[j] + inbuf[k++];
+					outbuf[j]  = (float)z;
+					j++;
+				}
+			}
+		}
+ 	} else {
+		if(dz->process != ITERATE_EXTEND && dz->vflag[IS_ITER_FADE]) {
+			for(i=0; i < inmsampsize; i++) {
+				k = i*dz->infile->channels;
+				for(n=0;n<dz->infile->channels;n++) {
+					z = outbuf[j] + (inbuf[k++] * level * gain[cnt]);
+					outbuf[j]  = (float)z;
+					j++;
+				}
+			}
+		} else if(dz->process == ITERATE_EXTEND) {
+			for(i=0; i < inmsampsize; i++) {
+				k = i*dz->infile->channels;
+				for(n=0;n<dz->infile->channels;n++) {
+					z = outbuf[j] + inbuf[k++];
+					outbuf[j]  = (float)z;
+					j++;
+				}
+			}
+		} else {
+			for(i=0; i < inmsampsize; i++) {
+				k = i*dz->infile->channels;
+				for(n=0;n<dz->infile->channels;n++) {
+					if(iterating)
+						z = outbuf[j] + (inbuf[k++] * gain[cnt]);
+					else
+						z = outbuf[j] + inbuf[k++];
+					outbuf[j]  = (float)z;
+					j++;
+				}
+			}
+		}
+	}
+ 	return(j);
+}
+
+/**************************** FIXA_ITER_SHIFT_INTERP ***************************/
+
+//TW COMPLETELY UPDATED FUNCTION : (flt-converted)
+int new_fixa_iter_shift_interp(int cnt,int passno,double *gain,double *pshift,int local_write_start,
+		int inmsampsize,double level,int pstep,int iterating,dataptr dz)
+{
+	register int i = 0, j = local_write_start;
+ 	double d = 0.0, part = 0.0;
+ 	float val, nextval, diff;
+ 	float *outbuf = dz->sampbuf[1];
+	float *inbuf  = dz->sampbuf[0];
+	double z;
+
+	if(passno == 0) {
+		if(dz->process != ITERATE_EXTEND && dz->vflag[IS_ITER_FADE]) {
+		 	while(i < inmsampsize) {
+		 		val     = inbuf[i++];
+		 		nextval = inbuf[i];
+		 		diff    = nextval - val;
+				z = val + ((double)diff * part);
+				z = (z * level);
+				z += outbuf[j];
+				outbuf[j++] = (float)z;
+		 		d      += dz->param[pstep];
+		 		i      = (int)d; 			/* TRUNCATE */
+		 		part   = d - (double)i; 
+		 	}
+		} else {
+		 	while(i < inmsampsize) {
+		 		val     = inbuf[i++];
+		 		nextval = inbuf[i];
+		 		diff    = nextval - val;
+				z = val + ((double)diff * part);
+				z += outbuf[j];
+		 		outbuf[j++] = (float)z;
+		 		d      += dz->param[pstep];
+		 		i      = (int)d; 			/* TRUNCATE */
+		 		part   = d - (double)i; 
+		 	}
+		}
+		pshift[cnt] = get_pshift(dz);
+	} else {
+		if(dz->process != ITERATE_EXTEND && dz->vflag[IS_ITER_FADE]) {
+		 	while(i < inmsampsize) {
+		 		val     = inbuf[i++];
+		 		nextval = inbuf[i];
+		 		diff    = nextval - val;
+				z = val + ((double)diff * part);
+				z = (z * level * gain[cnt]);
+				z += outbuf[j];
+		 		outbuf[j++] = (float)z;
+		 		d      += dz->param[pstep];
+		 		i      = (int)d; 			/* TRUNCATE */
+		 		part   = d - (double)i; 
+		 	}
+		} else if(dz->process == ITERATE_EXTEND) {
+		 	while(i < inmsampsize) {
+		 		val     = inbuf[i++];
+		 		nextval = inbuf[i];
+		 		diff    = nextval - val;
+				z = val + ((double)diff * part);
+				z += outbuf[j];
+		 		outbuf[j++] = (float)z;
+		 		d      += dz->param[pstep];
+		 		i      = (int)d; 			/* TRUNCATE */
+		 		part   = d - (double)i; 
+		 	}
+		} else {
+		 	while(i < inmsampsize) {
+		 		val     = inbuf[i++];
+		 		nextval = inbuf[i];
+		 		diff    = nextval - val;
+				z = val + ((double)diff * part);
+				if(iterating)
+					z = (z * gain[cnt]);
+				z += outbuf[j];
+		 		outbuf[j++] = (float)z;
+		 		d      += dz->param[pstep];
+		 		i      = (int)d; 			/* TRUNCATE */
+		 		part   = d - (double)i; 
+		 	}
+		}
+	}
+	dz->param[pstep] = pshift[cnt];
+ 	return(j);
+}
+
+/*********************** FIXA_ITER_SHIFT_INTERP_STEREO *************************/
+
+//TW COMPLETELY UPDATED FUNCTION : (flt-converted)
+int new_fixa_iter_shift_interp_stereo(int cnt,int passno,double *gain,double *pshift,int local_write_start,
+		int inmsampsize,double level,int pstep,int iterating,dataptr dz)
+{
+	register int i = 0, j = local_write_start, k;
+	int n;
+	double d = 0.0, part = 0.0;
+	float val, nextval, diff;
+	float *outbuf = dz->sampbuf[1];
+	float *inbuf  = dz->sampbuf[0];
+	double z;
+
+	if(passno == 0) {
+		if(dz->process != ITERATE_EXTEND && dz->vflag[IS_ITER_FADE]) {
+			while(i < inmsampsize) {
+				k = i*dz->infile->channels;
+				for(n=0;n<dz->infile->channels;n++) {
+					val     = inbuf[k];
+					nextval = inbuf[k+dz->infile->channels];
+					diff    = nextval - val;
+					z = val + ((double)diff * part);
+					z = (z * level);
+					z += outbuf[j];
+					outbuf[j++] = (float)z;
+					k++;
+				}
+				d   += dz->param[pstep];
+				i    = (int)d; 			/* TRUNCATE */
+				part = d - (double)i; 
+			}
+		} else {
+			while(i < inmsampsize) {
+				k = i*dz->infile->channels;
+				for(n=0;n<dz->infile->channels;n++) {
+					val     = inbuf[k];
+					nextval = inbuf[k+dz->infile->channels];
+					diff    = nextval - val;
+					z = val + ((double)diff * part);
+					z += outbuf[j];
+					outbuf[j++] = (float)z;
+					k++;
+				}
+				d   += dz->param[pstep];
+				i    = (int)d; 			/* TRUNCATE */
+				part = d - (double)i; 
+			}
+		}
+		pshift[cnt] = get_pshift(dz);
+	} else {
+		if(dz->process != ITERATE_EXTEND && dz->vflag[IS_ITER_FADE]) {
+			while(i < inmsampsize) {
+				k = i*dz->infile->channels;
+				for(n=0;n<dz->infile->channels;n++) {
+					val     = inbuf[k];
+					nextval = inbuf[k+dz->infile->channels];
+					diff    = nextval - val;
+					z = val + ((double)diff * part);
+					z = (z * level * gain[cnt]);
+					z += outbuf[j];
+					outbuf[j++] = (float)z;
+					k++;
+				}
+				d   += dz->param[pstep];
+				i    = (int)d; 			/* TRUNCATE */
+				part = d - (double)i; 
+			}
+		} else if(dz->process == ITERATE_EXTEND) {
+			while(i < inmsampsize) {
+				k = i*dz->infile->channels;
+				for(n=0;n<dz->infile->channels;n++) {
+					val     = inbuf[k];
+					nextval = inbuf[k+dz->infile->channels];
+					diff    = nextval - val;
+					z = val + ((double)diff * part);
+					z += outbuf[j];
+					outbuf[j++] = (float)z;
+					k++;
+				}
+				d   += dz->param[pstep];
+				i    = (int)d; 			/* TRUNCATE */
+				part = d - (double)i; 
+			}
+		} else {
+			while(i < inmsampsize) {
+				k = i*dz->infile->channels;
+				for(n=0;n<dz->infile->channels;n++) {
+					val     = inbuf[k];
+					nextval = inbuf[k+dz->infile->channels];
+					diff    = nextval - val;
+					z = val + ((double)diff * part);
+					if(iterating)
+						z = (z * gain[cnt]);
+					z += outbuf[j];
+					outbuf[j++] = (float)z;
+					k++;
+				}
+				d   += dz->param[pstep];
+				i    = (int)d; 			/* TRUNCATE */
+				part = d - (double)i; 
+			}
+		}
+	}
+	dz->param[pstep] = pshift[cnt];
+	return(j);
+}
+
+/******************************** GET_GAIN *****************************/
+
+double get_gain(dataptr dz)
+{
+	double scatter;
+	double newlgain = 0.0;
+	switch(dz->process) {
+	case(ITERATE_EXTEND):
+		newlgain = 1.0;
+		if (dz->param[ITER_ASCAT] > 0.0) {
+			scatter  = drand48() * dz->param[ITER_ASCAT];
+			scatter  = 1.0 - scatter;
+			newlgain = scatter;
+		}
+		break;
+	case(ITERATE):
+		newlgain = dz->param[ITER_GAIN];
+		if(dz->vflag[IS_ITER_ASCAT]) {
+			scatter  = drand48() * dz->param[ITER_ASCAT];
+			scatter  = 1.0 - scatter;
+			newlgain = scatter * (double)dz->param[ITER_GAIN];
+		}
+	}
+	return(newlgain);
+}
+
+/******************************** GET_PSHIFT *****************************/
+
+double get_pshift(dataptr dz)
+{
+	double scatter;
+	scatter = (drand48() * 2.0) - 1.0;
+	scatter *= dz->param[ITER_PSCAT];
+	return(pow(2.0,scatter * OCTAVES_PER_SEMITONE));
+}
+
+/******************************** ACCENT_STREAM *****************************/
+
+int accent_stream(dataptr dz) {
+	int n = 0, thispos = 0, last_write_end = 0, oflo = 0, seccnt, s_read;
+	float *bptr, zz;
+	double maxzz = 0.0, minzz = 0.0;
+	int overlap ,i, j, exit_status, t,v,m,done = 0;
+	double *brrk, convertor, thisval, nextval, valincr, atten = 1.0;
+	int nexttime, thistime;
+	float *sbrk = dz->extrabuf[0];
+	int *la  = dz->lparray[0];
+	if(((seccnt = dz->insams[0]/F_SECSIZE) * F_SECSIZE) < dz->insams[0])
+		seccnt++;
+	if((dz->ssampsread = fgetfbufEx(sbrk,seccnt * F_SECSIZE,dz->ifd[0],0)) < 0) {
+		sprintf(errstr,"Can't read samps from input soundfile.\n");
+		return(SYSTEM_ERROR);
+	}
+	s_read = dz->ssampsread;
+	for(n = 1;n < dz->itemcnt; n++) {
+		if(la[n] - la[n-1] <= 0) {
+			sprintf(errstr,"Entry times not in ascending order. Cannot proceed.\n");
+			return(DATA_ERROR);
+		}
+	}
+	if(dz->brksize[ACC_ATTEN]) {
+		if(dz->brksize[ACC_ATTEN]<2) {
+			sprintf(errstr,"Breaktable has only one value: Cannot proceed.\n");
+			return(DATA_ERROR);
+		}
+		convertor = (double)(dz->infile->srate * dz->infile->channels);
+		brrk = dz->brk[ACC_ATTEN];
+		n = 0;
+		nexttime = round(brrk[0] * convertor);
+		nextval  = brrk[1];
+		for(m = 1,t = 2,v = 3; m < dz->brksize[ACC_ATTEN]; m++,t+=2,v+=2) {
+			thistime = nexttime;
+			thisval  = nextval;
+			nexttime = round(brrk[t] * convertor);
+			nextval  = brrk[v];
+			valincr = (nextval - thisval)/(double)(nexttime - thistime);
+			if(nexttime >= s_read) {		/* IF brktable extends beyond end of sound */
+				nexttime = s_read;
+				done = 1;
+			}
+			atten = thisval;
+			while(n < nexttime) {
+				sbrk[n] = (float) /*round*/((double)sbrk[n] * atten);
+				atten += valincr;
+				n++;
+			}
+			if(done)				   	/* IF brktable extends beyond end of sound: break */
+				break;
+		}
+		while(n < s_read) {				/* IF brktable stops short of end of sound */
+			sbrk[n] = (float) /*round*/((double)sbrk[n] * atten);
+			n++;
+		}
+
+	} else if(dz->param[ACC_ATTEN] < 1.0) {
+		for(n=0;n<s_read;n++)
+			sbrk[n] = (float)/*round*/((double)sbrk[n] * dz->param[ACC_ATTEN]);
+	}
+	dz->tempsize = la[dz->itemcnt-1];
+	n = 0;
+	memset((char *)dz->sampbuf[0],0,dz->buflen * sizeof(float));
+	while(n < dz->itemcnt) {
+		thispos = la[n] - dz->total_samps_written;
+		if(thispos >= dz->buflen) {
+			if((exit_status = write_samps(dz->sampbuf[0],dz->buflen,dz))<0)
+				return(exit_status);
+			memset((char *)dz->sampbuf[0],0,dz->buflen * sizeof(float));
+			if(last_write_end > dz->buflen) {
+				last_write_end -= dz->buflen;
+				memcpy((char *)dz->sampbuf[0],(char *)(dz->sampbuf[0] + dz->buflen),last_write_end * sizeof(float));
+			} else  {
+				last_write_end = 0;
+			}
+		} else {
+			bptr = dz->sampbuf[0] + thispos;
+			if((overlap = last_write_end - thispos) <= 0) {
+				memcpy((char *)bptr,(char *)sbrk,dz->insams[0]* sizeof(float));
+				last_write_end = thispos + dz->insams[0];
+			} else {
+				for(i=0,j = thispos;i<overlap; i++,j++) {
+					zz    = *bptr + sbrk[i];
+					maxzz = max(zz,maxzz);
+					minzz = min(zz,minzz);
+					if(maxzz > F_MAXSAMP || minzz < F_MINSAMP) {
+						if(!oflo) {
+							fprintf(stdout,"WARNING: First overflow at event %d\n",n+1);
+							fflush(stdout);
+						}
+						oflo++;				
+					}
+					*bptr = (float)zz;
+					bptr++;
+	   			}
+				memcpy((char *)bptr,(char *)(sbrk + overlap),(dz->insams[0] - overlap) * sizeof(float));
+				last_write_end = thispos + dz->insams[0]; 
+			}
+			n++;
+		}
+	}
+	if(last_write_end > 0) {
+		if((exit_status = write_samps(dz->sampbuf[0],last_write_end,dz))<0)
+			return(exit_status);
+	}
+	if(oflo) {
+		if(oflo > 1) {
+			fprintf(stdout,"WARNING: there were %d overflows\n",oflo);
+			fflush(stdout);
+		} else {
+			fprintf(stdout,"WARNING: there was %d overflow\n",oflo);
+			fflush(stdout);
+		}
+	}
+	return(FINISHED);
+}
+
+//TW NEW FUNCTION (converted for floats)
+/******************************** DO_SEQUENCE *****************************/
+
+int do_sequence(dataptr dz)
+{
+	int exit_status = FINISHED, warned = 0;
+	double *d, transpos, time, level, kd, frac, sum;
+	float *obufptr, *ibufptr, *tbufptr;
+	int k, n, outlen, thissamp, samps_read, last_total_samps_written = 0, max_write = 0;
+	int m, c;
+	double thisval, nextval, diff, fracval, oval;
+	int chans = dz->infile->channels, srate = dz->infile->srate;
+
+	dz->total_samps_written = 0; 
+
+	if((samps_read = fgetfbufEx(dz->sampbuf[0], dz->insams[0],dz->ifd[0],0)) <= 0) {
+		sprintf(errstr,"Can't read bytes from input soundfile.\n");
+		return(SYSTEM_ERROR);
+	}
+	for(d = dz->parray[0]; d < dz->parray[1]; d+=3) {
+		tbufptr = dz->sampbuf[3], ibufptr = dz->sampbuf[0];
+		time = *d;
+		transpos = *(d+1);
+		level    = *(d+2) * dz->param[SEQ_ATTEN];
+		for(c = 0;c <chans;c++)
+			*tbufptr++ = *ibufptr++;
+		kd = 0.0;
+		do {
+			kd += transpos;
+			k = (int)floor(kd);
+			frac = kd - (double)k;
+			k *= chans;
+			if(k >= dz->insams[0] + chans)
+				break;
+			for(m=0;m<chans;m++) {
+				thisval = ibufptr[k];
+				nextval = ibufptr[k+chans];
+				diff    = nextval - thisval;
+				fracval = diff * frac;
+				oval    = thisval + fracval;
+				*tbufptr++ = (float)oval;
+				k++;
+			}
+		} while(k < dz->insams[0] + chans);	/* allows for wraparound point(s) at end */
+		outlen = tbufptr - dz->sampbuf[3];
+		thissamp = ((int)round(time * srate) * chans) - last_total_samps_written;
+		while(thissamp >= dz->buflen) {
+			if((exit_status = write_samps(dz->sampbuf[1],dz->buflen,dz))<0)
+				return(exit_status);
+			last_total_samps_written = dz->total_samps_written;
+			memcpy((char *)dz->sampbuf[1],(char *)dz->sampbuf[2],dz->buflen * sizeof(float));
+			memset((char *)dz->sampbuf[2],0,dz->buflen * sizeof(float));
+			max_write = 0;
+			thissamp -= dz->buflen;
+		}
+		obufptr = dz->sampbuf[1] + thissamp;
+		tbufptr = dz->sampbuf[3];
+		for(n=0;n<outlen;n++) {
+			sum = *obufptr + (*tbufptr * level);
+			if(!warned && (sum >= F_MAXSAMP)) {
+				print_outwarning_flush("OVERLOAD!!\n");
+				warned = 1;
+			}
+			*obufptr = (float)sum;
+			obufptr++;
+			tbufptr++;
+		}
+		if((obufptr - dz->sampbuf[1]) > max_write)
+			max_write = obufptr - dz->sampbuf[1];
+	}
+	if(max_write > 0)
+		exit_status = write_samps(dz->sampbuf[1],max_write,dz);
+	return(exit_status);
+}
+
+/******************************** DO_DOUBLING ********************************/
+/*RWD*/
+#define SAMPLE_T float
+
+int do_doubling(dataptr dz)
+{
+	int exit_status, k, m;
+	double now = 0.0, spliceincr, spliceratio, seg_advance = 0;
+	int splicelen_samps, seg_samps = 0, samps_left, samps_remain, n;
+	int chans = dz->infile->channels, finished = 0;
+	SAMPLE_T *obuf = dz->sampbuf[1], *ibuf = dz->sampbuf[0], *sbuf = dz->sampbuf[2], *sbufend;
+	SAMPLE_T *obufend = dz->sampbuf[1] + dz->buflen;
+	SAMPLE_T *ibufend = dz->sampbuf[0] + dz->buflen, *dnsplic, *upsplic, val;
+	SAMPLE_T *splicend, *splicstt;
+
+	dz->tempsize = dz->insams[0];
+	if(!dz->vflag[NO_TIME_EXPAND]) {
+		for(k = 1; k < dz->iparam[SEG_REPETS]; k++) {
+			if((dz->tempsize += dz->insams[0]) < 0) {
+				dz->tempsize = INT_MAX;
+				break;
+			}
+		}
+	}
+	splicelen_samps = round(SPLICEDUR * dz->infile->srate);
+	if((splicend = (SAMPLE_T *)malloc(splicelen_samps * chans * sizeof(SAMPLE_T)))==NULL) {
+		sprintf(errstr,"Insufficient Memory for end-splice buffer\n");
+		return(MEMORY_ERROR);
+	}
+	if((splicstt = (SAMPLE_T *)malloc(splicelen_samps * chans * sizeof(SAMPLE_T)))==NULL) {
+		sprintf(errstr,"Insufficient Memory for start-splice buffer\n");
+		return(MEMORY_ERROR);
+	}
+	memset((char *)splicend,0,splicelen_samps * chans * sizeof(SAMPLE_T));
+	memset((char *)splicstt,0,splicelen_samps * chans * sizeof(SAMPLE_T));
+	spliceincr = 1.0/(double)splicelen_samps;
+	if(dz->brksize[SEG_DUR] == 0) {
+		dz->iparam[SEG_DUR] = round(dz->param[SEG_DUR] * dz->infile->srate);
+		seg_advance = dz->param[SEG_DUR]  - SPLICEDUR;
+		seg_samps   = dz->iparam[SEG_DUR] - splicelen_samps;
+	}
+	if((exit_status = read_samps(dz->sampbuf[0],dz))< 0) {
+		sprintf(errstr,"Failure to read from input file\n");
+		return(SYSTEM_ERROR);
+	}
+	ibufend = dz->sampbuf[0] + dz->ssampsread;
+	samps_left = dz->ssampsread;
+	while(samps_left > 0) {
+		if(dz->brksize[SEG_DUR] > 0) {
+			read_value_from_brktable(now,SEG_DUR, dz);
+			dz->iparam[SEG_DUR] = round(dz->param[SEG_DUR] * dz->infile->srate);
+			seg_advance = dz->param[SEG_DUR]  - SPLICEDUR;
+			seg_samps   = dz->iparam[SEG_DUR] - splicelen_samps;
+		}
+		spliceratio = 0.0;
+		sbuf = dz->sampbuf[2];
+		/* ZERO THE SEGMENT BUFFER */
+		memset((char *)sbuf,0,dz->iparam[SEGLEN] * sizeof(SAMPLE_T));
+		dnsplic = splicend;
+		/* Copy downsplice from previous segment into the segment buffer */
+		for(n = 0; n < splicelen_samps; n++) {
+			for(m = 0;m < chans;  m++)
+				*sbuf++ = *dnsplic++;
+		}
+		sbuf = dz->sampbuf[2];
+		/* get upsplice of new segment */
+		upsplic = splicstt;
+		for(n = 0; n < splicelen_samps; n++) {
+			for(m = 0;m < chans;  m++) {
+				val = (SAMPLE_T)(*ibuf * spliceratio);
+		/* store it */
+				*upsplic++ = val;
+		/* and also add it to new-segment buffer */
+				*sbuf = (SAMPLE_T)(val + *sbuf);
+				sbuf++;
+				ibuf++;
+			}
+			spliceratio += spliceincr;
+			samps_left -= chans;
+			if(samps_left <= 0) {
+				if((exit_status = read_samps(dz->sampbuf[0],dz)) < 0) {
+					sprintf(errstr,"Failure to read from input file\n");
+					return(SYSTEM_ERROR);
+				}
+				if((samps_left = dz->ssampsread) == 0) {
+					finished = 1;
+					break;
+				}
+				ibuf = dz->sampbuf[0];
+				ibufend = ibuf + dz->ssampsread;
+			}
+		}
+		if(finished)
+			break;
+		/* Copy body of new sement to seg buffer */
+		while(n < seg_samps) {
+			for(m = 0;m < chans;  m++)
+				*sbuf++ = *ibuf++;
+			if((samps_left -= chans) <= 0) {
+				if((exit_status = read_samps(dz->sampbuf[0],dz)) < 0) {
+					sprintf(errstr,"Failure to read from input file\n");
+					return(SYSTEM_ERROR);
+				}
+				if((samps_left = dz->ssampsread) == 0) {
+					finished = 1;
+					break;
+				}
+				ibuf = dz->sampbuf[0];
+				ibufend = ibuf + dz->ssampsread;
+			}
+			n++;
+		}
+		if(finished)
+			break;
+		/* this is the COPYING-END of sbuf, prior to last splice */
+		sbufend = sbuf;
+		/* Do downsplice of new segment */
+		spliceratio = 1.0;
+		dnsplic = splicend;
+		for(n = 0; n < splicelen_samps; n++) {
+			spliceratio -= spliceincr;
+			for(m = 0;m < chans;  m++) {
+				val = (SAMPLE_T)(*ibuf * spliceratio);
+		/* and store in new-seg buffer */
+				*sbuf++    = val;
+		/* and in downsplice buffer */
+				*dnsplic++ = val;
+				ibuf++;
+
+			}
+			if((samps_left -= chans) <= 0) {
+				if((exit_status = read_samps(dz->sampbuf[0],dz)) < 0) {
+					sprintf(errstr,"Failure to read from input file\n");
+					return(SYSTEM_ERROR);
+				}
+				if((samps_left = dz->ssampsread) == 0) {
+					finished = 1;
+					break;
+				}
+				ibuf = dz->sampbuf[0];
+				ibufend = ibuf + dz->ssampsread;
+			}
+		}
+		if(finished)
+			break;
+		sbuf    = sbufend;
+		upsplic = splicstt;
+		/* Combine upslice with downsplice at end of seg buffer */
+		for(n = 0; n < splicelen_samps; n++) {
+			for(m = 0;m < chans;  m++) {
+				*sbuf = (SAMPLE_T)(*sbuf + *upsplic++);
+				sbuf++;
+			}
+		}
+		for(k=0;k<dz->iparam[SEG_REPETS];k++) {
+		/* at 1st repeat, replace initial start-splice with splice from end of seg to start of seg */
+			if(k == 1) {
+				sbuf = dz->sampbuf[2];
+				dnsplic = splicend;
+				upsplic = splicstt;
+				for(n = 0; n < splicelen_samps; n++) {
+					for(m = 0;m < chans;  m++)
+						*sbuf++ = (SAMPLE_T)(*dnsplic++ + *upsplic++);
+				}
+			}
+			sbuf = dz->sampbuf[2];
+			while(sbuf < sbufend) {
+				*obuf++ = *sbuf++;
+				if(obuf >= obufend) {
+					if((exit_status = write_samps(dz->sampbuf[1],dz->buflen,dz))<0)
+						return(exit_status);
+					obuf = dz->sampbuf[1];
+				}
+			}
+		}
+		if(dz->vflag[NO_TIME_EXPAND]) {
+			now  += seg_advance * dz->iparam[SEG_REPETS];
+			ibuf += seg_samps * chans * (dz->iparam[SEG_REPETS] - 1);
+			ibuf -= splicelen_samps * chans;
+			while(ibuf > ibufend) {
+				if((exit_status = read_samps(dz->sampbuf[0],dz)) < 0) {
+					sprintf(errstr,"Failure to read from input file\n");
+					return(SYSTEM_ERROR);
+				}
+				if((samps_left = dz->ssampsread) == 0) {
+					finished = 1;
+					break;
+				}
+				ibuf -= dz->buflen;
+				ibufend = dz->sampbuf[0] + dz->ssampsread;
+			}
+		} else {
+			now += seg_advance;
+		}
+		if(finished)
+			break;
+	}
+	if((samps_remain = obuf - dz->sampbuf[1]) > 0) {
+		if((exit_status = write_samps(dz->sampbuf[1],samps_remain,dz))<0)
+			return(exit_status);
+	}
+	return(FINISHED);
+}
+
+/******************************** DO_SEQUENCE2 *****************************/
+
+int do_sequence2(dataptr dz)
+{
+	int exit_status = FINISHED, warned = 0;
+	double *d, transpos, time, level, kd, frac;
+	float *obufptr, *ibufptr, *tbufptr;
+	float *tbuffer  = dz->sampbuf[dz->infilecnt+2];
+	float *obuf     = dz->sampbuf[dz->infilecnt];
+	int obuflen = dz->lparray[0][dz->infilecnt];
+	float *ovflwbuf = dz->sampbuf[dz->infilecnt+1];
+	int k, n, outlen, thissamp, last_total_samps_written = 0, max_write = 0, dur;
+	int m, c, insno;
+	float thisval, nextval;
+	double diff, fracval, sum;
+	int chans = dz->infile->channels, srate = dz->infile->srate;
+	int splicelen = (int)round(dz->param[SEQ_SPLIC] * MS_TO_SECS * dz->infile->srate), this_splicelen, samps_read;
+	double spliceincr = 1.0/(double)splicelen, this_spliceincr;
+	splicelen *= dz->infile->channels;
+	dz->total_samps_written = 0; 
+	for(n=0;n<dz->infilecnt;n++) {
+		if((samps_read = fgetfbufEx(dz->sampbuf[n], dz->insams[n],dz->ifd[n],0)) < 0) {
+			sprintf(errstr,"Can't read samples from input soundfile\n");
+			return(SYSTEM_ERROR);
+		}
+	}
+	for(d = dz->parray[0]; d < dz->parray[1]; d+=5) {
+		tbufptr = tbuffer;
+		memset((char *)tbuffer,0,obuflen * sizeof(float));
+		insno    = (int)*d;
+		time     = *(d+1);
+		transpos = *(d+2);
+		level    = *(d+3) * dz->param[SEQ_ATTEN];
+		dur      = (int)round(*(d+4) * dz->infile->srate) * dz->infile->channels;
+		ibufptr = dz->sampbuf[insno];
+		if(flteq(transpos,1.0)) {
+			memcpy((char *)tbuffer,(char *)ibufptr,dz->insams[insno] * sizeof(float));
+			tbufptr += dz->insams[insno];
+		} else {
+			for(c = 0;c <chans;c++)
+				*tbufptr++ = *ibufptr++;
+			kd = 0.0;
+			do {
+				kd += transpos;
+				k = (int)floor(kd);
+				frac = kd - (double)k;
+				k *= chans;
+				if(k >= dz->insams[insno] + chans)
+					break;
+				for(m=0;m<chans;m++) {
+					thisval = ibufptr[k];
+					nextval = ibufptr[k+chans];
+					diff    = nextval - thisval;
+					fracval = diff * frac;
+					*tbufptr++ = (float)(thisval + fracval);
+					k++;
+				}
+			} while(k < dz->insams[insno] + chans);	/* allows for wraparound point(s) at end */
+		}
+		if((outlen = tbufptr - tbuffer) > dur) {
+			this_splicelen = splicelen;
+			if(this_splicelen >= dur) {
+				this_splicelen = (dur/chans) - 1;
+				this_spliceincr = 1.0/(double)(this_splicelen);
+				this_splicelen *= chans;
+			} else 
+				this_spliceincr = spliceincr;
+			do_endsplice(tbuffer,dur,this_splicelen,this_spliceincr,dz->infile->channels);
+			outlen = dur;
+		}
+		thissamp = ((int)round(time * srate) * chans) - last_total_samps_written;
+		while(thissamp >= obuflen) {
+			if((exit_status = write_samps(obuf,obuflen,dz))<0)
+				return(exit_status);
+			last_total_samps_written = dz->total_samps_written;
+			memcpy((char *)obuf,(char *)ovflwbuf,obuflen * sizeof(float));
+			memset((char *)ovflwbuf,0,obuflen * sizeof(float));
+			max_write = 0;
+			thissamp -= obuflen;
+		}
+		obufptr = obuf + thissamp;
+		tbufptr = tbuffer;
+		for(n=0;n<outlen;n++) {
+			sum = *obufptr + (*tbufptr * level);
+			if(!warned && (fabs(sum) > F_MAXSAMP)) {
+				print_outwarning_flush("OVERLOAD!!\n");
+				warned = 1;
+			}
+			*obufptr = (float)sum;
+			obufptr++;
+			tbufptr++;
+		}
+		if((obufptr - obuf) > max_write)
+			max_write = obufptr - obuf;
+	}
+	if(max_write > 0)
+		exit_status = write_samps(obuf,max_write,dz);
+	return(exit_status);
+}
+
+/******************************** DO_ENDSPLICE *****************************/
+
+void do_endsplice(float *buf,int dur,int splicelen,double spliceincr,int chans)
+{
+	int n, startsplice = dur - splicelen;
+	int m;
+	double thisincr = 1.0 - spliceincr;
+	for(n = startsplice; n < dur; n+=chans) {
+		for(m=0;m<chans;m++) {
+			buf[n+m] = (float)(buf[n+m] * thisincr);
+			thisincr -= spliceincr;
+		}
+	}
+}
+
+/******************************* ITERATE *****************************/
+
+//TW COMPLETELY UPDATED FUNCTION : (flt-converted)
+int iterate
+(int cnt,int pass,double *gain,double *pshift,int write_end,int local_write_start,
+	int inmsampsize,double level,double *maxsamp,int pstep,int iterating,dataptr dz)
+{
+	int wr_end = 0;
+	switch(dz->iparam[ITER_PROCESS]) {
+	case(MONO):		      		
+		wr_end = iter(cnt,pass,gain,local_write_start,inmsampsize,level,maxsamp,iterating,dz);							
+		break;
+	case(STEREO):	      		
+		wr_end = iter_stereo(cnt,pass,gain,local_write_start,inmsampsize,level,maxsamp,iterating,dz);			 		
+		break;
+	case(MN_INTP_SHIFT):      	
+		wr_end = iter_shift_interp(cnt,pass,gain,pshift,local_write_start,inmsampsize,level,maxsamp,pstep,iterating,dz);				
+		break;
+	case(ST_INTP_SHIFT):      	
+		wr_end = iter_shift_interp_stereo(cnt,pass,gain,pshift,local_write_start,inmsampsize,level,maxsamp,pstep,iterating,dz);		
+		break;
+	case(FIXA_MONO):	      	
+		wr_end = fixa_iter(cnt,pass,gain,local_write_start,inmsampsize,level,maxsamp,iterating,dz);			 			
+		break;
+	case(FIXA_STEREO):	      	
+		wr_end = fixa_iter_stereo(cnt,pass,gain,local_write_start,inmsampsize,level,maxsamp,iterating,dz);		 		
+		break;
+	case(FIXA_MN_INTP_SHIFT): 	
+		wr_end = fixa_iter_shift_interp(cnt,pass,gain,pshift,local_write_start,inmsampsize,level,maxsamp,pstep,iterating,dz); 		
+		break;
+	case(FIXA_ST_INTP_SHIFT): 	
+		wr_end = fixa_iter_shift_interp_stereo(cnt,pass,gain,pshift,local_write_start,inmsampsize,level,maxsamp,pstep,iterating,dz); 
+		break;
+	}
+	return max(wr_end,write_end);
+}
+
+/**************************** ITER ***************************/
+
+//TW COMPLETELY UPDATED FUNCTION : (flt-converted)
+int iter(int cnt,int passno, double *gain,int local_write_start,int inmsampsize,double level,double *maxsamp,int iterating,dataptr dz)
+{
+	register int i, j = local_write_start;
+	float *outbuf = dz->sampbuf[1];
+	float *inbuf  = dz->sampbuf[0];
+	double z;
+	double thisgain;
+	if(passno == 0) {
+		gain[cnt] = get_gain(dz);
+		thisgain = gain[cnt];
+
+		if(dz->process != ITERATE_EXTEND && dz->vflag[IS_ITER_FADE]) {
+			for(i=0; i < inmsampsize; i++) {
+				z = outbuf[j] + (inbuf[i] * thisgain * level);
+				*maxsamp = max(*maxsamp,fabs(z));
+				outbuf[j++] = (float)z;
+			}
+		} else {
+			for(i=0; i < inmsampsize; i++) {
+				if(iterating)
+					z = outbuf[j] + (inbuf[i] * thisgain);
+				else
+					z = outbuf[j] + inbuf[i];
+				*maxsamp = max(*maxsamp,fabs(z));
+				outbuf[j++] = (float)z;
+			}
+		}
+	} else {
+		thisgain = gain[cnt];
+
+		if(dz->process != ITERATE_EXTEND && dz->vflag[IS_ITER_FADE]) {
+			for(i=0; i < inmsampsize; i++) {
+				z = outbuf[j] + (inbuf[i] * thisgain * level);
+				outbuf[j++] = (float)z;
+			}
+		} else {
+			for(i=0; i < inmsampsize; i++) {
+			if(iterating)
+				z = outbuf[j] + (inbuf[i] * thisgain);
+			else
+				z = outbuf[j] + inbuf[i];
+				outbuf[j++] = (float)z;
+			}
+		}
+	}
+	return(j);
+}
+
+/**************************** ITER_STEREO ***************************/
+
+//TW COMPLETELY UPDATED FUNCTION : (flt-converted)
+int iter_stereo(int cnt,int passno, double *gain,int local_write_start,int inmsampsize,double level,double *maxsamp,int iterating,dataptr dz)
+{
+	register int i, j = local_write_start, k;
+	int n;
+	float *outbuf = dz->sampbuf[1];
+	float *inbuf  = dz->sampbuf[0];
+	double z;
+	double thisgain;
+	if(passno == 0) {
+		gain[cnt] = get_gain(dz);
+		thisgain = gain[cnt];
+
+		if(dz->process != ITERATE_EXTEND && dz->vflag[IS_ITER_FADE]) {
+			for(i=0; i < inmsampsize; i++) {
+				k = i*dz->infile->channels;
+				for(n=0;n<dz->infile->channels;n++) {
+					z = outbuf[j] + (inbuf[k++] * thisgain * level);
+					*maxsamp = max(*maxsamp,fabs(z));
+					outbuf[j++]  = (float)z;
+				}
+			}
+		} else {
+			for(i=0; i < inmsampsize; i++) {
+				k = i*dz->infile->channels;
+				for(n=0;n<dz->infile->channels;n++) {
+					if(iterating)
+						z = outbuf[j] + (inbuf[k++] * thisgain);
+					else 
+						z = outbuf[j] + inbuf[k++];
+					*maxsamp = max(*maxsamp,fabs(z));
+					outbuf[j++]  = (float)z;
+				}
+			}
+		}
+	} else {
+		thisgain = gain[cnt];
+
+		if(dz->process != ITERATE_EXTEND && dz->vflag[IS_ITER_FADE]) {
+			for(i=0; i < inmsampsize; i++) {
+				k = i*dz->infile->channels;
+				for(n=0;n<dz->infile->channels;n++) {
+					z = outbuf[j] + (inbuf[k++] * thisgain * level);
+					outbuf[j++]  = (float)z;
+				}
+			}
+		} else {
+			for(i=0; i < inmsampsize; i++) {
+				k = i*dz->infile->channels;
+				for(n=0;n<dz->infile->channels;n++) {
+					if(iterating)
+						z = outbuf[j] + (inbuf[k++] * thisgain);
+					else 
+						z = outbuf[j] + inbuf[k++];
+					outbuf[j++]  = (float)z;
+				}
+			}
+		}
+	}
+	return(j);
+}
+
+/**************************** ITER_SHIFT_INTERP ***************************/
+
+//TW COMPLETELY UPDATED FUNCTION : (flt-converted)
+int iter_shift_interp(int cnt,int passno, double *gain,double *pshift,int local_write_start,
+		int inmsampsize,double level,double *maxsamp,int pstep,int iterating,dataptr dz)
+{
+	register int i = 0, j = local_write_start;
+	double d = 0.0, part = 0.0;
+	float val, nextval, diff;
+	float *outbuf = dz->sampbuf[1];
+	float *inbuf  = dz->sampbuf[0];
+	double z;
+	double thisgain;
+	if(passno == 0) {
+		gain[cnt] = get_gain(dz);
+		thisgain = gain[cnt];
+		if(dz->process != ITERATE_EXTEND && dz->vflag[IS_ITER_FADE]) {
+			while(i < inmsampsize) {
+				val     = inbuf[i++];
+				nextval = inbuf[i];
+				diff    = nextval - val;
+				z = val + ((double)diff * part);
+				z = (z * thisgain * level);
+				z += outbuf[j];
+//				*maxsamp = max(*maxsamp,abs(z));
+				*maxsamp = max(*maxsamp,fabs(z));
+				outbuf[j++] = (float)z;
+				d      += dz->param[pstep];
+				i      = (int)d; 			/* TRUNCATE */
+				part   = d - (double)i; 
+			}
+		} else {
+			while(i < inmsampsize) {
+				val     = inbuf[i++];
+				nextval = inbuf[i];
+				diff    = nextval - val;
+				z = val + ((double)diff * part);
+				if(iterating)
+					z = (z * thisgain);
+				z += outbuf[j];
+//				*maxsamp = max(*maxsamp,abs(z));
+				*maxsamp = max(*maxsamp,fabs(z));
+				outbuf[j++] = (float)z;
+				d      += dz->param[pstep];
+				i      = (int)d; 			/* TRUNCATE */
+				part   = d - (double)i; 
+			}
+		}
+		pshift[cnt] = get_pshift(dz);
+		dz->param[pstep] = pshift[cnt];
+	} else {
+		thisgain = gain[cnt];
+		if(dz->process != ITERATE_EXTEND && dz->vflag[IS_ITER_FADE]) {
+			while(i < inmsampsize) {
+				val     = inbuf[i++];
+				nextval = inbuf[i];
+				diff    = nextval - val;
+				z = val + ((double)diff * part);
+				z = (z * thisgain * level);
+				z += outbuf[j];
+				outbuf[j++] = (float)z;
+				d      += dz->param[pstep];
+				i      = (int)d; 			/* TRUNCATE */
+				part   = d - (double)i; 
+			}
+		} else {
+			while(i < inmsampsize) {
+				val     = inbuf[i++];
+				nextval = inbuf[i];
+				diff    = nextval - val;
+				z = val + ((double)diff * part);
+				if(iterating)
+					z = (z * thisgain);
+				z += outbuf[j];
+				outbuf[j++] = (float)z;
+				d      += dz->param[pstep];
+				i      = (int)d; 			/* TRUNCATE */
+				part   = d - (double)i; 
+			}
+		}
+		dz->param[pstep] = pshift[cnt];
+	}
+	return(j);
+}
+
+/*********************** ITER_SHIFT_INTERP_STEREO *************************/
+
+//TW COMPLETELY UPDATED FUNCTION : (flt-converted)
+int iter_shift_interp_stereo(int cnt,int passno, double *gain,double *pshift,int local_write_start,
+		int inmsampsize,double level,double *maxsamp,int pstep,int iterating,dataptr dz)
+{
+	register int i = 0, j = local_write_start, k;
+	int n;
+	double d = 0.0, part = 0.0;
+	float val, nextval, diff;
+	float *outbuf = dz->sampbuf[1];
+	float *inbuf  = dz->sampbuf[0];
+	double z;
+	double thisgain;
+	if(passno == 0) {
+		gain[cnt] = get_gain(dz);
+		thisgain = gain[cnt];
+
+		if(dz->process != ITERATE_EXTEND && dz->vflag[IS_ITER_FADE]) {
+			while(i < inmsampsize) {
+				k = i*dz->infile->channels;
+				for(n=0;n<dz->infile->channels;n++) {
+					val     = inbuf[k];
+					nextval = inbuf[k+dz->infile->channels];
+					diff    = nextval - val;
+					z = val + ((double)diff * part);
+					z = (z * thisgain * level);
+					z += outbuf[j];
+//					*maxsamp = max(*maxsamp,abs(z));
+					*maxsamp = max(*maxsamp,fabs(z));
+					outbuf[j++] = (float)z;
+					k++;
+				}
+				d   += dz->param[pstep];
+				i    = (int)d; 			/* TRUNCATE */
+				part = d - (double)i; 
+			}
+		} else {
+			while(i < inmsampsize) {
+				k = i*dz->infile->channels;
+				for(n=0;n<dz->infile->channels;n++) {
+					val     = inbuf[k];
+					nextval = inbuf[k+dz->infile->channels];
+					diff    = nextval - val;
+					z = val + ((double)diff * part);
+					if(iterating)
+						z = (z * thisgain);
+					z += outbuf[j];
+//					*maxsamp = max(*maxsamp,abs(z));
+					*maxsamp = max(*maxsamp,fabs(z));
+					outbuf[j++] = (float)z;
+					k++;
+				}
+				d   += dz->param[pstep];
+				i    = (int)d; 			/* TRUNCATE */
+				part = d - (double)i; 
+			}
+		}
+		pshift[cnt] = get_pshift(dz);
+		dz->param[pstep] = pshift[cnt];
+	} else {
+		thisgain = gain[cnt];
+
+		if(dz->process != ITERATE_EXTEND && dz->vflag[IS_ITER_FADE]) {
+			while(i < inmsampsize) {
+				k = i*dz->infile->channels;
+				for(n=0;n<dz->infile->channels;n++) {
+					val     = inbuf[k];
+					nextval = inbuf[k+dz->infile->channels];
+					diff    = nextval - val;
+					z = val + ((double)diff * part);
+					z = (z * thisgain * level);
+					z += outbuf[j];
+					outbuf[j++] = (float)z;
+					k++;
+				}
+				d   += dz->param[pstep];
+				i    = (int)d; 			/* TRUNCATE */
+				part = d - (double)i; 
+			}
+		} else {
+			while(i < inmsampsize) {
+				k = i*dz->infile->channels;
+				for(n=0;n<dz->infile->channels;n++) {
+					val     = inbuf[k];
+					nextval = inbuf[k+dz->infile->channels];
+					diff    = nextval - val;
+					z = val + ((double)diff * part);
+					if(iterating)
+						z = (z * thisgain);
+					z += outbuf[j];
+					outbuf[j++] = (float)z;
+					k++;
+				}
+				d   += dz->param[pstep];
+				i    = (int)d; 			/* TRUNCATE */
+				part = d - (double)i; 
+			}
+		}
+		dz->param[pstep] = pshift[cnt];
+	}
+	return(j);
+}
+
+/**************************** FIXA_ITER ***************************/
+
+//TW COMPLETELY UPDATED FUNCTION : (flt-converted)
+int fixa_iter(int cnt,int passno,double *gain,int local_write_start,int inmsampsize,double level,double *maxsamp,int iterating,dataptr dz)
+{
+	register int i, j = local_write_start;
+	float *outbuf = dz->sampbuf[1];
+	float *inbuf  = dz->sampbuf[0];
+	double z;
+
+	if(passno ==0) {
+		if(dz->process != ITERATE_EXTEND && dz->vflag[IS_ITER_FADE]) {
+			for(i=0; i < inmsampsize; i++) {
+				z = outbuf[j] + (inbuf[i] * level);
+				*maxsamp = max(*maxsamp,fabs(z));
+				outbuf[j]  = (float)z;
+				j++;
+			}
+		} else {
+			for(i=0; i < inmsampsize; i++) {
+				z = outbuf[j] + inbuf[i];
+				*maxsamp = max(*maxsamp,fabs(z));
+				outbuf[j]  = (float)z;
+				j++;
+			}
+		}
+	} else {
+		if(dz->process != ITERATE_EXTEND && dz->vflag[IS_ITER_FADE]) {
+			for(i=0; i < inmsampsize; i++) {
+				z = outbuf[j] + (inbuf[i] * level * gain[cnt]);
+				outbuf[j]  = (float)z;
+				j++;
+			}
+		} else {
+			for(i=0; i < inmsampsize; i++) {
+				if(iterating)
+					z = outbuf[j] + (inbuf[i] * gain[cnt]);
+				else
+				z = outbuf[j] + inbuf[i];
+				outbuf[j]  = (float)z;
+				j++;
+			}
+		}
+	}
+	return(j);
+}
+
+/**************************** FIXA_ITER_STEREO ***************************/
+
+//TW COMPLETELY UPDATED FUNCTION : (flt-converted)
+int fixa_iter_stereo(int cnt,int passno,double *gain,int local_write_start,int inmsampsize,double level,double *maxsamp,int iterating,dataptr dz)
+{
+	register int i, j = local_write_start, k;
+	int n;
+	float *outbuf = dz->sampbuf[1];
+	float *inbuf  = dz->sampbuf[0];
+	double z;
+
+	if(passno == 0) {
+		if(dz->process != ITERATE_EXTEND && dz->vflag[IS_ITER_FADE]) {
+			for(i=0; i < inmsampsize; i++) {
+				k = i*dz->infile->channels;
+				for(n=0;n<dz->infile->channels;n++) {
+					z = outbuf[j] + (inbuf[k++] * level);
+//					*maxsamp = max(*maxsamp,abs(z));
+					*maxsamp = max(*maxsamp,fabs(z));
+					outbuf[j]  = (float)z;
+					j++;
+				}
+			}
+		} else {
+			for(i=0; i < inmsampsize; i++) {
+				k = i*dz->infile->channels;
+				for(n=0;n<dz->infile->channels;n++) {
+					z = outbuf[j] + inbuf[k++];
+//					*maxsamp = max(*maxsamp,abs(z));
+					*maxsamp = max(*maxsamp,fabs(z));
+					outbuf[j]  = (float)z;
+					j++;
+				}
+			}
+		}
+ 	} else {
+		if(dz->process != ITERATE_EXTEND && dz->vflag[IS_ITER_FADE]) {
+			for(i=0; i < inmsampsize; i++) {
+				k = i*dz->infile->channels;
+				for(n=0;n<dz->infile->channels;n++) {
+					z = outbuf[j] + (inbuf[k++] * level * gain[cnt]);
+					outbuf[j]  = (float)z;
+					j++;
+				}
+			}
+		} else {
+			for(i=0; i < inmsampsize; i++) {
+				k = i*dz->infile->channels;
+				for(n=0;n<dz->infile->channels;n++) {
+					if(iterating)
+						z = outbuf[j] + (inbuf[k++] * gain[cnt]);
+					else
+						z = outbuf[j] + inbuf[k++];
+					outbuf[j]  = (float)z;
+					j++;
+				}
+			}
+		}
+	}
+ 	return(j);
+}
+
+/**************************** FIXA_ITER_SHIFT_INTERP ***************************/
+
+//TW COMPLETELY UPDATED FUNCTION : (flt-converted)
+int fixa_iter_shift_interp(int cnt,int passno,double *gain,double *pshift,int local_write_start,
+		int inmsampsize,double level,double *maxsamp,int pstep,int iterating,dataptr dz)
+{
+	register int i = 0, j = local_write_start;
+ 	double d = 0.0, part = 0.0;
+ 	float val, nextval, diff;
+ 	float *outbuf = dz->sampbuf[1];
+	float *inbuf  = dz->sampbuf[0];
+	double z;
+
+	if(passno == 0) {
+		if(dz->process != ITERATE_EXTEND && dz->vflag[IS_ITER_FADE]) {
+		 	while(i < inmsampsize) {
+		 		val     = inbuf[i++];
+		 		nextval = inbuf[i];
+		 		diff    = nextval - val;
+				z = val + ((double)diff * part);
+				z = (z * level);
+				z += outbuf[j];
+				*maxsamp = max(*maxsamp,fabs(z));
+				outbuf[j++] = (float)z;
+		 		d      += dz->param[pstep];
+		 		i      = (int)d; 			/* TRUNCATE */
+		 		part   = d - (double)i; 
+		 	}
+		} else {
+		 	while(i < inmsampsize) {
+		 		val     = inbuf[i++];
+		 		nextval = inbuf[i];
+		 		diff    = nextval - val;
+				z = val + ((double)diff * part);
+				z += outbuf[j];
+				*maxsamp = max(*maxsamp,fabs(z));
+		 		outbuf[j++] = (float)z;
+		 		d      += dz->param[pstep];
+		 		i      = (int)d; 			/* TRUNCATE */
+		 		part   = d - (double)i; 
+		 	}
+		}
+		pshift[cnt] = get_pshift(dz);
+	} else {
+		if(dz->process != ITERATE_EXTEND && dz->vflag[IS_ITER_FADE]) {
+		 	while(i < inmsampsize) {
+		 		val     = inbuf[i++];
+		 		nextval = inbuf[i];
+		 		diff    = nextval - val;
+				z = val + ((double)diff * part);
+				z = (z * level * gain[cnt]);
+				z += outbuf[j];
+		 		outbuf[j++] = (float)z;
+		 		d      += dz->param[pstep];
+		 		i      = (int)d; 			/* TRUNCATE */
+		 		part   = d - (double)i; 
+		 	}
+		} else {
+		 	while(i < inmsampsize) {
+		 		val     = inbuf[i++];
+		 		nextval = inbuf[i];
+		 		diff    = nextval - val;
+				z = val + ((double)diff * part);
+				if(iterating)
+					z = (z * gain[cnt]);
+				z += outbuf[j];
+		 		outbuf[j++] = (float)z;
+		 		d      += dz->param[pstep];
+		 		i      = (int)d; 			/* TRUNCATE */
+		 		part   = d - (double)i; 
+		 	}
+		}
+	}
+	dz->param[pstep] = pshift[cnt];
+ 	return(j);
+}
+
+/*********************** FIXA_ITER_SHIFT_INTERP_STEREO *************************/
+
+//TW COMPLETELY UPDATED FUNCTION : (flt-converted)
+int fixa_iter_shift_interp_stereo(int cnt,int passno,double *gain,double *pshift,int local_write_start,
+		int inmsampsize,double level,double *maxsamp,int pstep,int iterating,dataptr dz)
+{
+	register int i = 0, j = local_write_start, k;
+	int n;
+	double d = 0.0, part = 0.0;
+	float val, nextval, diff;
+	float *outbuf = dz->sampbuf[1];
+	float *inbuf  = dz->sampbuf[0];
+	double z;
+
+	if(passno == 0) {
+		if(dz->process != ITERATE_EXTEND && dz->vflag[IS_ITER_FADE]) {
+			while(i < inmsampsize) {
+				k = i*dz->infile->channels;
+				for(n=0;n<dz->infile->channels;n++) {
+					val     = inbuf[k];
+					nextval = inbuf[k+dz->infile->channels];
+					diff    = nextval - val;
+					z = val + ((double)diff * part);
+					z = (z * level);
+					z += outbuf[j];
+					*maxsamp = max(*maxsamp,fabs(z));
+					outbuf[j++] = (float)z;
+					k++;
+				}
+				d   += dz->param[pstep];
+				i    = (int)d; 			/* TRUNCATE */
+				part = d - (double)i; 
+			}
+		} else {
+			while(i < inmsampsize) {
+				k = i*dz->infile->channels;
+				for(n=0;n<dz->infile->channels;n++) {
+					val     = inbuf[k];
+					nextval = inbuf[k+dz->infile->channels];
+					diff    = nextval - val;
+					z = val + ((double)diff * part);
+					z += outbuf[j];
+					*maxsamp = max(*maxsamp,fabs(z));
+					outbuf[j++] = (float)z;
+					k++;
+				}
+				d   += dz->param[pstep];
+				i    = (int)d; 			/* TRUNCATE */
+				part = d - (double)i; 
+			}
+		}
+		pshift[cnt] = get_pshift(dz);
+	} else {
+		if(dz->process != ITERATE_EXTEND && dz->vflag[IS_ITER_FADE]) {
+			while(i < inmsampsize) {
+				k = i*dz->infile->channels;
+				for(n=0;n<dz->infile->channels;n++) {
+					val     = inbuf[k];
+					nextval = inbuf[k+dz->infile->channels];
+					diff    = nextval - val;
+					z = val + ((double)diff * part);
+					z = (z * level * gain[cnt]);
+					z += outbuf[j];
+					outbuf[j++] = (float)z;
+					k++;
+				}
+				d   += dz->param[pstep];
+				i    = (int)d; 			/* TRUNCATE */
+				part = d - (double)i; 
+			}
+		} else {
+			while(i < inmsampsize) {
+				k = i*dz->infile->channels;
+				for(n=0;n<dz->infile->channels;n++) {
+					val     = inbuf[k];
+					nextval = inbuf[k+dz->infile->channels];
+					diff    = nextval - val;
+					z = val + ((double)diff * part);
+					if(iterating)
+						z = (z * gain[cnt]);
+					z += outbuf[j];
+					outbuf[j++] = (float)z;
+					k++;
+				}
+				d   += dz->param[pstep];
+				i    = (int)d; 			/* TRUNCATE */
+				part = d - (double)i; 
+			}
+		}
+	}
+	dz->param[pstep] = pshift[cnt];
+	return(j);
+}
+

+ 241 - 0
dev/extend/main.c

@@ -0,0 +1,241 @@
+/*
+ * 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 <extend.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 <string.h>
+
+
+char errstr[2400];
+
+/*extern*/ int	sloom = 0;
+/*extern*/ int sloombatch = 0;
+/*extern*/ int anal_infiles = 0;
+/*extern*/ int is_converted_to_stereo = -1;
+/* updated TW June 2012 */
+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 UPDATE
+	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);
+#ifdef unix
+			fflush(stdout);		  /*RWD ???? */
+#endif
+			return(FAILED);
+		}
+					  /* GET PRE_DATA, ALLOCATE THE APPLICATION, CHECK FOR EXTRA INFILES */
+		cmdline    = argv;
+		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 (MOVED inside bracket)
+		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);
+}
+

+ 735 - 0
dev/extend/zigzag.c

@@ -0,0 +1,735 @@
+/*
+ * 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 <globcon.h>
+#include <processno.h>
+#include <modeno.h>
+#include <arrays.h>
+#include <extend.h>
+#include <cdpmain.h>
+
+#include <sfsys.h>
+
+#include <extend.h>
+
+int 	reverse_it(int incnt,dataptr dz);
+void 	do_down_splice(dataptr dz);
+int 	add_to_splicebuf(float *iptr,dataptr dz);
+int 	find_zzchunk(int **thisstart,int **lastend, int *ziglistend, int *minsamp, dataptr dz);
+int 	adjust_buffer(int minsamp, int *oldminsec, int init, dataptr dz);
+int 	zig_or_zag(int direction,int *here,int *next,int is_startsplice,int is_endsplice,
+				int *outbuf_space,int obufno,int splbufno, dataptr dz);
+int 	do_zigzags(int *thisstart,int *lastend,int *outbuf_space,int obufno,int splbufno,dataptr dz);
+int 	memcpy_with_check(char *bufptr,char *bufend,char *fromptr,int bytecnt);
+int 	setup_splices(int *base,int *last,int *here,int *next,int *after,int *end,
+				int *is_startsplice,int *is_endsplice,dataptr dz);
+static void do_end_splice(int samps_left,int obufno,dataptr dz);
+
+#define	ZIG		(1)
+#define UNKNOWN	(0)
+#define ZAG		(-1)
+
+#define NORMAL	(0)
+#define REVERSE	(1)
+
+#define SECMARGIN  (256) 
+
+
+/***************************** ZIGZAG **********************************/
+
+int zigzag(dataptr dz)
+{
+	int exit_status;
+	int *thisstart, *lastend = dz->lparray[ZIGZAG_TIMES], minsamp;
+	int oldminsec = 0;
+	int init = 1;
+    int *ziglistend = dz->lparray[ZIGZAG_TIMES] + dz->itemcnt;
+	int outbuf_space = dz->buflen, samps_left;
+	int obufno, splbufno;
+	switch(dz->process) {
+	case(ZIGZAG): 	obufno = 2;	splbufno = 3; break;
+	case(LOOP):
+	case(SCRAMBLE): obufno = 1;	splbufno = 2; break;
+	default:
+		sprintf(errstr,"Unknown case in	zigzag()\n");
+		return(PROGRAM_ERROR);
+	}
+	if((exit_status = find_zzchunk(&thisstart,&lastend,ziglistend,&minsamp,dz))!=CONTINUE) {
+		if(exit_status == FINISHED)
+			exit_status = GOAL_FAILED;
+		switch(dz->process) {
+		case(ZIGZAG): 	sprintf(errstr,"WARNING: No valid zigzag found\n"); 	break;
+		case(LOOP):   	sprintf(errstr,"WARNING: No valid loop found\n"); 	 	break;
+		case(SCRAMBLE): sprintf(errstr,"WARNING: No valid scramble found\n"); 	break;
+		}
+		return(exit_status);
+	}
+	if((exit_status = adjust_buffer(minsamp,&oldminsec,init,dz))<0)
+		return(exit_status);
+	init = 0;
+	while(lastend < ziglistend) {
+		if((exit_status = do_zigzags(thisstart,lastend,&outbuf_space,obufno,splbufno,dz))<0)
+			return(exit_status);
+		if((exit_status = find_zzchunk(&thisstart,&lastend,ziglistend,&minsamp,dz))!=CONTINUE) {
+			if(exit_status==FINISHED)
+				break;
+			else
+				return(exit_status);
+		}
+		if((exit_status = adjust_buffer(minsamp,&oldminsec,init,dz))<0)
+			return(exit_status);
+	}
+	samps_left = dz->sbufptr[obufno] - dz->sampbuf[obufno];
+	do_end_splice(samps_left,obufno,dz);
+	if(samps_left > 0)
+		return write_samps(dz->sampbuf[obufno],samps_left,dz);
+	return FINISHED;
+}
+
+/************************* DO_ZIGZAGS ************************************/
+
+int do_zigzags(int *thisstart,int *lastend,int *outbuf_space,int obufno,int splbufno,dataptr dz)
+{
+	int exit_status;
+	int direction;
+	int is_startsplice;
+	int is_endsplice;
+	int *last  = thisstart - 1;
+	int *here  = thisstart;
+	int *next  = thisstart + 1;
+	int *after = thisstart + 2;
+	int *base = dz->lparray[ZIGZAG_TIMES];
+	int *end  = dz->lparray[ZIGZAG_TIMES] + dz->itemcnt;
+	while(next <= lastend) {
+		direction = setup_splices(base,last,here,next,after,end,&is_startsplice,&is_endsplice,dz);
+ 		switch(dz->process) {
+		case(ZIGZAG):
+			break;				 /* both ZIGS (forward) and ZAGS (backwards) are played */
+		case(LOOP):
+		case(SCRAMBLE):			 
+			if(dz->iparray[ZIGZAG_PLAY][here - base]==TRUE)
+				direction = ZIG; /* FLAGS A (forward) PLAYED MOVE IN INFILE */
+			else
+				direction = ZAG; /* FLAGS A NON-PLAYED MOVE IN INFILE: which might be forward as well as backward */
+			break;
+		}
+		if((exit_status = zig_or_zag(direction,here,next,is_startsplice,is_endsplice,outbuf_space,obufno,splbufno,dz))<0)
+			return(exit_status);
+		last++;
+		here++;
+		next++;
+		after++;
+	}
+	return(FINISHED);
+}
+
+/****************************** ZIG_OR_ZAG ***********************************/
+
+int zig_or_zag
+(int direction,int *here,int *next,int is_startsplice,int is_endsplice,
+int *outbuf_space,int obufno, int splbufno, dataptr dz)
+{
+	int  exit_status;
+	int  bufno;
+	int incnt  = abs(*next - *here), advance;
+	int orig_incnt = incnt;
+	int samps_remain;
+	float *sbufend = dz->sampbuf[NORMAL] + dz->buflen;
+
+	switch(direction) {
+	case(ZIG):
+		bufno = NORMAL;
+		break;
+	case(ZAG):
+		switch(dz->process) {
+		case(ZIGZAG):
+			if((exit_status = reverse_it(incnt,dz))<0)
+				return(exit_status);
+			bufno = REVERSE;
+			break;
+		case(LOOP):
+		case(SCRAMBLE):
+			incnt  = *next - *here;
+			if((dz->sbufptr[NORMAL] += incnt) < dz->sampbuf[NORMAL] || dz->sbufptr[NORMAL] >= sbufend) {
+				sprintf(errstr,"Error in buffer accounting: zig_or_zag()\n");
+				return(PROGRAM_ERROR);
+			}
+			return(FINISHED);
+		default:
+			sprintf(errstr,"Unknown case in zig_or_zag()\n");
+			return(PROGRAM_ERROR);
+		}
+		break;
+	default:
+		sprintf(errstr,"Unknown case in zig_or_zag\n");
+		return(PROGRAM_ERROR);
+	}
+	if(is_startsplice) {
+		if((exit_status = add_to_splicebuf(dz->sbufptr[bufno],dz))<0)
+			return(exit_status);
+	}
+	if(*outbuf_space >= incnt) { 	/* ENOUGH SPACE IN OUTBUFFER To DO EVERYTHING */
+		if(is_startsplice) {
+			if((exit_status = memcpy_with_check
+			((char *)dz->sbufptr[obufno],(char *)dz->sampbuf[splbufno],
+			       (char *)dz->extrabuf[ZIGZAG_SPLBUF],dz->iparam[ZIG_SPLSAMPS]* sizeof(float)))<0)
+				return(exit_status);
+			dz->sbufptr[bufno]  += dz->iparam[ZIG_SPLSAMPS];
+			dz->sbufptr[obufno] += dz->iparam[ZIG_SPLSAMPS];
+			*outbuf_space       -= dz->iparam[ZIG_SPLSAMPS];
+			advance = incnt-(2*dz->iparam[ZIG_SPLSAMPS]);
+		} else
+			advance = incnt - dz->iparam[ZIG_SPLSAMPS];
+		if(!is_endsplice)
+			advance += dz->iparam[ZIG_SPLSAMPS];
+		if((exit_status = memcpy_with_check
+		((char *)dz->sbufptr[obufno],(char *)dz->sampbuf[splbufno],(char *)dz->sbufptr[bufno],advance * sizeof(float)))<0)
+			return(exit_status);
+		dz->sbufptr[obufno] += advance;
+		dz->sbufptr[bufno]  += advance;
+		*outbuf_space       -= advance;
+		if(is_endsplice) {
+			memmove((char *)dz->extrabuf[ZIGZAG_SPLBUF],
+				(char *)dz->sbufptr[bufno],dz->iparam[ZIG_SPLSAMPS]* sizeof(float));
+			do_down_splice(dz);
+			dz->sbufptr[bufno] += dz->iparam[ZIG_SPLSAMPS];
+		}
+		if(*outbuf_space <= 0) {
+			if((exit_status = write_samps(dz->sampbuf[obufno],dz->buflen,dz))<0)
+				return(exit_status);																	
+			dz->sbufptr[obufno] = dz->sampbuf[obufno];															
+			*outbuf_space = dz->buflen;
+		}
+	} else if(is_startsplice && (*outbuf_space <= dz->iparam[ZIG_SPLSAMPS])) {
+					/* OUTBUFFER SPACE LESS THAN (START)SPLICELEN */
+		samps_remain = dz->iparam[ZIG_SPLSAMPS];
+		dz->extrabufptr[ZIGZAG_SPLBUF] = dz->extrabuf[ZIGZAG_SPLBUF];
+
+		if((exit_status = memcpy_with_check
+		((char *)dz->sbufptr[obufno],(char *)dz->sampbuf[splbufno],(char *)dz->extrabufptr[ZIGZAG_SPLBUF],(*outbuf_space) * sizeof(float)))<0)
+			return(exit_status);
+		if((exit_status = write_samps(dz->sampbuf[obufno],dz->buflen,dz))<0)
+			return(exit_status);																	
+		dz->extrabufptr[ZIGZAG_SPLBUF] += *outbuf_space;
+		dz->sbufptr[obufno] = dz->sampbuf[obufno];															
+		samps_remain  -= *outbuf_space;								
+		*outbuf_space  = dz->buflen;
+		if(samps_remain > 0) {
+			if((exit_status = memcpy_with_check
+			((char *)dz->sbufptr[obufno],(char *)dz->sampbuf[splbufno],(char *)(dz->extrabufptr[ZIGZAG_SPLBUF]),samps_remain * sizeof(float)))<0)
+				return(exit_status);
+			dz->sbufptr[obufno] += samps_remain;															
+			*outbuf_space  -= samps_remain;									
+		}
+		dz->sbufptr[bufno] += dz->iparam[ZIG_SPLSAMPS];
+		advance = incnt - (2 *dz->iparam[ZIG_SPLSAMPS]);
+		if(!is_endsplice)
+			advance += dz->iparam[ZIG_SPLSAMPS];
+		if((exit_status = memcpy_with_check
+		((char *)dz->sbufptr[obufno],(char *)dz->sampbuf[splbufno],(char *)dz->sbufptr[bufno],advance * sizeof(float)))<0)
+			return(exit_status);
+		dz->sbufptr[obufno]     += advance;
+		dz->sbufptr[bufno] += advance;
+		*outbuf_space 	   -= advance;	
+		if(is_endsplice) {
+			memmove((char *)dz->extrabuf[ZIGZAG_SPLBUF],
+				 (char *)dz->sbufptr[bufno],(size_t)dz->iparam[ZIG_SPLSAMPS]* sizeof(float));
+			do_down_splice(dz);
+			dz->sbufptr[bufno] += dz->iparam[ZIG_SPLSAMPS];
+		}
+	} else if(*outbuf_space <= incnt - dz->iparam[ZIG_SPLSAMPS]) {
+					/* OUTBUFFER SPACE DOESN'T REACH UP INTO ENDSPLICE */
+		if(is_startsplice) {
+			if((exit_status = memcpy_with_check
+			((char *)dz->sbufptr[obufno],(char *)dz->sampbuf[splbufno],(char *)dz->extrabuf[ZIGZAG_SPLBUF],
+			       (int)dz->iparam[ZIG_SPLSAMPS]* sizeof(float)))<0)
+				return(exit_status);
+			dz->sbufptr[bufno]  += dz->iparam[ZIG_SPLSAMPS];
+			dz->sbufptr[obufno] += dz->iparam[ZIG_SPLSAMPS];
+			advance = *outbuf_space - dz->iparam[ZIG_SPLSAMPS];
+		} else 
+			advance = *outbuf_space;
+		if((exit_status = memcpy_with_check
+		((char *)dz->sbufptr[obufno],(char *)dz->sampbuf[splbufno],(char *)dz->sbufptr[bufno],advance * sizeof(float)))<0)
+			return(exit_status);
+		if((exit_status = write_samps(dz->sampbuf[obufno],dz->buflen,dz))<0)
+			return(exit_status);
+		dz->sbufptr[bufno] += advance;
+		dz->sbufptr[obufno]      = dz->sampbuf[obufno];
+		incnt         -= *outbuf_space;
+		*outbuf_space  = dz->buflen;
+		advance = incnt - dz->iparam[ZIG_SPLSAMPS];	 
+		if(!is_endsplice)
+			advance += dz->iparam[ZIG_SPLSAMPS];
+		if(advance > 0) {
+			if((exit_status = memcpy_with_check
+			((char *)dz->sbufptr[obufno],(char *)dz->sampbuf[splbufno],(char *)dz->sbufptr[bufno],advance * sizeof(float)))<0)
+				return(exit_status);
+			dz->sbufptr[obufno]     += advance;
+			dz->sbufptr[bufno] += advance;
+			*outbuf_space      -= advance;
+		}
+		if(is_endsplice) {
+			memmove((char *)dz->extrabuf[ZIGZAG_SPLBUF],(char *)dz->sbufptr[bufno],
+				(size_t)dz->iparam[ZIG_SPLSAMPS]* sizeof(float));
+			do_down_splice(dz);
+			dz->sbufptr[bufno] += dz->iparam[ZIG_SPLSAMPS];
+		}
+	} else {		/* OUTBUFFER SPACE REACHES INTO MIDDLE OF ENDSPLICE */
+		if(is_startsplice) {
+			if((exit_status = memcpy_with_check
+			((char *)dz->sbufptr[obufno],(char *)dz->sampbuf[splbufno],
+			      (char *)dz->extrabuf[ZIGZAG_SPLBUF],dz->iparam[ZIG_SPLSAMPS]* sizeof(float)))<0)
+				return(exit_status);
+			dz->sbufptr[bufno]  += dz->iparam[ZIG_SPLSAMPS];
+			dz->sbufptr[obufno] += dz->iparam[ZIG_SPLSAMPS];
+			*outbuf_space       -= dz->iparam[ZIG_SPLSAMPS];
+			advance = incnt - (2*dz->iparam[ZIG_SPLSAMPS]);
+		} else
+			advance = incnt - dz->iparam[ZIG_SPLSAMPS];
+		if(!is_endsplice) {
+			advance += dz->iparam[ZIG_SPLSAMPS];
+			if((exit_status = memcpy_with_check
+			((char *)dz->sbufptr[obufno],(char *)dz->sampbuf[splbufno],(char *)dz->sbufptr[bufno],(*outbuf_space) * sizeof(float)))<0)
+				return(exit_status);
+			if((exit_status = write_samps(dz->sampbuf[obufno],dz->buflen,dz))<0)
+				return(exit_status);
+			dz->sbufptr[bufno] += *outbuf_space;
+			dz->sbufptr[obufno] = dz->sampbuf[obufno];
+			advance -= *outbuf_space;
+			*outbuf_space = dz->buflen;
+			if((exit_status = memcpy_with_check
+			((char *)dz->sbufptr[obufno],(char *)dz->sampbuf[splbufno],(char *)dz->sbufptr[bufno],advance * sizeof(float)))<0)
+				return(exit_status);
+			dz->sbufptr[bufno]  += advance;
+			dz->sbufptr[obufno] += advance;
+			*outbuf_space       -= advance;
+		} else {
+			if((exit_status = memcpy_with_check
+			((char *)dz->sbufptr[obufno],(char *)dz->sampbuf[splbufno],(char *)dz->sbufptr[bufno],advance * sizeof(float)))<0)
+				return(exit_status);
+			dz->sbufptr[obufno] += advance;
+			dz->sbufptr[bufno]  += advance;
+			memmove((char *)dz->extrabuf[ZIGZAG_SPLBUF],
+				 (char *)dz->sbufptr[bufno],dz->iparam[ZIG_SPLSAMPS]* sizeof(float));
+			do_down_splice(dz);
+			dz->sbufptr[bufno] += dz->iparam[ZIG_SPLSAMPS];
+			*outbuf_space = dz->sampbuf[splbufno] - dz->sbufptr[obufno];
+			if(*outbuf_space > dz->iparam[ZIG_SPLSAMPS]) {
+				sprintf(errstr,"Error in counting logic: zig_or_zag()\n");
+				return(PROGRAM_ERROR);
+			}
+			if(*outbuf_space <= 0) {
+				sprintf(errstr,"Error 2 in counting logic: zig_or_zag()\n");
+				return(PROGRAM_ERROR);
+			}
+		}
+	}
+	if(direction ==ZAG) {
+		dz->sbufptr[0] -= orig_incnt;
+		dz->sbufptr[1]  = dz->sampbuf[1];
+	}
+	return(FINISHED);
+}
+
+/* RWD got as far as here...ARRRRGGGGHHHHH!!!!!!!! */
+
+/****************************** ADJUST_BUFFER ******************************/
+/* is all this simply to seek to minsamp? */
+int adjust_buffer(int minsamp, int *oldminsec, int init, dataptr dz)
+{
+	int minsec, secchange, sampchange = 0, samp_at_sector_start = 0;
+	minsec    = minsamp/SECMARGIN;		/* minimum sector in file that we need, for next read */
+	secchange = minsec - *oldminsec;	/* number of sectors we need to move buffer along */
+	*oldminsec = minsec;						
+
+	if(init) {				/* On first read */					
+		if(secchange<0) {	/* secchange must be >= 0 from start of file */
+			sprintf(errstr,"Anomaly in first pass of adjust_buffer()\n");
+			return(PROGRAM_ERROR);
+		}
+		if(secchange) {		/* seek to 1st buffer needed */
+			sampchange = secchange * SECMARGIN;
+			if(sndseekEx(dz->ifd[0],sampchange,0)<0) {		
+				sprintf(errstr,"sndseek: Failed in adjust_buffer()\n");
+				return(SYSTEM_ERROR);
+			}				/* find sample-number (in file) of first sample in buffer */
+			samp_at_sector_start = sampchange;
+		}					/* read 1st buffer */
+		if(fgetfbufEx(dz->sampbuf[0],dz->buflen,dz->ifd[0],0)<0) {  
+			sprintf(errstr,"read() 0 Failed in adjust_buffer()\n");
+			return(SYSTEM_ERROR);
+		}
+		dz->sbufptr[0] = dz->sampbuf[0] + (dz->lparray[ZIGZAG_TIMES][0] - samp_at_sector_start);	
+		return(FINISHED);			
+	}						/* IF NOT in first read */
+
+//TW UPDATE (Removed below) 
+//	if(!secchange) {		/* Data should have been checked to avoid zero zigs or zags */
+//		sprintf(errstr,"Search anomaly in adjust_buffer()\n");
+//		return(PROGRAM_ERROR);
+//	} 					
+ 
+/* sampchange = Change in samp position in file from current buffer start to next buffer start.
+ * NB, it should be impossible for this to exceed buffer_size
+ * because initial point must be within current buffer,
+ * & total length of any segment must be less than buffer_size (controlled by param range-setting) !!
+ */
+
+	if(abs(sampchange = secchange * SECMARGIN) > dz->buflen) {
+		sprintf(errstr,"Anomaly in sampseek arithmetic: adjust_buffer()\n");
+		return(PROGRAM_ERROR);
+	}
+							/* Seek first to start of current buff */
+							/* and then, by the calculated offset, to start of new buf */
+
+	if(sndseekEx(dz->ifd[0],minsec * SECMARGIN,0)<0) {
+		sprintf(errstr,"sndseek() 1 Failed in adjust_buffer()\n");
+		return(SYSTEM_ERROR);
+	}
+					/* read the new buffer */
+	if(fgetfbufEx(dz->sampbuf[0],dz->buflen,dz->ifd[0],0)<0) {
+		sprintf(errstr,"fgetfbufEx() Anomaly in adjust_buffer()\n");
+		return(SYSTEM_ERROR);
+	}		
+	
+	/* reposition buffer pointer within NEW buffer */
+	dz->sbufptr[0] -= sampchange;
+	if(dz->sbufptr[0] < dz->sampbuf[0]) {
+		sprintf(errstr,"adjust_buffer(): Input buffer anomaly - pointer off start of buffer.\n");
+		return(PROGRAM_ERROR);
+	}
+	if(dz->sbufptr[0] >= dz->sampbuf[1]) {
+		sprintf(errstr,"adjust_buffer(): Input buffer anomaly - pointer off end of buffer.\n");
+		return(PROGRAM_ERROR);
+	}
+	return(FINISHED);
+}
+
+/*************************** FIND_ZZCHUNK ************************************/
+
+int find_zzchunk(int **thisstart,int **lastend, int *ziglistend, int *minsamp, dataptr dz)
+{
+	int *p, min_samp, max_samp, lastmin_samp = 0, lastmax_samp = 0;
+	int check;
+	int max_smpsize = dz->buflen - SECMARGIN;	
+												/*  Max zig-segment permitted, taking into a/c */
+ 												/*	need to round up to a whole sector AT THE ENDS!! */
+ 	*thisstart  = *lastend;						/* Set start of current segment to end of last segment */
+	p = *thisstart;
+						/* WE'RE SEARCHING FOR THE earliest and latest times among successive zigtimes */
+	min_samp = *p;								/* so preset both of these to the current first zigtime */
+	max_samp = *p;
+	p++;
+	while(p < ziglistend) {							/* search forward through the zigtimes list */
+		check = 0;
+		if(*p < min_samp) {						/* if this zigtime earlier than any encountered so far */
+			lastmin_samp = min_samp;			/* store last earliest elsewhere, and keep new one */
+			min_samp = *p;
+			check = 1;	  						/* flag that a new earliest-time has been registered */
+		} else if(*p > max_samp) {				/* if this zigtime later than any encountered so far */
+			lastmax_samp = max_samp;			/* store last latest elsewhere, and keep new one */	
+			max_samp = *p;
+			check = 2;							/* flag that a new latest-time has been registered */
+		}
+		if(check) {									/* If a new earliest or latest time has been found */
+			if(max_samp - min_samp > max_smpsize) {	/* If the span between earliest and latest is TOO LARGE */
+				if(check==2)						/* restore the previous earliest(or latest) time */
+					max_samp = lastmax_samp;
+				else	
+					min_samp = lastmin_samp;
+				break;								/* and break from the loop */
+			}										/* (Otherwise next zigtime would be beyond a bufferlength) */
+		}
+		p++;
+	}
+	if(max_samp - min_samp < 0) {
+		sprintf(errstr,"Anomaly in find_zzchunk()\n");
+		return(PROGRAM_ERROR);
+	}
+	if(max_samp - min_samp == 0)
+		return(FINISHED);			
+	*minsamp = min_samp;							/* flag position of earliest time, as a samp-count in file */
+ 				/*	NB... 
+  				 *	if we reached end of ziglist (p = ziglistend), lastend = end of list = ziglistend - 1
+  				 *	if we dropped out of loop, because last found time was unacceptable, 
+  				 * we must baktrak in the the ziglist by 1. Hence...
+  				 */
+	*lastend = p - 1;
+
+	return(CONTINUE);
+}
+
+/********************** ADD_TO_SPLICEBUF *************************/
+
+int add_to_splicebuf(float *iptr,dataptr dz)
+{
+//TW CHANGED
+//	/*int*/float val;
+	double val;
+	float *sptr = dz->extrabuf[ZIGZAG_SPLBUF];
+	int n, m;
+	for(n=0;n<dz->iparam[ZIG_SPLICECNT];n++) {
+		for(m=0;m<dz->infile->channels;m++) {
+			val = *sptr + /*round*/(float)(*iptr * dz->parray[ZIGZAG_SPLICE][n]);
+			*sptr  = (float)val;
+			sptr++;
+			iptr++;
+		}
+	}
+	return(FINISHED);
+}
+
+/********************** DO_DOWN_SPLICE *************************/
+
+void do_down_splice(dataptr dz)
+{
+	/*int*/double val;
+	float *sptr = dz->extrabuf[ZIGZAG_SPLBUF];
+	int n, m;
+	for(n=dz->iparam[ZIG_SPLICECNT]-1;n>=0;n--) {
+		for(m = 0;m<dz->infile->channels;m++) {
+			val = /*round*/(*sptr * dz->parray[ZIGZAG_SPLICE][n]);
+			*sptr = (float)val;
+			sptr++;
+		}
+	}
+}
+
+/********************** REVERSE_IT ***************************/
+
+int reverse_it(int incnt,dataptr dz)
+{
+	int n;
+	int k, chans = dz->infile->channels;
+	float *s1ptr = dz->sbufptr[0];
+	float *s2ptr;
+	dz->sbufptr[1] = dz->sampbuf[1];  /* point to stsrt of reversed-segment buffer */
+	s2ptr = dz->sbufptr[1];
+	incnt /= chans;
+	s1ptr -= chans;
+	for(n=0;n<incnt;n++) {
+		for(k=0;k<chans;k++)
+			*s2ptr++ = *s1ptr++;
+		s1ptr -= 2 * chans;
+	}
+	return(FINISHED);
+}
+
+/********************** MEMCPY_WITH_CHECK ***************************/
+
+int memcpy_with_check(char *bufptr,char *bufend,char *fromptr,int bytecnt)
+{
+	if(bufend - bufptr < bytecnt) {
+		sprintf(errstr,"Attempted to copy too many bytes to buffer: memcpy_with_check()\n");
+		return(PROGRAM_ERROR);
+	}
+	if(bytecnt < 0) {
+		sprintf(errstr,"Attempted to copy -ve number of bytes: memcpy_with_check()\n");
+		return(PROGRAM_ERROR);
+	}
+
+	memmove(bufptr,fromptr,(size_t)bytecnt);
+	return(FINISHED);
+}
+
+/********************** SETUP_SPLICES ***************************/
+
+int setup_splices
+(int *base,int *last,int *here,int *next,int *after,int *end,int *is_startsplice,int *is_endsplice,dataptr dz)
+{
+	int predirection   = UNKNOWN;
+	int postdirection  = UNKNOWN;
+	int direction;
+	int place = here - base;
+	*is_startsplice = TRUE;
+	*is_endsplice   = TRUE;
+	if(here > base) {
+		if(*last < *here)
+			predirection = ZIG;
+		else			
+			predirection = ZAG;
+	}
+	if(after < end) {
+		if(*next < *after)
+			postdirection = ZIG;
+		else			
+			postdirection = ZAG;
+	}
+	if(*here < *next)
+		direction = ZIG;
+	else
+		direction = ZAG;
+	if(direction == predirection)
+		*is_startsplice = FALSE;
+	if(direction == postdirection)
+		*is_endsplice   = FALSE;
+	switch(dz->process) {
+	case(LOOP):
+	case(SCRAMBLE):
+		if(here > base 
+		&& dz->iparray[ZIGZAG_PLAY][place]==TRUE && dz->iparray[ZIGZAG_PLAY][place-1]==FALSE)
+			*is_startsplice = TRUE;
+		if(after < end
+		&& dz->iparray[ZIGZAG_PLAY][place]==TRUE && dz->iparray[ZIGZAG_PLAY][place+1]==FALSE)
+			*is_endsplice = TRUE;
+		break;
+	}
+	if(after==end && dz->iparam[ZIG_RUNSTOEND])
+		*is_endsplice   = FALSE;
+	if(here==base && *here == 0)
+		*is_startsplice = FALSE;
+	return(direction);
+}
+
+/********************** DO_END_SPLICE ***************************/
+
+void do_end_splice(int samps_left,int obufno,dataptr dz)
+{
+//TW CHANGED
+//	float *sptr, val;
+	float *sptr;
+	double val;
+	int  n/*, val*/;
+	int   m;
+	int  splicelen = dz->iparam[ZIG_SPLICECNT] * dz->infile->channels;
+	if(samps_left < splicelen) {
+		fprintf(stdout,"WARNING: No buffer space to do end splice. Possible click at end.\n");
+		fflush(stdout);
+	} else {
+		sptr = dz->sbufptr[obufno] - splicelen;
+		for(n=dz->iparam[ZIG_SPLICECNT]-1;n>=0;n--) {
+			for(m = 0;m<dz->infile->channels;m++) {
+				val = /*round*/(*sptr * dz->parray[ZIGZAG_SPLICE][n]);
+				*sptr = (float)val;
+				sptr++;
+			}
+		}		
+	}
+}
+
+//TW NEW FUNCTION (converted to float)
+/********************** DO_BTOB ***************************/
+
+int do_btob(dataptr dz)
+{
+	int exit_status,  chans = dz->infile->channels;
+	float *ibuf = dz->sampbuf[0], *obuf = dz->sampbuf[1], *sbuf = dz->sampbuf[2];
+	int total_samps_got = 0, obufcnt = 0, splicecnt = 0, startsamp, k, n, m;
+	double spliceval = 1.0, spliceincr = 1.0/(double)(dz->iparam[BTOB_SPLEN]/chans);
+	int samps_to_work_on = dz->insams[0] - dz->iparam[BTOB_CUT] - (dz->iparam[BTOB_SPLEN]/2);
+	int bufcnt = dz->insams[0]/dz->buflen;
+	int finished = 0;
+
+	if(bufcnt * dz->buflen < dz->insams[0])
+		bufcnt++;
+	for(k = bufcnt-1; k >=0; k--) {
+		if((sndseekEx(dz->ifd[0],k * dz->buflen,0)) < 0) {
+			sprintf(errstr,"sndseekEx() 1 Failed in do_btob()\n");
+			return(SYSTEM_ERROR);
+		}
+		if((exit_status = read_samps(ibuf,dz))<0)
+			return(exit_status);
+		for(n = dz->ssampsread-chans; n>=0;n-=chans) {
+			if(obuf==sbuf) {
+				for(m=0;m<chans;m++)
+					sbuf[splicecnt++] = (float)(ibuf[n+m] * spliceval);
+				spliceval -= spliceincr;			
+				if(splicecnt >= dz->iparam[BTOB_SPLEN]) {
+					finished = 1;
+					break;
+				}
+			} else {			/* if NOT in splice, check whether going into splice */
+				for(m=0;m<chans;m++)
+					obuf[obufcnt++] = ibuf[n+m];
+				if(obufcnt >= dz->buflen) {
+				if((exit_status = write_samps(obuf,dz->buflen,dz))<0)
+					return(exit_status);
+					obufcnt = 0;
+				}
+				if((total_samps_got += chans) >= samps_to_work_on) {
+					obuf= sbuf;
+					spliceval -= spliceincr;			
+				}
+			}
+		}
+		if(finished)
+			break;
+	}
+	startsamp = dz->iparam[BTOB_CUT] - (dz->iparam[BTOB_SPLEN]/2);
+	k = startsamp/dz->buflen;
+	if((sndseekEx(dz->ifd[0],k * dz->buflen,0)) < 0) {
+		sprintf(errstr,"sndseekEx() 2 Failed in do_btob()\n");
+		return(SYSTEM_ERROR);
+	}
+	startsamp -= k * dz->buflen;
+	splicecnt = 0;
+	spliceval = 0.0;
+	if((exit_status = read_samps(ibuf,dz))<0)
+		return(exit_status);
+	do {
+		for(n = startsamp; n <dz->ssampsread;n+=chans) {
+			if(obuf==sbuf) {
+				for(m=0;m<chans;m++)
+					sbuf[splicecnt+m] = (float)((ibuf[n+m] * spliceval) + sbuf[splicecnt+m]);
+				spliceval += spliceincr;
+				if((splicecnt += chans) >= dz->iparam[BTOB_SPLEN]) {
+					obuf = dz->sampbuf[1];
+					for(m=0;m<dz->iparam[BTOB_SPLEN];m++)
+						obuf[obufcnt++] = sbuf[m];
+					if(obufcnt >= dz->buflen) {
+						if((exit_status = write_samps(obuf,dz->buflen,dz))<0)
+							return(exit_status);
+						obufcnt = 0;
+					}
+				}
+			} else {
+				for(m=0;m<chans;m++)
+					obuf[obufcnt++] = ibuf[n+m];
+				if(obufcnt >= dz->buflen) {
+					if((exit_status = write_samps(obuf,dz->buflen,dz))<0)
+						return(exit_status);
+					obufcnt = 0;
+				}
+			}
+		}
+		startsamp = 0;
+		if((exit_status = read_samps(ibuf,dz))<0)
+			return(exit_status);
+	} while(dz->ssampsread > 0);
+	if(obufcnt > 0) {
+		if((exit_status = write_samps(obuf,obufcnt,dz))<0)
+			return(exit_status);
+	}
+	return(FINISHED);
+}
+