Browse Source

initial commit

richarddobson 3 years ago
parent
commit
2d933785d0

+ 22 - 0
dev/submix/CMakeLists.txt

@@ -0,0 +1,22 @@
+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(submix main.c ap_mix.c inbetwee.c mixmerge.c
+        mixprepro.c  mixshuf0.c mixshuf1.c mixshuf2.c newmix0.c
+        newmix1.c setupmix.c syncatt.c)
+
+target_link_libraries(submix cdp2k sfsys ${EXTRA_LIBRARIES})
+
+my_install(submix)
+

+ 2120 - 0
dev/submix/ap_mix.c

@@ -0,0 +1,2120 @@
+/*
+ * 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 <string.h>
+
+#include <structures.h>
+#include <cdpmain.h>
+#include <tkglobals.h>
+#include <pnames.h>
+#include <mix.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 <mix1.h>
+
+//TW UPDATE
+#include <ctype.h>
+
+#ifdef unix
+#define round(x) lround((x))
+#endif
+
+/********************************************************************************************/
+/********************************** FORMERLY IN buffers.c ***********************************/
+/********************************************************************************************/
+
+#define MAX_SYNCATT_CHANS	(STEREO)
+
+static int  create_mix_buffers(dataptr dz);
+static int  create_syncatt_buffer(dataptr dz);
+static int  create_mixtwo_buffer(dataptr dz);
+//TW UPDATE
+static int create_mixmany_buffer(dataptr dz);
+
+/********************************************************************************************/
+/********************************** FORMERLY IN pconsistency.c ******************************/
+/********************************************************************************************/
+
+static int  mixtwo_sndprops_consistency(dataptr dz);
+static int  get_filesearch_data(dataptr dz);
+static int  syncatt_presets(dataptr dz);
+static int  check_syncatt_window_factor(dataptr dz);
+static int  mixtwarp_consistency(dataptr dz);
+static int  mixswarp_consistency(dataptr dz);
+static int  mix_consistency(dataptr dz);
+static int  mix_atten(dataptr dz);
+static int  adjust_levels(int lineno,int total_words,dataptr dz);
+
+//TW UPDATES
+static int cyc_preprop(dataptr dz);
+static int create_cycinbi_buffer(dataptr dz);
+static int invalid_data_items(char *str);
+static int read_mixgrid_file(char *str,dataptr dz);
+static int read_and_scale_balance_data(char *filename,dataptr dz);
+static int addtomix_consistency(dataptr dz);
+static int mixmodel_consistency(dataptr dz);
+static int read_inbetween_ratios(char *filename,dataptr dz);
+
+/***************************************************************************************/
+/****************************** FORMERLY IN aplinit.c **********************************/
+/***************************************************************************************/
+
+/***************************** ESTABLISH_BUFPTRS_AND_EXTRA_BUFFERS **************************/
+
+int establish_bufptrs_and_extra_buffers(dataptr dz)
+{
+//	int is_spec = FALSE;
+	dz->extra_bufcnt = -1;	/* ENSURE EVERY CASE HAS A PAIR OF ENTRIES !! */
+	dz->bptrcnt = 0;
+	dz->bufcnt  = 0;
+	switch(dz->process) {
+	case(MIX):
+	case(MIXTEST):
+	case(MIXMAX):
+	case(MIXFORMAT):
+	case(MIXDUMMY):
+	case(MIXTWARP):
+	case(MIXSWARP):	   	   
+//TW UPDATE
+	case(MIX_PAN):	   	   
+	case(MIXGAIN):	   	   
+	case(MIXSHUFL):	   	   
+	case(MIXSYNC):
+//TW UPDATES
+	case(MIX_ON_GRID):
+	case(AUTOMIX):
+	case(ADDTOMIX):
+	case(MIX_MODEL):
+	case(MIX_AT_STEP):	   	   
+								dz->extra_bufcnt = 0;	dz->bufcnt = 0;		break;
+//TW UPDATE
+	case(MIXMANY):				dz->extra_bufcnt = 0;	dz->bufcnt = 3;		break;
+	case(MIXSYNCATT):			dz->extra_bufcnt = 0;	dz->bufcnt = 1;		break;
+	case(MIXTWO):
+	case(MIXBALANCE):			dz->extra_bufcnt = 0;	dz->bufcnt = 4;		break;
+	case(MIXCROSS):				dz->extra_bufcnt = 0;	dz->bufcnt = 2;		break;
+	case(MIXINTERL):			dz->extra_bufcnt = 0;	dz->bufcnt = 1 + MAX_MI_OUTCHANS;	break;
+	case(CYCINBETWEEN):
+	case(MIXINBETWEEN):			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(MIX):
+	case(MIXTWO):
+	case(MIXBALANCE):
+	case(MIXTEST):
+	case(MIXMAX):
+	case(MIXFORMAT):
+	case(MIXDUMMY):
+	case(MIXINTERL):
+	case(MIXMANY):
+	case(MIXINBETWEEN):
+	case(ADDTOMIX):
+	case(MIX_MODEL):
+	case(MIX_AT_STEP):	   	   
+					dz->array_cnt = 0; dz->iarray_cnt = 0; dz->larray_cnt = 0; dz->ptr_cnt = 0;	dz->fptr_cnt = 0; break;
+	case(CYCINBETWEEN):
+					dz->array_cnt = 0; dz->iarray_cnt = 0; dz->larray_cnt = 4; dz->ptr_cnt = 0;	dz->fptr_cnt = 0; break;
+
+	case(MIX_ON_GRID):
+	case(AUTOMIX):
+	case(MIXSWARP):	   	   
+	case(MIX_PAN):	   	   
+					dz->array_cnt = 1; dz->iarray_cnt = 0; dz->larray_cnt = 0; dz->ptr_cnt = 0;	dz->fptr_cnt = 0; break;
+	case(MIXGAIN):	   	   
+	case(MIXTWARP):
+	case(MIXSHUFL):	   	   
+					dz->array_cnt = 2; dz->iarray_cnt = 0; dz->larray_cnt = 0; dz->ptr_cnt = 0;	dz->fptr_cnt = 0; break;
+
+	case(MIXSYNC):	dz->array_cnt = 1; dz->iarray_cnt = 1; dz->larray_cnt = 0; dz->ptr_cnt = 0;	dz->fptr_cnt = 0; break;
+	case(MIXSYNCATT): dz->array_cnt=3; dz->iarray_cnt = 2; dz->larray_cnt = 3; dz->ptr_cnt = 0;	dz->fptr_cnt = 0; break;
+	case(MIXCROSS):	dz->array_cnt = 1; dz->iarray_cnt = 0; dz->larray_cnt = 0; dz->ptr_cnt = 0;	dz->fptr_cnt = 0; break;
+	}
+
+/*** WARNING ***
+ANY APPLICATION DEALING WITH A NUMLIST INPUT: MUST establish AT LEAST 1 double array: i.e. dz->array_cnt = at least 1
+**** WARNING ***/
+
+
+	if(dz->array_cnt < 0 || dz->iarray_cnt < 0 || dz->larray_cnt < 0 || dz->ptr_cnt < 0 || dz->fptr_cnt < 0) {
+		sprintf(errstr,"array_cnt not set in setup_internal_arrays_and_array_pointers()\n");	   
+		return(PROGRAM_ERROR);
+	}
+
+	if(dz->array_cnt > 0) {  
+		if((dz->parray  = (double **)malloc(dz->array_cnt * sizeof(double *)))==NULL) {
+			sprintf(errstr,"INSUFFICIENT MEMORY for internal double arrays.\n");
+			return(MEMORY_ERROR);
+		}
+		for(n=0;n<dz->array_cnt;n++)
+			dz->parray[n] = NULL;
+	}
+	if(dz->iarray_cnt > 0) {
+		if((dz->iparray = (int     **)malloc(dz->iarray_cnt * sizeof(int *)))==NULL) {
+			sprintf(errstr,"INSUFFICIENT MEMORY for internal int arrays.\n");
+			return(MEMORY_ERROR);
+		}
+		for(n=0;n<dz->iarray_cnt;n++)
+			dz->iparray[n] = NULL;
+	}
+	/* RWD all now floats */
+	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);
+		}
+		/* RWD 4:2002 lparray shadowed by lfarray for submix syncatt */
+
+		if((dz->lfarray = (float    **)malloc(dz->larray_cnt * sizeof(float *)))==NULL) {
+			sprintf(errstr,"INSUFFICIENT MEMORY for internal float arrays.\n");
+			return(MEMORY_ERROR);
+		}		
+		for(n=0;n<dz->larray_cnt;n++){
+			dz->lparray[n] = NULL;
+			dz->lfarray[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(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(MIX):	           setup_process_logic(MIXFILES_ONLY,	 	UNEQUAL_SNDFILE,	SNDFILE_OUT,	dz);	break;
+	case(MIXTWO):
+	case(MIXBALANCE):	   setup_process_logic(TWO_SNDFILES,	 	UNEQUAL_SNDFILE,	SNDFILE_OUT,	dz);	break;
+	case(MIXCROSS):		   setup_process_logic(TWO_SNDFILES,	 	UNEQUAL_SNDFILE,	SNDFILE_OUT,	dz);	break;
+	case(MIXINTERL):	   setup_process_logic(MANY_SNDFILES,	 	UNEQUAL_SNDFILE,	SNDFILE_OUT,	dz);	break;
+	case(CYCINBETWEEN):
+	case(MIXINBETWEEN):	   setup_process_logic(TWO_SNDFILES,	 	OTHER_PROCESS,		NO_OUTPUTFILE,	dz);	break;
+	case(MIXTEST):		   setup_process_logic(MIXFILES_ONLY,	 	SCREEN_MESSAGE,		NO_OUTPUTFILE,	dz);	break;
+	case(MIXFORMAT):	   setup_process_logic(NO_FILE_AT_ALL,	 	SCREEN_MESSAGE,		NO_OUTPUTFILE,	dz);	break;
+	case(MIXDUMMY):	   	   setup_process_logic(MANY_SNDFILES,	 	TO_TEXTFILE,		TEXTFILE_OUT,	dz);	break;
+//TW UPDATES
+	case(ADDTOMIX):	   setup_process_logic(ANY_NUMBER_OF_ANY_FILES, TO_TEXTFILE,		TEXTFILE_OUT,	dz);	break;
+	case(MIX_MODEL):   setup_process_logic(ANY_NUMBER_OF_ANY_FILES, TO_TEXTFILE,		TEXTFILE_OUT,	dz);	break;
+	case(MIXMANY):	   	   setup_process_logic(MANY_SNDFILES,	 	UNEQUAL_SNDFILE,	SNDFILE_OUT,	dz);	break;
+	case(MIX_ON_GRID):	   setup_process_logic(MANY_SNDFILES,	 	TO_TEXTFILE,		TEXTFILE_OUT,	dz);	break;
+	case(AUTOMIX):	       setup_process_logic(MANY_SNDFILES,	 	UNEQUAL_SNDFILE,	SNDFILE_OUT,	dz);	break;
+
+	case(MIXSYNC):	   	   setup_process_logic(SND_OR_MIXLIST_ONLY,	TO_TEXTFILE,		TEXTFILE_OUT,	dz);	break;
+	case(MIXSYNCATT): setup_process_logic(SND_SYNC_OR_MIXLIST_ONLY, TO_TEXTFILE,		TEXTFILE_OUT,	dz);	break;
+	case(MIXTWARP):	   	   setup_process_logic(MIXFILES_ONLY,	 	TO_TEXTFILE,		TEXTFILE_OUT,	dz);	break;
+	case(MIXSWARP):	   	   setup_process_logic(MIXFILES_ONLY,	 	TO_TEXTFILE,		TEXTFILE_OUT,	dz);	break;
+//TW UPDATES
+	case(MIX_PAN):	   	   setup_process_logic(MIXFILES_ONLY,	 	TO_TEXTFILE,		TEXTFILE_OUT,	dz);	break;
+	case(MIX_AT_STEP):	   setup_process_logic(MANY_SNDFILES,	 	TO_TEXTFILE,		TEXTFILE_OUT,	dz);	break;
+
+	case(MIXGAIN):	   	   setup_process_logic(MIXFILES_ONLY,	 	TO_TEXTFILE,		TEXTFILE_OUT,	dz);	break;
+	case(MIXSHUFL):	   	   setup_process_logic(MIXFILES_ONLY,	 	TO_TEXTFILE,		TEXTFILE_OUT,	dz);	break;
+	case(MIXMAX):
+		switch(dz->mode) {
+		case(MIX_LEVEL_ONLY):	  setup_process_logic(MIXFILES_ONLY,SCREEN_MESSAGE,		NO_OUTPUTFILE,	dz);	break;
+		case(MIX_CLIPS_ONLY):	  setup_process_logic(MIXFILES_ONLY,TO_TEXTFILE,		TEXTFILE_OUT,	dz);	break;
+		case(MIX_LEVEL_AND_CLIPS):setup_process_logic(MIXFILES_ONLY,TO_TEXTFILE,		TEXTFILE_OUT,	dz);	break;
+		default:
+			sprintf(errstr,"Unknown mode for MIXMAX in assign_process_logic()\n");
+			return(PROGRAM_ERROR);
+		}
+		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(MIXSHUFL):
+		if(dz->mode==MSH_DUPL_AND_RENAME)
+			dz->has_otherfile = TRUE;
+		else 
+			dz->has_otherfile = FALSE;
+		break;
+	case(MIXBALANCE):
+	case(MIXTWO):	  		/* normal file comparison ignores stereo-mono conflict */
+	case(MIXCROSS):			/* But most of these progs need consistent channel-count in input snds. */
+	case(MIXINTERL):		/* Sending header data  to 'otherfile' */
+	case(MIXINBETWEEN):		/* allows comparison to be made in a distinct function. */
+	case(CYCINBETWEEN):
+	case(AUTOMIX):
+		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) {
+	case(MIX):			exit_status = set_internalparam_data("iii",ap);				break;
+	case(MIXTWO):		exit_status = set_internalparam_data("dd",ap);				break;
+	case(MIXBALANCE):	exit_status = set_internalparam_data("",ap);				break;
+	case(MIXCROSS):	    
+		switch(mode) {
+		case(MCLIN):	exit_status = set_internalparam_data("0iid",ap);				break;
+		case(MCCOS):	exit_status = set_internalparam_data( "iid",ap);				break;	
+		}
+		break;
+	case(MIXINTERL):    exit_status = set_internalparam_data("",ap);					break;
+	case(CYCINBETWEEN):
+	case(MIXINBETWEEN): exit_status = set_internalparam_data("",ap);					break;
+	case(MIXTEST):		exit_status = set_internalparam_data("",ap);					break;
+	case(MIXMAX):		exit_status = set_internalparam_data("iii",ap);				break;
+	case(MIXFORMAT):	exit_status = set_internalparam_data("",ap);					break;
+	case(MIXMANY):	
+	case(MIX_ON_GRID):	
+	case(AUTOMIX):	
+	case(ADDTOMIX):	
+	case(MIX_MODEL):
+	case(MIX_AT_STEP):	
+
+	case(MIXDUMMY):		exit_status = set_internalparam_data("",ap);					break;
+	case(MIXSYNC):		exit_status = set_internalparam_data("",ap);					break;
+	case(MIXSYNCATT):	exit_status = set_internalparam_data("i",ap);					break;
+	case(MIXTWARP):		exit_status = set_internalparam_data("",ap);					break;
+	case(MIXSWARP):		exit_status = set_internalparam_data("",ap);					break;
+//TW UPDATE
+	case(MIX_PAN):		exit_status = set_internalparam_data("",ap);					break;
+	case(MIXGAIN):		exit_status = set_internalparam_data("",ap);					break;
+	case(MIXSHUFL):		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)	   
+{
+	aplptr ap = dz->application;
+
+	switch(ap->special_data) {
+	case(SNDFILENAME):				return read_new_filename(str,dz);
+//TW UPDATES
+	case(GRIDDED_MIX):				return read_mixgrid_file(str,dz);
+	case(AUTO_MIX):					return read_and_scale_balance_data(str,dz);
+	case(INBTWN_RATIOS):
+		if(dz->mode == INBI_RATIO)
+			return read_inbetween_ratios(str,dz);
+		break;
+	default:
+		sprintf(errstr,"Unknown special_data type: read_special_data()\n");
+		return(PROGRAM_ERROR);
+	}
+	return(FINISHED);	/* NOTREACHED */
+}
+
+/********************************************************************************************/
+/********************************** FORMERLY IN preprocess.c ********************************/
+/********************************************************************************************/
+
+/****************************** PARAM_PREPROCESS *********************************/
+
+int param_preprocess(dataptr dz)	
+{
+	int exit_status = FINISHED;
+
+	switch(dz->process) {
+	case(MIX):	
+	case(MIXMAX):		return mix_preprocess(dz);
+
+	case(MIXTWO):		
+		if((exit_status = create_sized_outfile(dz->outfilename,dz))<0)
+				return(exit_status);
+		if((exit_status = mixtwo_preprocess(dz))<0)
+			return(exit_status);
+		return FINISHED;
+	case(MIXCROSS):		return mixcross_preprocess(dz);
+	case(MIXINBETWEEN):	return get_inbetween_ratios(dz);
+	case(CYCINBETWEEN):	return cyc_preprop(dz);
+	case(MIXTEST):			case(MIXFORMAT):		case(MIXDUMMY):
+	case(MIXSYNC):			case(MIXSYNCATT):
+	case(MIXMANY):			case(MIX_ON_GRID):		case(AUTOMIX):	
+	case(ADDTOMIX):			case(MIX_AT_STEP):		case(MIX_MODEL):	
+
+		return(FINISHED);
+	case(MIXBALANCE):
+		if((dz->infile->channels > 2 ||  dz->otherfile->channels > 2) && (dz->otherfile->channels != dz->infile->channels)) {
+			sprintf(errstr,"With multichannel files, both files must have same number of channels.\n");
+			return(DATA_ERROR);
+		}
+		break;
+	case(MIXINTERL):
+		if(dz->infilecnt > MAX_MI_OUTCHANS) {
+			sprintf(errstr,"Too many infiles for interpolation program. Max %d\n",MAX_MI_OUTCHANS);
+			return(USER_ERROR);
+		}
+
+		/* RWD 4:2002  now we can open outfile with corect params! */
+		dz->infile->channels = dz->infilecnt;	/* ARRGH! */
+		if((exit_status = create_sized_outfile(dz->outfilename,dz))<0)
+				return(exit_status);
+
+
+		return(FINISHED);
+	case(MIXTWARP):
+		initrand48();
+		switch(dz->mode) {
+		case(MTW_TIMESORT):							break;
+		default:	dz->iparam[MSH_STARTLINE]--;	break;
+		}
+		return(FINISHED);
+	case(MIXSWARP):
+		initrand48();
+		switch(dz->mode) {
+		case(MSW_TWISTALL):	break;
+		case(MSW_TWISTONE): dz->iparam[MSW_TWLINE]--;		break;
+		default:			dz->iparam[MSH_STARTLINE]--;	break;
+		}
+		return(FINISHED);
+	case(MIXGAIN):
+		dz->iparam[MSH_STARTLINE]--;
+		return(FINISHED);
+	case(MIXSHUFL):
+		initrand48();
+		if((exit_status = check_new_filename(dz->wordstor[dz->extra_word],dz))<0)
+			return(exit_status);
+		dz->iparam[MSH_STARTLINE]--;
+		return(FINISHED);
+//TW UPDATE
+	case(MIX_PAN):
+		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 */
+{	
+	double normalisation;
+
+	switch(dz->process) {
+	case(MIX):			case(MIXCROSS):
+	case(MIXINTERL):	case(MIXINBETWEEN):	case(MIXMAX):	case(CYCINBETWEEN):
+		display_virtual_time(0L,dz);
+		break;
+	}
+	switch(dz->process) {
+	case(MIX):		   	return mmix(dz);
+	case(MIXTWO):
+		display_virtual_time(0L,dz);
+	   	return mixtwo(dz);
+	case(MIXBALANCE):	return cross_stitch(dz);
+	case(MIXCROSS):	   	return mix_cross(dz);
+	case(MIXINTERL):   	return mix_interl(dz);
+	case(CYCINBETWEEN):
+	case(MIXINBETWEEN):	return mix_inbetween(dz);
+	case(MIXMAX):	  	return mix_level_check(&normalisation,dz);
+	case(MIXTEST):	  	return mix_syntax_check(dz);
+
+	case(MIXFORMAT):  	
+		if(!sloom)
+			return usage2("fileformat");
+		return (FINISHED);	
+//TW UPDATES
+	case(MIXMANY):
+	   	return mixmany(dz);
+	case(AUTOMIX):		return do_automix(dz);
+	case(ADDTOMIX):		return addtomix(dz);
+	case(MIX_MODEL):	return mix_model(dz);
+	case(MIX_ON_GRID):	
+	case(MIX_AT_STEP):	
+
+	case(MIXDUMMY):   	return create_mixdummy(dz);
+
+	case(MIXSYNC):	  	return mix_sync(dz);
+	case(MIXSYNCATT): 	return synchronise_mix_attack(dz);
+
+	case(MIXTWARP):	  	return mix_timewarp(dz);
+	case(MIXSWARP):	  	return mix_spacewarp(dz);
+//TW UPDATE
+	case(MIX_PAN):	  	return panmix(dz);
+	case(MIXGAIN):	  	return mix_gain(dz);
+	case(MIXSHUFL):	  	return mix_shufl(dz);
+	default:
+		sprintf(errstr,"Unknown case in process_file()\n");
+		return(PROGRAM_ERROR);
+	}
+	return(FINISHED);	/* NOTREACHED */
+}
+
+/********************************************************************************************/
+/********************************** FORMERLY IN pconsistency.c ******************************/
+/********************************************************************************************/
+
+/****************************** CHECK_PARAM_VALIDITY_AND_CONSISTENCY *********************************/
+
+int check_param_validity_and_consistency(dataptr dz)
+{
+	int exit_status = FINISHED;
+	handle_pitch_zeros(dz);
+	switch(dz->process) {
+	case(MIX):
+		if(!(flteq(dz->param[MIX_ATTEN],1.0))) {
+			if((exit_status = mix_atten(dz)) <0)
+				return(exit_status);
+		}
+		/* fall thro */
+	case(MIXMAX):		return set_up_mix(dz);
+
+	case(MIXTWO):
+	case(MIXBALANCE):
+	case(MIXCROSS):
+	case(MIXINTERL):
+	case(MIXINBETWEEN):	return mixtwo_sndprops_consistency(dz);
+
+	case(MIXSYNCATT):	return syncatt_presets(dz);
+	case(MIXTWARP):		return mixtwarp_consistency(dz);
+	case(MIXSWARP):		return mixswarp_consistency(dz);
+
+	case(MIXGAIN):
+	case(MIXSHUFL):		return mix_consistency(dz);
+	case(MIX_MODEL):	return mixmodel_consistency(dz);
+	case(ADDTOMIX):		return addtomix_consistency(dz);
+	case(AUTOMIX):		/* bufer pointers established once infilecnt is known */
+		dz->bufcnt = dz->infilecnt + 1;
+		return establish_groucho_bufptrs_and_extra_buffers(dz);
+	}
+	return(FINISHED);
+}
+
+/******************************** MIXTWO_SNDPROPS_CONSISTENCY ********************************/
+/*RWD comment: for a large source file this is a heavy burden; we need inline buffer conversion rather than
+ a temporary file */
+/* RWD: this is mono/stereo only - where is that tested for? */
+int mixtwo_sndprops_consistency(dataptr dz)
+{
+	double infiledur2, infiledur, sr = (double)dz->infile->srate; 
+
+	int n, m, k, exit_status;
+	int tempfd;
+	float *tempbuf;
+	int samps_read, samps_written;	
+//TW just to make it clearer
+	int shsecsize = F_SECSIZE;
+//	int dbl_shsecsize = shsecsize * 2;
+	int outsize_stereo;
+
+	if(dz->infile->srate!=dz->otherfile->srate) {
+		sprintf(errstr,"Different sample-rates in input files: can't proceed.\n");
+		return(USER_ERROR);
+	}
+	switch(dz->process) {
+	case(MIXTWO): 		
+		if(dz->infile->channels > 2) {
+			if(dz->infile->channels != dz->otherfile->channels) {
+				sprintf(errstr,"With multichannel files, both files must have same number of channels.\n");
+				return(DATA_ERROR);
+			}
+			dz->outchans = dz->infile->channels;
+		} else  {
+			if(dz->infile->channels!=dz->otherfile->channels) {
+				fprintf(stdout,"INFO: Files have different channel count. Converting to stereo.\n");
+				fflush(stdout);
+				if((tempbuf = (float *)malloc(/*SECSIZE*/shsecsize * 2 * sizeof(float)))==NULL) {
+					sprintf(errstr,"Cannot create temporary buffer for mono to stereo conversion.\n");
+					return(MEMORY_ERROR);
+				}
+				if(dz->infile->channels == 1) {
+					is_converted_to_stereo = 0;
+					outsize_stereo = dz->insams[0] * 2;
+				} else {
+					is_converted_to_stereo = 1;
+					outsize_stereo = dz->insams[1] * 2;
+				}
+				if(sloom) {
+					if((tempfd = sndcreat_formatted("#temp",outsize_stereo,dz->infile->stype,
+							STEREO,dz->infile->srate,CDP_CREATE_NORMAL)) < 0) {
+						is_converted_to_stereo = -1;
+						sprintf(errstr,"Cannot open output file '#temp'\n");
+						return(DATA_ERROR);
+					}
+				} else if((tempfd = sndcreat_formatted("_temp",outsize_stereo,dz->infile->stype,
+						STEREO,dz->infile->srate,CDP_CREATE_NORMAL)) < 0) {
+					is_converted_to_stereo = -1;
+					sprintf(errstr,"Cannot open output file '_temp': %s\n",sferrstr());
+					return(DATA_ERROR);
+				}
+				while((samps_read  = fgetfbufEx(tempbuf, shsecsize,dz->ifd[is_converted_to_stereo],0))>0) {
+					int d_samps_read = samps_read * 2;
+					for(m = d_samps_read - 2,k = d_samps_read - 1, 
+							n = samps_read - 1;
+								n >=0; n--,m-=2,k-=2) {
+						tempbuf[m] = tempbuf[n];						
+						tempbuf[k] = tempbuf[n];						
+					}
+					if((samps_written = fputfbufEx(tempbuf,/*SECSIZE*/samps_read * 2,tempfd))<0) {
+						sprintf(errstr,"Can't write to output temporary soundfile: (is hard-disk full?).\n");
+						return(SYSTEM_ERROR);
+					}
+					if(samps_written != samps_read * 2) {
+						sprintf(errstr,"Error in data accounting while converting mono file to stereo.\n");
+						return(SYSTEM_ERROR);
+					}
+				}
+				dz->infile->channels = 2;
+
+				if(sndcloseEx(tempfd) < 0) {
+					sprintf(errstr,"Failed to close temporary stereo soundfile.\n");
+					return(SYSTEM_ERROR);
+				}
+				if(sndcloseEx(dz->ifd[is_converted_to_stereo]) < 0) {
+					sprintf(errstr,"Failed to close input soundfile, at conversion to stereo.\n");
+					return(SYSTEM_ERROR);
+				}
+				dz->ifd[is_converted_to_stereo] = -1;
+				if(sloom) {
+					if((dz->ifd[is_converted_to_stereo] = sndopenEx("#temp",0,CDP_OPEN_RDONLY)) < 0) {
+						sprintf(errstr,"Failed to reopen temporary file '#temp' for output.\n");
+						return(SYSTEM_ERROR);
+					}
+				} else {
+					if((dz->ifd[is_converted_to_stereo] = sndopenEx("_temp",0,CDP_OPEN_RDONLY)) < 0) {
+						sprintf(errstr,"Failed to reopen temporary file '#temp' for output.\n");
+						return(SYSTEM_ERROR);
+					}
+				}
+				sndseekEx(dz->ifd[is_converted_to_stereo],0,0);
+				dz->insams[is_converted_to_stereo] *= 2;
+			}
+		}
+		if((exit_status = reset_peak_finder(dz))<0)
+			return(exit_status);
+		break;
+	case(MIXBALANCE):
+		break;
+	default:	
+		if(dz->infile->channels!=dz->otherfile->channels) {
+			sprintf(errstr,"Different no. of channels in input files: can't proceed.\n");
+			return(USER_ERROR);
+		}
+		break;
+	}
+	if(dz->otherfile->filetype!=SNDFILE) {
+		sprintf(errstr,"2nd file is not a soundfile: can't proceed.\n");
+		return(USER_ERROR);
+	}
+	infiledur  =(double)(dz->insams[0]/dz->infile->channels)/sr; 
+	infiledur2 =(double)(dz->insams[1]/dz->infile->channels)/sr; 
+
+	switch(dz->process) {
+	case(MIXTWO):		
+		if(dz->param[MIX_SKIP] >= infiledur2) {
+			sprintf(errstr,"SKIP INTO 2ND FILE exceeds length of that file: cannot proceed\n");
+			return(DATA_ERROR);
+		}		
+		break;
+	case(MIXBALANCE):
+		break;
+	case(MIXCROSS):
+		if(dz->param[MCR_BEGIN] >= infiledur2 + dz->param[MCR_STAGGER]) {
+			sprintf(errstr,"CROSSFADE START is after end of 2nd sndfile: cannot proceed\n");
+			return(DATA_ERROR);
+		}
+		if(dz->param[MCR_END] > infiledur + infiledur2) {
+			sprintf(errstr,"CROSSFADE END is beyond end of sndfiles: cannot proceed\n");
+			return(DATA_ERROR);
+		}
+		break;
+	}
+	return(FINISHED);
+}
+
+/************************* GET_FILESEARCH_DATA ************************/
+
+int get_filesearch_data(dataptr dz)
+{   
+	int    exit_status;
+	int   srate = 0, total_words, n;
+	int    *inchans;
+	/* RWD: sets a scan window only; crude, but we keep it for now */
+//TW better to use global
+	int   shsecsize = F_SECSIZE, *samplen;
+	double filedur;
+	double minsyncscan;
+	double *start, *end;
+	int    textfile_filetype = dz->infile->filetype;
+
+	if(dz->linecnt > SF_MAXFILES) {
+		sprintf(errstr,"Maximum number of sndfiles [%d] exceeded.\n",SF_MAXFILES);
+		return(USER_ERROR);
+	} else if(dz->linecnt <= 0) {
+		sprintf(errstr,"No lines found in sync data file.\n");
+		return(USER_ERROR);
+	}
+	if((dz->parray[MSY_STARTSRCH] = (double *)malloc(dz->linecnt * sizeof(double)))==NULL) {
+		sprintf(errstr,"INSUFFICIENT MEMORY for sync startsearch array.\n");
+		return(MEMORY_ERROR);
+	}
+	start = dz->parray[MSY_STARTSRCH];
+	if((dz->parray[MSY_ENDSRCH] = (double *)malloc(dz->linecnt * sizeof(double)))==NULL) {
+		sprintf(errstr,"INSUFFICIENT MEMORY for sync endsearch array.\n");
+		return(MEMORY_ERROR);
+	}
+	end = dz->parray[MSY_ENDSRCH];
+	if((dz->lparray[MSY_SAMPSIZE] = (int *)malloc(dz->linecnt * sizeof(int)))==NULL) {
+		sprintf(errstr,"INSUFFICIENT MEMORY for sync sampsizes array.\n");
+		return(MEMORY_ERROR);
+	}
+	samplen = dz->lparray[MSY_SAMPSIZE];
+	if((dz->iparray[MSY_CHANS] = (int *)malloc(dz->linecnt * sizeof(int)))==NULL) {
+		sprintf(errstr,"INSUFFICIENT MEMORY for sync channels array.\n");
+		return(MEMORY_ERROR);
+	}
+	inchans = dz->iparray[MSY_CHANS];
+	if((dz->lparray[MSY_PEAKSAMP] = (int *)malloc(dz->linecnt * sizeof(int)))==NULL) {
+		sprintf(errstr,"INSUFFICIENT MEMORY for sync peaks array.\n");
+		return(MEMORY_ERROR);
+	}
+	if((exit_status = establish_file_data_storage_for_mix((int)1,dz))<0)
+		return(exit_status);
+	total_words = 0;
+	for(n=0;n<dz->linecnt;n++) {
+		if((exit_status = open_file_and_retrieve_props(n,dz->wordstor[total_words],&srate,dz))<0)
+			return(exit_status);
+		samplen[n]	= dz->insams[0];
+		inchans[n]	= dz->infile->channels;
+		total_words += dz->wordcnt[n];
+	}
+
+	if(srate > SAMPLE_RATE_DIVIDE)  dz->iparam[MSY_SRFAC]=2;
+	else							dz->iparam[MSY_SRFAC]=1;
+
+	minsyncscan = (double)((shsecsize * dz->iparam[MSY_SRFAC])/MAX_WINFAC)/(double)srate;
+
+	total_words = 0;
+	for(n=0;n<dz->linecnt;n++) {
+		switch(dz->wordcnt[n]) {
+		case(3):
+			if(dz->infile->filetype==MIXFILE) {
+				sprintf(errstr,"Anomalous line length [%d] in mixfile\n",dz->wordcnt[n]);
+				return(PROGRAM_ERROR);
+			}
+			if(sscanf(dz->wordstor[total_words+1],"%lf",&(start[n]))!=1) {
+				sprintf(errstr,"Failed to read starttime: line %d: get_filesearch_data()\n",n+1);
+				return(PROGRAM_ERROR);
+			}
+			if(sscanf(dz->wordstor[total_words+2],"%lf",&(end[n]))!=1) {
+				sprintf(errstr,"Failed to read endtime: line %d: get_filesearch_data()\n",n+1);
+				return(PROGRAM_ERROR);
+			}
+			if((start[n] < 0.0) || (end[n] < 0.0) || (start[n] + minsyncscan >= end[n])) {
+				sprintf(errstr,"Impossible or incompatible searchtimes [%.5lf to %.5lf]: line %d.\n",
+				start[n],end[n],n+1);
+				return(USER_ERROR);
+			}
+// TW MOVED July 2004
+			filedur = (double)(samplen[n]/inchans[n])/(double)srate;
+			if(start[n] >= filedur - minsyncscan) {
+				sprintf(errstr,"starttime on line %d is beyond effective file end.\n",n+1);
+				return(DATA_ERROR);
+			}
+			if(end[n] >= filedur)
+				end[n] = -1.0;	/* flags END_OF_SNDFILE */
+			break;
+		default:
+			start[n] = 0.0;
+			end[n]   = -1.0;	/* flags END_OF_SNDFILE */
+			break;
+		}
+		total_words += dz->wordcnt[n];
+	}
+	dz->infile->filetype = textfile_filetype;
+	return(FINISHED);
+}
+
+/************************* OPEN_FILE_AND_RETRIEVE_PROPS *******************************/
+
+int open_file_and_retrieve_props(int filecnt,char *filename,int *srate,dataptr dz)
+{
+	int exit_status;
+	if((exit_status = open_file_retrieve_props_open(filecnt,filename,srate,dz))<0)
+		return(exit_status);
+	if(sndcloseEx(dz->ifd[0])<0) {
+		sprintf(errstr, "Failed to close input file %s: line %d: open_file_and_retrieve_props()\n",filename,filecnt+1);
+		return(SYSTEM_ERROR);
+	}
+	dz->ifd[0] = -1;
+	return(FINISHED);
+}
+
+/************************* OPEN_FILE_RETRIEVE_PROPS_OPEN *******************************/
+
+int open_file_retrieve_props_open(int filecnt,char *filename,int *srate,dataptr dz)
+{
+	int exit_status;
+	double maxamp, maxloc;
+	int maxrep;
+	int getmax = 0, getmaxinfo = 0;
+	infileptr ifp;
+	if((ifp = (infileptr)malloc(sizeof(struct filedata)))==NULL) {
+		sprintf(errstr,"INSUFFICIENT MEMORY to store data on file %s\n",filename);
+		return(MEMORY_ERROR);
+	}
+	/* OK to use sndopenEx? */
+	if((dz->ifd[0] = sndopenEx(filename,0,CDP_OPEN_RDONLY)) < 0) {
+		sprintf(errstr,"Failed to open sndfile %s: line %d: open_file_retrieve_props_open()\n",filename,filecnt+1);
+		return(SYSTEM_ERROR);
+	}
+	/* this use revised version that recognizes floatsam sndfile */
+	if((exit_status = readhead(ifp,dz->ifd[0],filename,&maxamp,&maxloc,&maxrep,getmax,getmaxinfo))<0)
+		return(exit_status);
+	copy_to_fileptr(ifp,dz->infile);
+	if(dz->infile->filetype!=SNDFILE) {
+		sprintf(errstr,"%s is not a soundfile: line %d: open_file_retrieve_props_open()\n",filename,filecnt+1);
+		return(PROGRAM_ERROR);
+	}
+	if(filecnt==0)
+		*srate = dz->infile->srate;
+	else if(dz->infile->srate != *srate) {
+		sprintf(errstr,"incompatible srate: file %s: line %d: open_file_retrieve_props_open()\n",filename,filecnt+1);
+		return(DATA_ERROR);
+	}
+	if((dz->insams[0] = sndsizeEx(dz->ifd[0]))<0) {	    			
+		sprintf(errstr, "Can't read size of input file %s: line %d: open_file_retrieve_props_open()\n",filename,filecnt+1);
+		return(PROGRAM_ERROR);
+	}
+	if(dz->insams[0] <=0) {
+		sprintf(errstr, "Zero size for input file %s: line %d: open_file_retrieve_props_open()\n",filename,filecnt+1);
+		return(DATA_ERROR);
+	}			
+	return(FINISHED);
+}
+
+/***************************** SYNCATT_PRESETS **************************/
+
+int syncatt_presets(dataptr dz)
+{
+	int exit_status;
+	if(!check_syncatt_window_factor(dz))
+			return(USER_ERROR);
+	if((exit_status= get_filesearch_data(dz))<0)
+		return(exit_status);
+	return(FINISHED);
+}
+
+/***************************** CHECK_SYNCATT_WINDOW_FACTOR **************************/
+
+int check_syncatt_window_factor(dataptr dz)
+{
+	int valid_value = MIN_WINFAC;
+	while(valid_value <= MAX_WINFAC) {
+		if(dz->iparam[MSY_WFAC]==valid_value)
+			return(TRUE);
+		valid_value *= 2;
+	}
+	return(FALSE);
+}
+
+/****************************** MIXTWARP_CONSISTENCY *********************************/
+
+int mixtwarp_consistency(dataptr dz)
+{
+	switch(dz->mode) {
+	case(MTW_TIMESORT):	
+		break;
+	default:
+		if(dz->iparam[MSH_ENDLINE] < dz->iparam[MSH_STARTLINE]) {
+			sprintf(errstr,"Start and endline values incompatible.\n");
+			return(USER_ERROR);
+		}
+	}
+	return(FINISHED);
+}
+
+/****************************** MIXSWARP_CONSISTENCY *********************************/
+
+int mixswarp_consistency(dataptr dz)
+{
+	if(dz->mode!=MSW_TWISTALL && dz->mode!=MSW_TWISTONE) {
+		if(dz->iparam[MSH_ENDLINE] < dz->iparam[MSH_STARTLINE]) {
+			sprintf(errstr,"Start and endline values incompatible.\n");
+			return(USER_ERROR);
+		}
+	}
+	return(FINISHED);
+}
+
+/****************************** MIX_CONSISTENCY *********************************/
+
+int mix_consistency(dataptr dz)
+{
+	if(dz->iparam[MSH_ENDLINE] < dz->iparam[MSH_STARTLINE]) {
+		sprintf(errstr,"Start and endline values incompatible.\n");
+		return(USER_ERROR);
+	}
+	return(FINISHED);
+}
+
+//TW UPDATE: NEW FUNCTION
+/****************************** ADDTOMIX_CONSISTENCY *********************************/
+
+int addtomix_consistency(dataptr dz)
+{
+	if(dz->infile->filetype != MIXFILE) {
+		sprintf(errstr,"The FIRST FILE must be a MIXFILE.\n");
+		return(USER_ERROR);
+	}
+	return(FINISHED);
+}
+
+/********************************************************************************************/
+/********************************** FORMERLY IN buffers.c ***********************************/
+/********************************************************************************************/
+
+/**************************** ALLOCATE_LARGE_BUFFERS ******************************/
+
+int allocate_large_buffers(dataptr dz)
+{
+	switch(dz->process) {
+	case(MIX):			case(MIXMAX):			
+		return create_mix_buffers(dz);
+
+	case(MIXTWO):
+	case(MIXBALANCE):
+		return create_mixtwo_buffer(dz);
+
+	case(MIXINTERL):
+		dz->bufcnt = 1 + dz->infilecnt;
+		return create_sndbufs(dz);
+	case(MIXCROSS):		case(MIXINBETWEEN):		
+	case(AUTOMIX):
+		return create_sndbufs(dz);
+	case(CYCINBETWEEN):			
+		return create_cycinbi_buffer(dz);
+	case(MIXMANY):			
+		return create_mixmany_buffer(dz);
+
+	case(MIXSYNCATT):		
+		return create_syncatt_buffer(dz);
+
+	case(MIXFORMAT):	case(MIXDUMMY):		case(MIXTEST):
+	case(MIXTWARP):		case(MIXSWARP):		case(MIXGAIN):
+	case(MIXSHUFL):		case(MIXSYNC):		case(MIX_MODEL):
+	case(MIX_ON_GRID):	case(ADDTOMIX):		case(MIX_PAN):
+	case(MIX_AT_STEP):	
+
+		return(FINISHED);
+	default:
+		sprintf(errstr,"Unknown program no. in allocate_large_buffers()\n");
+		return(PROGRAM_ERROR);
+	}
+	return(FINISHED);	/* NOTREACHED */
+}
+
+/*************************** CREATE_MIX_BUFFERS **************************
+ *
+ * (1)	Basic buffersize needs an extra factor of 2 because MONO_TO_STEREO conversion
+ *		reads 1/2 a buffer into dz->sampbuf[STEREOBUF], and that 1/2 a buf needs to be
+ *		a multiple of F_SECSIZE samples!!
+ * (2)	As well as the input buffers, need an output buffer, 
+ 		and a stereo-buffer for panned-stereo.
+ * (3)	Initialise space left in outbuffer to all of it.
+ */
+
+int create_mix_buffers(dataptr dz)
+{
+	int exit_status;
+	size_t bigbufsize;
+	size_t bloksize = SECSIZE * 2;  			/* 1 */
+	/*RWD NB longsize_in_floats was longsize_in_shorts...*/
+//TW MIXMAX CALCULATIONS ARE DONE IN FLOATS, SO BUFFER-OF-LONGS NOT NEEDED
+	switch(dz->process) {
+	case(MIX):
+		dz->bufcnt += 2;					/* allow for panned_stereo_buffer and output buffer */
+		break;
+	case(MIXMAX):
+//TW AMPLITUDE SUM NOW IN FLOATS
+		dz->bufcnt += 2;					
+		break;
+	default:
+		sprintf(errstr,"Unknown case: create_mix_buffers()\n");
+		return(PROGRAM_ERROR);
+	}
+	bloksize = dz->bufcnt * bloksize;
+	bigbufsize = (size_t)Malloc(-1);
+	if((bigbufsize = (bigbufsize/bloksize) * bloksize) <= 0)
+		bigbufsize = bloksize;
+	if((dz->bigbuf = (float *)Malloc(bigbufsize)) == NULL) {
+		sprintf(errstr, "INSUFFICIENT MEMORY to create sound buffers.\n");
+		return(MEMORY_ERROR);
+	}
+
+	dz->buflen =(int)( bigbufsize/sizeof(float)/dz->bufcnt);	 		/* length of floats buffers */
+//TW NO ADJUSTMENTS NEEDED FOR BUFFER-0F-LONGS
+	if((exit_status = establish_groucho_bufptrs_and_extra_buffers(dz))<0)
+		return(exit_status);
+	dz->bufcnt -= 2;							 /* bufcnt is now a count of input buffers only */
+	dz->sampbuf[OBUFMIX] = dz->bigbuf;
+//TW NO ADJUSTMENTS NEEDED FOR BUFFER-0F-LONGS
+	dz->sampbuf[STEREOBUF] = dz->bigbuf + dz->buflen;
+
+	dz->sampbuf[IBUFMIX] = dz->sampbuf[STEREOBUF] + dz->buflen;
+	return(FINISHED);
+}
+
+/*************************** CREATE_SYNCATT_BUFFER **************************/
+
+int create_syncatt_buffer(dataptr dz)
+{
+	size_t bigbufsize;
+	long n, bufactor = dz->iparam[MSY_SRFAC] * MAX_SYNCATT_CHANS;
+	size_t fsecbytesize = F_SECSIZE * sizeof(float);
+	bigbufsize = (size_t)Malloc(-1);
+//TW SAFER
+	if((bigbufsize  = (bigbufsize/(fsecbytesize*bufactor)) * (fsecbytesize*bufactor))<=0) {
+		bigbufsize  = fsecbytesize*bufactor;
+	}
+	dz->buflen = (int)(bigbufsize/sizeof(float));
+	if((dz->bigbuf = (float *)malloc((size_t)(dz->buflen * sizeof(float)))) == 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);
+}
+
+/*************************** CREATE_MIXTWO_BUFFER **************************/
+
+int create_mixtwo_buffer(dataptr dz)
+{
+	size_t bigbufsize;
+	int n, bufactor;
+	int samptodouble = sizeof(double)/sizeof(float);
+	size_t fsecbytesize = F_SECSIZE * sizeof(float);
+	bigbufsize = (size_t) Malloc(-1);
+	if(dz->process == MIXBALANCE) {
+// MULTICHAN 2009 --> 
+		if(dz->infile->channels > 2)
+			dz->bufcnt = dz->infile->channels * 2;
+// <-- MULTICHAN 2009
+		if((bigbufsize  /= dz->bufcnt) <= 0) {
+			sprintf(errstr,"INSUFFICIENT MEMORY for sound buffers.\n");
+			return(MEMORY_ERROR);
+		}
+		if((bigbufsize = ((bigbufsize/fsecbytesize * dz->bufcnt) * fsecbytesize * dz->bufcnt)) <= 0) {
+			bigbufsize = fsecbytesize * dz->bufcnt;
+		}
+		if((dz->bigbuf = (float *)malloc((size_t)(bigbufsize * dz->bufcnt))) == NULL) {
+			sprintf(errstr,"INSUFFICIENT MEMORY to create sound buffers.\n");
+			return(MEMORY_ERROR);
+
+		}
+		dz->buflen = (int)(bigbufsize/sizeof(float));
+		dz->sampbuf[0] = dz->bigbuf;
+// MULTICHAN 2009 --> 
+		if(dz->infile->channels > 2)
+			dz->sampbuf[1] = dz->sampbuf[0] + (dz->buflen * dz->infile->channels);
+// <-- MULTICHAN 2009
+		else if(dz->infile->channels == 1)
+			dz->sampbuf[1] = dz->sampbuf[0] + dz->buflen;
+		else
+			dz->sampbuf[1] = dz->sampbuf[0] + (dz->buflen * 2);
+	} else {
+// MULTICHAN 2009 --> 
+		if(dz->infile->channels > 2) {
+			dz->bufcnt = 3 + samptodouble;
+			bufactor  = dz->bufcnt * dz->infile->channels;
+// <-- MULTICHAN 2009
+		} else
+			bufactor = (dz->bufcnt - 1) + samptodouble;
+		if((bigbufsize  = (bigbufsize/(fsecbytesize*bufactor)) * (fsecbytesize*bufactor))<=0)
+			bigbufsize  = fsecbytesize*bufactor;
+		if((dz->bigbuf = (float *) malloc(bigbufsize) ) == NULL) {
+			sprintf(errstr,"INSUFFICIENT MEMORY to create sound buffers.\n");
+			return(MEMORY_ERROR);
+		}
+// MULTICHAN 2009 --> 
+		if(dz->infile->channels > 2)
+			bufactor = dz->bufcnt;
+// <-- MULTICHAN 2009
+		bigbufsize /= bufactor;
+		dz->buflen = (int)(bigbufsize/sizeof(float));
+		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 * bufactor);
+	}
+	return(FINISHED);
+}
+
+// TW NEW FUNCTION: ADJUSTED FOR floats
+/*************************** CREATE_MIXMANY_BUFFER **************************/
+
+int create_mixmany_buffer(dataptr dz)
+{
+	size_t n, bufactor, bigbufsize;
+	size_t samptodouble = sizeof(double)/sizeof(float);
+	size_t fsecbytesize = F_SECSIZE * sizeof(float);
+	bigbufsize = (long)Malloc(-1);
+	bufactor = dz->bufcnt + samptodouble;
+	if((bigbufsize  = (bigbufsize/(fsecbytesize*bufactor)) * (fsecbytesize*bufactor))<=0) {
+		bigbufsize  = fsecbytesize*bufactor;
+	}
+	if((dz->bigbuf = (float *)malloc(bigbufsize)) == NULL) {
+		sprintf(errstr,"INSUFFICIENT MEMORY to create sound buffers.\n");
+		return(MEMORY_ERROR);
+	}
+	bigbufsize /= bufactor;
+	dz->buflen = (int)(bigbufsize/sizeof(float));
+	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 * bufactor);
+	return(FINISHED);
+}
+
+/*************************** CREATE_CYCINBI_BUFFER **************************/
+
+int create_cycinbi_buffer(dataptr dz)
+{
+	int n;
+	/*RWD April 2004 */ 
+	int insize_0,insize_1, bigbufsize;
+	insize_0 = dz->insams[0] * sizeof(float);
+	insize_1 = dz->insams[1] * sizeof(float);
+ /*	int bigbufsize = max(dz->infilesize[0], dz->infilesize[1]) + F_SECSIZE; */
+	bigbufsize = max(insize_0, insize_1) + F_SECSIZE; 
+	bigbufsize = (bigbufsize/F_SECSIZE) * F_SECSIZE * dz->bufcnt;
+	if((dz->bigbuf = (float *)malloc((size_t)(bigbufsize))) == NULL) {
+		sprintf(errstr,"INSUFFICIENT MEMORY to create sound buffers.\n");
+		return(MEMORY_ERROR);
+	}
+	bigbufsize /= dz->bufcnt;
+	dz->buflen = bigbufsize/sizeof(float);
+	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 * dz->bufcnt);
+	return(FINISHED);
+}
+
+/********************************************************************************************/
+/********************************** FORMERLY IN cmdline.c ***********************************/
+/********************************************************************************************/
+
+int get_process_no(char *prog_identifier_from_cmdline,dataptr dz)
+{
+	if     (!strcmp(prog_identifier_from_cmdline,"mix"))			dz->process = MIX;
+	else if(!strcmp(prog_identifier_from_cmdline,"test"))			dz->process = MIXTEST;
+	else if(!strcmp(prog_identifier_from_cmdline,"getlevel"))		dz->process = MIXMAX;
+	else if(!strcmp(prog_identifier_from_cmdline,"fileformat"))		dz->process = MIXFORMAT;
+	else if(!strcmp(prog_identifier_from_cmdline,"dummy"))			dz->process = MIXDUMMY;
+	else if(!strcmp(prog_identifier_from_cmdline,"timewarp"))		dz->process = MIXTWARP;
+	else if(!strcmp(prog_identifier_from_cmdline,"spacewarp"))		dz->process = MIXSWARP;
+	else if(!strcmp(prog_identifier_from_cmdline,"attenuate"))		dz->process = MIXGAIN;
+	else if(!strcmp(prog_identifier_from_cmdline,"shuffle"))		dz->process = MIXSHUFL;
+	else if(!strcmp(prog_identifier_from_cmdline,"sync"))			dz->process = MIXSYNC;
+	else if(!strcmp(prog_identifier_from_cmdline,"syncattack"))		dz->process = MIXSYNCATT;
+	else if(!strcmp(prog_identifier_from_cmdline,"merge"))			dz->process = MIXTWO;
+	else if(!strcmp(prog_identifier_from_cmdline,"balance"))		dz->process = MIXBALANCE;
+	else if(!strcmp(prog_identifier_from_cmdline,"crossfade"))		dz->process = MIXCROSS;
+	else if(!strcmp(prog_identifier_from_cmdline,"interleave"))		dz->process = MIXINTERL;
+	else if(!strcmp(prog_identifier_from_cmdline,"inbetween"))		dz->process = MIXINBETWEEN;
+//TW UPDATES
+	else if(!strcmp(prog_identifier_from_cmdline,"mergemany"))		dz->process = MIXMANY;
+	else if(!strcmp(prog_identifier_from_cmdline,"ongrid"))			dz->process = MIX_ON_GRID;
+	else if(!strcmp(prog_identifier_from_cmdline,"atstep"))			dz->process = MIX_AT_STEP;
+	else if(!strcmp(prog_identifier_from_cmdline,"faders"))			dz->process = AUTOMIX;
+	else if(!strcmp(prog_identifier_from_cmdline,"addtomix"))		dz->process = ADDTOMIX;
+	else if(!strcmp(prog_identifier_from_cmdline,"pan"))			dz->process = MIX_PAN;
+	else if(!strcmp(prog_identifier_from_cmdline,"model"))			dz->process = MIX_MODEL;
+	else if(!strcmp(prog_identifier_from_cmdline,"inbetween2"))		dz->process = CYCINBETWEEN;
+	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: submix NAME (mode) infiles     outfile(s) [parameters]:\n"
+	"OR:    submix NAME (mode) mixdatafile outfile    [parameters]:\n"
+	"\n"
+	"where NAME can be any one of\n"
+	"\n"
+	"merge      balance     crossfade   interleave   inbetween   inbetween2\n"
+	"mix        getlevel      attenuate\n"
+	"shuffle    timewarp      spacewarp      sync       syncattack\n"
+	"test       fileformat    dummy     addtomix     atstep\n"
+	"ongrid     faders      mergemany   pan          model\n"
+	"\n"
+	"Type 'submix  mix'  for more info on submix  mix.\n"
+	"Type 'submix  fileformat'  for more info on mixfile fileformat... ETC\n");
+	return(USAGE_ONLY);
+}
+
+/******************************** USAGE2 ********************************/
+
+int usage2(char *str)
+{
+	if(!strcmp(str,"mix")) {		
+	    sprintf(errstr,
+	    "MIX SOUNDS AS INSTRUCTED IN A MIXFILE\n\n"
+    	"USAGE:	submix mix mixfile outsndfile [-sSTART] [-eEND] [-gATTENUATION] [-a]\n\n"
+    	"START       gives starttime START (to start mixing later than zero).\n"
+    	"END         gives output endtime END (to stop mix before its true end).\n"
+    	"ATTENUATION reduces level of entire mix (range >0-1).\n\n"
+		"Note that the START and END params are intended for mix TESTING purposes only.\n"
+		"If you want to keep output from such a testmix, you should TOPNTAIL it.\n\n"
+    	"-a    alternative mix algorithm, slightly slower,\n"
+    	"      but may avoid clipping in special circumstances.\n");
+	} else if(!strcmp(str,"test")) {		
+	    sprintf(errstr,
+	    "TEST THE SYNTAX OF A MIXFILE\n\n"
+    	"USAGE:	submix test mixfile\n\n");
+	} else if(!strcmp(str,"getlevel")) {		
+	    sprintf(errstr,
+	    "  TEST THE MAXIMUM LEVEL OF A MIX, DEFINED IN A MIXFILE\n"
+	    "AND SUGGEST A GAIN FACTOR TO AVOID OVERLOAD, IF NECESSARY\n\n"
+    	"USAGE: submix getlevel 1   mixfile             [-sSTART] [-eEND]\n"
+    	"USAGE: submix getlevel 2-3 mixfile outtextfile [-sSTART] [-eEND]\n\n"
+    	"MODES...\n"
+    	"1) finds maximum level of mix.\n"
+    	"2) finds locations of clipping in mix.\n"
+    	"3) finds locations of clipping, and maxlevel, in mix.\n"
+      	"START gives starttime START (to start mixing later than zero).\n"
+    	"END   gives output endtime END (to stop mix before its true end).\n"
+  	     "OUTTEXTFILE  stores clipping locations (& maxlevel, in mode 3).\n\n"
+    	"You can alter the overall level of a mix with 'submix attenuate'.\n");
+	} else if(!strcmp(str,"fileformat")) {		
+	sprintf(errstr,
+	"MIXFILES CONSIST OF LINES WITH ONE OF THE FOLLOWING FORMATS\n"
+	"sndname starttime_in_mix  chans  level\n"
+	"sndname starttime_in_mix  1      level       pan\n"
+	"sndname starttime_in_mix  2      left_level  left_pan  right_level  right_pan\n\n"
+	"SNDNAME is name of a MONO or STEREO sndfile: ALL MUST BE OF SAME SAMPLING RATE.\n"
+	"CHANS   is number of channels in this soundfile (1 or 2 ONLY)\n"
+	"LEVEL   is loudness, as number (1 = unity gain) or dB (0dB = unity gain)\n"
+	"        Mono AND stereo files MAY have a SINGLE level parameter (NO pan data).\n"
+	"        In this case, MONO files in STEREO mixes are panned centrally.\n"
+	"        OTHERWISE....\n"
+	"        MONO files   must have 1 level & 1 pan parameter (ONLY).\n"
+	"        STEREO files MUST have 2 level & 2 pan params, 1 for each channel.\n"
+	"PAN     is spatial positioning of file (or file channel) in output mix.\n"
+	"        -1 HArd Left : 0 Centre : 1 Hard Right\n"
+	"        < -1 hard left & attenuated : > 1 hard right & attenuated.\n"
+	"ALSO....\n"
+	"1) The mixfile list need NOT be in starttime order.\n"
+	"2) Silence at start of mix IGNORED.(splice on afterwards if needed).\n"
+	"3) With exclusively mono inputs, with NO pan information, OR \n"
+	"   when ALL panned hard left, or ALL hard right, output is MONO.\n"
+	"   All other situations produce stereo output.\n"
+	"4) TAKE CARE WHEN PANNING BOTH CHANNELS OF A STEREO FILE.\n"
+	"   The channel contributions sum, so e.g. if both channels are\n"
+	"   panned to same position without attenuation, overload possible.\n"
+	"5) You may test for maximum level in your mix output with submix GETLEVEL.\n"
+	"   Reduce the mixfile level, if necessary, using 'submix attenuate'.\n"
+	"6) You may put comment lines in mixfiles : Start such line with a ';'\n"
+	"   Blank lines are ignored.\n");
+	} else if(!strcmp(str,"dummy")) {		
+	    sprintf(errstr,
+	    "CONVERT A LIST OF SNDFILES INTO A BASIC MIXFILE (FOR EDITING)\n\n"
+    	"USAGE: submix dummy mode infile1 infile2 [infile3..] mixfile\n"
+		"mode 1 - all files start at time zero.\n"
+		"mode 2 - each file starts where previous file ends.\n"
+		"mode 3 - (mono) files, first to left, remainder to right.\n");
+//TW UPDATES
+	} else if(!strcmp(str,"ongrid")) {		
+	    sprintf(errstr,
+	    "CONVERT LISTED SNDFILES TO BASIC MIXFILE ON TIMED GRID (FOR EDITING)\n\n"
+    	"USAGE: submix ongrid infil1 infil2 [infil3..] outmixfile gridfile\n\n"
+ 		"GRIDFILE a list of times (one for each input sound) of sounds in mix\n"
+		"         OR a list with some times preceded by 'x' (no space after 'x')\n"
+		"         where 'x' marks a time to actually use \n"
+		"         (other grid times being ignored).\n\n"
+		"Numbers, or gridpoint names, may follow times (on same line ONLY)\n\n"
+		"IF NO SOUND USED AT TIME ZERO, mix will skip to first snd actually used.\n"
+		"To avoid this, use a SILENT FILE at time zero.\n");
+	} else if(!strcmp(str,"atstep")) {		
+	    sprintf(errstr,
+	    "CONVERT LISTED SNDFILES TO BASIC MIXFILE WITH FIXED TIMESTEP BETWEEN ENTRIES\n\n"
+  	   	"USAGE: submix atstep infile1 infile2 [infile3..] outmixfile step\n\n"
+		"STEP is time, in seconds, between entry of each file.\n\n");
+	} else if(!strcmp(str,"faders")) {		
+	    sprintf(errstr,
+		"MIX SEVERAL MONO OR STEREO FILES USING TIME-CHANGING BALANCE-FUNCTION\n\n"
+    	"USAGE: submix faders inf1 inf2 [inf3..] outf balance-data envelope-data\n\n"
+    	"(NB do not mix mono and stereo in the input)\n"
+		"BALANCE-DATA  is a list of value sets.\n"
+		"              Each consisting of a time, followed by the\n"
+		"              RELATIVE level of each file in the mix, at that time.\n\n"
+		"              Whatever set of numbers is used, THESE ARE SCALED\n"
+		"              so the total set of levels used ON ANY LINE adds up to 1.0\n"
+		"              (This means that if all signals are at max level\n"
+		"              the output will never exceed max level)\n\n"
+		"              You can't use this data to vary the OVERALL level.\n"
+		"              and, in particular, the values cannot ALL be zero.\n\n"
+		"ENVELOPE-DATA is the loudness envelope to apply to the TOTAL sound.\n"
+		"              and this (also) can vary over time.\n");
+
+	} else if(!strcmp(str,"timewarp")) {		
+		sprintf(errstr,
+		"TIMEWARP THE DATA IN A MIXFILE\n\n"
+		"USAGE:  submix timewarp 1    inmixfile outmixfile\n"
+		"OR:     submix timewarp 2-5  inmixfile outmixfile   [-sstartline] [-eendline]\n"
+		"OR:     submix timewarp 6-16 inmixfile outmixfile Q [-sstartline] [-eendline]\n\n"
+		"STARTLINE: line at which warping begins (default: 1st in file)\n"
+		"ENDLINE  : line at which warping ends  (default: last in file).\n"
+		"MODES ARE....\n"
+		"1)  SORT INTO TIME ORDER.\n"
+		"2)  REVERSE TIMING PATTERN:  e.g. rit. of sound entries becomes an accel.\n"
+		"3)  REVERSE TIMING PATTERN & ORDER OF FILENAMES.\n"
+		"4)  FREEZE TIMEGAPS          between sounds, at FIRST timegap value.\n"
+		"5)  FREEZE TIMEGAPS & NAMES  ditto, and all files take firstfile name.\n"
+		"6)  SCATTER ENTRY TIMES      about orig vals. Q is scattering: Range(0-1).\n"
+		"7)  SHUFFLE UP ENTRY TIMES   shuffle times in file forward by time Q secs.\n"
+		"8)  ADD TO TIMEGAPS          add fixed val Q secs, to timegaps between sounds.\n"
+		"9)  CREATE FIXED TIMEGAPS 1  between all sounds,timegap = Q secs\n"
+		"10) CREATE FIXED TIMEGAPS 2  startval+Q,startval+2Q  etc\n"
+		"11) CREATE FIXED TIMEGAPS 3  startval*Q startval*2Q etc\n"
+		"12) CREATE FIXED TIMEGAPS 4  startval*Q     startval*Q*Q    etc\n"
+		"13) ENLARGE TIMEGAPS 1       multiply them by Q.\n"
+		"14) ENLARGE TIMEGAPS 2       by +Q, +2Q,+3Q  etc\n"
+		"15) ENLARGE TIMEGAPS 3       by *Q *2Q *3Q\n"
+		"16) ENLARGE TIMEGAPS 4       by *Q, *Q*Q, *Q*Q*Q  etc. (CARE!!)\n\n");
+	} else if(!strcmp(str,"shuffle")) {		
+		sprintf(errstr,
+		"SHUFFLE THE DATA IN A MIXFILE\n\n"
+		"USAGE: submix shuffle 1-6 inmixfile outmixfile         [-sstartl] [-eendl]\n"
+		"OR:    submix shuffle 7   inmixfile outmixfile newname [-sstartl] [-eendl] [-x]\n\n"
+		"STARTL: line at which shuffling begins (default: 1st in file)\n"
+		"ENDL  : line at which shuffling ends  (default: last in file).\n"
+		"MODES ARE....\n"
+		"1)  DUPLICATE EACH LINE.\n"
+		"2)  REVERSE ORDER OF FILENAMES.\n"
+		"3)  SCATTER ORDER OF FILENAMES.\n"
+		"4)  REPLACE SOUNDS IN SELECTED LINES WITH SOUND IN STARTLINE.\n"
+		"5)  OMIT LINES           (closing up timegaps appropriately)\n"
+		"6)  OMIT ALTERNATE LINES (closing up timegaps appropriately)\n"
+		"                         In modes 5 & 6 mix must be in correct time-order.\n"
+		"                         mixfiles can be time-ordered using timewarp mode 1\n"
+		"7)  DUPLICATE AND RENAME: duplicate each line with new sound, newname.\n\n"
+		"                         Program checks 'newname' is compatible sndfile, BUT,\n"
+		"-x  flag TURNS OFF 'newname' checking in mode 7.\n");
+	} else if(!strcmp(str,"attenuate")) {		
+		sprintf(errstr,
+		"ALTER THE OVERALL LEVEL OF A MIXFILE.\n\n"
+		"USAGE:  submix attenuate inmixfile outmixfile gainval [-sstartline] [-eendline]\n\n"
+		"GAINVAL must be > 0.0\n"
+		"STARTLINE: line at which attenuation begins (default: 1st in file)\n"
+		"ENDLINE  : line at which attenuation ends  (default: last in file).\n"
+		"You can test the overall level of a mix with 'submix getlevel'\n");
+	} else if(!strcmp(str,"spacewarp")) {		
+		sprintf(errstr,
+		"ALTER THE SPATIAL DISTRIBUTION OF A MIXFILE.\n\n"
+		"USAGE: submix spacewarp 1-2 inmixfile outmixfile Q     [-sstartl] [-eendl]\n"
+		"OR:    submix spacewarp 4-6 inmixfile outmixfile Q1 Q2 [-sstartl] [-eendl]\n"
+		"OR:    submix spacewarp 7   inmixfile outmixfile\n"
+		"OR:    submix spacewarp 8   inmixfile outmixfile Q\n"
+		"STARTL: line at which warping begins (default: 1st in file)\n"
+		"ENDL  : line at which warping ends  (default: last in file).\n"
+		"MODES ARE....\n"
+		"1) SOUNDS TO SAME POSITION           Q is position. (stereo files become mono)\n"
+		"2) NARROW SPATIAL SPREAD             Q is a +ve number < 1.0\n"
+		"3) SEQUENCE POSITIONS LEFTWARDS    over range Q1-Q2 (stereo files become mono)\n"
+		"4) SEQUENCE POSITIONS RIGHTWARDS   over range Q1-Q2 (stereo files become mono)\n"
+		"5) RANDOM-SCATTER POSITIONS      within range Q1-Q2 (stereo files become mono)\n"
+		"6) RANDOM, BUT ALTERNATE TO L/R OF THE CENTRE OF THE SPATIAL RANGE SPECIFIED.\n"
+		"                                        range Q1-Q2 (stereo files become mono)\n"
+		"7) INVERT STEREO IN ALTERNATE LINES OF MIXFILE: (Use to avoid clipping).\n"
+		"8) INVERT STEREO IN SPECIFIED LINE OF MIXFILE   Q is line number.\n");
+	} else if(!strcmp(str,"sync")) {		
+		sprintf(errstr,
+		"SYNCHRONISE SOUNDFILES IN A MIXFILE,\n"
+		"OR GENERATE SUCH A MIXFILE FROM A LIST OF SNDFILES.\n\n"
+		"USAGE: submix sync mode intextfile outmixfile\n\n"
+		"INTEXTFILE is list of sndfiles OR an existing mixfile.\n\n"
+		"MODES ARE....\n"
+		"1) SYNC SNDFILE MIDTIMES.\n"		
+		"2) SYNC SNDFILE ENDTIMES.\n");
+	} else if(!strcmp(str,"syncattack")) {		
+		sprintf(errstr,
+		"SYNCHRONISE ATTACKS OF SOUNDFILES, IN A MIXFILE,\n"
+		"OR GENERATE SUCH A MIXFILE FROM A LIST OF SNDFILES.\n\n"
+		"USAGE: submix syncattack intextfile outmixfile  [-wdiv] [-p]\n\n"
+		"INTEXTFILE is a list of sndfiles OR an existing mixfile.\n"		
+		"           with a sndfilelist (only), each sndname MAY be followed by 2 times,\n"
+		"           which limit the search area for the sound's attack.\n"
+		"-w         DIV is factor shortening window which scans for the attack.\n"
+   		"           It can be 2,4,8,16, or 32 ONLY.\n"
+   		"-p         Program finds peak-power segment, before locating its max sample.\n"
+   		"           Default: program looks purely for maxsample.\n\n"
+		"The program estimates output levels required to prevent clipping,\n"
+		"But estimate may be over-cautiously low: adjust with 'submix attenuate'.\n");
+	} else if(!strcmp(str,"merge")) {		
+		sprintf(errstr,
+		"QUICK MIX OF 2 SNDFILES (Mono or Stereo only).\n\n"
+		"USAGE: submix merge sndfile1 sndfile2 outfile\n"
+		"          [-sstagger] [-jskip] [-kskew] [-bstart] [-eend]\n"
+		"\n"
+		"STAGGER ...2nd file enters, 'stagger' secs after first.\n"
+		"SKIP ......skip by 'skip' secs into the 2nd file, before starting to mix.\n"
+		"SKEW.......1st sound has 'skew' times more gain than 2nd.\n"
+		"START .....Start the mix at the time specified.\n"
+		"END........Stop the mix at the time specified.\n"
+		"Stagger and Skip are approximated to within about one hundredth of a second.\n");
+//TW UPDATE
+	} else if(!strcmp(str,"mergemany")) {		
+		sprintf(errstr,
+		"QUICK MIX OF SEVERAL SNDFILES (WITH SAME NUMBER OF CHANNELS).\n\n"
+		"USAGE: submix mergemany sndfile1 sndfile2 [sndfile3 ....] outfile\n");
+	} else if(!strcmp(str,"balance")) {		
+		sprintf(errstr,
+		"MIX BETWEEN 2 SNDFILES USING A BALANCE FUNCTION.\n\n"
+		"USAGE: submix balance sndfile1 sndfile2 outfile\n"
+		"                            [-kbalance] [-bstart] [-eend]\n\n"
+		"(files may or may not have different number of channels).\n"
+		"\n"
+		"BALANCE ...Describes the relative level of the two sounds. (Range 0-1)\n"
+		"......File 1 level is multiplied by the balance function.\n"
+		"......File 2 level is multiplied by the inverse of the balance function.\n"
+		"Balance may vary over time.\n\n"
+		"START .....Start the mix at the time specified.\n"
+		"END........Stop the mix at the time specified.\n");	
+	} else if(!strcmp(str,"crossfade")) {		
+		sprintf(errstr,
+		"QUICK CROSSFADE BETWEEN SNDFILES (WITH SAME NUMBER OF CHANNELS).\n\n"
+		"USAGE: submix crossfade 1 sndfile1 sndfile2 outfile\n\t\t[-sSTAGGER] [-bBEGIN] [-eEND]\n"
+		"OR:    submix crossfade 2 sndfile1 sndfile2 outfile\n\t\t[-sSTAGGER] [-bBEGIN] [-eEND] [-pPOWFAC]\n\n"
+		"MODES ARE...\n"
+		"1) Linear crossfade.\n"
+		"2) Cosinusiodal crossfade\n\n"
+		"Crossfade is from sndfile1 towards sndfile2.\n\n"
+	    "STAGGER   2nd file starts 'stagger' secs. after 1st. (Default: 0)\n"
+		"BEGIN     crossfade starts at BEGIN secs. (>Stagger) (Default: 0)\n"
+		"END       crossfade ends at END secs. (>Begin) (Default: end of shortest file)\n"
+		"          If crossfade ends before end of file2, remainder of file2 plays on.\n"
+	    "POWFAC    crossfade skew.\n"
+		"          if powfac = 1, cosinusoidal-crossfade is normal.\n"
+		"          in range %.2lf - 1, cosin-fade begins rapidly then slows.\n"
+		"          in range 1 - %.0lf, cosin-fade begins slowly, then speeds up.\n\n"
+ 		"Stagger approximated in c. hundredths of a sec. For more precise stagger, \n" 
+		"splice silence to start of sndfile2 & use stagger 0 (or use 'submix mix').\n\n"
+		"(Only spectral morphing will create true morph between 2 sounds).\n",MIN_MCR_POWFAC,MAX_MCR_POWFAC);
+	} else if(!strcmp(str,"interleave")) {		
+		sprintf(errstr,
+		"INTERLEAVE MONO FILES TO MAKE MULTICHANNEL OUTFILE.\n\n"
+		"USAGE: submix interleave sndfile1 sndfile2 [sndfile3 sndfile4] outfile\n\n"
+		"MAx number of channels in output is %d\n"
+		"First sndfile goes to left channel of stereo, (or channel 1 of 4), etc.\n",MAX_MI_OUTCHANS);
+	} else if(!strcmp(str,"inbetween")) {		
+		sprintf(errstr,
+		"GENERATE A SET OF SOUNDS IN-BETWEEN THE 2 INPUT SOUNDS\n"
+		"      THROUGH WEIGHTED MIXES OF THE INPUT SOUNDS,\n"
+		"         FROM MOSTLY SOUND1 TO MOSTLY SOUND2.\n\n"
+		"USAGE: submix inbetween 1 infile1  infile2  outname  count\n"
+		"OR:    submix inbetween 2 infile1  infile2  outname  ratios\n\n"
+		"OUTNAME  is your GENERIC name for the output sndfiles.\n"
+		"         New soundfiles will be called outname001 outname002 etc\n\n"
+		"COUNT    If a single number (COUNT) is given to the program,\n"
+		"         it generates amplitude ratios for the new sounds, automatically,\n"
+		"         and COUNT is the number of inbetween outfiles to produce.\n\n"
+		"RATIOS   A ratio, or a list of ratios in a textfile. These are\n"
+		"         the level of file2 RELATIVE to file 1,for each new outfile,\n"
+		"         as FRACTIONS (Range 0-1)\n"
+		"         There must be an even number of values and in ascending order.\n\n"
+		"Ensure NONE of the files to be created already exists!!\n");
+	} else if(!strcmp(str,"inbetween2")) {		
+		sprintf(errstr,
+		"GENERATE A SET OF SOUNDS IN-BETWEEN THE 2 INPUT SOUNDS\n"
+		"      THROUGH INTERPOLATION PEGGED TO ZERO_CROSSINGS.\n\n"
+		"USAGE: submix inbetween2 infile1  infile2  outname  count  cutoff\n"
+		"OUTNAME  is your GENERIC name for the output sndfiles.\n"
+		"         New soundfiles will be called outname001 outname002 etc\n\n"
+		"COUNT    is the number of inbetween outfiles to produce.\n\n"
+		"CUTOFF   Is the frquency above which 'cycles' are ignored: \n"
+		"         usually noise, they are incorporated into other cycles.\n\n"
+		"Ensure NONE of the files to be created already exists!!\n");
+	} else if(!strcmp(str,"addtomix")) {		
+		sprintf(errstr,
+		"ADD SOUNDFILES (at max level and time end-of-file) TO EXISTING MIXFILE.\n\n"
+		"USAGE: submix addtomix mixfile sndfile1 [sndfile2 ........] outfile\n");
+	} else if(!strcmp(str,"model")) {		
+		sprintf(errstr,
+		"REPLACE SOUNDFILES IN EXISTING MIXFILE.\n\n"
+		"USAGE: submix model mixfile sndfile1 [sndfile2 ........] outfile\n");
+	} else if(!strcmp(str,"pan")) {		
+		sprintf(errstr,
+		"PAN A MIXFILE.\n\n"
+		"USAGE: submix pan inmixfile outmixfile pan\n\n"
+		"PAN may vary over time\n"
+		"    in this case, soundfiles in mix are POSITIONED differently\n"
+		"    depending on time they begin, and value in PAN file at that time.\n"
+		"    BUT the sounds THEMSELVES will not be panned (in the final mixdown)\n"); 
+	} else
+		sprintf(errstr,"Unknown option '%s'\n",str);
+	return(USAGE_ONLY);
+}
+
+/******************************** USAGE3 ********************************/
+
+int usage3(char *str1,char *str2)
+{	
+	if(!strcmp(str1,"test"))		
+		return(CONTINUE);
+	else if(!strcmp(str1,"fileformat"))	{
+		sprintf(errstr,"Too many parameters on command line.\n");
+		return(USAGE_ONLY);
+	} else
+		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);
+}
+
+
+/************************* MIX_ATTEN ******************************/
+
+int mix_atten(dataptr dz)
+{
+	int    exit_status;
+	int   lineno, total_words;
+
+ 	total_words = 0;
+	for(lineno=0;lineno<dz->linecnt;lineno++) {
+		if((exit_status = adjust_levels(lineno,total_words,dz))<0) {
+			return(exit_status);
+		}
+		total_words += dz->wordcnt[lineno];
+	}
+	return(FINISHED);
+}
+
+/********************** ADJUST_LEVELS ****************************/
+ 
+int adjust_levels(int lineno,int total_words,dataptr dz)
+{
+	int exit_status;
+	int wordcnt = dz->wordcnt[lineno], len;
+	char *thisword, temp[200]; 
+	double level;
+	int wordno = total_words + MIX_LEVELPOS;
+
+	thisword = dz->wordstor[wordno];
+	if((exit_status = get_level(thisword,&level))<0)
+		return(exit_status);
+	level *= dz->param[MIX_ATTEN];
+	sprintf(temp,"%lf",level);
+	if((len = (int)strlen(temp)) > (int)strlen(thisword)) {
+		if((dz->wordstor[wordno] = (char *)realloc((char *)dz->wordstor[wordno],(len+1)))==NULL)
+			return(MEMORY_ERROR);
+	}	
+	strcpy(dz->wordstor[wordno],temp);
+	if(wordcnt <= MIX_RLEVELPOS)
+		return(FINISHED);
+
+	wordno = total_words + MIX_RLEVELPOS;
+	thisword = dz->wordstor[wordno];
+	if((exit_status = get_level(thisword,&level))<0)
+		return(exit_status);
+	level *= dz->param[MIX_ATTEN];
+	sprintf(temp,"%lf",level);
+	if((len = (int)strlen(temp)) > (int)strlen(thisword)) {
+		if((dz->wordstor[wordno] = (char *)realloc((char *)dz->wordstor[wordno],(len+1)))==NULL)
+			return(MEMORY_ERROR);
+	}	
+	strcpy(dz->wordstor[wordno],temp);
+	return(FINISHED);
+}
+
+//TW UPDATE: NEW FUNCTIONS
+/********************** READ_MIXGRID_FILE ****************************/
+ 
+int read_mixgrid_file(char *str,dataptr dz)
+{
+	int linecnt = 0, timecnt = 0, is_marked = 0;
+	char temp[200], *q, *p;
+	double time, last_time = 0.0;
+	int arraysize = BIGARRAY;
+	FILE *fp;
+
+	if((fp = fopen(str,"r"))==NULL) {
+		sprintf(errstr,"Failed to open file %s to read the grid data\n",str);
+		return(DATA_ERROR);
+	}
+	if((dz->parray[0] = (double *)malloc(arraysize * sizeof(double)))==NULL) {
+		sprintf(errstr,"INSUFFICIENT MEMORY for grid data.\n");
+		return(MEMORY_ERROR);
+	}
+	while(fgets(temp,200,fp)==temp) {
+		q = temp;
+		linecnt++;
+		if(!get_word_from_string(&q,&p))
+			continue;
+		if(*p == 'x') {
+			p++;
+			if(!is_marked) {
+				timecnt = 0;
+				is_marked = 1;
+			}
+		} else if(is_marked)
+			continue;
+		if(sscanf(p,"%lf",&time)!=1) {
+			sprintf(errstr,"Failed to find a time at line %d\n",linecnt);
+			return(DATA_ERROR);
+		}
+		if(time < 0.0) {
+			sprintf(errstr,"Invalid timevalue (%lf) at line %d\n",time,linecnt);
+			return(DATA_ERROR);
+		}
+		if(timecnt>0) {
+			if(time < last_time) {
+				if(is_marked)
+					sprintf(errstr,"Marked times not in ascending order at line %d time %lf\n",linecnt,time);
+				else
+					sprintf(errstr,"Times not in ascending order at line %d time %lf\n",linecnt,time);
+				return(DATA_ERROR);
+			}
+		}
+		last_time = time;
+		dz->parray[0][timecnt] = time;
+		if(++timecnt >= arraysize) {
+			arraysize += BIGARRAY;
+			if((dz->parray[0] = (double *)realloc((char *)dz->parray[0],arraysize * sizeof(double)))==NULL) {
+				sprintf(errstr,"INSUFFICIENT MEMORY for grid data.\n");
+				return(MEMORY_ERROR);
+			}
+		}
+	}						
+	if(timecnt != dz->infilecnt) {
+		if(timecnt < dz->infilecnt) {
+			if(is_marked)
+				sprintf(errstr,"Insufficient times marked (%d) for the number of input files (%d).\n",
+				timecnt,dz->infilecnt);
+			else
+				sprintf(errstr,"Insufficient times listed (%d) for the number of input files (%d).\n",
+				timecnt,dz->infilecnt);
+			return(DATA_ERROR);
+		} else {
+			if(is_marked)
+				fprintf(stdout,"WARNING: Too many times marked (%d) for the number of input files (%d).\n",
+				timecnt,dz->infilecnt);
+			else
+				fprintf(stdout,"WARNING: Too many times listed (%d) for the number of input files (%d).\n",
+				timecnt,dz->infilecnt);
+			fflush(stdout);
+		}
+	}
+	if((dz->parray[0] = (double *)realloc((char *)dz->parray[0],dz->infilecnt * sizeof(double)))==NULL) {
+		sprintf(errstr,"INSUFFICIENT MEMORY for reallocate storage for grid data.\n");
+		return(MEMORY_ERROR);
+	}
+	if(!flteq(dz->parray[0][0],0.0)) {
+		fprintf(stdout,"WARNING: First time used is NOT AT ZERO :  Mix will start at start of 1st file\n");
+		fprintf(stdout,"WARNING: and will be curtailed by %.4lf secs at start.\n",dz->parray[0][0]);
+		fflush(stdout);
+	}
+	return(FINISHED);
+}
+
+/*************************** READ_AND_SCALE_BALANCE_DATA *******************************/
+
+int read_and_scale_balance_data(char *filename,dataptr dz)
+{
+	FILE *fp;
+	double *p, sum, errtime = 1.0/dz->infile->srate, lasttime = 0.0;
+	int datalen = dz->infilecnt + 1;
+	int arraysize = BIGARRAY;
+	char temp[200], *q;
+	int n = 0, m;
+	if((fp = fopen(filename,"r"))==NULL) {
+		sprintf(errstr,	"Can't open textfile %s to read data.\n",filename);
+		return(DATA_ERROR);
+	}
+	if((dz->parray[0] = (double *)malloc(arraysize * sizeof(double)))==NULL) {
+		sprintf(errstr,"INSUFFICIENT MEMORY for data.\n");
+		return(MEMORY_ERROR);
+	}
+	p = dz->parray[0];
+	while(fgets(temp,200,fp)==temp) {
+		q = temp;
+		while(*q != ENDOFSTR) {
+			if(!isspace(*q))
+				break;
+			q++;
+		}
+		if(*q == ';')
+			continue;
+		if(invalid_data_items(temp))
+			return(DATA_ERROR);
+		while(get_float_from_within_string(&q,p)) {
+			if(n%datalen==0)	{ /* time value */
+				if(n==0) {
+					lasttime = *p;
+					if(*p != 0.0) {
+						sprintf(errstr,"Data in datafile %s must begin at time zero\n",filename);
+						return(DATA_ERROR);
+					}
+				} else {
+					if (*p < lasttime + errtime) {
+						sprintf(errstr,"Times %lf and %lf too close in datafile %s\n",*p,lasttime,filename);
+						return(DATA_ERROR);
+					}
+				}
+			} else if(*p < 0.0) {
+				sprintf(errstr,"Negative gain values not permitted in datafile %s\n",filename);
+				return(DATA_ERROR);
+			}
+			p++;
+			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 data table.\n");
+					return(MEMORY_ERROR);
+				}
+				p = dz->parray[0] + n;		
+			}
+		}
+		if(n%datalen == 0) {
+			sum = 0.0;
+			for(m=1;m <= dz->infilecnt;m++)
+				sum += *(p-m);
+			if(sum <= 0.0) {
+				sprintf(errstr,"levels are zero at line %d\n",(n/datalen)+1);
+				return(DATA_ERROR);
+			}
+			sum = 1.0/sum;
+			for(m=1;m <= dz->infilecnt;m++)
+				*(p-m) *= sum;	/* scale all gain values */
+		}
+	}
+	if(n == 0) {
+		sprintf(errstr,"No data in textdata file %s\n",filename);
+		return(DATA_ERROR);
+	}
+	if(n%datalen != 0) {
+		sprintf(errstr,"Data in textdata file %s is not grouped correctly\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 data table.\n");
+		return(MEMORY_ERROR);
+	}
+	if(fclose(fp)<0) {
+		fprintf(stdout,"WARNING: Failed to close input textfile %s.\n",filename);
+		fflush(stdout);
+	}
+	dz->itemcnt = n;
+	p  = dz->parray[0];
+	return(FINISHED);
+}
+
+/****************************** MIXMODEL_CONSISTENCY *********************************/
+
+int mixmodel_consistency(dataptr dz)
+{
+	infileptr fpq;
+	int exit_status;
+	int n, m, sndfilecnt, totalwords = 0, thischans, filestart;
+	double maxamp, maxloc;
+	int maxrep;
+	int getmax = 0, getmaxinfo = 0;
+	if(dz->infile->filetype != MIXFILE) {
+		sprintf(errstr,"The FIRST FILE must be a MIXFILE.\n");
+		return(USER_ERROR);
+	}
+	for(n=0;n<dz->linecnt;n++)
+		totalwords += dz->wordcnt[n];
+	filestart = totalwords;
+	dz->itemcnt = filestart;
+	totalwords = 0;
+	if((fpq = (infileptr)malloc(sizeof(struct filedata)))==NULL) {
+		sprintf(errstr,"INSUFFICIENT MEMORY to store header data of soundfiles.\n");
+		return(MEMORY_ERROR);
+	}
+	for(n=0,m=filestart,sndfilecnt=1;n<dz->linecnt;n++,m++,sndfilecnt++) {
+		if(sndfilecnt >= dz->infilecnt) {
+			sprintf(errstr,"Insufficient soundfiles entered\n");
+			return(DATA_ERROR);
+		}
+		if((sscanf(dz->wordstor[totalwords + 2],"%d",&thischans)) != 1) {
+			sprintf(errstr,"Failed to get channel count in line %d of mixfile\n",m);
+			return(DATA_ERROR);
+		}
+		if((exit_status = readhead(fpq,dz->ifd[sndfilecnt],dz->wordstor[m],&maxamp,&maxloc,&maxrep,getmax,getmaxinfo))<0)
+			return(exit_status);
+		if(fpq->channels != thischans) {
+			sprintf(errstr,"channel count in line %d of mixfile incompatible with entered file %s\n",m,dz->wordstor[m]);
+			return(DATA_ERROR);
+		}
+		totalwords += dz->wordcnt[n];
+	}
+	if(sndfilecnt != dz->infilecnt) {
+		sprintf(errstr,"Too many soundfiles entered\n");
+		return(DATA_ERROR);
+	}
+	return FINISHED;
+}
+
+/************** READ_INBETWEEN_RATIOS ***********/
+
+int read_inbetween_ratios(char *str,dataptr dz)
+{
+	char temp[200], *p;
+	double q;
+	int n;
+	int arraysize = BIGARRAY;
+	FILE *fp;
+
+	if((fp = fopen(str,"r"))==NULL) {
+		sprintf(errstr,"Failed to open file %s to read the inbetween ratios\n",str);
+		return(DATA_ERROR);
+	}
+	if((dz->brk = (double **)malloc(sizeof(double *)))==NULL) {
+		sprintf(errstr,"INSUFFICIENT MEMORY for grid data.\n");
+		return(MEMORY_ERROR);
+	}
+	if((dz->no_brk = (char *)malloc(sizeof(char)))==NULL) {
+		sprintf(errstr,"INSUFFICIENT MEMORY for grid data.\n");
+		return(MEMORY_ERROR);
+	}
+	if((dz->iparam = (int *)malloc(sizeof(int)))==NULL) {
+		sprintf(errstr,"INSUFFICIENT MEMORY for grid data.\n");
+		return(MEMORY_ERROR);
+	}
+	if((dz->brk[0] = (double *)malloc(arraysize * sizeof(double)))==NULL) {
+		sprintf(errstr,"INSUFFICIENT MEMORY for grid data.\n");
+		return(MEMORY_ERROR);
+	}
+	n = 0;
+	while(fgets(temp,200,fp)==temp) {
+		p = temp;
+		while(get_float_from_within_string(&p,&q)) {
+			if(n > MAXBETWEEN) {
+				sprintf(errstr,"Too many inbetween-ratios in file: maximum %d\n",MAXBETWEEN);
+				return(USER_ERROR);
+			}
+			if(n >= arraysize) {
+				arraysize += BIGARRAY;
+				if((dz->brk[0] = (double *)realloc((char *)dz->brk[0],arraysize * sizeof(double)))==NULL) {
+					sprintf(errstr,"INSUFFICIENT MEMORY for inbetween ratios.\n");
+					return(MEMORY_ERROR);
+				}
+			}
+			if(q < 0.0 || q > 1.0) {
+				sprintf(errstr,"Inbetween value (%lf) out of range (0-1) at item %d\n",q,n+1);
+				return(DATA_ERROR);
+			}
+			dz->brk[0][n] = q;
+			n++;
+		}
+	}						
+	if((dz->brk[0] = (double *)realloc((char *)dz->brk[0],n * sizeof(double)))==NULL) {
+		sprintf(errstr,"INSUFFICIENT MEMORY for reallocate storage for grid data.\n");
+		return(MEMORY_ERROR);
+	}
+	dz->no_brk[INBETW] = FALSE;
+	dz->iparam[INBETW] = n;
+	return(FINISHED);
+}
+
+/**************************** CYC_PREPROP *************************/
+
+int cyc_preprop(dataptr dz)
+{
+	int n0, n1, lastn0, lastn1, c0, c1, cyclecnt;
+	int OK;
+	float *ibuf0 = dz->sampbuf[0], *ibuf1 = dz->sampbuf[1];
+	int *cycs0, *cycs1, *lens0, *lens1;
+	int n;
+	int hifrq_cut = (int)round((double)dz->infile->srate/dz->param[BTWN_HFRQ]);
+
+	if((dz->ssampsread = fgetfbufEx(ibuf0,dz->buflen,dz->ifd[0],0)) <= 0) {
+		sprintf(errstr,"Failed to read data: Infile 1\n");
+		return(SYSTEM_ERROR);
+	}
+	if((dz->ssampsread = fgetfbufEx(ibuf1,dz->buflen,dz->ifd[1],0)) <= 0) {
+		sprintf(errstr,"Failed to read data: Infile 2\n");
+		return(SYSTEM_ERROR);
+	}
+	n0 = 0;
+	while(ibuf0[n0] == 0) {
+		if(++n0 >= dz->insams[0]) {
+			sprintf(errstr,"No signal in first soundfile\n");
+			return(DATA_ERROR);
+		}
+	}
+	if(ibuf0[n0] < 0) {		/* force positive phase */
+		for(n=0;n<dz->insams[0];n++)
+			ibuf0[n] = (float)(-ibuf0[n]);
+	}
+	n1 = 0;
+	while(ibuf1[n1] == 0) {
+		if(++n1 >= dz->insams[1]) {
+			sprintf(errstr,"No signal in second soundfile\n");
+			return(DATA_ERROR);
+		}
+	}
+	if(ibuf1[n1] < 0) {	/* force positive phase */
+		for(n=0;n<dz->insams[1];n++)
+			ibuf1[n] = (float)(-ibuf1[n]);
+	}
+	n0 = 0;
+	n1 = 0;
+	OK = 1;
+	c0 = 0;
+	c1 = 0;
+	while(OK) {				/* This loop counts wavesets, with upper frq limit */
+		lastn0 = n0;
+		c0++;
+		lastn1 = n1;
+		c1++;
+		while(OK) {
+			while(ibuf0[n0] >= 0) {
+				if(++n0 >= dz->insams[0]) {
+					OK = 0;
+					break;
+				}
+			}
+			if(OK) {
+				while(ibuf0[n0] < 0) {
+					if(++n0 >= dz->insams[0]) {
+						OK = 0;
+						break;
+					}
+				}
+			}
+			if(!OK || (n0 - lastn0 > hifrq_cut))
+				break;
+		}
+		while(OK) {
+			while(ibuf1[n1] >= 0) {
+				if(++n1 >= dz->insams[1]) {
+					OK = 0;
+					break;
+				}
+			}
+			if(OK) {
+				while(ibuf1[n1] < 0) {
+					if(++n1 >= dz->insams[1]) {
+						OK = 0;
+						break;
+					}
+				}
+			}
+			if(!OK  || (n1 - lastn1 > hifrq_cut))
+				break;
+		}
+	}
+
+	if(c1 != c0) {
+		sprintf(errstr,"Unequal cycle counts\n");
+		return(PROGRAM_ERROR);
+	}
+	cyclecnt = c0;
+	if((dz->lparray[0] = malloc(cyclecnt * sizeof(int)))==NULL) {
+		sprintf(errstr,"Insufficient memory to store cycle positions for sound 1\n");
+		return(MEMORY_ERROR);
+	}
+	if((dz->lparray[1] = malloc(cyclecnt * sizeof(int)))==NULL) {
+		sprintf(errstr,"Insufficient memory to store cycle positions for sound 2\n");
+		return(MEMORY_ERROR);
+	}
+	if((dz->lparray[2] = malloc((cyclecnt - 1) * sizeof(int)))==NULL) {
+		sprintf(errstr,"Insufficient memory to store cycle lengths for sound 1\n");
+		return(MEMORY_ERROR);
+	}
+	if((dz->lparray[3] = malloc((cyclecnt -1) * sizeof(int)))==NULL) {
+		sprintf(errstr,"Insufficient memory to store cycle lengths for sound 2\n");
+		return(MEMORY_ERROR);
+	}
+	cycs0 = dz->lparray[0];
+	cycs1 = dz->lparray[1];
+	lens0 = dz->lparray[2];
+	lens1 = dz->lparray[3];
+
+	n0 = 0;
+	n1 = 0;
+	c0 = 0;
+	c1 = 0;
+	OK = 1;
+	while(OK) {			/* This loop stores the zero-crossing positions */
+		cycs0[c0++] = n0;
+		cycs1[c1++] = n1;
+		lastn0 = n0;
+		lastn1 = n1;
+		if(c0 >= cyclecnt)
+			OK = 0;
+		else {
+			while(OK) {
+				while(ibuf0[n0] >= 0)
+					n0++;
+				while(ibuf0[n0] < 0)
+					n0++;
+				if(n0 - lastn0 > hifrq_cut)
+					break;
+			}
+			while(OK) {
+				while(ibuf1[n1] >= 0)
+					n1++;
+				while(ibuf1[n1] < 0)
+					n1++;
+				if(n1 - lastn1 > hifrq_cut)
+					break;
+			}
+		}
+	}
+	for(n = 1;n < cyclecnt; n++) {
+		lens0[n-1] = cycs0[n] - cycs0[n-1];
+		lens1[n-1] = cycs1[n] - cycs1[n-1];
+	}
+	dz->itemcnt = cyclecnt;
+	return FINISHED;
+}
+
+int invalid_data_items(char *str) 
+{
+	char *p = str;
+	while(*p != ENDOFSTR) {
+		if(!(isspace(*p) || isdigit(*p) || *p =='.' || *p == '-')) {
+			sprintf(errstr,"Invalid (non-numeric) data in balance function.\n");
+			return 1;
+		}
+		p++;
+	}
+	return 0;
+}

+ 370 - 0
dev/submix/inbetwee.c

@@ -0,0 +1,370 @@
+/*
+ * 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 <filetype.h>
+#include <modeno.h>
+#include <logic.h>
+#include <arrays.h>
+#include <mix.h>
+#include <cdpmain.h>
+
+#include <sfsys.h>
+
+#ifdef unix
+#define round(x) lround((x))
+#endif
+
+static int  do_inbetweening(int n,dataptr dz);
+static int	cyclesync_inbetweening(int n,dataptr dz);
+static int  do_between_mix(int insamps1,int insamps2,int n,float *buf1,float *buf2,float *obuf,dataptr dz);
+static int  make_betweenfile_name(int n,char *generic_name,char **filename);
+static int  make_tk_betweenfile_name(int n,char *generic_name,char **filename);
+
+/***************************** MIX_INBETWEEN ****************************/
+
+int mix_inbetween(dataptr dz)
+{
+	int exit_status;
+	int n;
+	char *filename;
+
+	for(n=0;n<dz->iparam[INBETW];n++) {
+		if(!sloom) {
+			if((exit_status = make_betweenfile_name(n,dz->wordstor[dz->extra_word],&filename))<0)
+				return(exit_status);
+		} else {
+			if((exit_status = make_tk_betweenfile_name(n,dz->wordstor[dz->extra_word],&filename))<0)
+				return(exit_status);
+			fprintf(stdout,"INFO: making inbetween sound '%s'\n",filename);
+			fflush(stdout);
+			dz->total_samps_read = 0L;
+		}
+		dz->process_type = UNEQUAL_SNDFILE;	/* allow sndfile to be created: suitable for truncation */
+		if((exit_status = create_sized_outfile(filename,dz))<0) {
+			sprintf(errstr,"Failed to open inbetween file %s\n",filename);
+			free(filename);
+			return(exit_status);
+		}							
+		switch(dz->process) {
+		case(MIXINBETWEEN):
+			exit_status = do_inbetweening(n,dz);
+			break;
+		case(CYCINBETWEEN):
+			exit_status = cyclesync_inbetweening(n,dz);
+			break;
+		}
+		if(exit_status < 0) {
+			free(filename);
+			return(exit_status);
+		}
+#ifdef NOTDEF
+		if((exit_status = truncate_outfile(dz))<0) {
+			free(filename);
+			return(exit_status);
+		}
+#endif
+		dz->process_type = EQUAL_SNDFILE;	/* prevents further attempts to truncate on quitting here */
+		dz->outfiletype  = SNDFILE_OUT;		/* allows header to be written  */
+		if((exit_status = headwrite(dz->ofd,dz))<0) {
+			free(filename);
+			return(exit_status);
+		}
+		dz->outfiletype = NO_OUTPUTFILE;
+		if((exit_status = reset_peak_finder(dz))<0)
+			return(exit_status);
+		if(sndcloseEx(dz->ofd) < 0) {
+			sprintf(errstr, "WARNING: Can't close output soundfile %s\n",filename);
+			free(filename);
+			return(SYSTEM_ERROR);
+		}
+		free(filename);
+		dz->ofd = -1;
+		dz->process_type = OTHER_PROCESS;	/* prevents program from trying to operate further on an outfile */
+	}
+	return(FINISHED);
+}
+
+/****************************** DO_INBETWEENING **************************/
+
+int do_inbetweening(int n,dataptr dz)
+{
+	int  exit_status;
+	float *buf1 = dz->sampbuf[0];
+	float *buf2 = dz->sampbuf[1];
+	float *obuf = dz->sampbuf[2];
+	int  samps_left1, samps_left2, gross_samps_left;
+	int  samps_read1 = 0, samps_read2 = 0, gross_samps_read, last_total_samps_written;
+
+	dz->total_samps_written = 0;
+
+	if(sndseekEx(dz->ifd[0],0L,0)<0	|| sndseekEx(dz->ifd[1],0L,0)<0) {
+		sprintf(errstr,"ERROR: Seek failure in input files: do_inbetweening()\n");
+		return(SYSTEM_ERROR);
+	}
+	samps_left1 = dz->insams[0];
+	samps_left2 = dz->insams[1];
+	gross_samps_left = max(samps_left1,samps_left2);
+
+	while(gross_samps_left > 0) {
+		memset((char *)obuf,0,(size_t)(dz->buflen * sizeof(float)));
+//TW UDPATES
+		memset((char *)buf1,0,(size_t)(dz->buflen * sizeof(float)));
+		memset((char *)buf2,0,(size_t)(dz->buflen * sizeof(float)));
+
+		if(samps_left1>0) {		
+			if((samps_read1 = fgetfbufEx(buf1, dz->buflen,dz->ifd[0],0))<0) {
+				sprintf(errstr,"Failed to read data: Infile 1: do_inbetweening()\n");
+				return(SYSTEM_ERROR);
+			}
+			samps_left1 -= samps_read1;
+		}
+		if(samps_left2>0) {		
+			if((samps_read2 = fgetfbufEx(buf2, dz->buflen,dz->ifd[1],0))<0) {
+				sprintf(errstr,"Failed to read data: Infile 2: do_inbetweening()\n");
+				return(SYSTEM_ERROR);
+			}
+			samps_left2 -= samps_read2;
+		}
+		gross_samps_read = max(samps_read1,samps_read2);
+		gross_samps_left = max(samps_left1,samps_left2);
+
+		if((exit_status = do_between_mix(samps_read1,samps_read2,n,buf1,buf2,obuf,dz))<0)
+			return(exit_status);
+
+		last_total_samps_written = dz->total_samps_written;
+		if(gross_samps_read > 0) {
+			if((exit_status = write_samps(obuf, gross_samps_read,dz))<0)
+				return(exit_status);
+		}
+		if(dz->total_samps_written - last_total_samps_written != gross_samps_read) {
+			sprintf(errstr,"Anomaly writing data to file: do_inbetweening()\n");
+			return(PROGRAM_ERROR);
+		}
+	}
+	return(FINISHED);
+}
+
+/***************************** DO_BETWEEN_MIX ***************************/
+
+int do_between_mix(int insamps1,int insamps2,int n,float *buf1,float *buf2,float *obuf,dataptr dz)
+{
+	register int i;
+	int minspan = min(insamps1,insamps2);
+	int maxspan = max(insamps1,insamps2);	
+	double ratio = dz->brk[INBETW][n], invratio = 1.0 - ratio;
+	int  overflow_samps;
+	if     (insamps1 > insamps2)	overflow_samps = 1;
+	else if(insamps2 > insamps1)	overflow_samps = 2;
+	else							overflow_samps = 0;
+	for(i = 0; i < minspan; i++)
+		obuf[i] = (float)((buf1[i] * invratio) + (buf2[i] * ratio));
+	switch(overflow_samps) {
+	case(1):	
+		while(i < maxspan) {
+			obuf[i] = (float)(buf1[i] * invratio);
+			i++;
+		}
+		break;
+	case(2):	
+		while(i < maxspan) {
+			obuf[i] = (float)(buf2[i] * ratio);	
+			i++;
+		}
+		break;
+	}
+	return(FINISHED);
+}
+
+/**************************** MAKE_BETWEENFILE_NAME *******************************/
+
+int make_betweenfile_name(int n,char *generic_name,char **filename)
+{
+	int hundreds, tens, units;
+//TW REVISED Dec 2002
+//	char *p;
+	if(n >= MAXBETWEEN) {
+		sprintf(errstr,"Counting error: make_betweenfile_name()\n");
+		return(PROGRAM_ERROR);
+	}
+	n++;
+	hundreds = n/100;
+	n       -= hundreds * 100;
+	tens     =  n/10;
+	n       -= tens * 10;
+	units    =  n;
+//TW REVISED Dec 2002
+//	sprintf(errstr,"%s",generic_name);
+//	p = errstr + strlen(errstr);
+//	*p++ = hundreds + INT_TO_ASCII;
+//	*p++ = tens     + INT_TO_ASCII;
+//	*p++ = units    + INT_TO_ASCII;
+//	*p = ENDOFSTR;
+	
+	strcpy(errstr,generic_name);
+	insert_new_number_at_filename_end(errstr,hundreds,0);
+	insert_new_number_at_filename_end(errstr,tens,0);
+	insert_new_number_at_filename_end(errstr,units,0);
+	
+	if((*filename = (char *)malloc((strlen(errstr) + 6) * sizeof(char)))==NULL) {
+		sprintf(errstr,	"INSUFFICIENT MEMORY for filename.\n");
+		return(MEMORY_ERROR);
+	}
+	strcpy(*filename,errstr);
+	return(FINISHED);
+}
+
+/**************************** MAKE_TK_BETWEENFILE_NAME *******************************/
+
+int make_tk_betweenfile_name(int n,char *generic_name,char **filename)
+{
+//TW REVISED Dec 2002
+//	char *p;
+	if(n >= MAXBETWEEN) {
+		sprintf(errstr,"Counting error: make_tk_betweenfile_name()\n");
+		return(PROGRAM_ERROR);
+	}
+	strcpy(errstr,generic_name);
+//TW REVISED Dec 2002
+	insert_new_number_at_filename_end(errstr,n,1);
+//	p = errstr + strlen(errstr);
+//	p--;
+//	sprintf(p,"%d",n);
+	if((*filename = (char *)malloc((strlen(errstr) + 6) * sizeof(char)))==NULL) {
+		sprintf(errstr,	"INSUFFICIENT MEMORY for filename.\n");
+		return(MEMORY_ERROR);
+	}
+	strcpy(*filename,errstr);
+	return(FINISHED);
+}
+
+/**************************** CYCLESYNC_INBETWEENING *******************************/
+
+int cyclesync_inbetweening(int m,dataptr dz)
+{
+	int exit_status, isneg;
+	int n0, n1, n, cyclecnt;
+	int outcnt = dz->iparam[INBETW] + 1;
+	float *ibuf0 = dz->sampbuf[0], *ibuf1 = dz->sampbuf[1], *obuf = dz->sampbuf[2];
+	int *cycs0, *cycs1, *lens0, *lens1;
+	int thislen, j, k;
+	double lendiff, ratio, invratio, incr0, incr1, indx0, indx1;
+	double endval, startval, diff, frac, val0, val1;
+	int aa, bb;
+
+	cycs0 = dz->lparray[0];
+	cycs1 = dz->lparray[1];
+	lens0 = dz->lparray[2];
+	lens1 = dz->lparray[3];
+	cyclecnt = dz->itemcnt - 1;		/* there is one less length then there are zero-crossings */
+	j = 0;
+	m++;
+	for(n = 0;n < cyclecnt; n++) {
+		n0 = cycs0[n];
+		n1 = cycs1[n];
+		lendiff = (double)(lens1[n] - lens0[n]);
+		isneg = 0;
+		if(lendiff < 0.0) {
+			isneg = 1;
+			lendiff = -lendiff;
+		}
+		ratio = (double)m/(double)outcnt;
+		invratio = 1.0 - ratio;
+
+		/* FIND LENGTH OF CYCLE BY INTERPOLATING BETWEEN LENGTHS OF CYCLES IN TWO FILES */
+		
+		if(isneg)
+			thislen = lens0[n] - (int)round(lendiff * ratio);
+		else
+			thislen = lens0[n] + (int)round(lendiff * ratio);
+
+		/* FIND INCREMENT OF FILE-READING INDEX FOR EACH FILE */
+
+		incr0 = (double)lens0[n]/(double)thislen;
+		incr1 = (double)lens1[n]/(double)thislen;
+
+		/* SET INITIAL VALUE OF THIS CYCLE BY INTERP ON 1st VAL IN CYCLE IN 2 FILES */
+
+		obuf[j] = (float)((ibuf0[n0] * invratio) + (ibuf1[n1] * ratio));
+		if(++j >= dz->buflen) {
+			if((exit_status = write_samps(obuf,dz->buflen,dz))<0)
+				return(exit_status);
+			j = 0;
+		}
+
+		/* READ REST OF CYCLES */
+
+		indx0 = 0.0;
+		indx1 = 0.0;
+		for(k = 1; k < thislen; k ++) {
+			indx0 += incr0;
+			indx1 += incr1;
+
+			/* GET A VALUE FROM EACH FILE BY INTERPOLATED READING */
+			
+			aa = (int)round(n0 + floor(indx0));
+			startval = (double)ibuf0[aa];
+			if((bb = aa + 1) >= cycs0[n+1])	/* If interp goes beyond cycle-end, treat endval as 0 */
+				endval = 0.0;
+			else
+				endval = (double)ibuf0[bb];
+			diff = endval - startval;
+			frac = fmod(indx0,1.0);
+			val0 = startval + (diff * frac);
+
+			aa = (int)round(n1 + floor(indx1));
+			startval = (double)ibuf1[aa];
+			if((bb = aa + 1) >= cycs1[n+1])	/* If interp goes beyond cycle-end, treat endval as 0 */
+				endval = 0.0;
+			else
+				endval = (double)ibuf1[bb];
+			diff = endval - startval;
+			frac = fmod(indx1,1.0);
+			val1 = startval + (diff * frac);
+
+		/* SET OUTVAL BY INTERPOLATING BETWEEN VALS GOT FROM BOTH FILES */
+
+			obuf[j] = (float)((val0 * invratio) + (val1 * ratio));
+			if(++j >= dz->buflen) {
+				if((exit_status = write_samps(obuf,dz->buflen,dz))<0)
+					return(exit_status);
+				j = 0;
+			}
+		}
+	}
+	if(j > 0) {
+		if((exit_status = write_samps(obuf,j,dz))<0)
+			return(exit_status);
+	}
+	return(FINISHED);
+}

+ 238 - 0
dev/submix/main.c

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

+ 1043 - 0
dev/submix/mixmerge.c

@@ -0,0 +1,1043 @@
+/*
+ * 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 <filetype.h>
+#include <arrays.h>
+#include <mix.h>
+#include <cdpmain.h>
+
+#include <sfsys.h>
+
+#include <mix.h>
+#include <limits.h>
+
+#ifdef unix
+#define round(x) lround((x))
+#endif
+
+static int    do_mix2(float *inbuf1,float *inbuf2,double *dblbuf,float *obuf,dataptr dz);
+static int    do_mix2_stagger(float *inbuf1,float *obuf,dataptr dz);
+static int    do_mix2_skip(dataptr dz);
+
+static int 	  cross_stagger(int *total_samps_read,int *end_of_samps_to_process,float *obuf,dataptr dz);
+static int 	  pre_crossmix(int *samps_read2,int *cross_end,int *total_samps_read,
+						int *end_of_samps_to_process,float *inbuf1,float *inbuf2,float *obuf,dataptr dz);
+static int 	  crossmix(int *samps_read2,int *cross_end,int *total_samps_read,int *end_of_samps_to_process,
+						float *inbuf1,float *inbuf2,float *obuf,dataptr dz);
+static int 	  cross(int startcross,int endcross,float *inbuf1,float *inbuf2,float *obuf,dataptr dz);
+static double read_cos(double d,dataptr dz);
+static int 	  advance_in_files(int *samps_read2,int *total_samps_read,int *end_of_samps_to_process,
+						int *cross_end,float *inbuf1,float *inbuf2,dataptr dz);
+static void   copy_to_channel(float *inbuf,float *obuf,int sampcnt,int outchans);
+
+static int renew_bufs(int typ,float *buf0,float *buf1,dataptr dz);
+static int do_stitch(int typ,int *mbf,int *sbf,float *buf0,float *buf1,double atten,int bflen,dataptr dz);
+static int flush_bufs(int typ,int *mbf,int *sbf,float *buf0,float *buf1,dataptr dz);
+
+//TW JAN 2010: FOR MULTICHANNEL
+//static int read_automix_sound(int *activebuf,int *chans,int chantype,dataptr dz);
+static int read_automix_sound(int *activebuf,dataptr dz);
+
+/************************************ MIXTWO ************************************/
+
+int mixtwo(dataptr dz)
+{
+	int exit_status;
+	char tempfnam[200];
+	double *dblbuf = (double *) dz->sampbuf[3];		/* RWD I suppose we can keep this...*/
+	float *inbuf1  = dz->sampbuf[0];
+	float *inbuf2  = dz->sampbuf[1];
+	float *obuf    = dz->sampbuf[2];
+	int extra_skip;
+
+	if(dz->iparam[MIX_STTA] > 0) {
+		if((sndseekEx(dz->ifd[0],dz->iparam[MIX_STTA],0))<0) {
+			sprintf(errstr,"sndseek() failed in first file.\n");
+			return(SYSTEM_ERROR);
+		}
+	}
+	if((extra_skip = dz->iparam[MIX_STTA] - dz->iparam[MIX_STAGGER]) > 0) {
+		if((dz->iparam[MIX_SKIP] += extra_skip) > dz->insams[1]) {
+			sprintf(errstr,"Mix skips the 2nd file entirely.\n");
+			return(DATA_ERROR);
+		}
+	}
+	if(dz->iparam[MIX_SKIP] > 0) {
+		if((exit_status = do_mix2_skip(dz))<0)
+			return(exit_status);
+	}
+	if((dz->iparam[MIX_STAGGER] -= dz->iparam[MIX_STTA]) > 0) {
+		if((exit_status = do_mix2_stagger(inbuf1,obuf,dz))<0)
+			return(exit_status);
+	} else {
+		dz->iparam[MIX_STAGGER] = 0;
+	}
+	if((exit_status = do_mix2(inbuf1,inbuf2,dblbuf,obuf,dz))<0)
+		return(exit_status);
+	if(is_converted_to_stereo >= 0) {
+		strcpy(tempfnam,snd_getfilename(dz->ifd[is_converted_to_stereo]));
+		sndcloseEx(dz->ifd[is_converted_to_stereo]);
+		if(remove(tempfnam)<0)
+			fprintf(stdout, "ERROR: %s: Can't remove temporary stereo soundfile %s.\n",sferrstr(),tempfnam);
+		dz->ifd[is_converted_to_stereo] = -1;
+	}
+	return(FINISHED);
+}
+
+/************************************ DO_MIX2_SKIP ************************************/
+
+int do_mix2_skip(dataptr dz)
+{
+	if((sndseekEx(dz->ifd[1],dz->iparam[MIX_SKIP],0))<0) {
+		sprintf(errstr,"sndseek() failed: do_mix2_skip()\n");
+		return(SYSTEM_ERROR);
+	}
+	return(FINISHED);
+}
+
+/************************************ DO_MIX2_STAGGER ************************************/
+
+int do_mix2_stagger(float *inbuf1,float *obuf,dataptr dz)
+{
+	int exit_status;
+	int stagbufs,stagsamps, n;
+//TW
+	int  shsecsize = F_SECSIZE;	   /* RWD I suppose we can keep this...*/
+	int samps_read;
+
+
+	stagbufs  = dz->iparam[MIX_STAGGER]/dz->buflen;
+	stagsamps = dz->iparam[MIX_STAGGER] % dz->buflen;
+	/*RWD do we still need this test? Is it still kosher ? */
+	if(((stagsamps/shsecsize)*shsecsize) != stagsamps) {
+		sprintf(errstr,"Error in sector arithmetic: do_mix2_stagger()\n");
+		return(PROGRAM_ERROR);
+	}
+	while(stagbufs > 0) {
+		if((samps_read = fgetfbufEx(inbuf1,dz->buflen,dz->ifd[0],0)) < dz->buflen) {
+			if(samps_read < 0) {
+				sprintf(errstr,"Sound read error.\n");
+				return(SYSTEM_ERROR);
+			} else {			
+				sprintf(errstr,"Problem 1 reading from file1 during stagger\n");
+				return(PROGRAM_ERROR);
+			}
+		}
+		for(n=0;n<dz->buflen;n++)
+			obuf[n]  = (float)(inbuf1[n] * dz->param[MIX2_GAIN1]);
+		if((exit_status = write_samps(obuf,dz->buflen,dz))<0)
+			return(exit_status);
+		stagbufs--;
+	}			
+	if(stagsamps) {
+		if((samps_read = fgetfbufEx(inbuf1,stagsamps,dz->ifd[0],0)) < stagsamps) {
+			if(samps_read < 0) {
+				sprintf(errstr,"Sound read error.\n");
+				return(SYSTEM_ERROR);
+			} else {			
+				sprintf(errstr,"Problem 2 reading from file1 during stagger\n");
+				return(PROGRAM_ERROR);
+			}
+		}
+		for(n=0;n<stagsamps;n++)
+			obuf[n] = (float)(inbuf1[n]  * dz->param[MIX2_GAIN1]);
+		if((exit_status = write_samps(obuf,stagsamps,dz))<0)
+			return(exit_status);
+	}
+	return(FINISHED);
+}
+
+/************************************ DO_MIX2 ************************************/
+
+int do_mix2(float *inbuf1,float *inbuf2,double *dblbuf,float *obuf,dataptr dz)
+{
+	int exit_status;
+	int gross_samps_read = 1, gross_total_samps_read = 0, cutoff_in_buf;
+	int samps_read1, samps_read2, ssampsread, ssampsread1, ssampsread2, n;
+	unsigned int cutoff_samps;
+
+	cutoff_samps  = (dz->iparam[MIX_DURA] - dz->iparam[MIX_STTA]) - dz->iparam[MIX_STAGGER];
+	if((cutoff_samps) <= 0)
+		cutoff_samps = UINT_MAX;
+
+	
+	while(gross_samps_read > 0) {
+		memset((char *)inbuf1,0,(size_t)(dz->buflen * sizeof(float)));
+		memset((char *)inbuf2,0,(size_t)(dz->buflen * sizeof(float)));
+		memset((char *)dblbuf,0,(size_t)(dz->buflen * sizeof(double)));
+		if((samps_read1 = fgetfbufEx(inbuf1,dz->buflen,dz->ifd[0],0))<0) {
+			sprintf(errstr,"Problem reading from file1 during mix.\n");
+			return(SYSTEM_ERROR);
+		}
+		if((samps_read2 = fgetfbufEx(inbuf2,dz->buflen,dz->ifd[1],0))<0) {
+			sprintf(errstr,"Problem reading from file1 during mix.\n");
+			return(SYSTEM_ERROR);
+		}
+		if((gross_samps_read = max(samps_read1,samps_read2))<=0)
+			break;
+		gross_total_samps_read += gross_samps_read;
+
+		if(cutoff_samps > (unsigned int) gross_total_samps_read)
+			cutoff_in_buf = gross_samps_read;
+		else 
+			cutoff_in_buf = (cutoff_samps % dz->buflen);
+
+		ssampsread1 = samps_read1;
+		ssampsread1 = min(ssampsread1,cutoff_in_buf);
+
+		if(ssampsread1) {
+			for(n=0;n<ssampsread1;n++)
+				dblbuf[n] = inbuf1[n] * dz->param[MIX2_GAIN1];
+			if((ssampsread2 = samps_read2)>0) {
+				ssampsread2 = min(ssampsread2,cutoff_in_buf);
+				for(n=0;n<ssampsread2;n++)
+		 			dblbuf[n] += inbuf2[n] * dz->param[MIX2_GAIN2];
+			}
+		} else {
+			ssampsread2 = samps_read2;
+			ssampsread2 = min(ssampsread2,cutoff_in_buf);
+			for(n=0;n<ssampsread2;n++)
+	 			dblbuf[n] = inbuf2[n] * dz->param[MIX2_GAIN2];
+		}
+		ssampsread = gross_samps_read;
+		ssampsread = min(ssampsread,cutoff_in_buf);
+		for(n=0;n<ssampsread;n++)
+			obuf[n] = (float)dblbuf[n];
+		if(ssampsread > 0) {
+			if((exit_status = write_samps(obuf,ssampsread,dz))<0)
+				return(exit_status);
+		}
+		if((unsigned int)gross_total_samps_read >= cutoff_samps)
+			break;
+	}
+	return(FINISHED);
+}
+
+
+/******************************** MIX_CROSS **********************************/
+
+int mix_cross(dataptr dz)
+{
+	int exit_status;
+	float *inbuf1 = dz->sampbuf[0];
+	float *inbuf2 = dz->sampbuf[1];
+	float *obuf   = dz->sampbuf[0];
+	int samps_read2 = 0;
+	int end_of_samps_to_process = dz->iparam[MCR_END];
+	int cross_end = 0;
+	int total_samps_read = 0;
+	int remain;
+	if(end_of_samps_to_process <= 0) {
+		sprintf(errstr,"Accounting problem: mix_cross()\n");
+		return(PROGRAM_ERROR);
+	}
+	display_virtual_time(0,dz);
+	if(dz->iparam[MCR_STAGGER]>0 && (exit_status = cross_stagger(&total_samps_read,&end_of_samps_to_process,obuf,dz))<0)
+		return(exit_status);
+	if(end_of_samps_to_process <=0) {
+		sprintf(errstr,"Accounting problem 1: mix_cross()\n");
+		return(PROGRAM_ERROR);
+	}
+	while(total_samps_read <= dz->iparam[MCR_BEGIN]) {
+		if((exit_status = pre_crossmix
+		(&samps_read2,&cross_end,&total_samps_read,&end_of_samps_to_process,inbuf1,inbuf2,obuf,dz))<0)
+			return(exit_status);
+		if(exit_status == FINISHED)
+			break;
+	}
+	if(end_of_samps_to_process <=0) {
+		sprintf(errstr,"Accounting problem 2: mix_cross()\n");
+		return(PROGRAM_ERROR);
+	}
+	remain = samps_read2 - end_of_samps_to_process;
+	if(remain < 0) {
+		do {
+			if((exit_status = crossmix
+			(&samps_read2,&cross_end,&total_samps_read,&end_of_samps_to_process,inbuf1,inbuf2,obuf,dz))<0)
+				return(exit_status);
+		} while((remain = samps_read2 - end_of_samps_to_process) < 0);
+	}
+	if(remain)
+		memmove((char *)(obuf + cross_end),(char *)(inbuf2 + cross_end),(size_t)(remain * sizeof(float)));
+	if(samps_read2 > 0) {
+		if((exit_status = write_samps(obuf,samps_read2,dz))<0)
+			return(exit_status);
+	}
+	while((samps_read2 = fgetfbufEx(obuf, dz->buflen,dz->ifd[1],0))>0) {
+		if((exit_status = write_samps(obuf,samps_read2,dz))<0)
+			return(exit_status);
+	}
+	if(samps_read2<0) {
+		sprintf(errstr,"Sound read error.\n");
+		return(SYSTEM_ERROR);
+	}
+	return(FINISHED);
+}
+
+/******************************** CROSS **********************************/
+
+int cross(int startcross,int endcross,float *inbuf1,float *inbuf2,float *obuf,dataptr dz)
+{
+	double xxx, yyy;
+	register int i;
+	int crosindex  = dz->iparam[MCR_INDEX];
+	double crosfact = dz->param[MCR_CROSFACT];
+	double powfac;
+	switch(dz->iparam[MCR_CONTOUR]) {
+	case(MCR_LINEAR):	  		/* LINEAR */
+		for(i=startcross;i<endcross;i++) {
+			xxx = (double)crosindex * crosfact;
+			yyy = 1.0 - xxx;
+			obuf[i] = (float)((inbuf1[i] * yyy) + (inbuf2[i] * xxx));
+			crosindex++;
+		}
+		break;
+	case(MCR_COSIN):			   /* COSIN */
+		for(i=startcross;i<endcross;i++) {
+			xxx = (double)crosindex * crosfact;
+			xxx = read_cos(xxx,dz);
+			yyy = 1.0 - xxx;
+			obuf[i] = (float)((inbuf1[i] * yyy) + (inbuf2[i] * xxx));
+			crosindex++;
+		}
+		break;
+	case(MCR_SKEWED):		  	/* SKEWED COSIN */
+		powfac   = dz->param[MCR_POWFAC];
+		for(i=startcross;i<endcross;i++) {
+			xxx = (double)crosindex * crosfact;
+			xxx = pow(xxx,powfac);
+			xxx = read_cos(xxx,dz);
+			yyy = 1.0 - xxx;
+			obuf[i] = (float)((inbuf1[i] * yyy) + (inbuf2[i] * xxx));
+			crosindex++;
+		}
+		break;
+	}
+	dz->iparam[MCR_INDEX] = crosindex;
+	return(FINISHED);
+}
+
+/************************** READ_COS **********************/
+
+double read_cos(double d,dataptr dz)
+{
+	int j, k;
+	double frac, diff;
+	double *costable = dz->parray[MCR_COSTABLE];
+	d *= (double)MCR_TABLEN;
+	j = (int)d;	/* TRUNCATE */
+	if((k=j+1)>MCR_TABLEN)
+		return(1.0);
+	frac = d - (double)j;
+	diff = costable[k] - costable[j];
+	frac *= diff;
+	return(costable[j] + frac);
+}
+
+/************************** CROSSMIX **********************/
+
+int crossmix(int *samps_read2,int *cross_end,int *total_samps_read,int *end_of_samps_to_process,
+float *inbuf1,float *inbuf2,float *obuf,dataptr dz)
+{
+	int   exit_status;
+	if((exit_status = advance_in_files
+	(samps_read2,total_samps_read,end_of_samps_to_process,cross_end,inbuf1,inbuf2,dz))<0)
+		return(exit_status);
+	*cross_end = min(*cross_end,dz->buflen);
+	if((exit_status = cross(0L,*cross_end,inbuf1,inbuf2,obuf,dz))<0)
+		return(exit_status);
+	if(*cross_end==dz->buflen) {
+		if((exit_status = write_samps(obuf,dz->buflen,dz))<0)
+			return(exit_status);
+	}
+	return(FINISHED);
+}
+
+/************************** PRE_CROSSMIX **********************/
+
+int pre_crossmix(int *samps_read2,int *cross_end,int *total_samps_read,
+int *end_of_samps_to_process,float *inbuf1,float *inbuf2,float *obuf,dataptr dz)
+{
+	int   exit_status;
+	int  ssampstart, cross_start;
+	int  last_total_samps_read = *total_samps_read;
+	if((exit_status = advance_in_files
+	(samps_read2,total_samps_read,end_of_samps_to_process,cross_end,inbuf1,inbuf2,dz))<0)
+		return(exit_status);
+	if(*total_samps_read > dz->iparam[MCR_BEGIN]) {
+		if((cross_start = dz->iparam[MCR_BEGIN] - last_total_samps_read)>=dz->buflen) {
+			sprintf(errstr,"Accounting problem: pre_crossmix()\n");
+			return(PROGRAM_ERROR);
+		}
+		ssampstart = cross_start;
+		*cross_end = min(*cross_end,dz->buflen);
+		if((exit_status = cross(ssampstart,*cross_end,inbuf1,inbuf2,obuf,dz))<0)
+			return(exit_status);
+		if(*cross_end < dz->buflen)
+			return(FINISHED);
+	}
+	if((exit_status= write_samps(obuf,dz->buflen,dz))<0)
+		return(exit_status);
+	return(CONTINUE);
+}
+
+/************************** CROSS_STAGGER **********************/
+
+int cross_stagger(int *total_samps_read,int *end_of_samps_to_process,float *obuf,dataptr dz)
+{
+	int exit_status;
+	int  samps_read1, samps_written;
+	int stagger = dz->iparam[MCR_STAGGER];
+	int stagbufs  = stagger/dz->buflen;
+	int stagsamps = stagger%dz->buflen;
+//TW SAFE??
+//	if(((stagsamps/F_SECSIZE)*F_SECSIZE)!=stagsamps) {
+//		sprintf(errstr,"Sector accounting problem: cross_stagger()\n");
+//		return(PROGRAM_ERROR);
+//	}
+	while(stagbufs>0) {
+		if((samps_read1 = fgetfbufEx(obuf, dz->buflen,dz->ifd[0],0))!=dz->buflen) {
+			if(samps_read1<0) {
+				sprintf(errstr,"Sound read error.\n");
+				return(SYSTEM_ERROR);
+			} else {
+				sprintf(errstr,"First file read failed:1: cross_stagger()\n");
+				return(PROGRAM_ERROR);
+			}
+		}
+//		if((samps_written = fputfbufEx(obuf,dz->buflen,dz->ofd))!=dz->buflen) {
+		if((exit_status = write_samps_no_report(obuf,dz->buflen,&samps_written,dz))<0)
+			return(exit_status);
+		if(samps_written!=dz->buflen) { 
+			sprintf(errstr,"Problem writing samps:1: cross_stagger()\n");
+			return(PROGRAM_ERROR);
+		}
+		dz->total_samps_written  += samps_written;
+		*total_samps_read        += dz->buflen;
+ 		*end_of_samps_to_process -= dz->buflen;
+		stagbufs--;
+	}
+	if(stagsamps > 0) {
+		if((samps_read1 = fgetfbufEx(obuf, stagsamps,dz->ifd[0],0))!=stagsamps) {
+			if(samps_read1<0) {
+				sprintf(errstr,"Sound read error.\n");
+				return(SYSTEM_ERROR);
+			} else {
+				sprintf(errstr,"First file read failed:2: cross_stagger()\n");
+				return(PROGRAM_ERROR);
+			}
+		}
+//		if((samps_written = fputfbufEx(obuf,stagsamps,dz->ofd))!=stagsamps) {
+		if((exit_status = write_samps_no_report(obuf,stagsamps,&samps_written,dz) )< 0)
+			return(exit_status);
+		if(samps_written != stagsamps) {			
+			sprintf(errstr,"Problem writing samps:2: cross_stagger()\n");
+			return(PROGRAM_ERROR);
+		}
+		dz->total_samps_written  += stagsamps;
+		*total_samps_read        += stagsamps;
+ 		*end_of_samps_to_process -= stagsamps;
+	}
+	return(FINISHED);
+}
+
+/************************** ADVANCE_IN_FILES **********************/
+
+int advance_in_files(int *samps_read2,int *total_samps_read,int *end_of_samps_to_process,
+int *cross_end,float *inbuf1,float *inbuf2,dataptr dz)
+{
+	int samps_read1;	
+
+	*end_of_samps_to_process = dz->iparam[MCR_END] - *total_samps_read;
+	if((samps_read1 = fgetfbufEx(inbuf1, dz->buflen,dz->ifd[0],0))<0) {
+		sprintf(errstr,"First file read failed: advance_in_files()\n");
+		return(SYSTEM_ERROR);
+	}
+	if((*samps_read2 = fgetfbufEx(inbuf2, dz->buflen,dz->ifd[1],0))<0) {
+		sprintf(errstr,"Second file read failed: advance_in_files()\n");
+		return(SYSTEM_ERROR);
+	}
+	*total_samps_read += *samps_read2;	/* BECAUSE FADE IS TOWARDS FILE 2: and fade must END before then */
+	*cross_end = *end_of_samps_to_process;
+	return(FINISHED);
+}
+
+/************************************ MIX_INTERL ************************************/
+
+int mix_interl(dataptr dz)
+{
+	int exit_status;
+	float *inbuf  = dz->sampbuf[0];
+	float *outbuf = dz->sampbuf[1];	/* NB this buffer is large enough to take output */
+	
+	int samps_read, samps_left[MAX_MI_OUTCHANS];
+	int n, gross_samps_read, gross_samps_left = 0, last_total_samps_written, samps_to_write;
+
+	for(n=0;n<dz->infilecnt;n++)  {
+		samps_left[n] = dz->insams[n];
+		gross_samps_left = max(gross_samps_left,samps_left[n]);
+	}
+
+	while(gross_samps_left) {
+		memset((char *)outbuf,0,(size_t)(dz->buflen * dz->infilecnt * sizeof(float)));
+		gross_samps_read = 0;
+		gross_samps_left = 0;
+		for(n=0;n<dz->infilecnt;n++) {
+			if(samps_left[n]>0) {
+	 			if((samps_read = fgetfbufEx(inbuf,dz->buflen,dz->ifd[n],0))<0) {
+					sprintf(errstr,"Failed to read data from file %d: mix_interl()\n",n+1);
+					return(SYSTEM_ERROR);
+				}
+				samps_left[n] -= samps_read;
+				copy_to_channel(inbuf,outbuf+n,samps_read,dz->infilecnt);
+				gross_samps_read = max(gross_samps_read,samps_read);
+				gross_samps_left = max(gross_samps_left,samps_left[n]);
+			}
+		}
+		samps_to_write =  gross_samps_read*dz->infilecnt;
+		last_total_samps_written = dz->total_samps_written;
+		if(samps_to_write) {
+			if((exit_status = write_samps(outbuf,samps_to_write,dz))<0)
+				return(exit_status);
+		}
+		if(dz->total_samps_written - last_total_samps_written != samps_to_write) {
+			sprintf(errstr,"Problem writing data: mix_interl()\n");
+			return(PROGRAM_ERROR);
+		}
+	}
+// TW
+//	/*RWD too late here! */
+//	dz->infile->channels = dz->infilecnt;	/* Force output to final channel-count */
+
+	return(FINISHED);
+}
+
+/************************************ COPY_TO_CHANNEL ************************************/
+
+void copy_to_channel(float *inbuf,float *outbuf,int sampcnt,int outchans)
+{
+	int n, m;
+	for(n=0,m=0;n<sampcnt;n++,m+=outchans)
+		outbuf[m] = inbuf[n];	
+}
+
+/******************************** CROSS_STITCH *****************************/
+
+int cross_stitch(dataptr dz) {
+	double srate = (double)dz->infile->srate;
+	int n = 0, mbf, sbf, procend, input_procend;
+	int exit_status, t = 0,v=0,m=0,done = 0;
+	double *brrk = NULL, thisval, nextval = 0.0, valincr, atten = 0.0, val_here;
+	double time_here, lastrtime,nextrtime, lastval, tratio;
+
+	int nexttime = 0, thistime;
+	float *buf0 = dz->sampbuf[0];
+	float *buf1 = dz->sampbuf[1];
+	int typ;
+	int input_procskip, samps_to_skip = 0;
+
+	if(dz->param[MIX_SKEW] <= dz->param[MIX_SKIP]) {
+		sprintf(errstr,"Start and end times of mix are reversed, or equal.\n");
+		return(DATA_ERROR);
+	}
+	/* RWD make this samps */
+	dz->tempsize = 
+	(int)round((dz->param[MIX_SKEW] - dz->param[MIX_SKIP]) * (double)(srate * 
+	max(dz->infile->channels,dz->otherfile->channels)));
+	display_virtual_time(0,dz);
+	if(dz->infile->channels > 2) {
+		typ = 4;	/* multichan multichan */
+	} else if(dz->infile->channels==1) {
+		if(dz->otherfile->channels==1) {
+			typ = 0; 	/* mono mono */
+		} else {	
+			typ = 1;	/* mono stereo */
+		}
+	} else {
+		if(dz->otherfile->channels==1) {
+			typ = 2; 	/* stereo mono */
+		} else {	
+			typ = 3;	/* stereo stereo */
+		}
+	}
+	procend = dz->insams[0]/dz->infile->channels;
+	input_procend = (int)round(dz->param[MIX_SKEW] * srate);
+	procend = min(procend,input_procend);
+
+	if((input_procskip = (int)round(dz->param[MIX_SKIP] * srate)) > 0) {
+		samps_to_skip = input_procskip * dz->infile->channels;
+//TW SAFE??
+//		samps_to_skip /= (F_SECSIZE * dz->infile->channels);
+//		samps_to_skip *= (F_SECSIZE * dz->infile->channels);	/* skip to nearest sector */
+
+		if((sndseekEx(dz->ifd[0],samps_to_skip,0))<0) {
+			sprintf(errstr,"seek() failed searching for startpoint of mix in first file.\n");
+			return(SYSTEM_ERROR);
+		}
+		samps_to_skip = input_procskip * dz->otherfile->channels;
+//TW SAFE??
+//		samps_to_skip /= (F_SECSIZE * dz->otherfile->channels);
+//		samps_to_skip *= (F_SECSIZE * dz->otherfile->channels);	/* skip to nearest sector */
+
+		if((sndseekEx(dz->ifd[1],samps_to_skip,0))<0) {
+			sprintf(errstr,"sndseek() failed searching for startpoint of mix in second file.\n");
+			return(SYSTEM_ERROR);
+		}
+	}
+	if(dz->brksize[MIX_STAGGER]) {
+		brrk = dz->brk[MIX_STAGGER];
+		if(input_procskip > 0) {
+			thistime = samps_to_skip/dz->otherfile->channels;
+			time_here = (double)thistime/srate;
+			m = 0;
+			while(brrk[m] <= time_here) {
+				m += 2;
+				if(m >= dz->brksize[MIX_STAGGER]) {			/* IF beyond end of brk */
+					dz->param[MIX_STAGGER] = brrk[m-1];		/* set atten to last brkval */
+					dz->brksize[MIX_STAGGER] = 0;			/* set brkfile as not existing */
+					break;
+				}
+			}
+			if(dz->brksize[MIX_STAGGER]) {					/* If still in brkfile */
+				lastrtime = brrk[m-2];						/* Note previous brkpnt-time+val */
+				lastval   = brrk[m-1];
+				n = thistime;								/* set the internal sample counter to here */
+				t = m;										/* set pointer for (following) brkpnt times */
+				v = m+1;									/* set pointer for (following) brkpnt vals */
+				m /= 2;										/* set position in brk-pairs */
+				nextrtime = brrk[t];
+				nexttime  = round(nextrtime * srate);
+				nextval   = brrk[v];						
+															/* calc value at start-time */
+				tratio = (double)(time_here - lastrtime)/(double)(nextrtime - lastrtime);
+				val_here = ((nextval - lastval) * tratio) + lastval;
+				nexttime = thistime;						/* set up starting time & val */
+				nextval  = val_here;
+			}								
+		} else {
+			nexttime = round(brrk[0] * srate);
+			nextval  = brrk[1];	/* set up starting time & val */
+			n = 0;			   	/* set the internal sample counter to start */
+			t = 2;			   	/* set pointer for (following) brkpnt times */
+			v = 3;			   	/* set pointer for (following) brkpnt vals */
+			m = 1;			   	/* set position in brk-pairs */
+		}
+	} else {
+		n = input_procskip;
+	}
+	memset((char *)buf0,0,dz->buflen * dz->infile->channels* sizeof(float));
+	memset((char *)buf1,0,dz->buflen * dz->otherfile->channels * sizeof(float));
+	if((fgetfbufEx(buf0,dz->buflen * dz->infile->channels,dz->ifd[0],0)) < 0) {
+		sprintf(errstr,"Can't read samps from 1st soundfile.\n");
+		return(SYSTEM_ERROR);
+	}
+	if((fgetfbufEx(buf1,dz->buflen * dz->otherfile->channels,dz->ifd[1],0)) < 0) {
+		sprintf(errstr,"Can't read samps from 2nd soundfile.\n");
+		return(SYSTEM_ERROR);
+	}
+	mbf = 0;
+	sbf = 0;
+	if(dz->brksize[MIX_STAGGER] == 0)
+		atten = dz->param[MIX_STAGGER];
+	else {
+		for(; m < dz->brksize[MIX_STAGGER]; m++,t+=2,v+=2) {
+			thistime = nexttime;
+			thisval  = nextval;
+			nexttime = round(brrk[t] * srate);
+			nextval  = brrk[v];
+			valincr = (nextval - thisval)/(double)(nexttime - thistime);
+			if(nexttime >= procend) {		/* IF brktable extends beyond end of sound */
+				nexttime = procend;
+				done = 1;
+			}
+			atten = thisval;
+			while(n < nexttime) {
+  				if(do_stitch(typ,&mbf,&sbf,buf0,buf1,atten,dz->buflen,dz)) {
+					if((exit_status = renew_bufs(typ,buf0,buf1,dz))<0)
+						return(exit_status);
+					mbf = 0;
+					sbf = 0;
+				}
+				atten += valincr;
+				n++;
+			}
+			if(done)				   	/* IF brktable extends beyond end of sound: break */
+				break;
+		}
+	}
+	while(n < procend) {				/* IF brktable stops short of end of sound, or no brktable */
+		if(do_stitch(typ,&mbf,&sbf,buf0,buf1,atten,dz->buflen,dz)) {
+			if((exit_status = renew_bufs(typ,buf0,buf1,dz))<0)
+				return(exit_status);
+			mbf = 0;
+			sbf = 0;
+		}
+		n++;
+	}
+	return flush_bufs(typ,&mbf,&sbf,buf0,buf1,dz);
+}
+
+/******************************** DO_STITCH *****************************/
+
+int do_stitch(int typ,int *mbf,int *sbf,float *buf0,float *buf1,double atten,int bflen,dataptr dz)
+{
+	int bufdone = 0, k;
+	switch(typ) {
+	case(0):
+		buf0[*mbf] = (float)((buf0[*mbf] * atten) + (buf1[*mbf] * (1.0 - atten)));
+		if(++(*mbf) >=  bflen)
+			bufdone = 1;
+		break;
+	case(1):
+		buf1[*sbf] = (float)((buf0[*mbf] * atten) + (buf1[*sbf] * (1.0 - atten)));
+		(*sbf)++;
+		buf1[*sbf] = (float)((buf0[*mbf] * atten) + (buf1[*sbf] * (1.0 - atten)));
+		(*sbf)++;
+		if(++(*mbf) >=  bflen)
+			bufdone = 1;
+		break;
+	case(2):
+		buf0[*sbf] = (float)((buf0[*sbf] * atten) + (buf1[*mbf] * (1.0 - atten)));
+		(*sbf)++;
+		buf0[*sbf] = (float)((buf0[*sbf] * atten) + (buf1[*mbf] * (1.0 - atten)));
+		(*sbf)++;
+		if(++(*mbf) >=  bflen)
+			bufdone = 1;
+		break;
+	case(3):
+		buf0[*sbf] = (float)((buf0[*sbf] * atten) + (buf1[*sbf] * (1.0 - atten)));
+		(*sbf)++;
+		buf0[*sbf] = (float)((buf0[*sbf] * atten) + (buf1[*sbf] * (1.0 - atten)));
+		if(++(*sbf) >=  bflen * 2)
+			bufdone = 1;
+		break;
+	case(4):
+		for(k=0; k < dz->infile->channels; k++) {
+			buf0[*sbf] = (float)((buf0[*sbf] * atten) + (buf1[*sbf] * (1.0 - atten)));
+			(*sbf)++;
+		}
+		if(*sbf >=  bflen * dz->infile->channels)
+			bufdone = 1;
+		break;
+	}	
+	return(bufdone);
+}
+
+/******************************** RENEW_BUFS *****************************/
+
+int renew_bufs(int typ,float *buf0,float *buf1,dataptr dz)
+{
+	int exit_status;
+	switch(typ) {
+	case(0):
+		if((exit_status = write_samps(buf0,dz->buflen,dz))<0)
+			return(exit_status);
+		memset((char *)buf0,0,dz->buflen * sizeof(float));
+		memset((char *)buf1,0,dz->buflen * sizeof(float));
+		break;
+	case(1):
+		if((exit_status = write_samps(buf1,dz->buflen * 2,dz))<0)
+			return(exit_status);
+		memset((char *)buf0,0,dz->buflen * sizeof(float));
+		memset((char *)buf1,0,dz->buflen * 2 * sizeof(float));
+		break;
+	case(2):
+		if((exit_status = write_samps(buf0,dz->buflen * 2,dz))<0)
+			return(exit_status);
+		memset((char *)buf0,0,dz->buflen * 2 * sizeof(float));
+		memset((char *)buf1,0,dz->buflen * sizeof(float));
+		break;
+	case(3):
+		if((exit_status = write_samps(buf0,dz->buflen * 2,dz))<0)
+			return(exit_status);
+		memset((char *)buf0,0,dz->buflen * 2 * sizeof(float));
+		memset((char *)buf1,0,dz->buflen * 2 * sizeof(float));
+		break;
+	case(4):
+		if((exit_status = write_samps(buf0,dz->buflen * dz->infile->channels,dz))<0)
+			return(exit_status);
+		memset((char *)buf0,0,dz->buflen * dz->infile->channels * sizeof(float));
+		memset((char *)buf1,0,dz->buflen * dz->otherfile->channels * sizeof(float));
+		break;
+	}
+	if((fgetfbufEx(buf0,dz->buflen * dz->infile->channels,dz->ifd[0],0)) < 0) {
+		sprintf(errstr,"Can't read samps from 1st soundfile.\n");
+		return(SYSTEM_ERROR);
+	}
+	if((fgetfbufEx(buf1,dz->buflen * dz->otherfile->channels,dz->ifd[1],0)) < 0) {
+		sprintf(errstr,"Can't read samps from 2nd soundfile.\n");
+		return(SYSTEM_ERROR);
+	}
+	return(FINISHED);
+}
+
+/******************************** FLUSH_BUFS *****************************/
+
+int flush_bufs(int typ,int *mbf,int *sbf,float *buf0,float *buf1,dataptr dz)
+{
+	int exit_status;
+	switch(typ) {
+	case(0):						/* Output file takes its channel cnt from 1st input file : HENCE....  */
+		if(*mbf > 0) {
+			if((exit_status = write_samps(buf0,*mbf,dz))<0)
+				return(exit_status);
+		}							/* 1st input file MONO : output file MONO */
+		break;
+	case(1):
+		if(*sbf > 0) {
+			if((exit_status = write_samps(buf1,*sbf,dz))<0)
+				return(exit_status);
+		}							/* 1st input file MONO : output file STEREO */
+		dz->infile->channels = 2;	/* Force output file to have stereo header */
+		break;
+	case(2):						/* 1st input file STEREO : output file STEREO */
+	case(3):
+	case(4):
+		if(*sbf > 0) {
+			if((exit_status = write_samps(buf0,*sbf,dz))<0)
+				return(exit_status);
+		}
+		break;
+	}
+	return(FINISHED);
+}
+
+//TW JANUARY 2010: MODIFIED FOR MULTICHANNEL
+
+/*************************** DO_AUTOMIX *******************************/
+
+int do_automix(dataptr dz)
+{
+	double srate = (double)dz->infile->srate;
+	unsigned int nexttime, thistime, outcnt = 0, bufcnt = 0;
+	int outchans = 1, exit_status;
+	double *p = dz->parray[0], *arrayend = dz->parray[0] + dz->itemcnt;
+	double *thislevel, *nextlevel, *incr, sum, convertor_to_time, convertor_to_smps;
+	int *activebuf, overflows = 0;
+	unsigned int max_insams = 0;
+	int *chans, n;
+
+	if((chans = (int *)malloc(dz->infilecnt * sizeof(int)))==NULL) {
+		sprintf(errstr,"Insufficient memory for level stores\n");
+		return(MEMORY_ERROR);
+	}
+	if((thislevel = (double *)malloc(dz->infilecnt * sizeof(double)))==NULL) {
+		sprintf(errstr,"Insufficient memory for level stores\n");
+		return(MEMORY_ERROR);
+	}
+	if((nextlevel = (double *)malloc(dz->infilecnt * sizeof(double)))==NULL) {
+		sprintf(errstr,"Insufficient memory for level stores\n");
+		return(MEMORY_ERROR);
+	}
+	if((incr = (double *)malloc(dz->infilecnt * sizeof(double)))==NULL) {
+		sprintf(errstr,"Insufficient memory for level stores\n");
+		return(MEMORY_ERROR);
+	}
+	if((activebuf = (int *)malloc(dz->infilecnt * sizeof(int)))==NULL) {
+		sprintf(errstr,"Insufficient memory for level stores\n");
+		return(MEMORY_ERROR);
+	}
+	for(n=0;n<dz->infilecnt;n++) {
+		activebuf[n] = 1;
+		if(sndgetprop(dz->ifd[n],"channels", (char *)&(chans[n]), sizeof(int)) < 0) {
+			sprintf(errstr,"Failure to read channel data, for input file %d\n",n+1);
+			return(DATA_ERROR);
+		}
+		if(n>0 && chans[n] != chans[0]) {
+			sprintf(errstr,"Process only works with files having the same number of channels: file %d will not work\n",n+1);
+			return(DATA_ERROR);
+		}
+	}
+	outchans = chans[0];
+	convertor_to_smps = srate * outchans;
+	convertor_to_time = 1.0/convertor_to_smps;
+	for(n=0;n<dz->infilecnt;n++)
+		max_insams = max(max_insams,(unsigned int)dz->insams[n]);
+	dz->tempsize = max_insams;	/* for scrollbar display */
+	if((exit_status = create_sized_outfile(dz->outfilename,dz))<0)
+		return(exit_status);
+	if((exit_status = read_automix_sound(activebuf,dz))<0)
+		return(exit_status);
+	nexttime = (unsigned int)round(*p++ * convertor_to_smps);
+	for(n = 0;n<dz->infilecnt; n++)
+		nextlevel[n] = *p++;
+	while(outcnt < max_insams) {
+		thistime = nexttime;	  				/* establish amplitude ramps */
+		for(n = 0; n<dz->infilecnt; n++)
+			thislevel[n] = nextlevel[n];
+		if(p < arrayend) {
+			nexttime = (unsigned int)round(*p++ * convertor_to_smps);
+			for(n = 0;n<dz->infilecnt; n++) {
+				nextlevel[n] = *p++;
+				incr[n] = (nextlevel[n] - thislevel[n])/(double)(nexttime - thistime);
+			}
+		} else {								/* if amp-data runs out */
+			for(n = 0;n<dz->infilecnt; n++)		/* set amp increments to zero */
+				incr[n] = 0.0;
+			nexttime = max_insams;				/* and proceed to end of file */
+		}
+		nexttime = min(nexttime, max_insams);	/* if snd-data runs out, curtail loop to snd-data end */
+		while(outcnt < nexttime) {
+			sum = 0.0;
+			for(n=0;n<dz->infilecnt;n++) {
+				if(activebuf[n]) {
+					sum += dz->sampbuf[n][bufcnt] * thislevel[n];
+					thislevel[n] += incr[n];
+					if(outcnt >= (unsigned int)dz->insams[n])
+						activebuf[n] = 0;
+				}
+			}
+			if(fabs(sum) > F_MAXSAMP)
+				overflows++;
+			dz->sampbuf[dz->infilecnt][bufcnt] = (float)(sum * dz->param[0]);
+			if(++bufcnt >= (unsigned int)dz->buflen) {
+				if((exit_status = write_samps(dz->sampbuf[dz->infilecnt],dz->buflen,dz))<0)
+					return(exit_status);
+				if((exit_status = read_automix_sound(activebuf,dz))<0)
+					return(exit_status);
+				bufcnt = 0;
+			}
+			outcnt++;
+			if(dz->brksize[0]) {
+				if((exit_status = read_value_from_brktable((double)outcnt * convertor_to_time,0,dz))<0)
+					return(exit_status);
+			}
+		}
+	}
+	if(bufcnt) {
+		if((exit_status = write_samps(dz->sampbuf[dz->infilecnt],bufcnt,dz))<0)
+			return(exit_status);
+	}
+	if(overflows) {
+		fprintf(stdout,"WARNING: %d samples were clipped.\n",overflows);
+		fflush(stdout);
+	}
+	return(FINISHED);
+}
+
+/*************************** READ_AUTOMIX_SOUND *******************************/
+
+int read_automix_sound(int *activebuf,dataptr dz)
+{
+	int n;
+	for(n=0;n<dz->infilecnt;n++) {
+		if(!activebuf[n])		  	/* only read from files with data remaining */
+			continue;
+		if((dz->ssampsread = fgetfbufEx(dz->sampbuf[n],dz->buflen,dz->ifd[n],0)) < 0) {
+			sprintf(errstr,"Can't read samps from input soundfile %d.\n",n+1);
+			return(SYSTEM_ERROR);
+		}
+	}
+	return(FINISHED);
+}
+
+
+/************************************ MIXMANY ************************************/
+
+int mixmany(dataptr dz)
+{
+	int exit_status;
+	int gross_samps_read, n, m;
+	int ssampsread;
+	double *dblbuf = (double *)dz->sampbuf[2], maxdsamp = 0.0;
+	float *ibuf    = dz->sampbuf[0];
+	float *obuf    = dz->sampbuf[1];
+
+	dz->tempsize = 0;
+	for(n=0;n<=dz->infilecnt;n++)
+		dz->tempsize = max(dz->tempsize,dz->insams[n]);
+	display_virtual_time(0L,dz);
+	fprintf(stdout,"INFO: Finding maximum level\n");
+	fflush(stdout);
+	do {
+		memset((char *)ibuf,0,(size_t)dz->buflen * sizeof(float));
+		memset((char *)dblbuf,0,(size_t)dz->buflen * sizeof(double));
+		gross_samps_read = 0;
+		for(n=0;n<dz->infilecnt;n++) {
+			if((ssampsread = fgetfbufEx(ibuf,dz->buflen,dz->ifd[n],0))<0) {
+				sprintf(errstr,"Problem reading from file %d\n",n+1);
+				return(SYSTEM_ERROR);
+			}
+			gross_samps_read = max(gross_samps_read,ssampsread);
+
+			if(ssampsread > 0) {
+				for(m=0;m<ssampsread;m++)
+					dblbuf[m] += (double)ibuf[m];
+			}
+		}
+		if(gross_samps_read<=0)
+			break;
+		for(m=0;m<gross_samps_read;m++)
+			maxdsamp = max(maxdsamp,fabs(dblbuf[m]));
+
+	} while(gross_samps_read > 0);
+	maxdsamp = F_MAXSAMP/maxdsamp;
+	for(n=0;n<dz->infilecnt;n++) {
+		if(sndseekEx(dz->ifd[n],0,0)<0) {
+			sprintf(errstr,"seek failed for file %d\n",n+1);
+			return(SYSTEM_ERROR);
+		}
+	}
+	dz->total_samps_written = 0;
+	display_virtual_time(0,dz);
+	fprintf(stdout,"INFO: Doing the mix.\n");
+	fflush(stdout);
+	do {
+		memset((char *)ibuf,0,(size_t)dz->buflen * sizeof(float));
+		memset((char *)dblbuf,0,(size_t)dz->buflen * sizeof(double));
+		gross_samps_read = 0;
+		for(n=0;n<dz->infilecnt;n++) {
+			if((ssampsread = fgetfbufEx(ibuf,dz->buflen,dz->ifd[n],0))<0) {
+				sprintf(errstr,"Problem reading from file %d during mix.\n",n+1);
+				return(SYSTEM_ERROR);
+			}
+			gross_samps_read = max(gross_samps_read,ssampsread);
+			if(ssampsread  > 0) {
+				for(m=0;m<ssampsread;m++)
+					dblbuf[m] += (double)ibuf[m];
+			}
+		}
+		if(gross_samps_read<=0)
+			break;
+		for(m=0;m<gross_samps_read;m++)
+			obuf[m] = (float)(dblbuf[m] * maxdsamp);
+		if((exit_status = write_samps(obuf,gross_samps_read,dz))<0)
+			return(exit_status);
+	} while(gross_samps_read > 0);
+	return(FINISHED);
+}
+
+

+ 354 - 0
dev/submix/mixprepro.c

@@ -0,0 +1,354 @@
+/*
+ * Copyright (c) 1983-2013 Trevor Wishart and Composers Desktop Project Ltd
+ * http://www.trevorwishart.co.uk
+ * http://www.composersdesktop.com
+ *
+ This file is part of the CDP System.
+
+    The CDP System is free software; you can redistribute it
+    and/or modify it under the terms of the GNU Lesser General Public
+    License as published by the Free Software Foundation; either
+    version 2.1 of the License, or (at your option) any later version.
+
+    The CDP System is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public
+    License along with the CDP System; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+    02111-1307 USA
+ *
+ */
+
+
+
+/* floatsam version */
+#include <stdio.h>
+#include <stdlib.h>
+#include <limits.h>
+#include <structures.h>
+#include <tkglobals.h>
+#include <globcon.h>
+#include <filetype.h>
+#include <modeno.h>
+#include <mix.h>
+#include <sfsys.h>
+
+#ifdef unix
+#define round(x) lround((x))
+#endif
+
+static int  do_refill_acts(dataptr dz);
+static void sort_actions(dataptr dz);
+static int  init_inbufs(dataptr dz);
+static int  gen_mcr_table(dataptr dz);
+
+/************************** MIX_PREPROCESS ******************/
+
+int mix_preprocess(dataptr dz)
+{
+	int exit_status;
+	if((exit_status = do_refill_acts(dz))<0)						
+		return(exit_status);
+	sort_actions(dz);			
+	if(dz->iparam[MIX_STRTPOS] > 0)	   		/* Allow for mix not starting at zero time */
+		dz->iparam[MIX_STRTPOS_IN_ACTION] = (int)max(dz->iparam[MIX_STRTPOS] - dz->act[0]->position,0L);  
+/* NEW 2000 */
+	/* RWD now in samps */
+	dz->tempsize = (dz->act[dz->iparam[MIX_TOTAL_ACTCNT]-1]->position - dz->iparam[MIX_STRTPOS_IN_ACTION]);
+/* NEW 2000 */
+	return init_inbufs(dz);		
+}
+
+/*************************** DO_REFILL_ACTS **************************/
+
+int do_refill_acts(dataptr dz)
+{
+	int n;
+	int samps_used, actcnt = dz->iparam[MIX_TOTAL_ACTCNT];
+	int arraysize = actcnt + BIGARRAY;							/* Generate more space for further actions. */
+	if((dz->act=(actptr *)realloc(dz->act,arraysize * sizeof(actptr)))==NULL) {
+		sprintf(errstr,"INSUFFICIENT MEMORY to construct buffer-fill action pointers.\n");
+		return(MEMORY_ERROR);
+	}
+	for(n=0;n<dz->iparam[MIX_TOTAL_ACTCNT];n+=2) {				/* actions paired as ON/OFF, so we look only at ON bufs */
+		if(dz->act[n]->val->samplen > dz->buflen) {				/* If more data in (action's) file than fits in 1 buffer */
+			samps_used = 0;		
+			while((samps_used += dz->buflen) < dz->act[n]->val->samplen) {
+				if((dz->act[actcnt] = (actptr)malloc(sizeof(struct action)))==NULL) {
+					sprintf(errstr,"INSUFFICIENT MEMORY to construct buffer-fill actions.\n");
+					return(MEMORY_ERROR);
+				}
+				dz->act[actcnt]->val      = dz->act[n]->val;	/* Create a new action, using same vals as the original */
+				dz->act[actcnt]->position = dz->act[n]->position + samps_used;/* Positioned 1 further buflen later, and */
+				dz->act[actcnt]->role     = MIX_ACTION_REFILL;	/* with role REFILL */
+				if(++actcnt >= arraysize) {
+					arraysize += BIGARRAY;
+					if((dz->act=(actptr *)realloc(dz->act,arraysize * sizeof(actptr)))==NULL) {
+						sprintf(errstr,"INSUFFICIENT MEMORY to reallocate buffer-fill action pointers.\n");
+						return(MEMORY_ERROR);
+					}
+				}
+			}
+		}
+	}
+	if((dz->act=(actptr *)realloc(dz->act,actcnt * sizeof(actptr)))==NULL) {
+		sprintf(errstr,"INSUFFICIENT MEMORY to reallocate buffer-fill actions.\n");
+		return(MEMORY_ERROR);
+	}
+	dz->iparam[MIX_TOTAL_ACTCNT] = (int)actcnt;
+	return(FINISHED);
+}
+
+/************************* SORT_ACTIONS ****************************/
+
+void sort_actions(dataptr dz)
+{
+	actptr temp;   
+	int n, m;
+	for(n=0;n<dz->iparam[MIX_TOTAL_ACTCNT]-1;n++) {
+		for(m=n+1;m<dz->iparam[MIX_TOTAL_ACTCNT];m++) {
+			if(dz->act[m]->position < dz->act[n]->position) {
+				temp   = dz->act[n];
+				dz->act[n] = dz->act[m];	
+				dz->act[m] = temp;
+			}
+		}
+	}
+}
+
+/****************************** INIT_INBUFS *********************************
+ *
+ * (1)	Create the space for buffers within each bufitem. NB enough space
+ * 		for ALL these buffers must be allocated in the initial creation
+ * 		of 'inbuf' in create_buffers.
+ * (2)	Create the pointers to point to start and current_position in ACTIVE bufs.
+ */
+
+int init_inbufs(dataptr dz)
+{
+	int n;
+	float *thisbuf = dz->sampbuf[IBUFMIX];
+	dz->buflist = (mixbufptr *)malloc(dz->bufcnt * sizeof(mixbufptr));
+	for(n=0;n<dz->bufcnt;n++) {
+		dz->buflist[n] = NULL;
+		if((dz->buflist[n] = (mixbufptr)malloc(sizeof(struct bufitem)))==NULL) {
+			sprintf(errstr,"INSUFFICIENT MEMORY for buffer list.\n");
+			return(MEMORY_ERROR);
+		}
+		dz->buflist[n]->status = MIX_ACTION_OFF;
+		dz->buflist[n]->buf    = thisbuf;
+		dz->buflist[n]->here   = dz->buflist[n]->buf;
+		thisbuf += dz->buflen;
+	}
+	if((dz->activebuf = (int *)malloc(dz->bufcnt * sizeof(int)))==NULL) {
+		sprintf(errstr,"INSUFFICIENT MEMORY for active buffer list.\n");
+		return(MEMORY_ERROR);
+	}
+	if((dz->activebuf_ptr = (float **)malloc(dz->bufcnt * sizeof(float *)))==NULL) {
+		sprintf(errstr,"INSUFFICIENT MEMORY for active buffer pointer list.\n");
+		return(MEMORY_ERROR);
+	}
+	return(FINISHED);
+}
+
+/****************************** MIXTWO_PREPROCESS ************************************/
+
+int mixtwo_preprocess(dataptr dz)
+{
+	int shsecsize = F_SECSIZE * dz->infile->channels;
+	double k;
+	dz->iparam[MIX_STAGGER] = round(dz->param[MIX_STAGGER] * (double)dz->infile->srate) * dz->infile->channels;
+	dz->iparam[MIX_STAGGER] = (dz->iparam[MIX_STAGGER]/shsecsize) * shsecsize;
+	dz->iparam[MIX_STAGGER] = min(dz->iparam[MIX_STAGGER],dz->insams[0] - dz->infile->channels);
+
+	dz->iparam[MIX_SKIP] = round(dz->param[MIX_SKIP] * (double)dz->infile->srate) * dz->infile->channels;
+	dz->iparam[MIX_SKIP] = (dz->iparam[MIX_SKIP]/shsecsize) * shsecsize;
+	dz->iparam[MIX_SKIP] = min(dz->iparam[MIX_SKIP],dz->insams[1] - dz->infile->channels);
+	
+	if(((k = (dz->param[MIX_STTA] * (double)dz->infile->srate))  * (double)dz->infile->channels) >= (double)LONG_MAX)
+		dz->iparam[MIX_STTA] = INT_MAX;
+	else
+		dz->iparam[MIX_STTA] = round(dz->param[MIX_STTA] * (double)dz->infile->srate) * dz->infile->channels;
+	dz->iparam[MIX_STTA] = (dz->iparam[MIX_STTA]/shsecsize) * shsecsize;
+	dz->param[MIX2_GAIN1] = dz->param[MIX_SKEW]/(dz->param[MIX_SKEW] + 1.0);
+	dz->param[MIX2_GAIN2] = 1.0 - dz->param[MIX2_GAIN1];
+
+	if(((k = (dz->param[MIX_DURA] * (double)dz->infile->srate))  * (double)dz->infile->channels) >= (double)LONG_MAX)
+		dz->iparam[MIX_DURA] = dz->insams[0] + dz->insams[1];
+	else
+		dz->iparam[MIX_DURA] = round(k) * dz->infile->channels;
+
+	if(dz->iparam[MIX_DURA] <= dz->iparam[MIX_STAGGER]) {
+		sprintf(errstr,"Mix cuts off before 2nd file enters\n");
+		return(DATA_ERROR);
+	}
+	if(dz->iparam[MIX_STTA] >= dz->insams[0]) {
+		sprintf(errstr,"Mix does not start until first file has ended.\n");
+		return(DATA_ERROR);
+	}
+	if(dz->iparam[MIX_DURA] <= dz->iparam[MIX_STTA]) {
+		sprintf(errstr,"Mix end is before mix start.\n");
+		return(DATA_ERROR);
+	}
+	/* RWD all now in samps */
+	dz->tempsize = max((dz->insams[1]-dz->iparam[MIX_SKIP]+dz->iparam[MIX_STAGGER]),dz->insams[0]);
+	dz->tempsize = min(dz->tempsize,dz->iparam[MIX_DURA]);
+	dz->tempsize -= (dz->iparam[MIX_STTA]);
+
+	return(FINISHED);
+}
+
+/********************** MIXCROSS_PREPROCESS **********************/
+
+int mixcross_preprocess(dataptr dz)
+{
+	int exit_status;
+	int crosfact, maxend;
+
+		   	/* CONVERT TO SAMPLES */
+	dz->iparam[MCR_BEGIN]   = round(dz->param[MCR_BEGIN]   * dz->infile->srate) * dz->infile->channels;
+		
+		   	/* CONVERT TO SAMPLES AND APPROXIMATE TO SECTOR BOUNDARY */
+	dz->iparam[MCR_STAGGER] = round(dz->param[MCR_STAGGER] * dz->infile->srate) * dz->infile->channels;
+//TW SAFE ??
+//#ifdef NOTDEF
+//	dz->iparam[MCR_STAGGER] = (dz->iparam[MCR_STAGGER]/SECSIZE) * SECSIZE;
+//#endif
+	maxend = min(dz->insams[0],dz->iparam[MCR_STAGGER] + dz->insams[1]);
+
+	if(dz->param[MCR_END] > 0.0) {		/* i.e. HAS BEEN SET */
+		dz->iparam[MCR_END] = round(dz->param[MCR_END] * dz->infile->srate) * dz->infile->channels;
+		dz->iparam[MCR_END] = min(dz->iparam[MCR_END],maxend);	/* END may be curtailed by stagger's rounding */
+	} else
+		dz->iparam[MCR_END] = maxend;
+
+			/* TEST CROSSFADE PARAMS FOR CONSISTENCY */
+	if(dz->iparam[MCR_BEGIN] < dz->iparam[MCR_STAGGER]) {
+		sprintf(errstr,"Crossfade begins before end of stagger: Impossible.\n");
+		return(USER_ERROR);
+	}
+	if(dz->iparam[MCR_BEGIN] >=  dz->iparam[MCR_STAGGER] + dz->insams[1]) {
+		sprintf(errstr,"Crossfade begins after end of 2nd file: Impossible.\n");
+		return(USER_ERROR);
+	}
+	if((crosfact = dz->iparam[MCR_END] - dz->iparam[MCR_BEGIN])<=0) {
+		sprintf(errstr,"Crossfade length is zero or negative: Impossible.\n");
+		return(USER_ERROR);
+	}
+			/* SET UP LENGTH OF CROSSFADE, AND THE DIVIDE FACTOR FOR INDEXING THIS */
+	dz->param[MCR_CROSFACT] = 1.0/(double)crosfact;
+
+			/* SET CONTOUR TYPE */
+	if(dz->mode==MCLIN)
+		dz->iparam[MCR_CONTOUR] = MCR_LINEAR;
+	else if(flteq(dz->param[MCR_POWFAC],1.0))
+		dz->iparam[MCR_CONTOUR] = MCR_COSIN;
+	else
+		dz->iparam[MCR_CONTOUR] = MCR_SKEWED;
+
+			/* FOR COSIN CONTOUR TYPE : MAKE COSTABLE */
+	if(dz->iparam[MCR_CONTOUR]==MCR_SKEWED || dz->iparam[MCR_CONTOUR]==MCR_COSIN) {
+		if((exit_status = gen_mcr_table(dz))<0)
+			return(exit_status);
+	}
+			/* SET CROSS-FADE INDEX OT ZERO */
+	dz->iparam[MCR_INDEX]   = 0;
+	return(FINISHED);
+}
+
+/*** GONE TO TK *********************** GEN_MCR_TABLE **********************/
+
+int gen_mcr_table(dataptr dz)
+{
+	int n;
+	double *costable;
+	if((dz->parray[MCR_COSTABLE] = (double *)malloc((MCR_TABLEN+1)*	sizeof(double)))==NULL) {
+		sprintf(errstr,"INSUFFICIENT MEMORY for cosine table.\n");
+		return(MEMORY_ERROR);
+	}
+	costable = dz->parray[MCR_COSTABLE];
+	for(n=0;n<MCR_TABLEN;n++) {
+		costable[n]  = ((double)n/(double)(MCR_TABLEN)) * PI;
+		costable[n]  = cos(costable[n]);
+		costable[n] += 1.0;
+		costable[n] /= 2.0;
+		costable[n]  = 1.0 - costable[n];
+		costable[n]  = max(0.0,costable[n]);
+		costable[n]  = min(costable[n],1.0);
+	}
+	costable[n]  = 1.0;
+	return(FINISHED);
+}
+
+/******************************** GET_INBETWEEN_RATIOS ***************************/
+
+int get_inbetween_ratios(dataptr dz)
+{
+	double *p, scaler;
+	int n;
+	switch(dz->mode) {
+	case(INBI_RATIO):	/* now read as special data */
+		break;
+	case(INBI_COUNT):	/* GENERATE RATIOS AUTOMATICALLY IN A NEWLY MALLOCD brkpnt TABLE */
+		dz->iparam[INBETW] = round(dz->param[INBETW]);
+		if((dz->brk[INBETW] = (double *)malloc(dz->iparam[INBETW] * sizeof(double)))==NULL) {
+			sprintf(errstr,"INSUFFICIENT MEMORY for inbetween values store.\n");
+			return(MEMORY_ERROR);
+		}
+		dz->no_brk[INBETW] = FALSE;
+		p = dz->brk[INBETW];
+		scaler = 1.0/(double)(dz->iparam[INBETW]+1);
+		for(n=1;n<=dz->iparam[INBETW];n++)
+			*p++ = (double)n * scaler;
+		break;
+	default:
+		sprintf(errstr,"Unknown mode in get_inbetween_ratios()\n");
+		return(PROGRAM_ERROR);
+	}			
+	return(FINISHED);
+}
+
+/************** CHECK_NEW_FILENAME ***********/
+
+int check_new_filename(char *filename,dataptr dz)
+{
+	int exit_status;
+	double maxamp, maxloc;
+	int maxrep;
+	int getmax = 0, getmaxinfo = 0;
+	infileptr ifp;
+	if((ifp = (infileptr)malloc(sizeof(struct filedata)))==NULL) {
+		sprintf(errstr,"INSUFFICIENT MEMORY to store data on files.\n");
+		return(MEMORY_ERROR);
+	}
+	if(dz->mode!=MSH_DUPL_AND_RENAME || dz->vflag[MSH_NOCHECK])
+		return(FINISHED);
+	if(dz->infile->srate==0) {
+		sprintf(errstr,"srate not set: check_new_filename()\n");
+		return(PROGRAM_ERROR);
+	}
+	if(dz->ifd!=NULL)  /* set up by default in main() */
+		free(dz->ifd);
+	if((exit_status = establish_file_data_storage_for_mix((int)1,dz))<0)
+		return(exit_status);
+
+	if((dz->ifd[0] = sndopenEx(filename,0,CDP_OPEN_RDONLY)) < 0) {
+		sprintf(errstr,"Failed to open sndfile %s: check_new_filename()\n",filename);
+		return(DATA_ERROR);
+	}
+	if((exit_status = readhead(ifp,dz->ifd[0],filename,&maxamp,&maxloc,&maxrep,getmax,getmaxinfo))<0)
+		return(exit_status);
+	copy_to_fileptr(ifp,dz->otherfile);
+	if(dz->otherfile->filetype!=SNDFILE) {
+		sprintf(errstr,"%s is not a soundfile: check_new_filename()\n",filename);
+		return(DATA_ERROR);
+	}
+	if(dz->otherfile->srate != dz->infile->srate) {
+		sprintf(errstr,"Incompatible srate: check_new_filename()\n");
+		return(DATA_ERROR);
+	}
+	return(FINISHED);
+}

+ 499 - 0
dev/submix/mixshuf0.c

@@ -0,0 +1,499 @@
+/*
+ * 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 <string.h>
+#include <structures.h>
+#include <tkglobals.h>
+#include <globcon.h>
+#include <processno.h>
+#include <modeno.h>
+#include <arrays.h>
+#include <mix.h>
+#include <cdpmain.h>
+
+#include <sfsys.h>
+#include <osbind.h>
+
+static int  get_times(double *timestor,dataptr dz);
+static int  adjust_stereo(int lineno,int total_words,int wordcnt,double param,dataptr dz);
+static int  adjust_position(char **thisword,double param,dataptr dz);
+static int  treat_short_mono_line(int lineno,int wordno,double param,dataptr dz);
+static int  treat_short_stereo_line(int lineno,int wordno,double param,dataptr dz);
+static int  investigate_timings(double *duration,double *min_time,dataptr dz);
+
+/************************* MIX_SHUFL ******************************/
+
+int mix_shufl(dataptr dz)
+{
+	switch(dz->mode) {
+	case(MSH_OMIT_ALT):
+	case(MSH_OMIT):				return do_time_manip(dz);
+
+	case(MSH_DUPLICATE):
+	case(MSH_DUPL_AND_RENAME):	return do_time_and_name_copy(dz);
+
+	case(MSH_SCATTER):			return randomise_names(dz);
+	case(MSH_REVERSE_N):		return do_name_reverse(dz);
+	case(MSH_FIXED_N):			return do_name_freeze(dz);
+	default:
+		sprintf(errstr,"Unknown mode in mix_shufl()\n");
+		return(PROGRAM_ERROR);
+	}
+	return(FINISHED);	/* NOTREACHED */
+}
+
+/************************* MIX_TIMEWARP ******************************/
+
+int mix_timewarp(dataptr dz)
+{
+	switch(dz->mode) {
+	case(MTW_REVERSE_NT):	return do_name_and_time_reverse(dz);
+	case(MTW_FREEZE_NT): 	return do_name_and_time_freeze(dz);
+
+	case(MTW_REVERSE_T):	case(MTW_FREEZE_T):		case(MTW_SCATTER):		case(MTW_DOMINO):
+	case(MTW_CREATE_TG_1):	case(MTW_CREATE_TG_2):	case(MTW_CREATE_TG_3):	case(MTW_CREATE_TG_4):
+	case(MTW_ENLARGE_TG_1):	case(MTW_ENLARGE_TG_2):	case(MTW_ENLARGE_TG_3):	case(MTW_ENLARGE_TG_4):
+	case(MTW_ADD_TO_TG):	case(MTW_TIMESORT):
+		return do_time_manip(dz);
+	default:
+		sprintf(errstr,"Unknown mode in mix_timewarp()\n");
+		return(PROGRAM_ERROR);
+	}
+	return(FINISHED);	/* NOTREACHED */
+}
+
+/************************* MIX_SPACEWARP ******************************/
+
+int mix_spacewarp(dataptr dz)
+{
+	int    exit_status;
+	int   n, total_words;
+	int    is_even = TRUE;
+	double position = 0.0;
+	int    *maxwordsize;
+	double duration = 0.0, min_time = 0.0, *timestor = NULL;
+	double spacerange = 0.0, leftedge = 0.0;
+	switch(dz->mode) {
+	case(MSW_TWISTALL):
+	case(MSW_TWISTONE):
+		return mix_twisted(dz);
+	case(MSW_LEFTWARDS):
+	case(MSW_RIGHTWARDS):
+		if((exit_status = investigate_timings(&duration,&min_time,dz))<0)
+			return(exit_status);
+		timestor = dz->parray[MSW_TIMESTOR];
+		/* fall thro */
+	case(MSW_RANDOM):
+	case(MSW_RANDOM_ALT):
+		spacerange = fabs(dz->param[MSW_POS2] - dz->param[MSW_POS1]);
+		leftedge   = min(dz->param[MSW_POS1],dz->param[MSW_POS2]);
+		break;
+	case(MSW_NARROWED):	
+	case(MSW_FIXED):	
+		break;
+	default:
+		sprintf(errstr,"Unknown mode in mix_spacewarp()\n");
+		return(PROGRAM_ERROR);
+	}
+	total_words = 0;
+	for(n=0;n<dz->iparam[MSH_STARTLINE];n++)
+		total_words += dz->wordcnt[n];
+	for(n=dz->iparam[MSH_STARTLINE];n<dz->iparam[MSH_ENDLINE];n++) {
+		switch(dz->mode) {
+		case(MSW_NARROWED):	
+			if((exit_status = adjust_stereo(n,total_words,dz->wordcnt[n],dz->param[MSW_NARROWING],dz))<0)
+				return(exit_status);
+			break;
+		case(MSW_FIXED):	
+			if((exit_status = adjust_stereo(n,total_words,dz->wordcnt[n],dz->param[MSW_POS1],dz))<0)
+				return(exit_status);
+			break;
+		default:
+			switch(dz->mode) {
+			case(MSW_RANDOM):
+				position  = (drand48() * POSITIONS)/POSITIONS;
+				break;
+			case(MSW_RANDOM_ALT):
+				switch(is_even) {
+				case(TRUE):	position = (drand48() * HALF_POSTNS)/POSITIONS; 				break;	/* Force Left */	
+				case(FALSE):position = (POSITIONS - (drand48() * HALF_POSTNS))/POSITIONS;	break;	/* Force Right */	
+				}
+				is_even = !is_even;
+				break;
+			case(MSW_LEFTWARDS):
+//TW UPDATE
+				if(duration > FLTERR)
+					position = (timestor[n] - min_time)/duration;
+				else {
+					sprintf(errstr,"Files do not Progress in Time : Hence cannot MOVE Leftwards\n");
+					return(USER_ERROR);
+				}
+				position = 1.0 - position;
+				break;
+			case(MSW_RIGHTWARDS):
+//TW UPDATE
+				if(duration > FLTERR)
+					position  = (timestor[n] - min_time)/duration;
+				else {
+					sprintf(errstr,"Files do not Progress in Time : Hence cannot MOVE Rightwards\n");
+					return(USER_ERROR);
+				}
+				break;
+			}
+			position *= spacerange;
+			position += leftedge;
+			if((exit_status = adjust_stereo(n,total_words,dz->wordcnt[n],position,dz))<0)
+				return(exit_status);
+			break;
+		}
+		total_words += dz->wordcnt[n];
+	}
+	if((exit_status = get_maxwordsize(&maxwordsize,dz))<0)
+		return(exit_status);
+	if((exit_status = output_mixfile_lines(maxwordsize,dz))<0)
+		return(exit_status);
+	free(maxwordsize);
+	return(FINISHED);
+}
+
+/*************************** GET_TIMES ***************************/
+
+int get_times(double *timestor,dataptr dz)
+{
+	int n, timeloc;
+	int total_wordcnt = 0;
+	for(n=0;n<dz->linecnt;n++) {
+		if(dz->wordcnt[n] < 2) {
+			sprintf(errstr,"PRoblem getting line times: get_times_and_timediffs()\n");
+			return(PROGRAM_ERROR);
+		}
+		timeloc = total_wordcnt + MIX_TIMEPOS;
+		if(sscanf(dz->wordstor[timeloc],"%lf",&(timestor[n]))!=1) {
+			sprintf(errstr,"Problem reading time: get_times_and_timediffs()\n");
+			return(PROGRAM_ERROR);
+		}
+		total_wordcnt += dz->wordcnt[n];
+	}
+	return(FINISHED);
+}
+
+/************************** ADJUST_STEREO **************************/
+
+int adjust_stereo(int lineno,int total_words,int wordcnt,double param,dataptr dz)
+{
+	int  exit_status;
+	char *thisword;
+	int  chans;
+	int levelwordno = total_words + MIX_LEVELPOS;
+	int lpanwordno  = total_words + MIX_PANPOS;
+	int rpanwordno  = total_words + MIX_RPANPOS;
+	int chanwordno  = total_words + MIX_CHANPOS;
+	switch(wordcnt) {
+	case(MIX_MINLINE):
+		thisword = dz->wordstor[chanwordno];
+		if(sscanf(thisword,"%d",&chans)!=1) {
+			sprintf(errstr,"Failed to get channel count: adjust_stereo()\n");
+			return(PROGRAM_ERROR);
+		}
+		switch(chans) {
+		case(MONO):				
+			switch(dz->mode) {
+			case(MSW_NARROWED):	return(FINISHED);	/* mono,   unpanned, files can't be narrowed */
+			default:  			return treat_short_mono_line(lineno,levelwordno,param,dz);
+			}					/* mono,   unpanned, wordstor has to be extended to take 1 new vals */
+			break;				/* stereo, unpanned, wordstor has to be extended to take 3 new vals */
+		case(STEREO):			return treat_short_stereo_line(lineno,levelwordno,param,dz);
+		default:
+			sprintf(errstr,"Invalid channel count: adjust_stereo()\n");
+			return(PROGRAM_ERROR);
+		}
+		break; 
+	case(MIX_MAXLINE):
+		if((exit_status = adjust_position(&(dz->wordstor[rpanwordno]),param,dz))<0)
+			return(exit_status);
+		/* fall thro */
+	case(MIX_MIDLINE):
+		return adjust_position(&(dz->wordstor[lpanwordno]),param,dz);
+		break;
+	default:
+		sprintf(errstr,"Impossible wordcnt: adjust_stereo()\n");
+		return(PROGRAM_ERROR);
+	}
+	return(FINISHED);	/* NOTREACHED */
+}
+
+/************************* ADJUST_POSITION ******************************/
+
+int adjust_position(char **thisword,double param,dataptr dz)
+{
+	double position;
+	int    newlen;
+	if(dz->mode==MSW_NARROWED) {
+		if(!strcmp(*thisword,"C"))
+			position = 0.0;
+		else if(!strcmp(*thisword,"L"))
+			position = -1.0;
+		else if(!strcmp(*thisword,"R"))
+			position = 1.0;
+		else if(sscanf(*thisword,"%lf",&position)!=1) {
+			sprintf(errstr,"Failed to get pan value: adjust_position()\n");
+			return(PROGRAM_ERROR);
+		}
+		param *= position;
+	}
+	sprintf(errstr,"%.4lf",param);	
+	newlen = strlen(errstr);
+	if(newlen > (int)strlen(*thisword)) {
+		if((*thisword = 
+		(char *)realloc(*thisword,(newlen+1) * sizeof(char)))==NULL) {
+			sprintf(errstr,"INSUFFICIENT MEMORY to reallocate thisword store.\n");
+			return(MEMORY_ERROR);
+		}
+	}
+	strcpy(*thisword,errstr);
+	return(FINISHED);
+}
+
+/************************* TREAT_SHORT_STEREO_LINE ******************************/
+
+int treat_short_stereo_line(int lineno,int wordno,double param,dataptr dz)
+{
+
+#define STEREO_EXTRA_WORDS (3)
+
+	int n, m;
+	int  wordlen;
+	if((dz->wordstor = (char **)realloc(dz->wordstor,(dz->all_words + STEREO_EXTRA_WORDS) * sizeof(char *)))==NULL) {
+		sprintf(errstr,"INSUFFICIENT MEMORY to reallocate word store.\n");
+		return(MEMORY_ERROR);
+	}
+	for(n=0,m=dz->all_words;n<STEREO_EXTRA_WORDS;n++,m++)
+		dz->wordstor[m] = NULL;
+	dz->all_words += STEREO_EXTRA_WORDS;
+	for(n=dz->all_words-STEREO_EXTRA_WORDS-1;n>wordno;n--)
+		dz->wordstor[n+STEREO_EXTRA_WORDS] = dz->wordstor[n];
+	dz->wordcnt[lineno] += STEREO_EXTRA_WORDS;		 
+	for(n=wordno+1;n<=wordno+STEREO_EXTRA_WORDS;n++)
+		dz->wordstor[n] = NULL;
+
+	switch(dz->mode) {
+	case(MSW_NARROWED):		sprintf(errstr,"%.4lf",-param);		break;
+	default:				sprintf(errstr,"%.4lf",param);		break;
+	}
+
+	wordlen = strlen(errstr);
+	if((dz->wordstor[wordno+1] = (char *)malloc((wordlen+1) * sizeof(char)))==NULL) {
+		sprintf(errstr,"INSUFFICIENT MEMORY to allocate wordstore %d\n",wordno+1+1);
+		return(MEMORY_ERROR);
+	}	
+	strcpy(dz->wordstor[wordno+1],errstr);
+
+	wordlen = strlen(dz->wordstor[wordno]);
+	if((dz->wordstor[wordno+2] = (char *)malloc((wordlen+1) * sizeof(char)))==NULL) {
+		sprintf(errstr,"INSUFFICIENT MEMORY to allocate wordstore %d\n",wordno+2+1);
+		return(MEMORY_ERROR);
+	}	
+	strcpy(dz->wordstor[wordno+2],dz->wordstor[wordno]);
+
+	sprintf(errstr,"%.4lf",param);
+	wordlen = strlen(errstr);
+	if((dz->wordstor[wordno+3] = (char *)malloc((wordlen+1) * sizeof(char)))==NULL) {
+		sprintf(errstr,"INSUFFICIENT MEMORY to allocate wordstore %d\n",wordno+3+1);
+		return(MEMORY_ERROR);
+	}	
+	strcpy(dz->wordstor[wordno+3],errstr);
+	return(FINISHED);
+}			
+
+/************************* TREAT_SHORT_MONO_LINE ******************************/
+
+int treat_short_mono_line(int lineno,int wordno,double param,dataptr dz)
+{
+
+#define MONO_EXTRA_WORDS (1)
+	int n, m;
+	int  wordlen;
+	if((dz->wordstor = (char **)realloc(dz->wordstor,(dz->all_words + MONO_EXTRA_WORDS) * sizeof(char *)))==NULL) {
+		sprintf(errstr,"INSUFFICIENT MEMORY for word stores.\n");
+		return(MEMORY_ERROR);
+	}
+	for(n=0,m=dz->all_words;n<MONO_EXTRA_WORDS;n++,m++)
+		dz->wordstor[m] = NULL;
+	dz->all_words += MONO_EXTRA_WORDS;
+	for(n=dz->all_words-MONO_EXTRA_WORDS-1;n>wordno;n--)
+		dz->wordstor[n+MONO_EXTRA_WORDS] = dz->wordstor[n];
+	dz->wordcnt[lineno] += MONO_EXTRA_WORDS;		 
+	dz->wordstor[wordno+1] = NULL;
+
+	sprintf(errstr,"%.4lf",param);
+	wordlen = strlen(errstr);
+	if((dz->wordstor[wordno+1] = (char *)malloc((wordlen+1) * sizeof(char)))==NULL) {
+		sprintf(errstr,"INSUFFICIENT MEMORY for word store %d\n",wordno+1+1);
+		return(MEMORY_ERROR);
+	}	
+	strcpy(dz->wordstor[wordno+1],errstr);
+	return(FINISHED);
+}			
+
+/************************* INVESTIGATE_TIMINGS ******************************/
+
+int investigate_timings(double *duration,double *min_time,dataptr dz)
+{
+	int exit_status;
+	int   n;
+	double *timestor;
+	double max_time;
+	if((dz->parray[MSW_TIMESTOR] = (double *)malloc(dz->linecnt * sizeof(double)))==NULL) {
+		sprintf(errstr,"INSUFFICIENT MEMORY for times store.\n");
+		return(MEMORY_ERROR);
+	}
+	timestor = dz->parray[MSW_TIMESTOR];
+	if((exit_status = get_times(timestor,dz))<0)
+		return(exit_status);
+	max_time  = timestor[dz->iparam[MSH_STARTLINE]];
+	*min_time = timestor[dz->iparam[MSH_STARTLINE]];
+	for(n=dz->iparam[MSH_STARTLINE]+1;n<dz->iparam[MSH_ENDLINE];n++) {
+		max_time  = max(timestor[n],max_time);
+		*min_time = min(timestor[n],*min_time);
+	}
+	*duration = max_time - *min_time;
+	return(FINISHED);
+}
+
+//TW UPDATE: NEW FUNCTION
+/************************* PANMIX ******************************/
+
+int panmix(dataptr dz)
+{
+	int newlen, exit_status;
+	int baspos = 0, basposnext = 0, n, linelen;		   /*RWD Nov 2003 added init for basposnext */
+	int levelwordno, lpanwordno, rpanwordno, chanwordno;
+	double time, level;
+	char temp[200];
+	int *maxwordsize;
+	for(n=0;n<dz->linecnt;n++) {
+		basposnext += dz->wordcnt[n];
+		levelwordno = baspos + MIX_LEVELPOS;
+		lpanwordno  = baspos + MIX_PANPOS;
+		rpanwordno  = baspos + MIX_RPANPOS;
+		chanwordno  = baspos + MIX_CHANPOS;
+		time = atof(dz->wordstor[baspos + 1]);
+		if(dz->brksize[PAN_PAN]) {
+			if((exit_status = read_value_from_brktable(time,PAN_PAN,dz))<0)
+				return(exit_status);
+		}
+		linelen = basposnext - baspos;
+		switch(linelen) {
+		case(MIX_MINLINE):				/* STEREO CASE : SHORT LINE */
+			level = atof(dz->wordstor[levelwordno]);
+			level /= 2.0;
+			sprintf(errstr,"%.4lf",level);
+			strcat(errstr," ");
+			sprintf(temp,"%.4lf",dz->param[PAN_PAN]);	
+			strcat(temp," ");
+			strcat(errstr,temp);
+			strcpy(temp,errstr);
+			strcat(errstr,temp);
+			newlen = strlen(errstr);
+			if(newlen > (int)strlen(dz->wordstor[levelwordno])) {
+				if((dz->wordstor[levelwordno] = 
+				(char *)realloc(dz->wordstor[levelwordno],(newlen+1) * sizeof(char)))==NULL) {
+					sprintf(errstr,"INSUFFICIENT MEMORY to reallocate thisword store.\n");
+					return(MEMORY_ERROR);
+				}
+			}
+			strcpy(dz->wordstor[levelwordno],errstr);
+			break;
+		case(MIX_MAXLINE):				/* STEREO CASE : LONG LINE */
+			level = atof(dz->wordstor[levelwordno]);
+			level += atof(dz->wordstor[levelwordno+2]);
+			level /= 4.0;				/* Average level: = (level_left + level-right) / 2.0 */
+										/* This average level from BOTH channels is to be put at SAME position */
+										/* Therefore, divide by two again */
+			sprintf(errstr,"%.4lf",level);
+			newlen = strlen(errstr);
+
+			if(newlen > (int)strlen(dz->wordstor[levelwordno])) {
+				if((dz->wordstor[levelwordno] = 
+				(char *)realloc(dz->wordstor[levelwordno],(newlen+1) * sizeof(char)))==NULL) {
+					sprintf(errstr,"INSUFFICIENT MEMORY to reallocate thisword store.\n");
+					return(MEMORY_ERROR);
+				}
+			}
+			if(newlen > (int)strlen(dz->wordstor[levelwordno+2])) {
+				if((dz->wordstor[levelwordno+2] = 
+				(char *)realloc(dz->wordstor[levelwordno+2],(newlen+1) * sizeof(char)))==NULL) {
+					sprintf(errstr,"INSUFFICIENT MEMORY to reallocate thisword store.\n");
+					return(MEMORY_ERROR);
+				}
+			}
+			strcpy(dz->wordstor[levelwordno],errstr);
+			strcpy(dz->wordstor[levelwordno+2],errstr);
+
+			sprintf(errstr,"%.4lf",dz->param[PAN_PAN]);	
+			if(newlen > (int)strlen(dz->wordstor[lpanwordno])) {
+				if((dz->wordstor[lpanwordno] = 
+				(char *)realloc(dz->wordstor[lpanwordno],(newlen+1) * sizeof(char)))==NULL) {
+					sprintf(errstr,"INSUFFICIENT MEMORY to reallocate thisword store.\n");
+					return(MEMORY_ERROR);
+				}
+			}
+			if(newlen > (int)strlen(dz->wordstor[rpanwordno])) {
+				if((dz->wordstor[rpanwordno] = 
+				(char *)realloc(dz->wordstor[rpanwordno],(newlen+1) * sizeof(char)))==NULL) {
+					sprintf(errstr,"INSUFFICIENT MEMORY to reallocate thisword store.\n");
+					return(MEMORY_ERROR);
+				}
+			}
+			strcpy(dz->wordstor[lpanwordno],errstr);
+			strcpy(dz->wordstor[rpanwordno],errstr);
+			break;
+		case(MIX_MIDLINE):				/* MONO CASE */
+			sprintf(errstr,"%.4lf",dz->param[PAN_PAN]);	
+			newlen = strlen(errstr);
+			if(newlen > (int)strlen(dz->wordstor[lpanwordno])) {
+				if((dz->wordstor[lpanwordno] = 
+				(char *)realloc(dz->wordstor[lpanwordno],(newlen+1) * sizeof(char)))==NULL) {
+					sprintf(errstr,"INSUFFICIENT MEMORY to reallocate thisword store.\n");
+					return(MEMORY_ERROR);
+				}
+			}
+			strcpy(dz->wordstor[lpanwordno],errstr);
+			break;
+		}
+		baspos = basposnext;
+	}
+	if((exit_status = get_maxwordsize(&maxwordsize,dz))<0)
+		return(exit_status);
+	if((exit_status = output_mixfile_lines(maxwordsize,dz))<0)
+		return(exit_status);
+	free(maxwordsize);
+	return(FINISHED);
+}
+

+ 1279 - 0
dev/submix/mixshuf1.c

@@ -0,0 +1,1279 @@
+/*
+ * 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 <mix.h>
+#include <cdpmain.h>
+
+#include <sfsys.h>
+#include <osbind.h>
+#include <float.h>
+
+static int  get_maxpostdec(int *maxpostdec,dataptr dz);
+static int  get_postdec(char *thisword);
+static int  get_times_and_timediffs(double *timestor,double *timediff,dataptr dz);
+
+static int  reverse_times(double *timestor,double *timediff,dataptr dz);
+static int  freeze_times(double *timestor,double *timediff,dataptr dz);
+static int  delete_times(double *timestor,double *timediff,dataptr dz);
+static int  altdel_times(double *timestor,double *timediff,dataptr dz);
+static int  regular_times(double *timestor,double *timediff,dataptr dz);
+static int  arithme_times(double *timestor,double *timediff,dataptr dz);
+static int  aritexp_times(double *timestor,double *timediff,dataptr dz);
+static int  geometr_times(double *timestor,double *timediff,dataptr dz);
+static int  geomexp_times(double *timestor,double *timediff,dataptr dz);
+static int  exponen_times(double *timestor,double *timediff,dataptr dz);
+static int  expoexp_times(double *timestor,double *timediff,dataptr dz);
+static int  spacing_times(double *timestor,double *timediff,dataptr dz);
+static int  scatter_times(double *timestor,double *timediff,dataptr dz);
+static int  shuffle_times(double *timestor,double *timediff,dataptr dz);
+static int  stretch_times(double *timestor,double *timediff,dataptr dz);
+
+static int  put_new_time(int total_words,int postdec,double timeval,dataptr dz);
+
+static int  convert_level(int lineno,int total_words,int *maxwordsize,
+						double *llevelstor,double *rlevelstor,int lmaxlevelsize,int rmaxlevelsize,dataptr dz);
+static int  get_levels(int lineno,int total_words,
+						double *llevelstor,double *rlevelstor,int *lmaxlevelsize,int *rmaxlevelsize,dataptr dz);
+static void delete_wordstorage_space_of_all_deleted_lines(int oldwordcnt,char **wordcopy,dataptr dz);
+
+/************************* DO_TIME_MANIP ******************************/
+
+int do_time_manip(dataptr dz)
+{
+	int    exit_status;
+	double *timestor, *timediff;
+	int    *maxwordsize = NULL, postdec = 0;
+	if((dz->parray[MTW_TIMESTOR] = (double *)malloc(dz->linecnt * sizeof(double)))==NULL) {
+		sprintf(errstr,"INSUFFICIENT MEMORY for times store.\n");
+		return(MEMORY_ERROR);
+	}
+	if((dz->parray[MTW_TIMEDIFF] = (double *)malloc(dz->linecnt * sizeof(double)))==NULL) {
+		sprintf(errstr,"INSUFFICIENT MEMORY for timesteps store.\n");
+		return(MEMORY_ERROR);
+	}
+	timestor = dz->parray[MTW_TIMESTOR];
+	timediff = dz->parray[MTW_TIMEDIFF];
+
+	if((exit_status = get_maxpostdec(&postdec,dz))<0)
+		return(exit_status);
+
+	if((exit_status = get_times_and_timediffs(timestor,timediff,dz))<0)
+		return(exit_status);
+
+	switch(dz->process) {
+	case(MIXTWARP):
+		switch(dz->mode) {
+		case(MTW_TIMESORT):	
+			break;
+		case(MTW_REVERSE_T):	
+			if((exit_status = reverse_times(timestor,timediff,dz))<0)
+				return(exit_status);
+			break;
+		case(MTW_FREEZE_T):		
+			if((exit_status = freeze_times(timestor,timediff,dz))<0)
+				return(exit_status);
+			break;
+	  	case(MTW_SCATTER):		
+	  		if((exit_status = scatter_times(timestor,timediff,dz))<0)
+	  			return(exit_status);
+	  		break;
+	 	case(MTW_DOMINO):		
+	 		if((exit_status = shuffle_times(timestor,timediff,dz))<0)
+	 			return(exit_status);
+	 		break;
+ 		case(MTW_ADD_TO_TG):	
+ 			if((exit_status = spacing_times(timestor,timediff,dz))<0)
+ 				return(exit_status);
+ 			break;
+		case(MTW_CREATE_TG_1):	
+			if((exit_status = regular_times(timestor,timediff,dz))<0)
+				return(exit_status);
+			break;
+ 		case(MTW_CREATE_TG_2):	
+ 			if((exit_status = aritexp_times(timestor,timediff,dz))<0)
+ 				return(exit_status);
+ 			break;
+		case(MTW_CREATE_TG_3):	
+			if((exit_status = geomexp_times(timestor,timediff,dz))<0)
+				return(exit_status);
+			break;
+		case(MTW_CREATE_TG_4):	
+			if((exit_status = expoexp_times(timestor,timediff,dz))<0)
+				return(exit_status);
+			break;
+		case(MTW_ENLARGE_TG_1):	
+			if((exit_status = stretch_times(timestor,timediff,dz))<0)
+				return(exit_status);
+			break;
+		case(MTW_ENLARGE_TG_2):	
+			if((exit_status = arithme_times(timestor,timediff,dz))<0)
+				return(exit_status);
+			break;
+		case(MTW_ENLARGE_TG_3):	
+			if((exit_status = geometr_times(timestor,timediff,dz))<0)
+				return(exit_status);
+			break;
+		case(MTW_ENLARGE_TG_4):	
+			if((exit_status = exponen_times(timestor,timediff,dz))<0)
+				return(exit_status);
+			break;
+		default:
+			sprintf(errstr,"Unknown case in do_time_manip()\n");
+			return(PROGRAM_ERROR);
+		}
+		break;
+	case(MIXSHUFL):
+		switch(dz->mode) {
+		case(MSH_OMIT_ALT):		
+			if((exit_status = altdel_times(timestor,timediff,dz))<0)
+				return(exit_status);
+			break;
+		case(MSH_OMIT):			
+			if((exit_status = delete_times(timestor,timediff,dz))<0)
+				return(exit_status);
+			break;
+		default:
+			sprintf(errstr,"Unknown case in do_time_manip()\n");
+			return(PROGRAM_ERROR);
+		}
+		break;
+	default:
+		sprintf(errstr,"Unknown case in do_time_manip()\n");
+		return(PROGRAM_ERROR);
+	}
+	if((exit_status = retime_the_lines(timestor,postdec,dz))<0)
+		return(exit_status);
+	if((exit_status = timesort_mixfile(timestor,dz))<0)
+		return(exit_status);
+	if((exit_status = get_maxwordsize(&maxwordsize,dz))<0)
+		return(exit_status);
+
+	if((exit_status = output_mixfile_lines(maxwordsize,dz))<0)
+		return(exit_status);
+	free(maxwordsize);
+	return(FINISHED);
+}
+
+/************************** REVERSE_TIMES **************************/
+
+int reverse_times(double *timestor,double *timediff,dataptr dz)
+{
+	int n, m, k; 
+	int this_linecnt;
+	if(dz->iparam[MSH_ENDLINE] - dz->iparam[MSH_STARTLINE] < 2) {
+		sprintf(errstr,"CAN'T REVERSE TIME PATTERN: TOO FEW LINES\n");
+		return(DATA_ERROR);
+	}
+	this_linecnt = (dz->iparam[MSH_ENDLINE] - dz->iparam[MSH_STARTLINE]) - 2;
+	for(n = 0, k=dz->iparam[MSH_STARTLINE]+1, m = dz->iparam[MSH_ENDLINE] - 2; n<this_linecnt; n++, k++, m--)
+		timestor[k] = timestor[k-1] + timediff[m];
+	return(FINISHED);
+}
+
+/************************** STRETCH_TIMES **************************/
+
+int stretch_times(double *timestor,double *timediff,dataptr dz)
+{
+	int n; 
+	for(n=max(dz->iparam[MSH_STARTLINE],1);n<dz->iparam[MSH_ENDLINE];n++)
+		timediff[n-1] *= dz->param[MTW_PARAM];
+	for(n=1; n<dz->linecnt; n++) {
+		if(DBL_MAX - timestor[n-1] <= timediff[n-1]) {
+			sprintf(errstr,"Numbers got too large.\n");
+			return(GOAL_FAILED);
+		}
+		timestor[n] = timestor[n-1] + timediff[n-1];
+	}
+	return(FINISHED);
+}
+
+/************************** FREEZE_TIMES **************************/
+
+int freeze_times(double *timestor,double *timediff,dataptr dz)
+{
+	int n; 
+	for(n=dz->iparam[MSH_STARTLINE]+1;n<dz->iparam[MSH_ENDLINE]-1;n++)
+		timediff[n] = timediff[dz->iparam[MSH_STARTLINE]];
+	for(n=1; n<dz->linecnt; n++)
+		timestor[n] = timestor[n-1] + timediff[n-1];
+	return(FINISHED);
+}
+
+/************************** DELETE_TIMES **************************/
+
+int delete_times(double *timestor,double *timediff,dataptr dz)
+{
+	int n, m, k; 
+	int del_lines = dz->iparam[MSH_ENDLINE] - dz->iparam[MSH_STARTLINE];
+	int new_total_wordcnt = 0, current_word_to_copy, total_wordcnt, oldlinecnt, oldwordcnt;
+	char **wordcopy;
+
+	if((wordcopy = (char **)malloc(dz->all_words * sizeof(char *)))==NULL) {
+		sprintf(errstr,"INSUFFICIENT MEMORY for wordcopy pointers store.\n");
+		return(MEMORY_ERROR);
+	}
+	for(n=0;n<dz->all_words;n++)
+		wordcopy[n] = dz->wordstor[n];
+
+	if(dz->iparam[MSH_STARTLINE]==0 && dz->iparam[MSH_ENDLINE] == dz->linecnt) {
+		free(wordcopy);
+		sprintf(errstr,"Whole file would be deleted!\n");
+		return(USER_ERROR);
+	}
+
+	for(n=1; n < dz->linecnt; n++) {
+		if(timestor[n] < timestor[n-1]) {
+			free(wordcopy);
+			sprintf(errstr,"mixfile lines are not in correct time-order\n");
+			return(USER_ERROR);
+		}
+	}
+
+	for(n=dz->iparam[MSH_STARTLINE],m = dz->iparam[MSH_ENDLINE]; m < dz->linecnt-1; n++,m++)
+		timediff[n] = timediff[m];				/* adjust times: by shuffling down timediffs */
+	for(n=0;n<dz->iparam[MSH_STARTLINE];n++)
+		new_total_wordcnt += dz->wordcnt[n];
+	total_wordcnt =  new_total_wordcnt;
+	for(n=dz->iparam[MSH_STARTLINE];n<dz->linecnt;n++)
+		total_wordcnt += dz->wordcnt[n];
+	current_word_to_copy =  new_total_wordcnt;
+	for(n=dz->iparam[MSH_STARTLINE];n<dz->iparam[MSH_ENDLINE];n++)
+		current_word_to_copy += dz->wordcnt[n];
+	for(n=dz->iparam[MSH_STARTLINE],m = dz->iparam[MSH_ENDLINE]; m < dz->linecnt; n++,m++) {
+
+		for(k=0;k<dz->wordcnt[m];k++)
+			dz->wordstor[new_total_wordcnt++] = dz->wordstor[current_word_to_copy++];				
+		dz->wordcnt[n] = dz->wordcnt[m];
+	}
+	oldlinecnt    = dz->linecnt;
+	oldwordcnt    = dz->all_words;
+	dz->linecnt  -= del_lines;
+	dz->all_words = new_total_wordcnt;
+
+	delete_wordstorage_space_of_all_deleted_lines(oldwordcnt,wordcopy,dz);
+	free(wordcopy);
+	for(n=1; n<dz->linecnt; n++)
+		timestor[n] = timestor[n-1] + timediff[n-1];
+	return(FINISHED);
+}
+
+/************************** ALTDEL_TIMES **************************/
+
+int altdel_times(double *timestor,double *timediff,dataptr dz)
+{
+	int n, copied_or_deleted_line, k; 
+	int new_total_wordcnt = 0, current_word_to_copy, oldlinecnt, oldwordcnt, new_linecnt;
+	char **wordcopy;
+
+	if((wordcopy = (char **)malloc(dz->all_words * sizeof(char *)))==NULL) {
+		sprintf(errstr,"INSUFFICIENT MEMORY for wordcopy pointers store.\n");
+		return(MEMORY_ERROR);
+	}
+	for(n=0;n<dz->all_words;n++)
+		wordcopy[n] = dz->wordstor[n];
+
+	copied_or_deleted_line = dz->iparam[MSH_STARTLINE];
+	for(n=dz->iparam[MSH_STARTLINE]; n <= dz->iparam[MSH_ENDLINE]; n++) {
+		if(++copied_or_deleted_line >= dz->linecnt)			/* SKIP DELETED LINE */
+			break;
+		timediff[n] = timediff[copied_or_deleted_line];		/* SHUFFLE BACK TIME DIFFERENCES */
+		if(++copied_or_deleted_line >= dz->linecnt)
+			break;
+	}
+	while(copied_or_deleted_line < dz->linecnt)				/* RESET TIMEDIFFS OF ANY REMAINING LINES */
+		timediff[n++] = timediff[copied_or_deleted_line++];
+
+	for(n=0;n<dz->iparam[MSH_STARTLINE];n++)
+		new_total_wordcnt += dz->wordcnt[n];
+
+	current_word_to_copy = new_total_wordcnt;
+
+	new_linecnt = dz->iparam[MSH_STARTLINE];
+	copied_or_deleted_line = dz->iparam[MSH_STARTLINE];
+	for(n=dz->iparam[MSH_STARTLINE]; n < dz->iparam[MSH_ENDLINE];n++) {
+		current_word_to_copy += dz->wordcnt[copied_or_deleted_line];/* SKIP DELETED LINE */
+		if(++copied_or_deleted_line >= dz->linecnt)					
+			break;
+		for(k=0;k<dz->wordcnt[copied_or_deleted_line];k++)			/* COPY RETAINED LINE */
+			dz->wordstor[new_total_wordcnt++] = dz->wordstor[current_word_to_copy++];				
+		dz->wordcnt[n] = dz->wordcnt[copied_or_deleted_line];		/* RESET NEW LINE-WORDCNT */
+		new_linecnt++;												/* COUNT NEW TOTAL LINES  */
+		if(++copied_or_deleted_line >= dz->linecnt)
+			break;
+	}
+	while(copied_or_deleted_line<dz->linecnt) {						/* RESET WORDCNTS OF ANY REMAINING LINES */
+		dz->wordcnt[n] = dz->wordcnt[copied_or_deleted_line];
+		new_linecnt++;												/* KEEP COUNTING NEW TOTAL LINES  */
+		copied_or_deleted_line++;
+	}
+	while(current_word_to_copy<dz->all_words)		  				/* COPY ANY REMAINING LINES */
+		dz->wordstor[new_total_wordcnt++] = dz->wordstor[current_word_to_copy++];
+
+	oldlinecnt    = dz->linecnt;
+	oldwordcnt    = dz->all_words;
+	dz->linecnt   = new_linecnt;
+	dz->all_words = new_total_wordcnt;
+
+	delete_wordstorage_space_of_all_deleted_lines(oldwordcnt,wordcopy,dz);
+	free(wordcopy);
+	for(n=1; n<dz->linecnt; n++)
+		timestor[n] = timestor[n-1] + timediff[n-1];
+	return(FINISHED);
+}
+
+/************************** REGULAR_TIMES **************************/
+
+int regular_times(double *timestor,double *timediff,dataptr dz)
+{  int n; 
+   for(n=max(dz->iparam[MSH_STARTLINE],1);n<dz->iparam[MSH_ENDLINE];n++)
+	timediff[n-1] = dz->param[MTW_PARAM];
+    for(n=1; n<dz->linecnt; n++)
+      	timestor[n] = timestor[n-1] + timediff[n-1];
+	return(FINISHED);
+}
+
+/************************** ARITHME_TIMES **************************/
+
+int arithme_times(double *timestor,double *timediff,dataptr dz)
+{
+	int n;
+	double base_factor = dz->param[MTW_PARAM]; 
+	for(n=max(dz->iparam[MSH_STARTLINE],1);n<dz->iparam[MSH_ENDLINE];n++) {
+		timediff[n-1] += dz->param[MTW_PARAM];
+		if(DBL_MAX - dz->param[MTW_PARAM] <= base_factor) {
+			sprintf(errstr,"Numbers got too large.\n");
+			return(GOAL_FAILED);
+		}
+		dz->param[MTW_PARAM] += base_factor;
+	}
+	for(n=1; n<dz->linecnt; n++) {
+		if(DBL_MAX - timestor[n-1] <= timediff[n-1]) {
+			sprintf(errstr,"Numbers got too large.\n");
+			return(GOAL_FAILED);
+		}
+		timestor[n] = timestor[n-1] + timediff[n-1];
+		if(timestor[n]<0.0) {
+			sprintf(errstr,"NEGATIVE TIME GENERATED AT LINE %d\n",n+1);
+			return(GOAL_FAILED);
+		}
+	}
+	return(FINISHED);
+}
+
+/************************** ARITEXP_TIMES **************************/
+
+int aritexp_times(double *timestor,double *timediff,dataptr dz)
+{
+	int n;
+	double value; 
+	value = timediff[dz->iparam[MSH_STARTLINE]];
+	for(n=dz->iparam[MSH_STARTLINE]+1;n<dz->iparam[MSH_ENDLINE]-1;n++) {
+		if(DBL_MAX - value <= dz->param[MTW_PARAM]) {
+			sprintf(errstr,"Numbers got too large.\n");
+			return(GOAL_FAILED);
+		}
+		value      += dz->param[MTW_PARAM];
+		timediff[n] = value;
+	}
+	for(n=1; n<dz->linecnt; n++) {
+		if(DBL_MAX - timestor[n-1] <= timediff[n-1]) {
+			sprintf(errstr,"Numbers got too large.\n");
+			return(GOAL_FAILED);
+		}
+		timestor[n] = timestor[n-1] + timediff[n-1];
+		if(timestor[n]<0.0) {
+			sprintf(errstr,"NEGATIVE TIME GENERATED AT LINE %d\n",n+1);
+			return(GOAL_FAILED);
+		}
+	}
+	return(FINISHED);
+}
+
+/************************** GEOMETR_TIMES **************************/
+
+int geometr_times(double *timestor,double *timediff,dataptr dz)
+{
+	int n; 
+	double base_factor = dz->param[MTW_PARAM]; 
+	for(n=max(dz->iparam[MSH_STARTLINE],1);n<dz->iparam[MSH_ENDLINE];n++) {
+		if(dz->param[MTW_PARAM] > 1.0) {
+			if(DBL_MAX/dz->param[MTW_PARAM] <= timediff[n-1]) {
+				sprintf(errstr,"Numbers got too large.\n");
+				return(GOAL_FAILED);
+			}
+		}
+		timediff[n-1] *= dz->param[MTW_PARAM];
+		dz->param[MTW_PARAM] += base_factor;
+	}
+	for(n=1; n<dz->linecnt; n++) {
+		if(DBL_MAX - timestor[n-1] <= timediff[n-1]) {
+			sprintf(errstr,"Numbers got too large.\n");
+			return(GOAL_FAILED);
+		}
+		timestor[n] = timestor[n-1] + timediff[n-1];
+		if(timestor[n]<0.0) {
+			sprintf(errstr,"NEGATIVE TIME GENERATED AT LINE %d\n",n+1);
+			return(GOAL_FAILED);
+		}
+	}
+	return(FINISHED);
+}
+
+/************************** GEOMEXP_TIMES **************************/
+
+int geomexp_times(double *timestor,double *timediff,dataptr dz)
+{
+	int n; 
+	double value, base_factor = dz->param[MTW_PARAM]; 
+	value = timediff[dz->iparam[MSH_STARTLINE]];
+	for(n=dz->iparam[MSH_STARTLINE]+1;n<dz->iparam[MSH_ENDLINE]-1;n++) {
+		if(dz->param[MTW_PARAM] > 1.0) {
+			if(DBL_MAX/(dz->param[MTW_PARAM]) <= value) {
+				sprintf(errstr,"Numbers got too large.\n");
+				return(GOAL_FAILED);
+			}
+		}
+		timediff[n] = value * dz->param[MTW_PARAM];
+		if(DBL_MAX - dz->param[MTW_PARAM] <= base_factor) {
+			sprintf(errstr,"Numbers got too large.\n");
+			return(GOAL_FAILED);
+		}
+		dz->param[MTW_PARAM] += base_factor;
+	}
+	for(n=1; n<dz->linecnt; n++) {
+		if(DBL_MAX - timestor[n-1] <= timediff[n-1]) {
+			sprintf(errstr,"Numbers got too large.\n");
+			return(GOAL_FAILED);
+		}
+		timestor[n] = timestor[n-1] + timediff[n-1];
+		if(timestor[n]<0.0) {
+			sprintf(errstr,"NEGATIVE TIME GENERATED AT LINE %d\n",n+1);
+			return(GOAL_FAILED);
+		}
+	}
+	return(FINISHED);
+}
+
+/************************** EXPONEN_TIMES **************************/
+
+int exponen_times(double *timestor,double *timediff,dataptr dz)
+{
+	int n;
+	double base_factor = dz->param[MTW_PARAM]; 
+	for(n=max(dz->iparam[MSH_STARTLINE],1);n<dz->iparam[MSH_ENDLINE];n++) {
+		if(DBL_MAX/dz->param[MTW_PARAM] <= timediff[n-1]) {
+			sprintf(errstr,"Numbers got too large.\n");
+			return(GOAL_FAILED);
+		}
+		timediff[n-1] *= dz->param[MTW_PARAM];
+		dz->param[MTW_PARAM] *= base_factor;
+	}
+	for(n=1; n<dz->linecnt; n++) {
+		if(DBL_MAX - timestor[n-1] <= timediff[n-1]) {
+			sprintf(errstr,"Numbers got too large.\n");
+			return(GOAL_FAILED);
+		}
+		timestor[n] = timestor[n-1] + timediff[n-1];
+		if(timestor[n]<0.0) {
+			sprintf(errstr,"NEGATIVE TIME GENERATED AT LINE %d\n",n+1);
+			return(GOAL_FAILED);
+		}
+	}
+	return(FINISHED);
+}
+
+/************************** EXPOEXP_TIMES **************************/
+
+int expoexp_times(double *timestor,double *timediff,dataptr dz)
+{
+	int n; 
+	double value, base_factor = dz->param[MTW_PARAM];
+	value = timediff[dz->iparam[MSH_STARTLINE]];
+	for(n=dz->iparam[MSH_STARTLINE]+1;n<dz->iparam[MSH_ENDLINE]-1;n++) {
+		if(DBL_MAX/value <= dz->param[MTW_PARAM]) {
+			sprintf(errstr,"Numbers got too large.\n");
+			return(GOAL_FAILED);
+		}
+		
+		timediff[n] = value * dz->param[MTW_PARAM];
+		if(DBL_MAX/dz->param[MTW_PARAM] <= base_factor) {
+			sprintf(errstr,"Numbers got too large.\n");
+			return(GOAL_FAILED);
+		}
+		dz->param[MTW_PARAM] *= base_factor;
+	}
+	for(n=1; n<dz->linecnt; n++) {
+		if(DBL_MAX - timestor[n-1] <= timediff[n-1]) {
+			sprintf(errstr,"Numbers got too large.\n");
+			return(GOAL_FAILED);
+		}
+		timestor[n] = timestor[n-1] + timediff[n-1];
+		if(timestor[n]<0.0) {
+			sprintf(errstr,"NEGATIVE TIME GENERATED AT LINE %d\n",n+1);
+			return(GOAL_FAILED);
+		}
+	}
+	return(FINISHED);
+}
+
+/************************** SPACING_TIMES **************************/
+
+int spacing_times(double *timestor,double *timediff,dataptr dz)
+{   
+	int n; 
+	for(n = max(dz->iparam[MSH_STARTLINE],1);n<dz->iparam[MSH_ENDLINE];n++)
+		timediff[n-1] += dz->param[MTW_PARAM];
+	for(n=1; n<dz->linecnt; n++) {
+		timestor[n] = timestor[n-1] + timediff[n-1];
+		if(timestor[n]<0.0) {
+			sprintf(errstr,"NEGATIVE TIME GENERATED AT LINE %d\n",n+1);
+			return(GOAL_FAILED);
+		}
+	}
+	return(FINISHED);
+}
+
+/************************** SHUFFLE_TIMES **************************/
+
+int shuffle_times(double *timestor,double *timediff,dataptr dz)
+{
+	int n; 
+	n = max(dz->iparam[MSH_STARTLINE],1);
+	timediff[n-1] += dz->param[MTW_PARAM];
+	for(; n<dz->iparam[MSH_ENDLINE]; n++) {
+		timestor[n] = timestor[n-1] + timediff[n-1];
+		if(timestor[n]<0.0) {
+			sprintf(errstr,"NEGATIVE TIME GENERATED AT LINE %d\n",n+1);
+			return(GOAL_FAILED);
+		}
+	}
+	return(FINISHED);
+}
+
+/************************** SCATTER_TIMES **************************/
+
+int scatter_times(double *timestor,double *timediff,dataptr dz)
+{
+	int n; 
+	double base_scatter = 0, scatdirection;
+	if(dz->iparam[MSH_STARTLINE]==0) {
+		base_scatter = (timediff[0]/2.0) * drand48() * dz->param[MTW_PARAM];
+		timestor[0] += base_scatter;
+	}
+	for(n=max(dz->iparam[MSH_STARTLINE],1);n<dz->iparam[MSH_ENDLINE]-1;n++) {
+		scatdirection   = (drand48() * 2.0) - 1.0;
+		if(scatdirection<0.0)
+			timestor[n] += (timediff[n]/2.0) * drand48() * dz->param[MTW_PARAM];
+		else
+			timestor[n] -= (timediff[n-1]/2.0) * drand48() * dz->param[MTW_PARAM];
+	}
+	if(dz->iparam[MSH_ENDLINE]==dz->linecnt)
+		timestor[dz->linecnt-1] -= (timediff[dz->linecnt-2]/2.0) * drand48() * dz->param[MTW_PARAM];
+	else {
+		scatdirection   = (drand48() * 2.0) - 1.0;
+		if(scatdirection<0.0)
+			timestor[dz->iparam[MSH_ENDLINE]-1] += 
+			(timediff[dz->iparam[MSH_ENDLINE]]/2.0) * drand48() * dz->param[MTW_PARAM];
+		else
+			timestor[dz->iparam[MSH_ENDLINE]-1] -= 
+			(timediff[dz->iparam[MSH_ENDLINE]-1]/2.0) * drand48() * dz->param[MTW_PARAM];
+	}
+	if(dz->iparam[MSH_STARTLINE]==0){
+		for(n=0; n<dz->linecnt; n++)
+			timestor[n] -= base_scatter;
+	}
+	return(FINISHED);
+}
+
+/*************************** GET_TIMES_AND_TIMEDIFFS ***************************/
+
+int get_times_and_timediffs(double *timestor,double *timediff,dataptr dz)
+{
+	int n, timeloc;
+	int total_wordcnt = 0;
+	for(n=0;n<dz->linecnt;n++) {
+		if(dz->wordcnt[n] < 2) {
+			sprintf(errstr,"Problem getting line times: get_times_and_timediffs()\n");
+			return(PROGRAM_ERROR);
+		}
+		timeloc = total_wordcnt + MIX_TIMEPOS;
+		if(sscanf(dz->wordstor[timeloc],"%lf",&(timestor[n]))!=1) {
+			sprintf(errstr,"Problem reading time: get_times_and_timediffs()\n");
+			return(PROGRAM_ERROR);
+		}
+		total_wordcnt += dz->wordcnt[n];
+	}
+	for(n=1;n<dz->linecnt;n++)
+		timediff[n-1] = timestor[n] - timestor[n-1];
+	return(FINISHED);
+}
+
+/*************************** retime_the_lines ***************************/
+
+int retime_the_lines(double *timestor,int postdec,dataptr dz)
+{
+	int exit_status;
+	int lineno;
+	int total_words = 0;
+	for(lineno=0;lineno<dz->linecnt;lineno++) {
+		if((exit_status = put_new_time(total_words,postdec,timestor[lineno],dz))<0)
+			return(exit_status);
+		total_words += dz->wordcnt[lineno];
+	}
+	return(FINISHED);
+}
+
+/************************** PUT_NEW_TIME ***************************/
+
+int put_new_time(int total_words,int postdec,double timeval,dataptr dz)
+{
+	int wordno, newlen;
+	wordno = total_words + MIX_TIMEPOS;
+	switch(postdec) {
+	case(0):	sprintf(errstr,"%.0lf",timeval);
+	case(1):	sprintf(errstr,"%.1lf",timeval);
+	case(2):	sprintf(errstr,"%.2lf",timeval);
+	case(3):	sprintf(errstr,"%.3lf",timeval);
+	case(4):	sprintf(errstr,"%.4lf",timeval);
+	default:	sprintf(errstr,"%.5lf",timeval);   /* DEFAULT_DECIMAL_REPRESENTATION */
+	}
+	if((newlen = (int)strlen(errstr)) > (int)strlen(dz->wordstor[wordno])) {
+		if((dz->wordstor[wordno] = (char *)realloc(dz->wordstor[wordno],(newlen+1) * sizeof(char)))==NULL) {
+			sprintf(errstr,"INSUFFICIENT MEMORY for wordstore %d\n",wordno+1);
+			return(MEMORY_ERROR);
+		}
+	}
+	strcpy(dz->wordstor[wordno],errstr);
+	return(FINISHED);
+}
+
+/********************** GET_MAXWORDSIZE ****************************/
+ 
+int get_maxwordsize(int **maxwordsize,dataptr dz)
+{
+	int total_words = 0, n;
+	int m;
+	if((*maxwordsize = (int *)malloc(MIX_MAXLINE * sizeof(int)))==NULL) {
+		sprintf(errstr,"INSUFFICIENT MEMORY for max wordsize store.\n");
+		return(MEMORY_ERROR);
+	}
+	for(m=0;m<MIX_MAXLINE;m++)
+		(*maxwordsize)[m] = 0;
+
+	for(n=0;n<dz->linecnt;n++) {						
+		for(m=0;m<dz->wordcnt[n];m++)
+			(*maxwordsize)[m] = (int)max((int)(*maxwordsize)[m],(int)strlen(dz->wordstor[total_words+m]));
+		total_words += dz->wordcnt[n];											
+	}
+	return(FINISHED);
+}
+
+/********************** GET_MAXPOSTDEC ****************************/
+ 
+int get_maxpostdec(int *maxpostdec,dataptr dz)
+{
+	int total_words = 0, n, timewordno;
+	for(n=0;n<dz->linecnt;n++) {
+		timewordno = total_words + MIX_TIMEPOS;						
+		*maxpostdec = max(*maxpostdec,get_postdec(dz->wordstor[timewordno]));
+		total_words += dz->wordcnt[n];											
+	}
+	return(FINISHED);
+}
+
+/********************** GET_POSTDEC ****************************/
+ 
+int get_postdec(char *thisword)
+{
+	char *p = thisword;
+	int finished = FALSE;
+	int post_dec = 0;
+	while(*p != '.') {
+		if(*p==ENDOFSTR) {
+			finished = TRUE;
+			break;
+		}
+		p++;
+	}
+	if(!finished) {
+		p++;
+		while(*p != ENDOFSTR) {
+			post_dec++;
+			p++;
+		}
+	}
+	return post_dec;
+}
+
+/************************* MIX_GAIN ******************************/
+
+int mix_gain(dataptr dz)
+{
+	int    exit_status;
+	int   lineno, total_words;
+	double *llevelstor, *rlevelstor;
+	int    *maxwordsize = NULL, lmaxlevelsize = 0, rmaxlevelsize = 0;
+	if((dz->parray[MIX_LLEVELSTOR] = (double *)malloc(dz->linecnt * sizeof(double)))==NULL) {
+		sprintf(errstr,"INSUFFICIENT MEMORY for left levels store.\n");
+		return(MEMORY_ERROR);
+	}
+	if((dz->parray[MIX_RLEVELSTOR] = (double *)malloc(dz->linecnt * sizeof(double)))==NULL) {
+		sprintf(errstr,"INSUFFICIENT MEMORY for right levels store.\n");
+		return(MEMORY_ERROR);
+	}
+	llevelstor = dz->parray[MIX_LLEVELSTOR];
+	rlevelstor = dz->parray[MIX_RLEVELSTOR];
+
+	if((exit_status = get_maxwordsize(&maxwordsize,dz))<0)
+		return(exit_status);
+
+ 	total_words = 0;
+	for(lineno=0;lineno<dz->linecnt;lineno++) {
+		if((exit_status = get_levels(lineno,total_words,llevelstor,rlevelstor,&lmaxlevelsize,&rmaxlevelsize,dz))<0) {
+			free(maxwordsize);
+			return(exit_status);
+		}
+		total_words += dz->wordcnt[lineno];
+	}
+ 	total_words = 0;
+	for(lineno=0;lineno<dz->linecnt;lineno++) {
+		if((exit_status = convert_level
+		(lineno,total_words,maxwordsize,llevelstor,rlevelstor,lmaxlevelsize,rmaxlevelsize,dz))<0) {
+			free(maxwordsize);
+			return(exit_status);
+		}
+		total_words += dz->wordcnt[lineno];
+	}
+	free(maxwordsize);
+	return(FINISHED);
+}
+
+/********************** GET_LEVELS ****************************/
+ 
+int get_levels(int lineno,int total_words,
+double *llevelstor,double *rlevelstor,int *lmaxlevelsize,int *rmaxlevelsize,dataptr dz)
+{
+	int exit_status;
+	int wordcnt = dz->wordcnt[lineno];
+	char *thisword; 
+	double level;
+	int wordno = total_words + MIX_LEVELPOS;
+
+	thisword = dz->wordstor[wordno];
+	if((exit_status = get_level(thisword,&level))<0)
+		return(exit_status);
+	if(lineno >= dz->iparam[MSH_STARTLINE] && lineno < dz->iparam[MSH_ENDLINE])
+		llevelstor[lineno] = level * dz->param[MIX_GAIN];
+	else
+		llevelstor[lineno] = level;
+	sprintf(errstr,"%.4lf",level);
+	*lmaxlevelsize = max(*lmaxlevelsize,(int)strlen(errstr));
+
+	if(wordcnt <= MIX_RLEVELPOS)
+		return(FINISHED);
+
+	wordno = total_words + MIX_RLEVELPOS;
+	thisword = dz->wordstor[wordno];
+	if((exit_status = get_level(thisword,&level))<0)
+		return(exit_status);
+	if(lineno >= dz->iparam[MSH_STARTLINE] && lineno <= dz->iparam[MSH_ENDLINE])
+		rlevelstor[lineno] = level * dz->param[MIX_GAIN];
+	else
+		rlevelstor[lineno] = level;
+	sprintf(errstr,"%.4lf",level);
+	*rmaxlevelsize = max(*rmaxlevelsize,(int)strlen(errstr));
+	return(FINISHED);
+}
+
+/************************** CONVERT_LEVEL ***************************/
+
+int convert_level(int lineno,int total_words,int *maxwordsize,
+				double *llevelstor,double *rlevelstor,int lmaxlevelsize,int rmaxlevelsize,dataptr dz)
+{
+	int    n, m, spacecnt;
+	int   wordno;
+	int    wordcnt = dz->wordcnt[lineno];
+	for(n=0;n<wordcnt;n++) {
+		wordno = total_words + n;
+		switch(n) {
+		case(MIX_NAMEPOS):
+		case(MIX_CHANPOS):
+		case(MIX_PANPOS):
+		case(MIX_RPANPOS):
+		case(MIX_TIMEPOS):
+			if((spacecnt = maxwordsize[n] - strlen(dz->wordstor[wordno]))<0) {
+				sprintf(errstr,"word alignment error: 1: convert_level()\n");
+				return(PROGRAM_ERROR);
+			}
+			spacecnt++;
+			fprintf(dz->fp,"%s",dz->wordstor[wordno]);
+			for(m=0;m<spacecnt;m++)
+				fprintf(dz->fp," ");
+			break;
+		case(MIX_LEVELPOS):
+			sprintf(errstr,"%.4lf",llevelstor[lineno]);
+			if((spacecnt = lmaxlevelsize - strlen(errstr))<0) {
+				sprintf(errstr,"word alignment error: 2: convert_level()\n");
+				return(PROGRAM_ERROR);
+			}
+			spacecnt++;
+			fprintf(dz->fp,"%s",errstr);
+			for(m=0;m<spacecnt;m++)
+				fprintf(dz->fp," ");
+			break;
+		case(MIX_RLEVELPOS):
+			sprintf(errstr,"%.4lf",rlevelstor[lineno]);
+			if((spacecnt = rmaxlevelsize - strlen(errstr))<0) {
+				sprintf(errstr,"word alignment error: 3: convert_level()\n");
+				return(PROGRAM_ERROR);
+			}
+			spacecnt++;
+			fprintf(dz->fp,"%s",errstr);
+			for(m=0;m<spacecnt;m++)
+				fprintf(dz->fp," ");
+			break;
+		default:
+			sprintf(errstr,"Impossible line wordcnt: convert_level()\n");
+			return(PROGRAM_ERROR);
+		}
+	}
+	fprintf(dz->fp,"\n");
+	return(FINISHED);
+}
+
+/*********************** DO_NAME_AND_TIME_REVERSE **************************/
+
+int do_name_and_time_reverse(dataptr dz)
+{
+	int    exit_status;
+	double *timestor, *timediff;
+	int    *maxwordsize = NULL, postdec = 0;
+	int   *name_index;
+	char   *temp;
+	int   lineno, newlineno, total_words = 0, half_linecnt;
+
+	if((dz->parray[MTW_TIMESTOR] = (double *)malloc(dz->linecnt * sizeof(double)))==NULL) {
+		sprintf(errstr,"INSUFFICIENT MEMORY for times store.\n");
+		return(MEMORY_ERROR);
+	}
+	if((dz->parray[MTW_TIMEDIFF] = (double *)malloc(dz->linecnt * sizeof(double)))==NULL) {
+		sprintf(errstr,"INSUFFICIENT MEMORY for timegaps store.\n");
+		return(MEMORY_ERROR);
+	}
+	if((name_index = (int *)malloc(dz->linecnt * sizeof(int)))==NULL) {
+		sprintf(errstr,"INSUFFICIENT MEMORY for name index store.\n");
+		return(PROGRAM_ERROR);
+	}
+
+	timestor = dz->parray[MTW_TIMESTOR];
+	timediff = dz->parray[MTW_TIMEDIFF];
+
+	if((exit_status = get_maxpostdec(&postdec,dz))<0) {
+		free(name_index);
+		return(exit_status);
+	}
+	if((exit_status = get_times_and_timediffs(timestor,timediff,dz))<0) {
+		free(name_index);
+		return(exit_status);
+	}
+	if((exit_status = reverse_times(timestor,timediff,dz))<0) {
+		free(name_index);
+		return(exit_status);
+	}
+	for(lineno=0;lineno<dz->linecnt;lineno++) {
+		name_index[lineno] = total_words;
+		total_words += dz->wordcnt[lineno];
+	}
+	half_linecnt  = dz->iparam[MSH_ENDLINE] - dz->iparam[MSH_STARTLINE];
+	half_linecnt  = half_linecnt/2; /* TRUNCATE */
+	half_linecnt += dz->iparam[MSH_STARTLINE];
+
+	for(lineno=dz->iparam[MSH_STARTLINE],newlineno=dz->iparam[MSH_ENDLINE]-1;lineno < half_linecnt;lineno++,newlineno--) {
+		temp            					= dz->wordstor[name_index[lineno]];
+		dz->wordstor[name_index[lineno]] 	= dz->wordstor[name_index[newlineno]];
+		dz->wordstor[name_index[newlineno]] = temp;
+	}		
+
+	if((exit_status = retime_the_lines(timestor,postdec,dz))<0) {
+		free(name_index);
+		return(exit_status);
+	}
+	if((exit_status = get_maxwordsize(&maxwordsize,dz))<0) {
+		free(name_index);
+		return(exit_status);
+	}
+	if((exit_status = output_mixfile_lines(maxwordsize,dz))<0) {
+		free(maxwordsize);
+		free(name_index);
+		return(exit_status);
+	}
+	free(maxwordsize);
+	free(name_index);
+	return(FINISHED);
+}
+
+/*********************** DO_NAME_AND_TIME_FREEZE **************************/
+
+int do_name_and_time_freeze(dataptr dz)
+{
+	int    exit_status;
+	double *timestor, *timediff;
+	int    *maxwordsize = NULL, postdec = 0;
+	int   *name_index;
+	int   lineno, total_words = 0;
+
+	if((dz->parray[MTW_TIMESTOR] = (double *)malloc(dz->linecnt * sizeof(double)))==NULL) {
+		sprintf(errstr,"INSUFFICIENT MEMORY for times store.\n");
+		return(MEMORY_ERROR);
+	}
+	if((dz->parray[MTW_TIMEDIFF] = (double *)malloc(dz->linecnt * sizeof(double)))==NULL) {
+		sprintf(errstr,"INSUFFICIENT MEMORY for timegaps store.\n");
+		return(MEMORY_ERROR);
+	}
+	if((name_index = (int *)malloc(dz->linecnt * sizeof(int)))==NULL) {
+		sprintf(errstr,"INSUFFICIENT MEMORY for name index store.\n");
+		return(PROGRAM_ERROR);
+	}
+
+	timestor = dz->parray[MTW_TIMESTOR];
+	timediff = dz->parray[MTW_TIMEDIFF];
+
+	if((exit_status = get_maxpostdec(&postdec,dz))<0) {
+		free(name_index);
+		return(exit_status);
+	}
+	if((exit_status = get_times_and_timediffs(timestor,timediff,dz))<0) {
+		free(name_index);
+		return(exit_status);
+	}
+	if((exit_status = freeze_times(timestor,timediff,dz))<0) {
+		free(name_index);
+		return(exit_status);
+	}
+	for(lineno=0;lineno<dz->linecnt;lineno++) {
+		name_index[lineno] = total_words;
+		total_words += dz->wordcnt[lineno];
+	}
+
+	for(lineno=dz->iparam[MSH_STARTLINE]+1;lineno < dz->iparam[MSH_ENDLINE];lineno++) {
+		free(dz->wordstor[name_index[lineno]]);
+		dz->wordstor[name_index[lineno]] = dz->wordstor[name_index[dz->iparam[MSH_STARTLINE]]];
+	}
+
+	if((exit_status = retime_the_lines(timestor,postdec,dz))<0) {
+		free(name_index);
+		return(exit_status);
+	}
+	if((exit_status = get_maxwordsize(&maxwordsize,dz))<0) {
+		free(name_index);
+		return(exit_status);
+	}
+	if((exit_status = output_mixfile_lines(maxwordsize,dz))<0) {
+		free(maxwordsize);
+		free(name_index);
+		return(exit_status);
+	}
+	free(maxwordsize);
+	free(name_index);
+	return(FINISHED);
+}
+
+/*********************** TIMESORT_MIXFILE **************************/
+
+int timesort_mixfile(double *timestor,dataptr dz)
+{
+	int    n, m; 
+	int   lineno, startword, endword;
+	double temptime, *timecopy;
+	int   *line_wordindex, total_words, running_total_words;
+	int    *permm, tempperm, *wordcnt_copy;
+	char   **wordcopy;
+	total_words = 0;
+	for(n=0;n<dz->linecnt;n++)
+		total_words += dz->wordcnt[n];
+	if((permm = (int *)malloc(dz->linecnt * sizeof(int)))==NULL) {
+		sprintf(errstr,"INSUFFICIENT MEMORY for permutation.");
+		return(MEMORY_ERROR);
+	}
+	if((wordcnt_copy = (int *)malloc(dz->linecnt * sizeof(int)))==NULL) {
+		sprintf(errstr,"INSUFFICIENT MEMORY for wordcnt copy.");
+		return(MEMORY_ERROR);
+	}
+	if((line_wordindex = (int *)malloc((dz->linecnt + 1) * sizeof(int)))==NULL) {
+		sprintf(errstr,"INSUFFICIENT MEMORY for word index.");
+		return(MEMORY_ERROR);
+	}
+	if((timecopy = (double *)malloc(dz->linecnt * sizeof(double)))==NULL) {
+		sprintf(errstr,"INSUFFICIENT MEMORY for time copy.");
+		return(MEMORY_ERROR);
+	}
+	if((wordcopy = (char **)malloc(total_words * sizeof(char *)))==NULL) {
+		sprintf(errstr,"INSUFFICIENT MEMORY for word copy.");
+		return(MEMORY_ERROR);
+	}
+	for(n=0;n<dz->linecnt;n++)
+		permm[n] = n;
+	for(n=0;n<dz->linecnt;n++)
+		timecopy[n] = timestor[n];
+	total_words = 0;
+	for(n=0;n<dz->linecnt;n++) {
+		line_wordindex[n] = total_words;
+		total_words += dz->wordcnt[n];
+	}
+	line_wordindex[dz->linecnt] = total_words;
+	for(n=1;n<dz->linecnt;n++) {
+		temptime = timecopy[n];
+		tempperm = permm[n];
+		m = n-1;
+		while(m >= 0 && timecopy[m] > temptime) {
+			timecopy[m+1] = timecopy[m];
+			permm[m+1]    = permm[m];
+			m--;
+		}			
+		timecopy[m+1] = temptime;
+		permm[m+1]    = tempperm;
+	}
+	running_total_words = 0;
+	for(n=0;n<dz->linecnt;n++) {
+		lineno = permm[n];
+		wordcnt_copy[n] = dz->wordcnt[permm[n]];
+		startword = line_wordindex[lineno];
+		endword   = line_wordindex[lineno+1];
+		for(m=0;m<wordcnt_copy[n];m++) {
+			wordcopy[running_total_words] = dz->wordstor[startword+m]; 
+			if(++running_total_words > total_words) {
+				free(permm);
+				free(wordcnt_copy);
+				free(line_wordindex);
+				free(timecopy);
+				free(wordcopy);
+				sprintf(errstr,"Accounting error in timesort_mixfile()\n");
+				return(PROGRAM_ERROR);
+			}
+		}
+	}
+	for(n=0;n<total_words;n++)
+		dz->wordstor[n] = wordcopy[n];
+	for(n=0;n<dz->linecnt;n++)
+		dz->wordcnt[n]  = wordcnt_copy[n];
+	free(permm);
+	free(wordcnt_copy);
+	free(line_wordindex);
+	free(timecopy);
+	free(wordcopy);
+	return(FINISHED);
+}
+
+/*********************** DELETE_WORDSTORAGE_SPACE_OF_ALL_DELETED_LINES **************************/
+
+void delete_wordstorage_space_of_all_deleted_lines(int oldwordcnt,char **wordcopy,dataptr dz)
+{
+	int n, m;
+	int is_kept;
+	for(m=0;m<oldwordcnt;m++) {
+		is_kept = FALSE;
+		for(n=0;n<dz->all_words;n++) {
+			if(wordcopy[m] == dz->wordstor[n]) {
+				is_kept = TRUE;
+				break;
+			}
+		}
+		if(!is_kept)
+			free(wordcopy[m]);
+	}
+}
+
+/********************** MIX_SYNC ****************************/
+ 
+int mix_sync(dataptr dz)
+{
+	int    exit_status;
+	int   srate;
+	int	   this_namelen, max_namelen = 0, max_timeword = 0, *inchans;												
+	int   n;
+	double maxfiletime = 0.0, midtime, *timestor;
+
+	if(dz->infile->filetype==MIXFILE)
+		return mix_sync_a_mixfile(dz);
+
+	if(dz->all_words==0) {
+		sprintf(errstr,"No words in source file.\n");
+		return(PROGRAM_ERROR);
+	}
+	if((dz->parray[MSY_TIMESTOR] = (double *)malloc(dz->linecnt * sizeof(double)))==NULL) {
+		sprintf(errstr,"INSUFFICIENT MEMORY for times store.\n");
+		return(MEMORY_ERROR);
+	}
+	timestor = dz->parray[MSY_TIMESTOR];
+	if((dz->iparray[MSY_CHANS] = (int *)malloc(dz->linecnt * sizeof(int)))==NULL) {
+		sprintf(errstr,"INSUFFICIENT MEMORY for channels store.\n");
+		return(MEMORY_ERROR);
+	}
+	inchans = dz->iparray[MSY_CHANS];
+	if((exit_status = establish_file_data_storage_for_mix((int)1,dz))<0)
+		return(exit_status);
+	for(n=0;n<dz->all_words;n++) {						/* for each sndfile name */
+		if((this_namelen = strlen(dz->wordstor[n]))<=0) {
+			sprintf(errstr,"filename error: line %d: mix_sync()\n",n+1);
+			return(PROGRAM_ERROR);
+		}
+		max_namelen = max(max_namelen,this_namelen);
+		if((exit_status = open_file_and_retrieve_props(n,dz->wordstor[n],&srate,dz))<0)
+			return(exit_status);
+		inchans[n]  = dz->infile->channels;
+		/*RWD NB clac from sampsize */
+		timestor[n] = (double)(dz->insams[0]/dz->infile->channels)/(double)dz->infile->srate;
+		maxfiletime = max(maxfiletime,timestor[n]);
+	}
+	midtime = maxfiletime/2.0;
+	for(n=0;n<dz->all_words;n++) {
+		switch(dz->mode) {
+		case(MIX_SYNCEND):	timestor[n] = maxfiletime - timestor[n];		break;
+		case(MIX_SYNCMID):	timestor[n] = midtime     - timestor[n]/2.0;	break;
+		case(MIX_SYNCSTT):	timestor[n] = 0.0;								break;
+		default:
+			sprintf(errstr,"Unknown mode in mix_sync()\n");
+			return(PROGRAM_ERROR);
+		}
+		sprintf(errstr,"%.5lf",timestor[n]);
+		max_timeword = max(max_timeword,(int)strlen(errstr));
+	}							
+	for(n=0;n<dz->all_words;n++) {						
+		if((exit_status = sync_and_output_mixfile_line
+		(n,dz->wordstor[n],max_namelen,max_timeword,timestor[n],1.0,dz))<0)
+			return(exit_status);
+	}
+	return(FINISHED);
+}
+
+/********************** MIX_SYNC_A_MIXFILE ****************************/
+
+int mix_sync_a_mixfile(dataptr dz)
+{
+	int    exit_status;
+	int   srate;
+	int   n, total_words;
+	double maxfiletime = 0.0, midtime, *timestor;
+	int    *maxwordsize = NULL, postdec;
+
+	if(dz->linecnt==0) {
+		sprintf(errstr,"No words in source file.\n");
+		return(PROGRAM_ERROR);
+	}
+	if((dz->parray[MSY_TIMESTOR] = (double *)malloc(dz->linecnt * sizeof(double)))==NULL) {
+		sprintf(errstr,"INSUFFICIENT MEMORY for times store.\n");
+		return(MEMORY_ERROR);
+	}
+	timestor = dz->parray[MSY_TIMESTOR];
+	if((exit_status = establish_file_data_storage_for_mix((int)1,dz))<0)
+		return(exit_status);
+	total_words = 0;
+	for(n=0;n<dz->linecnt;n++) {						/* for each sndfile name */
+		if((exit_status = open_file_and_retrieve_props(n,dz->wordstor[total_words],&srate,dz))<0)
+			return(exit_status);
+		/*RWD NB calc from sampsize */
+		timestor[n]  = (double)(dz->insams[0]/dz->infile->channels)/(double)dz->infile->srate;
+		maxfiletime  = max(maxfiletime,timestor[n]);
+		total_words += dz->wordcnt[n];
+	}
+	midtime = maxfiletime/2.0;
+	for(n=0;n<dz->linecnt;n++) {
+		switch(dz->mode) {
+		case(MIX_SYNCEND):	timestor[n] = maxfiletime - timestor[n];		break;
+		case(MIX_SYNCMID):	timestor[n] = midtime     - timestor[n]/2.0;	break;
+		case(MIX_SYNCSTT):	timestor[n] = 0.0;								break;
+		default:
+			sprintf(errstr,"Unknown mode in mix_sync()\n");
+			return(PROGRAM_ERROR);
+		}
+	}							
+	postdec = DEFAULT_DECIMAL_REPRESENTATION;
+	if((exit_status = retime_the_lines(timestor,postdec,dz))<0)
+		return(exit_status);
+	if((exit_status = timesort_mixfile(timestor,dz))<0)
+		return(exit_status);
+	if((exit_status = get_maxwordsize(&maxwordsize,dz))<0)
+		return(exit_status);
+	if((exit_status = output_mixfile_lines(maxwordsize,dz))<0)
+		return(exit_status);
+	free(maxwordsize);
+	return(FINISHED);
+}
+
+/************************* SYNC_AND_OUTPUT_MIXFILE_LINE *******************************/
+
+int sync_and_output_mixfile_line
+(int lineno,char *filename,int max_namelen,int max_timeword,double timestor,double gain,dataptr dz)
+{
+	int space_count, n;
+	if((space_count = max_namelen - strlen(filename))<0) {
+		sprintf(errstr,"Anomaly 1 in space counting: sync_and_output_mixfile_line()\n");
+		return(PROGRAM_ERROR);
+	}
+	space_count++;
+	fprintf(dz->fp,"%s",filename);
+	for(n=0;n<space_count;n++)
+		fprintf(dz->fp," ");
+
+	sprintf(errstr,"%.5lf",timestor);
+	if((space_count = max_timeword - strlen(errstr))<0) {
+		sprintf(errstr,"Anomaly 2 in space counting: sync_and_output_mixfile_line()\n");
+		return(PROGRAM_ERROR);
+	}
+	space_count++;
+	fprintf(dz->fp,"%s",errstr);
+	for(n=0;n<space_count;n++)
+		fprintf(dz->fp," ");
+	switch(dz->iparray[MSY_CHANS][lineno]) {
+	case(MONO):
+		if(flteq(gain,1.0))
+			fprintf(dz->fp,"  1  1.0  C\n");
+		else
+			fprintf(dz->fp,"  1  %.5lf  C\n",gain);
+		break;
+	case(STEREO):	
+		if(flteq(gain,1.0))
+			fprintf(dz->fp,"  2  1.0  L  1.0  R\n");
+		else
+			fprintf(dz->fp,"  2  %.5lf  L  %.5lf  R\n",gain,gain);
+		break;
+	default:
+		sprintf(errstr,"Unknown case in create_and_output_mixfile_line()\n");
+		return(PROGRAM_ERROR);
+	}
+	return(FINISHED);
+}

+ 385 - 0
dev/submix/mixshuf2.c

@@ -0,0 +1,385 @@
+/*
+ * 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 <string.h>
+#include <structures.h>
+#include <tkglobals.h>
+#include <globcon.h>
+#include <processno.h>
+#include <modeno.h>
+#include <arrays.h>
+#include <filetype.h>
+#include <mix.h>
+#include <cdpmain.h>
+
+#include <sfsys.h>
+#include <osbind.h>
+
+
+static int  check_chans(int lineno,int oldwordpos,dataptr dz);
+static void insert_word(char **permm,int permlen,int *name_index,int m,int t,dataptr dz);
+static void prefix_word(char **perm,int permlen,int *name_index,int m,dataptr dz);
+static void shuflup_words(char **perm,int permlen,int k);
+static int  output_mixfile_line(char **wordstor,int total_words,int wordcnt,int *maxwordsize,dataptr dz);
+
+/************************* DO_TIME_AND_NAME_COPY ************************/
+
+int do_time_and_name_copy(dataptr dz)
+{
+	int  exit_status;
+	int  extra_words = 0;
+	int  *maxwordsize;
+	int total_words = 0, new_words = 0, words_above = 0, moveindex;
+	int new_total_words, oldwordpos, orig_oldwordpos, newwordpos;
+	int  n, lineno, wordno, newlines, lines_above, oldlinecnt;
+
+	if(dz->mode==MSH_DUPL_AND_RENAME) {	   /* space for the new sndfilename must bhave been allocated */
+		if(dz->extra_word<0) {
+			sprintf(errstr,"extra_word not accounted for: do_time_and_name_copy()\n");
+			return(PROGRAM_ERROR);
+		}
+		extra_words = 1;
+	}
+
+	newlines    = dz->iparam[MSH_ENDLINE] - dz->iparam[MSH_STARTLINE];
+	lines_above = dz->linecnt - dz->iparam[MSH_ENDLINE];
+
+	for(n=0;n<dz->linecnt;n++)
+		total_words += dz->wordcnt[n];
+
+	for(n=dz->iparam[MSH_ENDLINE];n<dz->linecnt;n++)
+		words_above += dz->wordcnt[n];
+
+	for(n=dz->iparam[MSH_STARTLINE];n<dz->iparam[MSH_ENDLINE];n++)
+		new_words += dz->wordcnt[n];
+
+	new_total_words = total_words + new_words;
+
+	if((dz->wordstor = (char **)realloc(dz->wordstor,(new_total_words+extra_words) * sizeof(char *)))==NULL) {
+		sprintf(errstr,"INSUFFICIENT MEMORY for word store.\n");
+		return(MEMORY_ERROR);								/* alloc space for all new words */
+	}
+	for(n=total_words+extra_words; n < new_total_words+extra_words;n++)
+		dz->wordstor[n] = NULL;
+
+	oldlinecnt = dz->linecnt;
+	dz->linecnt += newlines;
+
+	if((dz->wordcnt = (int *)realloc(dz->wordcnt,dz->linecnt * sizeof(int)))==NULL) {
+		sprintf(errstr,"INSUFFICIENT MEMORY for word count store.\n");
+		return(MEMORY_ERROR);								/* alloc space for all new line wordcnts */
+	}
+	for(n=oldlinecnt; n < dz->linecnt;n++)
+		dz->wordcnt[n] = 0;
+
+	dz->all_words  += new_words;							/* update total wordcnt: good housekeeping */
+			
+	oldwordpos      = total_words + extra_words     - 1;
+	newwordpos      = new_total_words + extra_words - 1;
+												/* 'MOVE' WORDS BEYOND THE ACTED-ON LINES + ANY EXTRA_WORD */
+	for(n=0;n<(words_above+extra_words);n++) {	
+		dz->wordstor[newwordpos] = dz->wordstor[oldwordpos];
+		newwordpos--;
+		oldwordpos--;
+		if(oldwordpos<0) {
+			sprintf(errstr,"Accounting problem 0: do_time_and_name_copy()\n");
+			return(PROGRAM_ERROR);
+		}
+	}
+	for(n=oldlinecnt;n<dz->linecnt;n++)			/* Put correct wordcnt in place for these moved lines */
+		dz->wordcnt[n] = dz->wordcnt[n - newlines];
+ 
+ 	if(dz->mode==MSH_DUPL_AND_RENAME)  			/* adjust address where new sndfilename is now found */
+		dz->extra_word += new_words;
+
+	oldwordpos = 0;								/* GO TO THE END OF THE WORDS TO DUPLICATE */
+	for(lineno=0;lineno<dz->iparam[MSH_ENDLINE];lineno++)
+		oldwordpos += dz->wordcnt[lineno];
+	oldwordpos--;
+	newwordpos = oldwordpos + new_words; 		/* MOVING BACKWARDS, DUPLICATE THE ACTED-ON LINES */
+
+	for(lineno = dz->iparam[MSH_ENDLINE]-1,moveindex = newlines;lineno>=dz->iparam[MSH_STARTLINE];lineno--,moveindex--) {
+
+		orig_oldwordpos = oldwordpos;			/* CREATE WORDS IN A DUPLICATE LINE */
+		for(wordno=dz->wordcnt[lineno]-1;wordno>=0;wordno--) {		
+												/* CHECKING THE CHANNEL If process DEMANDS IT */
+  			if(wordno==MIX_CHANPOS && dz->mode==MSH_DUPL_AND_RENAME && dz->vflag[MSH_NOCHECK]==FALSE) {
+				if((exit_status = check_chans(lineno,oldwordpos,dz))<0)
+					return(exit_status);
+			}									/* SUBSTITUTING NEW NAME: IF process DEMANDS IT */
+  			if(wordno==MIX_NAMEPOS && dz->mode==MSH_DUPL_AND_RENAME)
+				dz->wordstor[newwordpos] = dz->wordstor[dz->extra_word];
+			else
+				dz->wordstor[newwordpos] = dz->wordstor[oldwordpos];
+			oldwordpos--;
+			newwordpos--;
+			if(lineno > 0 && wordno > 0) {
+				if(oldwordpos<0) {
+					sprintf(errstr,"Accounting problem 1: do_time_and_name_copy()\n");
+					return(PROGRAM_ERROR);
+				}
+			}
+		}
+		dz->wordcnt[lineno+moveindex] = dz->wordcnt[lineno];
+
+		oldwordpos = orig_oldwordpos;			/* THEN ALSO MOVE WORDS OF ORIGINAL LINE */
+		if(newwordpos < oldwordpos) {
+			sprintf(errstr,"Accounting problem 2: do_time_and_name_copy()\n");
+			return(PROGRAM_ERROR);
+		}
+		for(wordno=dz->wordcnt[lineno]-1;wordno>=0;wordno--) {
+			dz->wordstor[newwordpos] = dz->wordstor[oldwordpos];
+			oldwordpos--;
+			newwordpos--;
+		}
+		if(moveindex-1 < 0) {
+			sprintf(errstr,"Accounting problem 2a: do_time_and_name_copy()\n");
+			return(PROGRAM_ERROR);
+		}
+		dz->wordcnt[lineno+moveindex-1] = dz->wordcnt[lineno];
+	}
+											
+	if((exit_status = get_maxwordsize(&maxwordsize,dz))<0)
+		return(exit_status);
+	if((exit_status = output_mixfile_lines(maxwordsize,dz))<0)
+		return(exit_status);
+	free(maxwordsize);
+	return(FINISHED);
+}
+
+/************************* OUTPUT_MIXFILE_LINES ******************************/
+
+int output_mixfile_lines(int *maxwordsize,dataptr dz)
+{
+	int exit_status;
+	int n;
+	int total_words = 0;
+	for(n=0;n<dz->linecnt;n++) {						
+		if((exit_status = output_mixfile_line(dz->wordstor,total_words,dz->wordcnt[n],maxwordsize,dz))<0)
+			return(exit_status);
+		total_words += dz->wordcnt[n];
+	}
+	return(FINISHED);
+}
+
+/************************* CHECK_CHANS ******************************/
+
+int check_chans(int lineno,int oldwordpos,dataptr dz)
+{
+	int chans;
+	if(sscanf(dz->wordstor[oldwordpos],"%d",&chans)!=1) {
+		sprintf(errstr,"Failed to read channel value:line %d: check_chans()\n",lineno+1);
+		return(PROGRAM_ERROR);
+	}
+	if(chans!=dz->otherfile->channels) {
+		sprintf(errstr,"New named file has incompatible channel cnt: line %d: check_chans()\n",lineno+1);
+		return(DATA_ERROR);
+	}
+	return(FINISHED);
+}
+
+/************************* DO_NAME_REVERSE ******************************/
+
+int do_name_reverse(dataptr dz)
+{
+	int exit_status;
+	int  *maxwordsize;
+	int *name_index;
+	int half_linecnt;
+	char *temp;
+	int lineno, newlineno, total_words = 0;
+
+	if((name_index = (int *)malloc(dz->linecnt * sizeof(int)))==NULL) {
+		sprintf(errstr,"do_name_reverse()\n");
+		return(PROGRAM_ERROR);
+	}
+	if((exit_status = get_maxwordsize(&maxwordsize,dz))<0) {
+		free(name_index);
+		return(exit_status);
+	}
+	for(lineno=0;lineno<dz->linecnt;lineno++) {
+		name_index[lineno] = total_words;
+		total_words += dz->wordcnt[lineno];
+	}
+
+	half_linecnt  = dz->iparam[MSH_ENDLINE] - dz->iparam[MSH_STARTLINE];
+	half_linecnt  = half_linecnt/2; /* TRUNCATE */
+	half_linecnt += dz->iparam[MSH_STARTLINE];
+
+	for(lineno=dz->iparam[MSH_STARTLINE],newlineno=dz->iparam[MSH_ENDLINE]-1;lineno < half_linecnt;lineno++,newlineno--) {
+		temp            					= dz->wordstor[name_index[lineno]];
+		dz->wordstor[name_index[lineno]] 	= dz->wordstor[name_index[newlineno]];
+		dz->wordstor[name_index[newlineno]] = temp;
+	}		
+	if((exit_status = output_mixfile_lines(maxwordsize,dz))<0) {
+		free(maxwordsize);
+		free(name_index);
+		return(exit_status);
+	}
+	free(maxwordsize);
+	free(name_index);
+	return(FINISHED);
+}
+
+/************************* DO_NAME_FREEZE ******************************/
+
+int do_name_freeze(dataptr dz)
+{
+	int exit_status;
+	int  *maxwordsize;
+	int *name_index;
+	int lineno, total_words = 0;
+
+	if((name_index = (int *)malloc(dz->linecnt * sizeof(int)))==NULL) {
+		sprintf(errstr,"do_name_reverse()\n");
+		return(PROGRAM_ERROR);
+	}
+	if((exit_status = get_maxwordsize(&maxwordsize,dz))<0) {
+		free(name_index);
+		return(exit_status);
+	}	
+	for(lineno=0;lineno<dz->linecnt;lineno++) {
+		name_index[lineno] = total_words;
+		total_words += dz->wordcnt[lineno];
+	}
+
+	for(lineno=dz->iparam[MSH_STARTLINE];lineno < dz->iparam[MSH_ENDLINE];lineno++)
+		dz->wordstor[name_index[lineno]] = dz->wordstor[name_index[dz->iparam[MSH_STARTLINE]]];
+
+	if((exit_status = output_mixfile_lines(maxwordsize,dz))<0) {
+		free(name_index);
+		free(maxwordsize);
+		return(exit_status);
+	}
+	free(name_index);
+	free(maxwordsize);
+	return(FINISHED);
+}
+
+/************************** RANDOMISE_NAMES **************************/
+
+int randomise_names(dataptr dz)
+{
+	int  exit_status;
+	int  *maxwordsize;
+	int *name_index;
+	int lineno, total_words = 0;
+	int n, m, t; 
+	int permlen = dz->iparam[MSH_ENDLINE] - dz->iparam[MSH_STARTLINE];
+	char **permm;
+
+	if((name_index = (int *)malloc(dz->linecnt * sizeof(int)))==NULL) {
+		sprintf(errstr,"randomise_names(): 1\n");
+		return(PROGRAM_ERROR);
+	}
+	if((permm = (char **)malloc(permlen * sizeof(char *)))==NULL) {
+		free(name_index);
+		sprintf(errstr,"randomise_names(): 2\n");
+		return(PROGRAM_ERROR);
+	}
+	if((exit_status = get_maxwordsize(&maxwordsize,dz))<0) {
+		free(name_index);
+		free(permm);
+		return(exit_status);
+	}	
+	for(lineno=0;lineno<dz->linecnt;lineno++) {
+		name_index[lineno] = total_words;
+		total_words += dz->wordcnt[lineno];
+	}
+	for(n=0;n<permlen;n++) {
+		t = (int)(drand48() * (double)(n+1));
+		if(t==n)
+			prefix_word(permm,permlen,name_index,n+dz->iparam[MSH_STARTLINE],dz);
+		else
+			insert_word(permm,permlen,name_index,n+dz->iparam[MSH_STARTLINE],t,dz);
+	}
+	for(n=0,m=dz->iparam[MSH_STARTLINE];n<permlen;n++,m++)
+		dz->wordstor[name_index[m]] = permm[n];
+	if((exit_status = output_mixfile_lines(maxwordsize,dz))<0) {
+		free(name_index);
+		free(permm);
+		free(maxwordsize);
+		return(exit_status);
+	}
+	free(name_index);
+	free(permm);
+	free(maxwordsize);
+	return(FINISHED);
+}
+
+/****************************** INSERT_WORD ****************************/
+
+void insert_word(char **permm,int permlen,int *name_index,int m,int t,dataptr dz)
+{   
+	shuflup_words(permm,permlen,t+1);
+	permm[t+1] = dz->wordstor[name_index[m]];
+}
+
+/****************************** PREFIX_WORD ****************************/
+
+void prefix_word(char **permm,int permlen,int *name_index,int m,dataptr dz)
+{
+	shuflup_words(permm,permlen,0);
+	permm[0] = dz->wordstor[name_index[m]];
+}
+
+/****************************** SHUFLUP_WORDS ****************************/
+
+void shuflup_words(char **permm,int permlen,int k)
+{
+	int n;
+	char **i;
+	int z = permlen - 1;
+	i = &(permm[z]);
+	for(n = z; n > k; n--) {
+		*i = *(i-1);
+		i--;
+	}
+}
+
+/************************** OUTPUT_MIXFILE_LINE ***************************/
+
+int output_mixfile_line(char **wordstor,int total_words,int wordcnt,int *maxwordsize,dataptr dz)
+{
+	int n, m, spacecnt;
+	int wordno;
+	for(n = 0;n<wordcnt;n++) {
+		wordno = total_words + n;
+		if((spacecnt = maxwordsize[n] - strlen(wordstor[wordno]))<0) {
+			sprintf(errstr,"Word alignment error: output_mixfile_line()\n");
+			return(PROGRAM_ERROR);
+		}
+		spacecnt++;
+		fprintf(dz->fp,"%s",wordstor[wordno]);
+		for(m=0;m<spacecnt;m++)
+			fprintf(dz->fp," ");
+	}
+	fprintf(dz->fp,"\n");
+	return(FINISHED);
+}

+ 685 - 0
dev/submix/newmix0.c

@@ -0,0 +1,685 @@
+/*
+ * 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 <mix.h>
+#include <cdpmain.h>
+
+#include <sfsys.h>
+
+static int  test_mixdata_in_line(int wordcnt,char **wordstor,int total_words,int *chans,int lineno,dataptr dz);
+static int  test_right_level(char *str,int lineno);
+static int  test_right_pan(char *str,int lineno);
+static int  test_left_level(char *str,int lineno);
+static int  test_left_pan(char *str,int lineno);
+static int  open_file_and_test_props(int filecnt,char *filename,int *srate,int chans,int lineno,dataptr dz);
+
+static int  syntax_check_mix(dataptr dz);
+//TW UPDATED FUNCTION
+static int  create_and_output_mixfile_line(int infilno,int max_namelen,double *running_total,dataptr dz);
+
+static int  output_mixfile_line(char **wordstor,int *maxwordsize,int start_word_no,int words_in_line,dataptr dz);
+static int  twist_mixfile_line(char **wordstor,int *maxwordsize,int start_word_no,int words_in_line,dataptr dz);
+static int  output_aligned_word(char *thisword,int maxthiswordsize,dataptr dz);
+static int  mirror_panning(char *thisword, int maxthiswordsize,dataptr dz);
+
+/*************************** MIX_SYNTAX_CHECK *************************/
+
+int mix_syntax_check(dataptr dz)
+{
+	int exit_status;
+	if((exit_status = syntax_check_mix(dz))<0)
+		return(exit_status);
+	if(exit_status==CONTINUE)
+		sprintf(errstr,"MIX SYNTAX IS CORRECT.\n");
+	return(FINISHED);
+}
+
+/********************** SYNTAX_CHECK_MIX ****************************/
+ 
+int syntax_check_mix(dataptr dz)
+{
+	int    exit_status;
+	int    chans;
+	int   srate=0;
+	char   *filename;
+	int    filecnt = 0;												
+	int   total_words = 0, n;
+	if(dz->infile->filetype == MIXFILE)
+		return(CONTINUE);
+	if((exit_status = establish_file_data_storage_for_mix((int)1,dz))<0)
+		return(exit_status);
+	for(n=0;n<dz->linecnt;n++) {						/* for each mixfile line */
+		if(dz->wordstor[total_words][0]==';') {
+			total_words += dz->wordcnt[n];
+			continue;	
+		}	
+		filename = dz->wordstor[total_words];			/* get the filename */
+		if(strlen(filename)<=0) {
+			sprintf(errstr,"filename error: line %d\n",dz->linecnt+1);
+			return(FINISHED);
+		}
+		if((exit_status = test_mixdata_in_line(dz->wordcnt[n],dz->wordstor,total_words,&chans,n,dz))!=CONTINUE)
+			return(FINISHED);
+		total_words += dz->wordcnt[n];
+		if((exit_status = open_file_and_test_props(filecnt,filename,&srate,chans,n,dz))<0)
+			return(exit_status);
+		if(exit_status!=CONTINUE)
+			return(FINISHED);
+		filecnt++;											/* count the ACTUALLY USED lines: ignore comments */
+	}
+	if(filecnt==0) {
+		sprintf(errstr,"No active mixfile lines.\n");
+		return(FINISHED);
+	}
+	return(CONTINUE);
+}
+
+/**************************** TEST_MIXDATA_IN_LINE ********************************/
+
+int test_mixdata_in_line(int wordcnt,char **wordstor,int total_words,int *chans,int lineno,dataptr dz)
+{
+	int exit_status;
+	double time;
+	switch(wordcnt) {
+	case(MIX_MAXLINE):
+		if((exit_status = test_right_level(wordstor[total_words+MIX_RLEVELPOS],lineno))!=CONTINUE)	/* 6d */
+			return(FINISHED);
+		if((exit_status = test_right_pan(wordstor[total_words+MIX_RPANPOS],lineno))!=CONTINUE)
+			return(FINISHED);
+		/* fall thro */
+	case(MIX_MIDLINE):
+		if((exit_status = test_left_pan(wordstor[total_words+MIX_PANPOS],lineno))!=CONTINUE)		/* 6c */
+			return(FINISHED);
+		/* fall thro */
+	case(MIX_MINLINE):
+		if(sscanf(dz->wordstor[total_words+MIX_TIMEPOS],"%lf",&time)!=1)  {
+			sprintf(errstr,"Cannot read time data: line %d\n",lineno+1);
+			return(FINISHED);
+		}
+		if(time < 0.0) {
+			sprintf(errstr,"time value less than 0.0 time: line %d\n",lineno+1);
+			return(FINISHED);
+		}
+		if(sscanf(dz->wordstor[total_words+MIX_CHANPOS],"%d",chans)!=1) {
+			sprintf(errstr,"Cannot read channel data: line %d\n",lineno+1);
+			return(FINISHED);
+		}
+		if(*chans < MONO || *chans > STEREO) {
+			sprintf(errstr,"channel value out of range: line %d\n",lineno+1);
+			return(FINISHED);
+		}
+		if((exit_status = test_left_level(wordstor[total_words+MIX_LEVELPOS],lineno))!=CONTINUE)
+			return(FINISHED);
+		break;
+	default:
+		sprintf(errstr,"Illegal mixfile line-length: line %d\n",lineno+1);
+		return(FINISHED);
+	}
+	if(wordcnt==MIX_MIDLINE && *chans!=MONO) {
+		sprintf(errstr,"Invalid channel count, or line length: line %d\n",lineno+1);
+		return(FINISHED);
+	}
+	if(wordcnt==MIX_MAXLINE && *chans!=STEREO) {
+		sprintf(errstr,"Invalid channel count, or line too long: line %d\n",lineno+1);
+		return(FINISHED);
+	}
+	return(CONTINUE);
+}
+
+/************************** TEST_RIGHT_LEVEL ************************/
+
+int test_right_level(char *str,int lineno)
+{
+	double rlevel;
+	if(is_dB(str)) {
+		if(!get_leveldb(str,&rlevel)) {
+			sprintf(errstr,"Error in chan2 level: line %d\n",lineno+1);
+			return(FINISHED);
+		}		
+	} else {
+		if(sscanf(str,"%lf",&rlevel)!=1) {
+			sprintf(errstr,"Error2 in chan2 level: line %d\n",lineno+1);
+			return(FINISHED);
+		}
+	}
+	if(rlevel < 0.0) {
+		sprintf(errstr,"chan2 level out of range: line %d\n",lineno+1);
+		return(FINISHED);
+	}
+	return(CONTINUE);
+}
+
+/*********************** TEST_RIGHT_PAN **********************/
+
+int test_right_pan(char *str,int lineno)
+{
+	double pan;
+	switch(str[0]) {
+	case('L'): 
+	case('R'): 
+	case('C'): return(CONTINUE);
+	default:
+		if(sscanf(str,"%lf",&pan)!=1) {
+			sprintf(errstr,"Error in chan2 pan: line %d\n",lineno+1);
+			return(FINISHED);
+		}
+		if(pan < MINPAN || pan > MAXPAN)  {
+			sprintf(errstr,"chan2 pan out of range: line %d\n",lineno+1);
+			return(FINISHED);
+		}
+		break;
+	}
+	return(CONTINUE);
+}
+
+/*************** TEST_LEFT_LEVEL ******************/
+
+int test_left_level(char *str,int lineno)
+{
+	double level;
+	if(is_dB(str)) {
+		if(!get_leveldb(str,&level)) {
+			sprintf(errstr,"Error in (chan1) level: line %d\n",lineno+1);
+			return(FINISHED);
+		}		
+	} else {
+		if(sscanf(str,"%lf",&level)!=1) {
+			sprintf(errstr,"Error in (chan1) level: line %d\n",lineno+1);
+			return(FINISHED);
+		}
+	}
+	if(level < 0.0) {
+		sprintf(errstr,"(chan1) level out of range: line %d\n",lineno+1);
+		return(FINISHED);
+	}
+	return(CONTINUE);
+}
+
+/************************** TEST_LEFT_PAN ************************/
+
+int test_left_pan(char *str,int lineno)
+{
+	double pan;
+	switch(str[0]) {
+	case('L'): 
+	case('R'): 
+	case('C'): return(CONTINUE);
+	default:
+		if(sscanf(str,"%lf",&pan)!=1) {
+			sprintf(errstr,"Error in (chan1) pan: line %d\n",lineno+1);
+			return(FINISHED);
+		}
+		if(pan < MINPAN || pan > MAXPAN)  {
+			sprintf(errstr,"(chan1) pan out of range: line %d\n",lineno+1);
+			return(FINISHED);
+		}
+	}
+	return(CONTINUE);
+}
+
+/************************* OPEN_FILE_AND_TEST_PROPS *******************************/
+
+int open_file_and_test_props(int filecnt,char *filename,int *srate,int chans,int lineno,dataptr dz)
+{
+	int exit_status;
+	double maxamp, maxloc;
+	int maxrep;
+	int getmax = 0, getmaxinfo = 0;
+	infileptr ifp;
+	if((ifp = (infileptr)malloc(sizeof(struct filedata)))==NULL) {
+		sprintf(errstr,"INSUFFICIENT MEMORY to store data on files.\n");
+		return(MEMORY_ERROR);
+	}
+	if((dz->ifd[0] = sndopenEx(filename,0,CDP_OPEN_RDONLY)) < 0) {
+		sprintf(errstr,"Failed to open sndfile %s: line %d\n",filename,lineno+1);
+		return(FINISHED);
+	}
+	if((exit_status = readhead(ifp,dz->ifd[0],filename,&maxamp,&maxloc,&maxrep,getmax,getmaxinfo))<0)
+		return(exit_status);
+	copy_to_fileptr(ifp,dz->infile);
+	if(dz->infile->filetype!=SNDFILE) {
+		sprintf(errstr,"%s is not a soundfile: line %d\n",filename,lineno+1);
+		return(FINISHED);
+	}
+	if(dz->infile->channels!=chans) {
+		sprintf(errstr,"channel-cnt in file '%s' different to channel value given: line %d\n",filename,lineno+1);
+		return(FINISHED);
+	}
+	if(filecnt==0)
+		*srate = dz->infile->srate;
+	else if(dz->infile->srate != *srate) {
+		sprintf(errstr,"incompatible srate: file %s: line %d\n",filename,lineno+1);
+		return(FINISHED);
+	}
+	if((dz->insams[0] = sndsizeEx(dz->ifd[0]))<0) {	    			
+		sprintf(errstr, "Can't read size of input file %s: line %d\n",filename,lineno+1);
+		return(PROGRAM_ERROR);
+	}
+	if(dz->insams[0] <=0) {
+		sprintf(errstr, "Zero size for input file %s: line %d\n",filename,lineno+1);
+		return(FINISHED);
+	}			
+	if(sndcloseEx(dz->ifd[0])<0) {
+		sprintf(errstr, "Failed to close input file %s: line %d\n",filename,lineno+1);
+		return(SYSTEM_ERROR);
+	}
+	dz->ifd[0] = -1;
+	return(CONTINUE);
+}
+
+/********************** CREATE_MIXDUMMY ****************************/
+ 
+int create_mixdummy(dataptr dz)
+{
+	int    exit_status;
+	int   srate;
+	int	   this_namelen, max_namelen = 0;												
+	int   n;
+	double running_total = 0.0;
+	sndcloseEx(dz->ifd[0]);
+	dz->ifd[0] = -1;
+	if(dz->all_words==0) {
+		sprintf(errstr,"No words in source file.\n");
+		return(PROGRAM_ERROR);
+	}
+	dz->infilecnt = 1;		/* program now utilises only 1 file at a time : needs data storage for only 1 file */
+	if((exit_status = establish_file_data_storage_for_mix((int)1,dz))<0)
+		return(exit_status);
+	for(n=0;n<dz->all_words;n++) {						/* for each sndfile name */
+		if((this_namelen = strlen(dz->wordstor[n]))<=0) {
+			sprintf(errstr,"filename error: line %d\n",dz->linecnt+1);
+			return(PROGRAM_ERROR);
+		}
+		max_namelen = max(max_namelen,this_namelen);
+	}
+	for(n=0;n<dz->all_words;n++) {						/* for each sndfile name */
+		if((exit_status = open_file_and_retrieve_props(n,dz->wordstor[n],&srate,dz))<0)
+			return(exit_status);
+		if(dz->mode == 2 && dz->infile->channels != 1) {
+			sprintf(errstr,"This process only works with mono input files.\n");
+			return(DATA_ERROR);
+		}
+		if((exit_status = create_and_output_mixfile_line(n,max_namelen,&running_total,dz))<0)
+			return(exit_status);
+	}
+	return(FINISHED);
+}
+
+/************************* CREATE_AND_OUTPUT_MIXFILE_LINE *******************************/
+
+//TW FUNCTION UPDATED (including flotsam conversion)
+int create_and_output_mixfile_line(int infilno,int max_namelen,double *running_total,dataptr dz)
+{
+	int space_count, n;
+	double filetime = 0.0; /* default value : MIXDUMMY , mode MD_TOGETHER */
+
+	if((space_count = max_namelen - strlen(dz->wordstor[infilno]))<0) {
+		sprintf(errstr,"Anomaly in space counting: create_and_output_mixfile_line()\n");
+		return(PROGRAM_ERROR);
+	}
+	space_count++;
+	fprintf(dz->fp,"%s",dz->wordstor[infilno]);
+	for(n=0;n<space_count;n++)
+		fprintf(dz->fp," ");
+	switch(dz->process) {
+	case(MIXDUMMY):
+		if(dz->mode == MD_FOLLOW) {
+			filetime = *running_total;
+			*running_total += (double)(dz->insams[0]/dz->infile->channels)/(double)dz->infile->srate;
+		}
+		break;			
+	case(MIX_ON_GRID):		
+		filetime = dz->parray[0][infilno];	
+		break;
+	case(MIX_AT_STEP):		
+			filetime = *running_total;
+			*running_total += dz->param[MIX_STEP];
+		break;
+	}
+	switch(dz->infile->channels) {
+	case(MONO):
+		if(dz->process == MIXDUMMY && dz->mode == 2) {
+			if(infilno == 0)
+				fprintf(dz->fp,"%.4lf  1  1.0  L\n",filetime);
+			else
+				fprintf(dz->fp,"%.4lf  1  1.0  R\n",filetime);
+		} else
+			fprintf(dz->fp,"%.4lf  1  1.0  C\n",filetime);
+		break;
+	case(STEREO):	fprintf(dz->fp,"%.4lf  2  1.0  L  1.0  R\n",filetime);	break;
+	default:
+		sprintf(errstr,"Invalid number of input channels for one of mix input files (Must be mono or stereo).\n");
+		return(DATA_ERROR);
+	}
+	return(FINISHED);
+}
+
+/********************** OUTPUT_MIXFILE_LINE ****************************/
+ 
+int output_mixfile_line(char **wordstor,int *maxwordsize,int start_word_no,int words_in_line,dataptr dz)
+{
+	int space_count, n, m;
+	int wordno;
+	for(n = 0;n < words_in_line; n++) {
+		wordno = start_word_no + n;
+		fprintf(dz->fp,"%s",wordstor[wordno]);
+		if((space_count = maxwordsize[n] - strlen(wordstor[wordno]))<0) {
+			sprintf(errstr,"Error in space_count: output_mixfile_line()\n");
+			return(PROGRAM_ERROR);
+		}
+		space_count++;
+		for(m=0; m < space_count;m++)
+			fprintf(dz->fp," ");
+	}
+	fprintf(dz->fp,"\n");
+	return(FINISHED);
+}
+
+/********************** MIX_TWISTED ****************************/
+ 
+int mix_twisted(dataptr dz)
+{
+	int    exit_status;
+	double time, llevel, lpan, rlevel, rpan;
+	int    chans, m;
+	int   n;
+	char   *filename;
+	int    filecnt = 0;												
+	int   total_words = 0, initial_total_words;
+	int    *maxwordsize;
+	if((maxwordsize = (int *)malloc(MIX_MAXLINE * sizeof(int)))==NULL) {
+		sprintf(errstr,"INSUFFICIENT MEMORY to store maximum word sizes.\n");
+		return(MEMORY_ERROR);
+	}
+	for(m=0;m<MIX_MAXLINE;m++)
+		maxwordsize[m] = 0;
+
+	for(n=0;n<dz->linecnt;n++) {						
+		filename = dz->wordstor[total_words];			
+		if(strlen(filename)<=0) {
+			free(maxwordsize);
+			sprintf(errstr,"filename error: line %d: mix_twisted()\n",filecnt+1);
+			return(PROGRAM_ERROR);
+		}
+		if((exit_status = get_mixdata_in_line			
+		(dz->wordcnt[n],dz->wordstor,total_words,&time,&chans,&llevel,&lpan,&rlevel,&rpan,filecnt,dz))<0) {
+			free(maxwordsize);
+			return(exit_status);
+		}
+		initial_total_words = total_words;
+		for(m=0;m<dz->wordcnt[n];m++)
+			maxwordsize[m] = (int)max((int)maxwordsize[m],(int)strlen(dz->wordstor[initial_total_words+m]));
+		total_words += dz->wordcnt[n];
+		if((exit_status = finalise_and_check_mixdata_in_line(dz->wordcnt[n],chans,llevel,&lpan,&rlevel,&rpan))<0) {
+			free(maxwordsize);
+			return(exit_status);
+		}
+		filecnt++;											
+	}
+	maxwordsize[MIX_PANPOS]   = (int)max((int)maxwordsize[MIX_PANPOS],(int)3);	/* allow pan to be converted text to number */
+	maxwordsize[MIX_RPANPOS]  = (int)max((int)maxwordsize[MIX_RPANPOS],(int)3);
+	maxwordsize[MIX_PANPOS]++;											/* allow for pan to become negative */
+	maxwordsize[MIX_RPANPOS]++;
+
+	total_words = 0;
+	filecnt = 0;
+	for(n=0;n<dz->linecnt;n++) {						
+		filename = dz->wordstor[total_words];			
+		initial_total_words = total_words;
+		total_words += dz->wordcnt[n];
+		switch(dz->mode) {
+		case(MSW_TWISTALL):
+			if(ODD(filecnt)) {
+				if((exit_status = twist_mixfile_line(dz->wordstor,maxwordsize,initial_total_words,dz->wordcnt[n],dz))<0) {
+					free(maxwordsize);
+					return(exit_status);
+				}
+			} else {
+				if((exit_status = output_mixfile_line(dz->wordstor,maxwordsize,initial_total_words,dz->wordcnt[n],dz))<0) {
+					free(maxwordsize);
+					return(exit_status);
+				}
+			}
+			break;
+		case(MSW_TWISTONE):
+			if(filecnt == dz->iparam[MSW_TWLINE]) {
+ 				if((exit_status = twist_mixfile_line(dz->wordstor,maxwordsize,initial_total_words,dz->wordcnt[n],dz))<0) {
+					free(maxwordsize);
+					return(exit_status);
+				}
+			} else {
+				if((exit_status = output_mixfile_line(dz->wordstor,maxwordsize,initial_total_words,dz->wordcnt[n],dz))<0) {
+					free(maxwordsize);
+					return(exit_status);
+				}
+			}
+			break;
+		default:
+			sprintf(errstr,"Unknown mode in mix_twisted()\n");
+			return(PROGRAM_ERROR);
+		}
+		filecnt++;											
+	}
+
+	free(maxwordsize);
+	return(FINISHED);
+}
+
+/********************** TWIST_MIXFILE_LINE ****************************/
+ 
+int twist_mixfile_line(char **wordstor,int *maxwordsize,int start_word_no,int words_in_line,dataptr dz)
+{
+	int exit_status;
+	int n;
+	int wordno;
+	for(n = 0;n < words_in_line; n++) {
+		wordno = n + start_word_no;
+		switch(n) {
+		case(MIX_NAMEPOS):
+		case(MIX_TIMEPOS):
+		case(MIX_CHANPOS):
+		case(MIX_LEVELPOS):
+		case(MIX_RLEVELPOS):
+			if((exit_status = output_aligned_word(wordstor[wordno],maxwordsize[n],dz))<0)
+				return(exit_status);
+			break;
+		case(MIX_PANPOS):
+		case(MIX_RPANPOS):
+			if((exit_status = mirror_panning(wordstor[wordno],maxwordsize[n],dz))<0)
+				return(exit_status);
+			break;
+		default:
+			sprintf(errstr,"Impossible word no: twist_mixfile_line()\n");
+			return(PROGRAM_ERROR);
+		}
+	}   	
+	fprintf(dz->fp,"\n");
+	return(FINISHED);
+}
+
+/********************** MIRROR_PANNING ****************************/
+ 
+int mirror_panning(char *thisword, int maxthiswordsize,dataptr dz)
+{
+	int exit_status;
+	double pan;
+	int was_neg = FALSE, newlen, leading_zero_cnt = 0;
+	char *p;
+	if(!strcmp(thisword,"C"))
+		return output_aligned_word(thisword,maxthiswordsize,dz);
+	else if(!strcmp(thisword,"L")) 
+		return output_aligned_word("R",maxthiswordsize,dz);
+	else if(!strcmp(thisword,"R"))
+		return output_aligned_word("L",maxthiswordsize,dz);
+	else if(sscanf(thisword,"%lf",&pan)!=1) {
+		sprintf(errstr,"Failed to get pan value 1: mirror_panning()\n");
+		return(PROGRAM_ERROR);
+	}
+	if(flteq(pan,0.0)) {
+		if((exit_status = output_aligned_word(thisword,maxthiswordsize,dz))<0)
+		return(exit_status);
+	} else {
+		if(pan < 0.0)
+			was_neg = TRUE;
+		pan = -pan;
+		sprintf(errstr,"%lf",pan);
+		newlen = strlen(thisword);
+		leading_zero_cnt = 0;
+		p = thisword;
+		if(was_neg)
+			p = thisword+1;
+		while(*p=='0') {
+			leading_zero_cnt++;
+			p++;
+		}
+		if(*p=='.') {
+			if(leading_zero_cnt==0)
+				newlen++;							/* Allow for leading 0 being added */
+			else
+				newlen -= leading_zero_cnt - 1;		/* Allow for xs leading zeroes being taken away */
+		}
+		if(was_neg)		newlen--;		/* Allow for decimal point being removed */
+		else			newlen++;		/* Allow for decimal point being added */
+		
+		*(errstr + newlen) = ENDOFSTR;
+		if((exit_status = output_aligned_word(errstr,maxthiswordsize,dz))<0)
+			return(exit_status);
+	}
+	return(FINISHED);
+}
+
+/********************** OUTPUT_ALIGNED_WORD ****************************/
+ 
+int output_aligned_word(char *thisword,int maxthiswordsize,dataptr dz)
+{
+	int space_count, n;
+	fprintf(dz->fp,"%s",thisword);
+	if((space_count = maxthiswordsize - strlen(thisword))<0) {
+		sprintf(errstr,"Error in space_count: output_aligned_word()\n");
+		return(PROGRAM_ERROR);
+	}
+	space_count++;
+	for(n=0; n < space_count;n++)
+		fprintf(dz->fp," ");
+	return(FINISHED);
+}
+
+//TW UPDATE: NEW FUNCTION
+/********************** ADDTOMIX ****************************/
+ 
+int addtomix(dataptr dz)
+{
+	int    exit_status;
+	int	   total_wordcnt, *chans;												
+	int    n, m, sndfiles_in = dz->infilecnt - 1;
+	char	temp[200], temp2[200];
+	infileptr fq;
+	double maxamp, maxloc;
+	int maxrep;
+	int getmax = 0, getmaxinfo = 0;
+	if(sndfiles_in <= 0) {
+		sprintf(errstr,"No new sound files remembered.\n");
+		return(PROGRAM_ERROR);
+	}
+	if(dz->linecnt <= 0) {
+		sprintf(errstr,"None of original mixdata remembered.\n");
+		return(PROGRAM_ERROR);
+	}
+	if((fq = (infileptr)malloc(sizeof(struct filedata)))==NULL) {
+		sprintf(errstr,"INSUFFICIENT MEMORY to store data on files.\n");
+		return(MEMORY_ERROR);
+	}
+	if ((chans = (int *)malloc(sndfiles_in * sizeof(int)))==NULL) {
+		sprintf(errstr,"INSUFFICIENT MEMORY to store channel count information.\n");
+		return(MEMORY_ERROR);
+	}
+	for(n = sndfiles_in,m = dz->all_words - 1; n>=1; n--,m--) {
+		if((exit_status = readhead(fq,dz->ifd[n],dz->wordstor[m],&maxamp,&maxloc,&maxrep,getmax,getmaxinfo))<0) {
+			sprintf(errstr,"Cannot read header of soundfile %s\n",dz->wordstor[m]);
+			return(USER_ERROR);
+		}
+		if(((chans[n-1] = fq->channels) < 1) || (chans[n-1] > 2)) {
+			sprintf(errstr,"Soundfile %s has wrong number of channels [%d] for this process.\n",dz->wordstor[m],chans[n-1]);
+			return(DATA_ERROR);
+		}
+    }
+	
+	total_wordcnt = 0;
+	for(n=0;n< dz->linecnt;n++) {
+		for(m=0;m<dz->wordcnt[n];m++) {
+			if(m==0)
+				strcpy(temp,dz->wordstor[total_wordcnt++]);
+			else {
+				strcat(temp," ");
+				strcat(temp,dz->wordstor[total_wordcnt++]);
+			}
+			if(total_wordcnt >= dz->all_words) {
+				sprintf(errstr,"Word Count error.\n");
+				return(PROGRAM_ERROR);
+			}
+		}
+		strcat(temp,"\n");
+		if(fputs(temp,dz->fp)<0) {
+			sprintf(errstr,"Failed to write mixfile line %d to output file.\n",n+1);
+			return(SYSTEM_ERROR);
+		}
+	}
+	m = 0;
+	while(total_wordcnt < dz->all_words) {
+		strcpy(temp,dz->wordstor[total_wordcnt]);
+		sprintf(temp2,"%lf",dz->duration);
+		strcat(temp," ");
+		strcat(temp,temp2);
+
+		if(chans[m] == 1)
+			strcat(temp,"  1 1.0 C\n");
+		else
+			strcat(temp," 2 1.0 L 1.0 R\n");
+		if(fputs(temp,dz->fp)<0) {
+			sprintf(errstr,"Failed to write mixfile line %d to output file.\n",n+1);
+			return(SYSTEM_ERROR);
+		}
+		if(++total_wordcnt > dz->all_words) {
+			sprintf(errstr,"Word Count error.\n");
+			return(PROGRAM_ERROR);
+		}
+		m++;
+		n++;
+	}
+	return(FINISHED);
+}
+

+ 1124 - 0
dev/submix/newmix1.c

@@ -0,0 +1,1124 @@
+/*
+ * 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 <filetype.h>
+#include <mix.h>
+#include <cdpmain.h>
+
+#include <sfsys.h>
+#include <string.h>
+
+#define	START	(0)
+#define	LEFT	(0)
+#define	RIGHT	(1)
+
+#define MAX_CLIP_DISPLAY (16)
+
+static int  adjust_buffer_status(int n,int *thispos,int *active_bufcnt,dataptr dz);
+static int  read_samps_to_an_inbuf(int n,dataptr dz);
+static void make_stereo(float *inbuf,dataptr dz);
+static int  make_stereo_left_only(float *inbuf,dataptr dz);
+static int  make_stereo_right_only(float *inbuf,dataptr dz);
+static int  adjust_activebufs_list(int active_bufcnt,dataptr dz);
+static int  do_mix(int samps_to_mix,int *position_in_outbuf,int active_bufcnt,int *outbuf_space,dataptr dz);
+static void do_level_check(int samps_to_mix,double *d_maxsamp,int *maxloc,int active_bufcnt,
+			int *outbuf_space,int *clipsize,int *total_samps_used,int *position_in_outbuf,dataptr dz);
+static int  do_silence(int samps_to_mix,int *position_in_outbuf,int *outbuf_space,dataptr dz);
+static void do_zero_level(int samps_to_mix,int *position_in_outbuf,
+			int *outbuf_space,int *total_samps_used,dataptr dz);
+static int  do_mix2(int samps_to_mix,int *position_in_outbuf,int active_bufcnt,int *outbuf_space,dataptr dz);
+static void do_the_level(float *olbuf,int *opos,int cnt,double *d_maxsamp,int *maxloc,int *clipsize,
+			int total_samps_used,dataptr dz);
+static double gain_to_db(double val);
+static int  mix_read_samps(float *inbuf,int samps_to_read,int n,dataptr dz);
+static int  scale_smps(int n,dataptr dz);
+
+static int clipcnt = 0;
+
+/*************************** MMIX *******************************/
+
+int mmix(dataptr dz)
+{
+	int exit_status;
+	int n;
+	int thispos, nextpos, samps_to_mix;
+	int position_in_outbuf = 0;
+	int active_bufcnt = 0;
+	int outbuf_space = dz->buflen;
+	display_virtual_time(0L,dz);
+	if(sloom) {
+		if(dz->iparam[MIX_STRTPOS_IN_ACTION] > 0) {
+			fprintf(stdout,"INFO: Skipping initial part of mix.\n");
+			fflush(stdout);
+		}
+	}
+	for(n=0;n<dz->iparam[MIX_TOTAL_ACTCNT]-1;n++) {	/* Switch bufs ON or OFF as indicated in act[], & get position */
+		if((exit_status = adjust_buffer_status(n,&thispos,&active_bufcnt,dz))<0)
+			return(exit_status);					/* and while doing so, count active buffers. */
+
+		nextpos = (dz->act[n+1])->position;				/* Get next position, (from which to calc dur of this mix-chunk) */
+		if((exit_status = adjust_activebufs_list(active_bufcnt,dz))<0)
+			return(exit_status);					/* Ensure only pointers in ACTIVE bufs are in buf-pointer list */
+		if(dz->iparam[MIX_STRTPOS] > 0) {			/* If mix does not start at zero */ 
+			if(nextpos <= dz->iparam[MIX_STRTPOS]){	/* update MIX_STRTPOS_IN_ACTION */
+				dz->iparam[MIX_STRTPOS_IN_ACTION] = (int)(dz->iparam[MIX_STRTPOS_IN_ACTION] - (nextpos - thispos));	
+				continue;							/* and skip action until we reach a valid mix-action */
+			}
+		}											/* If we're in a valid mix action */
+ 													/* i.e. there is >zero time between this action and next */
+													/* AND time is later than time where mix-action starts */
+		if((samps_to_mix = nextpos - thispos - dz->iparam[MIX_STRTPOS_IN_ACTION])>0) {
+			if(active_bufcnt==0) {					/* If no buffers are active, fill time with silence. */
+				if((exit_status = do_silence(samps_to_mix,&position_in_outbuf,&outbuf_space,dz))<0)
+					return(exit_status);
+			} else {		   						/* Else, do mix */
+				switch(dz->vflag[ALTERNATIVE_MIX]) {
+				case(FALSE):   
+					if((exit_status = do_mix(samps_to_mix,&position_in_outbuf,active_bufcnt,&outbuf_space,dz))<0)
+						return(exit_status);
+				  	break;
+				case(TRUE):   
+					if((exit_status = do_mix2(samps_to_mix,&position_in_outbuf,active_bufcnt,&outbuf_space,dz))<0)
+						return(exit_status);
+					break;								 
+				default:
+					sprintf(errstr,"Unknown mixtype. mmix()\n");
+					return(PROGRAM_ERROR);					
+				}									/* Having got to start of actual mixing, */
+			}										/* MIX_STRTPOS_IN_ACTION is set to zero  */
+ 													/* and NO LONGER  affects calculations.  */
+			dz->iparam[MIX_STRTPOS_IN_ACTION] = dz->iparam[MIX_STRTPOS]  = 0;
+		}
+	}												/* Write any data remaining in output buffer. */
+	if(position_in_outbuf > 0)
+		return write_samps(dz->sampbuf[OBUFMIX],position_in_outbuf,dz);	
+	return FINISHED;
+}
+
+/*************************** MIX_LEVEL_CHECK *****************************/
+
+int mix_level_check(double *normalisation, dataptr dz)
+{
+	int exit_status;
+	int n;
+	int thispos, nextpos, samps_to_mix;
+/* JUNE 2000 --> */
+	double dbnormalisation;
+/* <-- JUNE 2000 */
+	int position_in_outbuf = 0;
+//TW REMOVED 'maxsamp' and corrected printing of long (now double) items
+	int maxloc  = 0;
+	int active_bufcnt = 0;
+	int outbuf_space = dz->buflen;
+	int clipsize = 0;
+	int total_samps_used = 0;
+	/* RWD */
+	double d_maxsamp = 0.0;
+
+	switch(dz->mode) {
+	case(MIX_LEVEL_ONLY):
+		break;
+	case(MIX_LEVEL_AND_CLIPS):	
+	case(MIX_CLIPS_ONLY):	
+		if(dz->fp == NULL) {
+			sprintf(errstr,"Output textfile not established: mix_level_check()\n");
+			return(PROGRAM_ERROR);
+		}
+		break;
+	}
+	display_virtual_time(0L,dz);
+	for(n=0;n<dz->iparam[MIX_TOTAL_ACTCNT]-1;n++) {
+		if((exit_status = adjust_buffer_status(n,&thispos,&active_bufcnt,dz))<0)
+			return(exit_status);				
+		nextpos = (dz->act[n+1])->position;
+		if((exit_status = adjust_activebufs_list(active_bufcnt,dz))<0)
+			return(exit_status);				
+		if(dz->iparam[MIX_STRTPOS] > 0) {
+			if(nextpos <= dz->iparam[MIX_STRTPOS])  {
+				dz->iparam[MIX_STRTPOS_IN_ACTION] = (int)(dz->iparam[MIX_STRTPOS_IN_ACTION] - (nextpos - thispos));
+				continue;
+			}
+		}		
+		if((samps_to_mix = nextpos - thispos - dz->iparam[MIX_STRTPOS_IN_ACTION])>0) {
+			if(active_bufcnt==0)
+				do_zero_level(samps_to_mix,&position_in_outbuf,&outbuf_space,&total_samps_used,dz);				
+			else
+				do_level_check(samps_to_mix,&d_maxsamp,&maxloc,active_bufcnt,
+				&outbuf_space,&clipsize,&total_samps_used,&position_in_outbuf,dz);				
+			dz->iparam[MIX_STRTPOS_IN_ACTION] = dz->iparam[MIX_STRTPOS]  = 0;
+		}
+	}
+//TW makes code function clear
+	*normalisation = F_MAXSAMP / d_maxsamp;
+/* JUNE 2000 --> */
+	dbnormalisation = gain_to_db(*normalisation);
+/* <-- JUNE 2000 */
+	switch(dz->mode) {
+	case(MIX_LEVEL_ONLY):
+		sprintf(errstr,"MAX SAMPLE ENCOUNTERED : %lf at %lf secs\nNORMALISATION REQUIRED : %lf   OR  %.4lfdB\n",
+		d_maxsamp,(double)maxloc/(double)dz->out_chans/(double)dz->infile->srate,*normalisation,dbnormalisation);
+		break;
+	case(MIX_LEVEL_AND_CLIPS):	
+		fprintf(dz->fp,"\nMAX SAMPLE ENCOUNTERED : %lf at %lf secs\n",
+		d_maxsamp,(double)maxloc/(double)dz->out_chans/(double)dz->infile->srate);
+		fprintf(dz->fp,"NORMALISATION REQUIRED : %lf   OR  %.4lfdB\n",
+		*normalisation,dbnormalisation);
+		if(sloom) {
+			fprintf(stdout,"INFO: MAX SAMPLE ENCOUNTERED : %lf at %lf secs\n",
+			d_maxsamp,(double)maxloc/(double)dz->out_chans/(double)dz->infile->srate);
+			fprintf(stdout,"INFO: NORMALISATION REQUIRED : %lf   OR  %.4lfdB\n",*normalisation,dbnormalisation);
+			fflush(stdout);
+		}
+		break;
+	case(MIX_CLIPS_ONLY):	
+		if(sloom) {
+			if(dz->mode == MIX_CLIPS_ONLY && clipcnt == 0) {
+				fprintf(dz->fp,"No clipping.\n");
+				fprintf(stdout,"INFO: No clipping.\n");
+				fflush(stdout);
+			}
+		}
+		break;
+	default:
+		sprintf(errstr,"Unknown case in mix_level_check()\n");
+		return(PROGRAM_ERROR);
+	}
+	return(FINISHED);
+}
+
+/************************** ADJUST_BUFFER_STATUS **************************
+ *
+ * 	And keep track of number of active buffers (active_bufcnt).
+ */
+
+int adjust_buffer_status(int n,int *thispos,int *active_bufcnt,dataptr dz)
+{
+	int exit_status;
+	switch(dz->act[n]->role) {
+	case(MIX_ACTION_ON):									/* buffer is being used for 1st time in this mix-action */
+		(*active_bufcnt)++;									/* Increment the count of ACTIVE buffers */
+		dz->buflist[dz->act[n]->val->bufno]->status = MIX_ACTION_ON;	/* Change buffer status to ON */
+		/* fall thro */
+	case(MIX_ACTION_REFILL):								/* buffer is being reused OR used for 1st time */
+		if((exit_status = read_samps_to_an_inbuf(n,dz))<0)	/* Read_samples into buffer */
+			return(exit_status);
+		if((exit_status = scale_smps(n,dz))<0)				/* Scale the samples */
+			return(exit_status);
+		dz->buflist[dz->act[n]->val->bufno]->here = dz->buflist[dz->act[n]->val->bufno]->buf;
+		break;												/* Reset location_in_buffer_pointer (here) to buffer start */
+
+	case(MIX_ACTION_OFF):									/* buffer is finished with */
+		dz->buflist[dz->act[n]->val->bufno]->status = MIX_ACTION_OFF;	/* Change buffer status to OFF */
+		(*active_bufcnt)--;									/* Decrement the number of ACTIVE buffers */
+		break;
+	default:
+		sprintf(errstr,"Unknown case in adjust_buffer_status()\n");
+		return(PROGRAM_ERROR);
+	}
+	*thispos = dz->act[n]->position; 							/* Return position (starttime-in-samps) of the action */
+	return(FINISHED);
+}
+
+/************************* READ_SAMPS_TO_AN_INBUF ***************************/
+
+int read_samps_to_an_inbuf(int n,dataptr dz)
+{
+	int exit_status;
+	int  samps_to_read = dz->buflen;
+	float *inbuf = dz->buflist[dz->act[n]->val->bufno]->buf;
+	switch(dz->act[n]->val->stereo) {
+	case(MONO):					
+	case(STEREO):				
+		if((exit_status = mix_read_samps(inbuf,samps_to_read,n,dz))<0)
+			return(exit_status);
+		break;
+	case(MONO_TO_STEREO):			
+		samps_to_read /= 2;
+		if((exit_status = mix_read_samps(dz->sampbuf[STEREOBUF],samps_to_read,n,dz))<0)
+			return(exit_status);
+		make_stereo(inbuf,dz);
+		dz->ssampsread *= 2;
+		break;
+	case(MONO_TO_CENTRE):					 
+		samps_to_read /= 2;
+		if((exit_status = mix_read_samps(dz->sampbuf[STEREOBUF],samps_to_read,n,dz))<0)
+			return(exit_status);
+		break;
+	case(MONO_TO_LEFT):				
+		samps_to_read /= 2;
+		if((exit_status = mix_read_samps(dz->sampbuf[STEREOBUF],samps_to_read,n,dz))<0)
+			return(exit_status);
+		if((exit_status = make_stereo_left_only(inbuf,dz))<0)
+			return(exit_status);
+		dz->ssampsread *= 2;
+		break;
+	case(MONO_TO_RIGHT):			
+		samps_to_read /= 2;
+		if((exit_status = mix_read_samps(dz->sampbuf[STEREOBUF],samps_to_read,n,dz))<0)
+			return(exit_status);
+		if((exit_status = make_stereo_right_only(inbuf,dz))<0)
+			return(exit_status);
+		dz->ssampsread *= 2;
+		break;
+	case(STEREO_MIRROR):
+	case(STEREO_TO_CENTRE):
+	case(STEREO_TO_LEFT):
+	case(STEREO_TO_RIGHT):
+	case(STEREOLEFT_TO_LEFT):
+	case(STEREOLEFT_TO_RIGHT):
+	case(STEREOLEFT_PANNED):
+	case(STEREORIGHT_TO_LEFT):
+	case(STEREORIGHT_TO_RIGHT):
+	case(STEREORIGHT_PANNED):
+	case(STEREO_PANNED):
+		if((exit_status = mix_read_samps(dz->sampbuf[STEREOBUF],samps_to_read,n,dz))<0)
+			return(exit_status);
+		break;
+	default:
+		sprintf(errstr,"Unknown case in read_samps_to_an_inbuf()\n");
+		return(PROGRAM_ERROR);
+	}
+	return(FINISHED);
+}
+
+/****************************** MAKE_STEREO ***************************#
+ *
+ * Duplicate mono samples to make stereo buffer.
+ */
+
+void make_stereo(float *inbuf,dataptr dz)
+{
+	int m, k;
+	for(k=0;k<dz->ssampsread;k++) {
+		m = k * 2;
+		inbuf[m++] = dz->sampbuf[STEREOBUF][k];
+		inbuf[m]   = dz->sampbuf[STEREOBUF][k];
+	}
+}
+
+/******************** MAKE_STEREO_LEFT_ONLY ***************************#
+ *
+ * Put mono samples in left ONLY of stereo buffer.
+ */
+
+int make_stereo_left_only(float *inbuf,dataptr dz)
+{
+	int m, k;
+	memset((char *)inbuf,0,dz->buflen * sizeof(float));
+	for(k=0,m=0;k<dz->ssampsread;k++,m+=2)
+		inbuf[m] = dz->sampbuf[STEREOBUF][k];
+	return(FINISHED);
+}
+
+/******************** MAKE_STEREO_RIGHT_ONLY ***************************#
+ *
+ * Put mono samples in left ONLY of stereo buffer.
+ */
+
+int make_stereo_right_only(float *inbuf,dataptr dz)
+{
+	int m, k;
+	memset((char *)inbuf,0,dz->buflen * sizeof(float));
+	for(k=0,m=1;k<dz->ssampsread;k++,m+=2)
+		inbuf[m] = dz->sampbuf[STEREOBUF][k];
+	return(FINISHED);
+}
+
+/*********************** ADJUST_ACTIVEBUFS_LIST **************************
+ *
+ * Set the activebuf pointers to point only to the active buffers!!
+ *
+ * NB active_bufcnt has been reset by adjust_buffer_status()
+ */
+
+int adjust_activebufs_list(int active_bufcnt,dataptr dz)
+{   
+	int n, k = 0;
+	for(n=0;n<dz->bufcnt;n++) {
+		if(dz->buflist[n]->status == MIX_ACTION_ON) {
+			dz->activebuf[k] = n;
+			dz->activebuf_ptr[k++] = dz->buflist[n]->here;
+		}
+	}
+	if(k>active_bufcnt) {
+		sprintf(errstr,"Accounting error: adjust_activebufs_list()\n");
+		return(PROGRAM_ERROR);
+	}
+	return(FINISHED);
+}
+
+/************************* DO_MIX **********************************
+ *
+ * This algorithm puts all the samples from buffer 1 into output, then
+ * sums in all the samples form buffer 2, and so on. This is fastest
+ * routine (slightly) but risks a sample overflowing on the Nth buffer
+ * and hence giving CLIPPING, whereas, in do_mix2,  the sample sums are
+ * accumulated in a long & hence later sample additions might negate
+ * the overflow, negating the clipping in the final output.
+ */
+
+int do_mix(int samps_to_mix,int *position_in_outbuf,int active_bufcnt,int *outbuf_space,dataptr dz)
+{
+	int exit_status;
+	int  opos = *position_in_outbuf;
+	int   m, start = opos;
+	int  n, overflow;
+	float *obuf = dz->sampbuf[OBUFMIX];
+	float *outptr = obuf+opos;
+	if(dz->iparam[MIX_STRTPOS] > 0) {			/* If mix doesn't start at mixlist start, */						
+		for(n=0;n<active_bufcnt;n++)			/* and hence most likely not at buffer start, */
+			dz->activebuf_ptr[n] += dz->iparam[MIX_STRTPOS_IN_ACTION];
+	} 											/* increment pointers in all active_bufs to actual mix start */
+
+	if((overflow = samps_to_mix - (*outbuf_space)) <= 0) {	/* If samps_to_write DOESN'T overflow output buffer */
+	
+		memmove((char *)outptr,(char *)(dz->activebuf_ptr[0]),samps_to_mix  *sizeof(float));
+		dz->activebuf_ptr[0] += samps_to_mix;				/* Increment pointer in this active buf */
+		dz->buflist[dz->activebuf[0]]->here += samps_to_mix;/* Increment current_position_in_buffer_pointer also */
+		opos += samps_to_mix;								/* Increment position_in_outbuf */
+								 							
+		for(m=1;m<active_bufcnt;m++) {						/* For each of remaining ACTIVE buffers */
+			opos = start;									/* Reset output-buf pointer to start-of-write point */
+			for(n=0;n<samps_to_mix;n++) 					/* Add in samples from the other buffers */
+				obuf[opos++] += *(dz->activebuf_ptr[m]++);
+			dz->buflist[dz->activebuf[m]]->here += samps_to_mix;		
+															/* And update current_position_in_buffer_pointers */
+		}
+		if((*outbuf_space = dz->buflen - opos)<=0) {		/* if output buffer is full */
+			if((exit_status = write_samps(obuf,dz->buflen ,dz))<0)
+				return(exit_status);						/* write a full buffer */
+			*outbuf_space = dz->buflen;						/* and reset available space and buffer position */
+			opos = 0;
+		}
+		*position_in_outbuf = opos;
+		return(FINISHED);
+															/* IF samps_to_write DOES overflow output buffer */
+	} else {												/* which can only happen ONCE, */
+															/* as in- & out- bufs are same size */
+		if(*outbuf_space>0) {
+			memmove((char *)(outptr),(char *)(dz->activebuf_ptr[0]),(*outbuf_space) * sizeof(float));
+			dz->activebuf_ptr[0] += *outbuf_space;
+			dz->buflist[dz->activebuf[0]]->here += *outbuf_space;	
+			opos += *outbuf_space;
+			for(m=1;m<active_bufcnt;m++) {
+				opos = start;
+				for(n=0;n<*outbuf_space;n++)
+					obuf[opos++] += *(dz->activebuf_ptr[m]++);
+				dz->buflist[dz->activebuf[m]]->here += *outbuf_space;
+			}
+		}
+		if((exit_status = write_samps(obuf,dz->buflen,dz))<0)
+			return(exit_status);
+		if(overflow) {
+			start = opos = 0;
+			memmove((char *)obuf,(char *)(dz->activebuf_ptr[0]),overflow*sizeof(float));
+			dz->activebuf_ptr[0] += overflow;
+			dz->buflist[dz->activebuf[0]]->here += overflow;
+			opos = overflow;
+			for(m=1;m<active_bufcnt;m++) {
+				opos = start;
+				for(n=0;n<overflow;n++)
+					obuf[opos++] += *(dz->activebuf_ptr[m]++);
+				dz->buflist[dz->activebuf[m]]->here += overflow;
+			}
+		}
+	}
+	*outbuf_space = dz->buflen - opos;						/* Reset the space-left-in-outbuf */
+	*position_in_outbuf = opos;
+	return(FINISHED);
+}
+
+/************************* DO_LEVEL_CHECK **********************************
+ *
+ * As do_mix, but finds max sample.
+ */
+
+void do_level_check(int samps_to_mix,double *d_maxsamp,int *maxloc,int active_bufcnt,
+int *outbuf_space,int *clipsize,int *total_samps_used,int *position_in_outbuf,dataptr dz)
+{
+	int  opos = *position_in_outbuf;
+	int m, start = opos;
+	float *active_start = dz->activebuf_ptr[0];
+	int n, overflow, k;
+	float *olbuf = dz->sampbuf[OBUFMIX];
+	
+	if(sloom) {
+		if(dz->iparam[MIX_STRTPOS_IN_ACTION] > 0) {
+			fprintf(stdout,"INFO: Skipping initial part of mix.\n");
+			fflush(stdout);
+		}
+	}
+	if(dz->iparam[MIX_STRTPOS] > 0) {
+		for(n=0;n<active_bufcnt;n++)
+			dz->activebuf_ptr[n] += dz->iparam[MIX_STRTPOS_IN_ACTION];
+	} 
+	if((overflow = samps_to_mix - (*outbuf_space)) <= 0) {
+		for(k=0;k<samps_to_mix;k++)
+			olbuf[opos++] = *active_start++;
+		dz->buflist[dz->activebuf[0]]->here += samps_to_mix;		
+		opos += samps_to_mix;						
+		for(m=1;m<active_bufcnt;m++) {					
+			opos = start;						
+			for(n=0;n<samps_to_mix;n++)					
+				olbuf[opos++] += *(dz->activebuf_ptr[m]++);
+			dz->buflist[dz->activebuf[m]]->here += samps_to_mix;			
+		}
+		opos = start;
+		do_the_level(olbuf,&opos,samps_to_mix,d_maxsamp,maxloc,clipsize,*total_samps_used,dz);
+		*total_samps_used += samps_to_mix;
+	} else {								
+		if(*outbuf_space > 0) {	
+			for(k=0;k<*outbuf_space;k++)
+				olbuf[opos++] = *active_start++;
+			dz->activebuf_ptr[0] += *outbuf_space;	
+			dz->buflist[dz->activebuf[0]]->here += *outbuf_space;		
+			for(m=1;m<active_bufcnt;m++) {
+				opos = start;
+				for(n=0;n<*outbuf_space;n++)
+					olbuf[opos++] += *(dz->activebuf_ptr[m]++);
+				dz->buflist[dz->activebuf[m]]->here += *outbuf_space;	
+			}
+			opos = start;
+			do_the_level(olbuf,&opos,*outbuf_space,d_maxsamp,maxloc,clipsize,*total_samps_used,dz);
+			*total_samps_used += *outbuf_space;
+		}
+		if(!sloom)
+			display_virtual_time(*total_samps_used,dz);
+		if(overflow) {
+			start = opos = 0;					
+			active_start = dz->activebuf_ptr[0];
+			for(k=0;k<overflow;k++)
+				olbuf[opos++] = *active_start++;
+			dz->buflist[dz->activebuf[0]]->here += overflow;		
+			for(m=1;m<active_bufcnt;m++) {				
+				opos = start;
+				for(n=0;n<overflow;n++)
+					olbuf[opos++] += *(dz->activebuf_ptr[m]++);
+				dz->buflist[dz->activebuf[m]]->here += overflow;		
+			}
+			opos = start;
+			do_the_level(olbuf,&opos,overflow,d_maxsamp,maxloc,clipsize,*total_samps_used,dz);
+			*total_samps_used += overflow;
+		}
+	}
+	*outbuf_space = dz->buflen - opos;					
+	*position_in_outbuf = opos;
+	return;
+}
+
+/************************* DO_SILENCE ***********************************/
+
+int do_silence(int samps_to_mix,int *position_in_outbuf,int *outbuf_space,dataptr dz)
+{
+	int exit_status;
+	int opos = *position_in_outbuf;
+	int overflow;
+	float *obuf = dz->sampbuf[OBUFMIX];
+	while((overflow = samps_to_mix - *outbuf_space) > 0) {
+		memset((char *)(obuf+opos),0,(*outbuf_space) * sizeof(float));
+		if((exit_status = write_samps(obuf,dz->buflen,dz))<0)
+			return(exit_status);
+		opos = 0;
+		*outbuf_space = dz->buflen;
+		samps_to_mix = overflow;
+	}
+	if(samps_to_mix) {
+		memset((char *)(obuf+opos),0,samps_to_mix*sizeof(float));
+		opos += samps_to_mix;
+		*outbuf_space = dz->buflen - opos;
+	}
+	*position_in_outbuf = opos;
+	return(FINISHED);
+}
+
+/************************* DO_ZERO_LEVEL ***********************************/
+
+void do_zero_level(int samps_to_mix,int *position_in_outbuf,int *outbuf_space,int *total_samps_used,dataptr dz)
+{
+	int overflow;
+	while((overflow = samps_to_mix - *outbuf_space) > 0) {
+		*total_samps_used += dz->buflen;
+		display_virtual_time(*total_samps_used,dz);
+		*position_in_outbuf = 0;
+		*outbuf_space = dz->buflen;
+		samps_to_mix = overflow;
+	}
+	if(samps_to_mix) {
+		*total_samps_used += samps_to_mix;
+		*position_in_outbuf += samps_to_mix;
+		*outbuf_space = dz->buflen - *position_in_outbuf;
+	}
+}
+
+/******************************** DO_MIX2 ***************************
+ *
+ * Alternative mix algorithm that SUMS all the buffers for a single sample
+ * then puts into output, before proceeding to next sample.
+ * In this routine some +ve overflow may be cancelled by a subsequent -ve
+ * sample (and vice versa), preventing final signal overflow.
+ * However this is slightly slower.
+ */
+
+int do_mix2(int samps_to_mix,int *position_in_outbuf,int active_bufcnt,int *outbuf_space,dataptr dz)
+{
+	int exit_status;
+	int m /*, samp_sum*/;
+	double d_samp_sum;			/*RWD*/
+	int n, overflow;
+	float *obuf = dz->sampbuf[OBUFMIX];
+	int opos = *position_in_outbuf;
+	if(dz->iparam[MIX_STRTPOS] > 0) {
+		for(n=0;n<active_bufcnt;n++)
+			dz->activebuf_ptr[n] += dz->iparam[MIX_STRTPOS_IN_ACTION];
+	}
+	if((overflow = samps_to_mix - *outbuf_space) <= 0) {
+		for(n=0;n<samps_to_mix;n++) {
+			d_samp_sum = *(dz->activebuf_ptr[0]++);
+			for(m=1;m<active_bufcnt;m++)
+				d_samp_sum += *(dz->activebuf_ptr[m]++);
+			obuf[opos++] = (float)d_samp_sum;
+		}
+		for(m=0;m<active_bufcnt;m++)
+			dz->buflist[dz->activebuf[m]]->here += samps_to_mix;
+	} else {
+		if(*outbuf_space > 0) {	/* APRIL 1995 */
+			for(n=0;n<*outbuf_space;n++) {
+				d_samp_sum = *(dz->activebuf_ptr[0]++);
+				for(m=1;m<active_bufcnt;m++)
+					d_samp_sum += *(dz->activebuf_ptr[m]++);
+				obuf[opos++] = (float)d_samp_sum;
+			}
+			for(m=0;m<active_bufcnt;m++)
+				dz->buflist[dz->activebuf[m]]->here += *outbuf_space;
+		}
+		if((exit_status = write_samps(obuf,dz->buflen,dz))<0)
+			return(exit_status);
+		if(overflow) {
+			opos = 0;
+			for(n=0;n<overflow;n++) {
+				d_samp_sum = *(dz->activebuf_ptr[0]++);
+				for(m=1;m<active_bufcnt;m++)
+					d_samp_sum += *(dz->activebuf_ptr[m]++);
+				obuf[opos++] = (float)d_samp_sum;
+			}
+			for(m=0;m<active_bufcnt;m++)
+				dz->buflist[dz->activebuf[m]]->here += overflow;
+		}
+	}
+	*outbuf_space = dz->buflen - opos;
+	*position_in_outbuf = opos;
+	return(FINISHED);
+}
+
+/***************************** DO_THE_LEVEL ********************************/
+
+void do_the_level
+(float *olbuf,int *opos,int cnt,double *d_maxsamp,int *maxloc,int *clipsize,int total_samps_used,dataptr dz)
+{
+	int clipstart = 0, z /*, thisval*/;
+	double d_thisval;  /*RWD */
+	int this_opos = *opos;
+	switch(dz->mode) {
+	case(MIX_LEVEL_ONLY):
+		for(z=0;z<cnt;z++) {
+			if((d_thisval = fabs(olbuf[this_opos])) > *d_maxsamp) {
+				*d_maxsamp = d_thisval;
+				*maxloc  = total_samps_used + this_opos;
+			}
+			this_opos++;
+		}
+		break;
+	case(MIX_CLIPS_ONLY):	
+		for(z=0;z<cnt;z++) {
+			if(fabs(olbuf[this_opos]) > F_MAXSAMP) {
+				if(*clipsize==0)
+					clipstart = total_samps_used + this_opos;
+				(*clipsize)++;
+			} else {
+				if(*clipsize > 0) {
+					if(sloom) {
+						if(clipcnt <= MAX_CLIP_DISPLAY) {
+							if(clipcnt == MAX_CLIP_DISPLAY) {
+								fprintf(stdout,"INFO: See output data file for more information on clipping.\n");
+							} else {
+								fprintf(stdout,"INFO: Clip at time %lf secs : sample %d : For %d samples\n",
+								(double)clipstart/(double)dz->out_chans/(double)dz->infile->srate,clipstart,*clipsize);
+							}
+							fflush(stdout);
+						}
+					}
+					fprintf(dz->fp,"Clip at time %lf secs : sample %d : For %d samples\n",
+					(double)clipstart/(double)dz->out_chans/(double)dz->infile->srate,clipstart,*clipsize);
+					*clipsize = 0;
+					clipcnt++;
+				}
+			}
+			this_opos++;
+		}
+		break;
+	case(MIX_LEVEL_AND_CLIPS):	
+		for(z=0;z<cnt;z++) {
+			if((d_thisval = fabs(olbuf[this_opos])) > *d_maxsamp) {
+				*d_maxsamp = d_thisval;
+				*maxloc  =  total_samps_used + this_opos;
+			}
+			if(d_thisval > F_MAXSAMP) {
+				if(*clipsize==0)
+					clipstart = total_samps_used + this_opos;
+				(*clipsize)++;
+			} else {
+				if(*clipsize>0) {
+					if(sloom) {
+						if(clipcnt <= MAX_CLIP_DISPLAY) {
+							if(clipcnt == MAX_CLIP_DISPLAY) {
+								fprintf(stdout,"INFO: See output data file for more information on clipping.\n");
+							} else {
+								fprintf(stdout,"INFO: Clip at time %lf secs : sample %d : For %d samples\n",
+								(double)clipstart/(double)dz->out_chans/(double)dz->infile->srate,clipstart,*clipsize);
+							}
+							fflush(stdout);
+						}
+					}
+					fprintf(dz->fp,"Clip at time %lf secs : sample %d : For %d samples\n",
+					(double)clipstart/(double)dz->out_chans/(double)dz->infile->srate,clipstart,*clipsize);
+					*clipsize = 0;
+					clipcnt++;
+				}
+			}
+			this_opos++;
+		}
+		break;
+	}
+	*opos = this_opos;
+	if(sloom)
+		display_virtual_time((total_samps_used + this_opos),dz);
+}
+
+/************************ GAIN_TO_DB ************************/
+
+double gain_to_db(double val)
+{
+	val = log10(val);
+	val *= 20.0;
+	return(val);
+}
+
+/*************************** MIX_READ_SAMPS **************************/
+
+int mix_read_samps(float *inbuf,int samps_to_read,int n,dataptr dz)
+{
+	int thisfile = dz->act[n]->val->ifd;
+	if((dz->ssampsread = fgetfbufEx(inbuf, samps_to_read,thisfile,0)) < 0) {
+		sprintf(errstr, "Can't read samps from input soundfile %d\n",n+1);
+		return(SYSTEM_ERROR);
+	}
+	return(FINISHED);
+}
+
+/************************* SCALE_SMPS **************************/
+
+int scale_smps(int n,dataptr dz)
+{
+	int m, k;
+	double thisscale;
+	float *inbuf = dz->buflist[dz->act[n]->val->bufno]->buf;
+	float *stereobuf = dz->sampbuf[STEREOBUF];
+	int stereo_state = dz->act[n]->val->stereo;
+	switch(stereo_state) {
+	case(MONO): 					/* Scale the mono source. */
+		m = 0;
+		thisscale = dz->act[n]->val->llscale;
+		if(thisscale==0.0) {
+		
+			memset((char *)inbuf,0,dz->buflen * sizeof(float));
+		}
+		else if(thisscale != 1.0){
+			while(m<dz->ssampsread) {
+				inbuf[m] = (float)(inbuf[m] * thisscale);
+				m++;
+			}
+			break;
+		}
+		break;
+	case(MONO_TO_CENTRE):				/*  work on the 1/2 buflen still in the stereobuf. */ 
+		m = 0;							/* Scale it and copy to both L and R in inbuf.     */
+		k = 0;
+		thisscale = dz->act[n]->val->llscale;
+		if(thisscale==0.0) {
+		
+			memset((char *)inbuf,0,dz->buflen * sizeof(float));
+		}
+		else if(thisscale == 1.0){
+			while(m<dz->ssampsread) {
+				inbuf[k]   = stereobuf[m];
+				inbuf[k+1] = inbuf[k];
+				k+=2;
+				m++;
+			}
+		}
+		else{
+			while(m<dz->ssampsread) {
+				inbuf[k]   = (float)(stereobuf[m] * thisscale);
+				inbuf[k+1] = inbuf[k];
+				k+=2;
+				m++;
+			}
+			break;
+		}
+       	dz->ssampsread *= 2;
+		break;
+	case(STEREO_TO_CENTRE):				/* sum the stereo pair in stereobuf */
+ 		m = 0;							/* Scale the result (already adjusted for centring) */
+		k = 0;							/*and copy to both L and R in inbuf */
+		thisscale = dz->act[n]->val->llscale;
+		if(thisscale==0.0) {
+			memset((char *)inbuf,0,dz->buflen * sizeof(float));
+		}
+		else if(thisscale==1.0){
+			while(m<dz->ssampsread) {
+				inbuf[k] = (float)(stereobuf[m]+stereobuf[m+1]);
+				inbuf[k+1] = inbuf[k];
+				k+=2;
+				m+=2;
+			}
+		}
+		else{
+			while(m<dz->ssampsread) {
+				inbuf[k] = (float)((stereobuf[m]+stereobuf[m+1]) * thisscale);
+				inbuf[k+1] = inbuf[k];
+				k+=2;
+				m+=2;
+			}
+			break;
+		}
+		break;
+	case(MONO_TO_LEFT):				/*  scale left of stereo source only: (right is preset to zero!). */
+		thisscale = dz->act[n]->val->llscale;
+		if(thisscale==0.0) {
+			memset((char *)inbuf,0,dz->buflen * sizeof(float));
+		}
+		else if(thisscale!=1.0){
+			m = LEFT;
+			while(m<dz->ssampsread) {
+				inbuf[m] = (float)(inbuf[m] * thisscale);
+				m += 2;
+			}			
+		}
+		break;
+	case(MONO_TO_RIGHT):				/* scale right of stereo source only: (left is preset to zero!).*/
+		thisscale = dz->act[n]->val->rrscale;
+		if(thisscale==0.0) {
+			memset((char *)inbuf,0,dz->buflen * sizeof(float));
+		}
+		else if(thisscale != 1.0){
+			m = RIGHT;
+			while(m<dz->ssampsread) {
+				inbuf[m] = (float)(inbuf[m] * thisscale);
+				m += 2;
+			}			
+		}
+		break;
+	case(MONO_TO_STEREO):			/* scale each channel of stereo_ified source.*/
+	case(STEREO): 					/* scale each channel of stereo source.*/
+		m = LEFT;
+		thisscale = dz->act[n]->val->llscale;
+		if(thisscale==0.0) {
+			while(m<dz->ssampsread) {
+				inbuf[m] = 0.0f;
+				m += 2;
+			}
+		}
+		else if(thisscale != 1.0){
+			while(m<dz->ssampsread) {
+				inbuf[m] = (float)(inbuf[m] * thisscale);
+				m += 2;
+			}			
+		}
+		m = RIGHT;
+		thisscale = dz->act[n]->val->rrscale;
+		if(thisscale==0.0) {
+			while(m<dz->ssampsread) {
+				inbuf[m] = 0.0f;
+				m += 2;
+			}
+		}
+		else if(thisscale != 1.0){
+			while(m<dz->ssampsread) {
+				inbuf[m] = (float)(inbuf[m] * thisscale);
+				m += 2;
+			}		
+		}
+		break;
+	case(STEREO_MIRROR):				/* Scale L channel (in stereobuf) & copy to R.	   */
+ 										/* Then scale R channel (in stereobuf) & copy to L */
+		m = RIGHT;	/* put to right */
+		k = LEFT;	/* the scaled left channel */
+		thisscale = dz->act[n]->val->llscale;
+		if(thisscale==0.0) {
+			while(m<dz->ssampsread) {
+				inbuf[m] = 0.0f;
+				m += 2;
+			}
+		}
+		else if(thisscale==1.0){
+			while(m<dz->ssampsread) {
+				inbuf[m] = stereobuf[k];
+				m += 2;
+				k += 2;
+			}			
+		}
+		else{
+			while(m<dz->ssampsread) {
+				inbuf[m] = (float)(stereobuf[k] * thisscale);
+				m += 2;
+				k += 2;
+			}			
+		}
+		m = LEFT;	/* put to left */
+		k = RIGHT;	/* the scaled right channel */	
+		thisscale = dz->act[n]->val->rrscale;
+		if(thisscale==0.0) {
+			while(m<dz->ssampsread) {
+				inbuf[m] = 0.0f;
+				m += 2;
+			}
+		}
+		else if(thisscale==1.0){
+			while(m<dz->ssampsread) {
+				inbuf[m] = stereobuf[k];
+				m += 2;
+				k += 2;
+			}
+		}
+		else {
+			while(k<dz->ssampsread) {
+				inbuf[m] = (float)(stereobuf[k] * thisscale);
+				m += 2;
+				k += 2;
+			}			
+		}
+		break;
+	case(STEREO_PANNED): 				/* each stereo INPUT channel contributes to each stereo OUTPUT channel. */
+										/* So copy scaled version of first to each outchan, */
+										/* then do same to 2nd inchans, ADDING it into the outbuf */
+		m = 0;
+		thisscale = dz->act[n]->val->llscale;
+		while(m<dz->ssampsread) {
+			inbuf[m] =(float)(stereobuf[m] * thisscale);
+			m += 2;
+		}
+		m = 0;
+		thisscale = dz->act[n]->val->lrscale;
+		while(m<dz->ssampsread) {
+			inbuf[m+1] = (float)(stereobuf[m] * thisscale);
+			m += 2;
+		}
+		m = 1;
+		thisscale = dz->act[n]->val->rlscale;
+		while(m<dz->ssampsread) {
+			inbuf[m-1] = (float)(inbuf[m-1] + (stereobuf[m] * thisscale));
+			m += 2;
+		}
+		m = 1;
+		thisscale = dz->act[n]->val->rrscale;
+		while(m<dz->ssampsread) {
+			inbuf[m] = (float)(inbuf[m]  + (stereobuf[m] * thisscale));
+			m += 2;
+		}
+		break; 
+	case(STEREO_TO_LEFT):				/* both channels are at same level, but both panned to left. */
+ 	case(STEREO_TO_RIGHT):				/* Preset outbuf to zero, then sum each pair of stereo channels, */
+										/* scale result and write to left. */
+										/* For STEREO_TO_RIGHT Ditto , but write to right. */
+	
+		if(stereo_state==STEREO_TO_LEFT) {
+			m = START;	/* read from start */
+			k = LEFT;	/* write to left */
+			thisscale = dz->act[n]->val->llscale;
+		} else {
+			m = START;	/* read from start */
+			k = RIGHT;	/* write to right */
+			thisscale = dz->act[n]->val->rrscale;
+		}
+		memset((char *)inbuf,0,dz->buflen * sizeof(float));
+		
+		if(thisscale==0.0) {
+			;
+		}
+		else if(thisscale==1.0){
+			while(m<dz->ssampsread) {
+				inbuf[k] = (float)(stereobuf[m]+stereobuf[m+1]);
+				k+=2;
+				m+=2;
+			}
+		}
+		else{
+			while(m<dz->ssampsread) {
+				inbuf[k] = (float)((stereobuf[m]+stereobuf[m+1]) * thisscale);
+				k+=2;
+				m+=2;
+			}			
+		}
+		break;
+	case(STEREOLEFT_TO_LEFT):				/* for STEREOLEFT_TO_LEFT there is no right channel output or input. */
+ 	case(STEREORIGHT_TO_RIGHT):				/* zero outbuf, & copy scaled left channel to left outchan */
+											/* For STEREORIGHT_TO_RIGHT there is no left channel output or input. */
+ 											/* zero outbuf, & copy scaled right channel to right output */
+ 	
+		if(stereo_state==STEREOLEFT_TO_LEFT) {
+			m = LEFT;	/* write from left to left */
+			thisscale = dz->act[n]->val->llscale;
+		} else {
+			m = RIGHT;	/* write from right to right */
+			thisscale = dz->act[n]->val->rrscale;
+		}
+		memset((char *)inbuf,0,dz->buflen * sizeof(float));
+		if(thisscale==0.0) {
+			;
+		}
+		else if(thisscale==1.0){
+			while(m<dz->ssampsread) {
+				inbuf[m] = stereobuf[m];
+				m+=2;
+			}
+		}
+		else {
+			while(m<dz->ssampsread) {
+				inbuf[m] = (float)(stereobuf[m] * thisscale);
+				m+=2;
+			}		
+		}
+		break;
+	case(STEREOLEFT_TO_RIGHT):				/* For STEREOLEFT_TO_RIGHT there is no L chan output or R chan input. */
+ 	case(STEREORIGHT_TO_LEFT):				/* Zero buffer, & copy scaled left chan to right */
+ 											/* For STEREORIGHT_TO_LEFT there is no R chan output or L chan input. */
+ 											/* Zero buffer, & copy scaled right chan to left */
+	
+		if(stereo_state==STEREOLEFT_TO_RIGHT) {
+			m = LEFT;	/* write from left to right */
+			k = RIGHT;
+			thisscale = dz->act[n]->val->rrscale;
+		} else {
+			m = RIGHT;	/* write from right to left */
+			k = LEFT;
+			thisscale = dz->act[n]->val->llscale;
+		}
+		memset((char *)inbuf,0,dz->buflen * sizeof(float));
+		if(thisscale==0.0) {
+			;
+		}
+		else if(thisscale==1.0){
+			while(m<dz->ssampsread) {
+				inbuf[k] = stereobuf[m];
+				m+=2;
+				k+=2;
+			}
+		}
+		else{
+			while(m<dz->ssampsread) {
+				inbuf[k] = (float)(stereobuf[m] * thisscale);
+				m+=2;
+				k+=2;
+			}		
+		}
+		break;
+	case(STEREOLEFT_PANNED):				/* For STEREOLEFT_PANNED there is no R chan input. */
+ 	case(STEREORIGHT_PANNED):				/* Copy left input, left_scaled, to left. */
+ 											/* Then copy left input right_scaled to right. */
+ 											/* For STEREORIGHT_PANNED there is no L chan input. */
+ 											/* Copy right input, right_scaled, to right. */
+ 											/* Then copy right input left_scaled to left.*/
+	
+		if(stereo_state==STEREOLEFT_PANNED) {
+			m = LEFT;	/* left to left */
+			thisscale = dz->act[n]->val->llscale;
+		} else {
+			m = RIGHT;	/* right to right */
+			thisscale = dz->act[n]->val->rrscale;
+		}
+		if(thisscale==0.0) {
+			while(m<dz->ssampsread) {
+				inbuf[m] = 0.0f;
+				m+=2;
+			}
+		}
+		else if(thisscale==1.0){
+			while(m<dz->ssampsread) {
+				inbuf[m] = stereobuf[m];
+				m+=2;
+			}
+		}
+		else{
+			while(m<dz->ssampsread) {
+				inbuf[m] = (float)(stereobuf[m] * thisscale);
+				m+=2;
+			}			
+		}
+		if(stereo_state==STEREOLEFT_PANNED) {
+			m = LEFT;	/* left to right */
+			k = RIGHT;
+			thisscale = dz->act[n]->val->rrscale;
+		} else {
+			m = RIGHT;	/* right to left */
+			k = LEFT;
+			thisscale = dz->act[n]->val->llscale;
+		}
+		if(thisscale==0.0) {
+			while(m<dz->ssampsread) {
+				inbuf[m] = 0.0f;
+				m+=2;
+			}
+		}
+		else if(thisscale==1.0){
+			while(m<dz->ssampsread) {
+				inbuf[k] = stereobuf[m];
+				m+=2;
+				k+=2;
+			}
+		}
+		else{
+			while(m<dz->ssampsread) {
+				inbuf[k] = (float)(stereobuf[m] * thisscale);
+				m+=2;
+				k+=2;
+			}		
+		}
+		break;
+	default:
+		sprintf(errstr,"Unknown case in scale_smps()\n");
+		return (PROGRAM_ERROR);
+	}
+	return(FINISHED);
+}

+ 880 - 0
dev/submix/setupmix.c

@@ -0,0 +1,880 @@
+/*
+ * 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 <processno.h>
+#include <tkglobals.h>
+#include <mix.h>
+#include <globcon.h>
+#include <cdpmain.h>
+#include <filetype.h>
+
+#include <sfsys.h>
+
+#ifdef unix
+#define round(x) lround((x))
+#endif
+
+static int establish_action_value_storage_for_mix(dataptr dz);
+static int open_file_and_get_props(int filecnt,char *filename,int *srate,int chans,dataptr dz);
+static int allocate_actions(int filecnt,dataptr dz);
+static int assign_stereo_sense(int chans,double lpan,double rpan,double llevel,double rlevel,dataptr dz);
+static int unmark_freeable_bufs(int **bufsflag,int *bufsflagcnt,int startpos,int this,int longbitsize,dataptr dz);
+static int get_free_buf(int **bufsflag,int *bufsflagcnt,int longbitsize,int *thisbuf,dataptr dz);
+#ifdef NOTDEF
+static int assign_scaling(int here,double llevel,double rlevel,double lpan,double rpan,
+			int *llscale,int *rrscale,int *lrscale,int *rlscale,dataptr dz);
+#else
+static int d_assign_scaling(int here,double llevel,double rlevel,double lpan,double rpan,
+double *llscale,double *rrscale,double *lrscale,double *rlscale,dataptr dz);
+#endif
+static int check_right_level(char *str,double *rlevel,int filecnt);
+static int check_right_pan(char *str,double *pan,int filecnt);
+static int check_left_pan(char *str,double *pan,int filecnt);
+static int check_left_level(char *str,double *level,int filecnt);
+static int unmark_buf(int **bufsflag,int *bufsflagcnt,int thisbuf,int longbitsize);
+static int mark_buf(int **bufsflag,int *bufsflagcnt,int thisbuf,int longbitsize,dataptr dz);
+static int reallocate_bufsflag(int z,int **bufsflag,int *bufsflagcnt);
+
+/********************** SET_UP_MIX ****************************/
+ 
+int set_up_mix(dataptr dz)
+{
+	int exit_status;
+	double time, llevel, lpan, rlevel, rpan;
+	int    chans;
+	int   startpos, endpos, n;
+	int *bufsflag = NULL;
+	int bufsflagcnt = 0;
+	double filetime, eventend;
+	int longbitsize = sizeof(int) * CHARBITSIZE;
+	int srate=0, end_of_mix = -1;
+	int mix_end_set   = FALSE;
+	int mix_end_specified = FALSE;
+	int mix_start_set = FALSE;
+	char *filename;
+	int filecnt = 0;												
+	int total_words = 0;
+
+	if(dz->param[MIX_START] >= dz->param[MIX_END]) {
+		sprintf(errstr,"Mix starts after it ends.\n");
+		return(USER_ERROR);
+	}
+	dz->iparam[MIX_STRTPOS] 		  = 0;
+	dz->iparam[MIX_STRTPOS_IN_ACTION] = 0;
+	dz->iparam[MIX_TOTAL_ACTCNT]      = 0;
+	if((exit_status = establish_file_data_storage_for_mix(dz->linecnt,dz))<0)
+		return(exit_status);
+	if((exit_status = establish_action_value_storage_for_mix(dz))<0)
+		return(exit_status);
+	for(n=0;n<dz->linecnt;n++) {						/* for each mixfile line */
+		filename = dz->wordstor[total_words];			/* get the filename */
+		if(strlen(filename)<=0) {
+			sprintf(errstr,"filename error: line %d: parse_mixfile_for_data()\n",filecnt+1);
+			return(PROGRAM_ERROR);
+		}
+		if((exit_status = get_mixdata_in_line			
+		(dz->wordcnt[n],dz->wordstor,total_words,&time,&chans,&llevel,&lpan,&rlevel,&rpan,filecnt,dz))<0)
+			return(exit_status);
+		total_words += dz->wordcnt[n];
+		if(time >= dz->param[MIX_END])					/* If line starts after specified mix end, ignore */
+			continue;
+		if((exit_status = finalise_and_check_mixdata_in_line(dz->wordcnt[n],chans,llevel,&lpan,&rlevel,&rpan))<0)
+			return(exit_status);
+		if((exit_status = open_file_and_get_props(filecnt,filename,&srate,chans,dz))<0)
+			return(exit_status);
+		filetime = (double)(dz->insams[filecnt]/chans)/(double)srate;
+		if((eventend = time + filetime) < dz->param[MIX_START])	/* If line ends before specified mix start, ignore */
+			continue;
+		if(!mix_start_set) {								/* if mix start param not set yet, set it */
+			dz->iparam[MIX_STRTPOS]           = (int)round(dz->param[MIX_START] * (double)(srate * dz->out_chans));
+			dz->iparam[MIX_STRTPOS_IN_ACTION] = dz->iparam[MIX_STRTPOS];
+			mix_start_set = TRUE;
+		}
+		if(!mix_end_set) {									/* if mix end param not set yet, set it */
+			if(!flteq(dz->param[MIX_END],dz->application->default_val[MIX_END])) {	 /* if mixend param given by user */
+				end_of_mix = round(dz->param[MIX_END] * (double)srate) * dz->out_chans;
+				if(end_of_mix < 0) {
+					sprintf(errstr,"Error in end_of_mix logic: parse_mixfile_for_data()\n");
+					return(PROGRAM_ERROR);
+				}
+				mix_end_specified = TRUE;
+			}
+			mix_end_set = TRUE;
+		}
+		if((exit_status = allocate_actions(filecnt,dz))<0)	/* assign values to mix ON and OFF actions */
+			return(exit_status);
+		startpos = round(time * (double)srate) * chans;		/* startposition, in samples, of this file */
+		dz->valstor[filecnt]->stereo  = assign_stereo_sense(chans,lpan,rpan,llevel,rlevel,dz);
+		if(dz->valstor[filecnt]->stereo == MONO_TO_STEREO
+		|| dz->valstor[filecnt]->stereo == MONO_TO_CENTRE
+		|| dz->valstor[filecnt]->stereo == MONO_TO_LEFT
+		|| dz->valstor[filecnt]->stereo == MONO_TO_RIGHT) {
+			startpos             *= STEREO;					/* startposition, in output samples, of this file */
+			dz->insams[filecnt]  *= STEREO;					/* EFFECTIVE sample-dur of file: it's converted to stereo */
+		}
+		if((exit_status = unmark_freeable_bufs				/* finds buffers which are not (any longer) in use */
+		(&bufsflag,&bufsflagcnt,startpos,dz->iparam[MIX_TOTAL_ACTCNT],longbitsize,dz))<0)
+			return(exit_status);
+		dz->valstor[filecnt]->ifd  	= dz->ifd[filecnt];
+		if((exit_status = get_free_buf(&bufsflag,&bufsflagcnt,longbitsize,&(dz->valstor[filecnt]->bufno),dz))<0) 	
+			return(exit_status);	  						/* Allocate a buffer which is not currently in use */	
+		if((exit_status = d_assign_scaling(dz->iparam[MIX_TOTAL_ACTCNT],llevel,rlevel,lpan,rpan,
+		&(dz->valstor[filecnt]->llscale),&(dz->valstor[filecnt]->rrscale),
+		&(dz->valstor[filecnt]->lrscale),&(dz->valstor[filecnt]->rlscale),dz))<0)
+			return(exit_status);							/* Assign the input sound amplitude scaling */
+		endpos =  startpos + dz->insams[filecnt];			/* Find end-of-current-file in output stream */
+		if(mix_end_specified && (end_of_mix < endpos)) {	/* If file ends aftert mix ends */
+			endpos  = end_of_mix;						 	/* curtail (effective) length */
+			dz->insams[filecnt] = end_of_mix - startpos;
+		}
+		dz->valstor[filecnt]->samplen = dz->insams[filecnt]; 			/* store (effective) length */
+		dz->act[dz->iparam[MIX_TOTAL_ACTCNT]++]->position = startpos;	/* store outputstream-position of mix start */
+		dz->act[dz->iparam[MIX_TOTAL_ACTCNT]++]->position = endpos;		/* store outputstream-position of mix end   */
+		filecnt++;											/* count the ACTUALLY USED lines */
+	}
+	if(!mix_end_set || filecnt==0) {
+		sprintf(errstr,"No mixfile line is active within the time limits specified.\n");
+		return(DATA_ERROR);
+	}
+	if(bufsflagcnt)
+		free(bufsflag);
+    dz->bufcnt++;		/* bufcnt is number assigned to highest assigned buf, COUNTING FROM ZERO */
+						/* Hence, actual bufcnt is 1 more than this */
+
+	dz->infile->channels = dz->out_chans;	/* output channels(evenutally derived from dz->infile->channels) */
+//TW SET UP AFTER OUTCHANS KNOWN
+	if(dz->process!=MIXMAX) {
+		if((exit_status = create_sized_outfile(dz->outfilename,dz))<0)
+			return(exit_status);
+	}
+	return(FINISHED);						/* is highest number of channels encountered in infiles */
+}
+
+/**************************** ESTABLISH_FILE_DATA_STORAGE_FOR_MIX ********************************/
+
+int establish_file_data_storage_for_mix(int filecnt,dataptr dz)
+{
+	int n;
+	if(dz->insams!=NULL)		
+		free(dz->insams);	 	/* in TK insams[0] also used in parse accounting */
+	if(dz->ifd!=NULL)
+		free(dz->ifd);
+	if((dz->insams = (int *)malloc(filecnt * sizeof(int)))==NULL) {
+		sprintf(errstr,"INSUFFICIENT MEMORY to allocate infile samplesize array.\n");
+		return(MEMORY_ERROR);
+	}
+	if((dz->ifd = (int  *)malloc(filecnt * sizeof(int)))==NULL) {
+		sprintf(errstr,"INSUFFICIENT MEMORY to allocate infile pointers array.\n");		   	
+		return(MEMORY_ERROR);
+	}
+	for(n=0;n<filecnt;n++)
+		dz->ifd[n] = -1;
+	return(FINISHED);
+}
+
+/**************************** ESTABLISH_ACTION_VALUE_STORAGE_FOR_MIX ********************************/
+
+int establish_action_value_storage_for_mix(dataptr dz)
+{
+	int n;
+	if((dz->valstor  = (actvalptr *)malloc(dz->linecnt * sizeof(actvalptr)))==NULL) {
+		sprintf(errstr,"INSUFFICIENT MEMORY for mix action values store.\n");
+		return(MEMORY_ERROR);
+	}
+	for(n=0;n<dz->linecnt;n++) {
+		dz->valstor[n] = NULL;		
+		if((dz->valstor[n]=(actvalptr)malloc(sizeof(struct actval)))==NULL) {
+			sprintf(errstr,"INSUFFICIENT MEMORY for mix action value store %d\n",n+1);				
+			return(MEMORY_ERROR);
+		}
+	}
+	return(FINISHED);
+}
+
+/**************************** GET_MIXDATA_IN_LINE ********************************/
+
+int get_mixdata_in_line(int wordcnt,char **wordstor,int total_words,double *time,int *chans,
+double *llevel,double *lpan,double *rlevel,double *rpan,int filecnt,dataptr dz)
+{
+	int exit_status;
+	switch(wordcnt) {
+	case(MIX_MAXLINE):
+		if((exit_status = check_right_level(wordstor[total_words+MIX_RLEVELPOS],rlevel,filecnt))<0)	/* 6d */
+			return(exit_status);
+		if((exit_status = check_right_pan(wordstor[total_words+MIX_RPANPOS],rpan,filecnt))<0)
+			return(exit_status);
+		/* fall thro */
+	case(MIX_MIDLINE):
+		if((exit_status = check_left_pan(wordstor[total_words+MIX_PANPOS],lpan,filecnt))<0)		/* 6c */
+			return(exit_status);
+		/* fall thro */
+	case(MIX_MINLINE):
+		if(sscanf(dz->wordstor[total_words+1],"%lf",time)!=1
+		|| sscanf(dz->wordstor[total_words+2],"%d",chans)!=1) {
+			sprintf(errstr,"Error scanning data: get_mixdata_in_line()\n");
+			return(PROGRAM_ERROR);
+		}
+		if((exit_status = check_left_level(wordstor[total_words+3],llevel,filecnt))<0)
+			return(exit_status);
+		break;
+	default:
+		sprintf(errstr,"Illegal line length: get_mixdata_in_line()\n");
+		return(PROGRAM_ERROR);
+	}
+	return(FINISHED);
+}
+
+/**************************** FINALISE_AND_CHECK_MIXDATA_IN_LINE ********************************/
+
+int  finalise_and_check_mixdata_in_line(int wordcnt,int chans,double llevel,
+					double *lpan,double *rlevel,double *rpan)
+{
+	switch(wordcnt) {
+	case(MIX_MINLINE):
+		switch(chans) {
+		case(1): 
+			*lpan = 0.0;						/* 6a */
+			break;
+		case(2): 
+			*rlevel = llevel;				/* 6b */
+			*lpan   = -1.0;
+			*rpan   = 1.0;
+		}
+		break;
+	case(MIX_MIDLINE):
+		if(chans!=1) {
+			sprintf(errstr,"Error parsing data: finalise_and_check_mixdata_in_line()\n");
+			return(PROGRAM_ERROR);
+		}
+		break;
+	case(MIX_MAXLINE):
+		if(chans!=2) {
+			sprintf(errstr,"Error parsing data: finalise_and_check_mixdata_in_line()\n");
+			return(PROGRAM_ERROR);
+		}
+		break;
+	}
+	return(FINISHED);
+}
+
+
+/************************* OPEN_FILE_AND_GET_PROPS *******************************/
+
+int open_file_and_get_props(int filecnt,char *filename,int *srate,int chans,dataptr dz)
+{
+	int exit_status;
+	double maxamp, maxloc;
+	int maxrep;
+	int getmax = 0, getmaxinfo = 0;
+	infileptr ifp;
+	if((ifp = (infileptr)malloc(sizeof(struct filedata)))==NULL) {
+		sprintf(errstr,"INSUFFICIENT MEMORY to store data on files.\n");
+		return(MEMORY_ERROR);
+	}
+	if((dz->ifd[filecnt] = sndopenEx(filename,0,CDP_OPEN_RDONLY)) < 0) {
+		sprintf(errstr,"Failed to open sndfile %s: %s\n",filename,sferrstr());
+		return(SYSTEM_ERROR);
+	}
+	if((exit_status = readhead(ifp,dz->ifd[filecnt],filename,&maxamp,&maxloc,&maxrep,getmax,getmaxinfo))<0)
+		return(exit_status);
+	copy_to_fileptr(ifp,dz->infile);
+	if(dz->infile->filetype!=SNDFILE) {
+		sprintf(errstr,"Non soundfile encountered [%s]: open_file_and_get_props()\n",filename);
+		return(PROGRAM_ERROR);
+	}
+	if(dz->infile->channels!=chans) {
+		sprintf(errstr,"Incorrect channels found [%s]: open_file_and_get_props()\n",filename);
+		return(PROGRAM_ERROR);
+	}
+	if(filecnt==0)
+		*srate = dz->infile->srate;
+	else if(dz->infile->srate != *srate) {
+		sprintf(errstr,"incompatible srates: [file %s] open_file_and_get_props()\n",filename);
+		return(PROGRAM_ERROR);
+	}
+	if((dz->insams[filecnt] = sndsizeEx(dz->ifd[filecnt]))<0) {	    			
+		sprintf(errstr, "Can't read size of input file %s: open_file_and_get_props()\n",filename);
+		return(PROGRAM_ERROR);
+	}
+	if(dz->insams[filecnt] <=0) {
+		sprintf(errstr, "Zero size for input file %s: open_file_and_get_props()\n",filename);
+		return(PROGRAM_ERROR);
+	}			
+	return(FINISHED);
+}
+
+/*********************** ALLOCATE_ACTIONS *************************/
+
+int allocate_actions(int filecnt,dataptr dz)
+{
+	int new_total = dz->iparam[MIX_TOTAL_ACTCNT] + 2;
+	if(dz->iparam[MIX_TOTAL_ACTCNT]==0) {
+		if((dz->act = (actptr *)malloc(new_total * sizeof(actptr)))==NULL) {
+			sprintf(errstr,"INSUFFICIENT MEMORY for mix actions store.\n");
+			return(MEMORY_ERROR);
+		}
+	} else {
+		if((dz->act=(actptr *)realloc(dz->act,new_total * sizeof(actptr)))==NULL) {
+			sprintf(errstr,"INSUFFICIENT MEMORY ro reallocate mix actions store.\n");
+			return(MEMORY_ERROR);
+		}
+	}
+	if((dz->act[dz->iparam[MIX_TOTAL_ACTCNT]] = (actptr)malloc(sizeof(struct action)))==NULL) {
+		sprintf(errstr,"INSUFFICIENT MEMORY for final mix action store.\n");
+		return(MEMORY_ERROR);
+	}
+	dz->act[dz->iparam[MIX_TOTAL_ACTCNT]]->val    = dz->valstor[filecnt];
+	dz->act[dz->iparam[MIX_TOTAL_ACTCNT]]->role   = MIX_ACTION_ON;
+	if((dz->act[dz->iparam[MIX_TOTAL_ACTCNT]+1] = (actptr)malloc(sizeof(struct action)))==NULL) {
+		sprintf(errstr,"INSUFFICIENT MEMORY for further mix action store.\n");
+		return(MEMORY_ERROR);
+	}
+	dz->act[dz->iparam[MIX_TOTAL_ACTCNT]+1]->val  = dz->valstor[filecnt];
+	dz->act[dz->iparam[MIX_TOTAL_ACTCNT]+1]->role = MIX_ACTION_OFF;
+	return(FINISHED);
+}
+
+/********************* ASSIGN_STEREO_SENSE **************************/
+
+int assign_stereo_sense(int chans,double lpan,double rpan,double llevel,double rlevel,dataptr dz)
+{
+	switch(chans) {
+	case(MONO):
+		if(dz->out_chans==MONO)		return(MONO);
+		else if(lpan <= -1.0)	 	return(MONO_TO_LEFT);
+		else if(lpan >= 1.0)		return(MONO_TO_RIGHT);
+		else if(flteq(lpan,0.0))	return(MONO_TO_CENTRE);
+		else						return(MONO_TO_STEREO);
+		break;
+	case(STEREO):
+		if(flteq(rlevel,0.0)) {
+			if(lpan <= -1.0)		return(STEREOLEFT_TO_LEFT);
+			else if(lpan >= 1.0)	return(STEREOLEFT_TO_RIGHT);
+			else					return(STEREOLEFT_PANNED);
+		}
+		else if(flteq(llevel,0.0)) {
+			if(rpan <= -1.0)		return(STEREORIGHT_TO_LEFT);
+			else if(rpan >= 1.0)	return(STEREORIGHT_TO_RIGHT);
+			else					return(STEREORIGHT_PANNED);
+		} else if(lpan <= -1.0 &&  rpan >= 1.0)								return(STEREO);
+		else if(lpan >= 1.0 && rpan <= -1.0)								return(STEREO_MIRROR);
+		else if(flteq(lpan,0.0) && flteq(rpan,0.0) && flteq(rlevel,llevel))	return(STEREO_TO_CENTRE);
+		else if((lpan <= -1.0) && flteq(rpan,lpan) && flteq(rlevel,llevel))	return(STEREO_TO_LEFT);
+		else if((rpan >= 1.0)  && flteq(rpan,lpan) && flteq(rlevel,llevel))	return(STEREO_TO_RIGHT);
+		break;
+	}
+	return(STEREO_PANNED);
+}
+
+/************************* UNMARK_FREEABLE_BUFS ***********************
+ *
+ * (1)	If a buffer has been switched off BEFORE now, then it is
+ *		available for use!! unmark it!!
+ * (2)	If a buffer is subsequently turned back on, this catches it!!
+ *		A buffer can ONLY be turned back on LATER (!), and is hence
+ *		LATER in this list EVEN though it is not yet fully time-sorted!!  (1998 ???)
+ */
+
+int unmark_freeable_bufs(int **bufsflag,int *bufsflagcnt,int startpos,int this,int longbitsize,dataptr dz)
+{
+	int exit_status;
+	int n;
+	for(n=0;n<this;n++) {
+		switch(dz->act[n]->role) {
+		case(MIX_ACTION_ON):				/* 2 */
+			if((exit_status = mark_buf(bufsflag,bufsflagcnt,dz->act[n]->val->bufno,longbitsize,dz))<0)
+				return(exit_status);
+			break;
+		case(MIX_ACTION_OFF):				/* 1 */
+			if(dz->act[n]->position < startpos)	{
+				if((exit_status = unmark_buf(bufsflag,bufsflagcnt,dz->act[n]->val->bufno,longbitsize))<0)
+					return(exit_status);
+			}
+			break;
+		}
+	}
+	return(FINISHED);
+}
+
+/************************** GET_FREE_BUF ***************************
+ *
+ * Get the FIRST available free buffer.
+ * (1)	Going through each int.
+ * (2)	Set the mask to start of int.
+ * (3)	For each position in the int..
+ * (4)	If that byte is NOT set, break, thisbuf counts which byte
+ *	and therefore which buffer it is.
+ * (5)	Advance the mask.
+ * (6)	Advance the buffer counter.
+ * (7)	Set the appropriate bit for this buffer, return buffer no.
+ */
+
+int get_free_buf(int **bufsflag,int *bufsflagcnt,int longbitsize,int *thisbuf,dataptr dz)
+{
+	int exit_status=0;
+	int y=0, z=0, got_it = 0;
+	int mask=0;
+	*thisbuf = 0;
+	for(z=0;z<*bufsflagcnt;z++) {			/* 1 */
+		mask = 1;	    					/* 2 */
+		for(y=0;y<longbitsize;y++) {		/* 3 */
+			if(!(mask & (*bufsflag)[z])) {	/* 4 */
+				got_it = 1;
+				break;
+			}
+			mask <<= 1;						/* 5 */
+			(*thisbuf)++;					/* 6 */
+		}
+		if(got_it)
+			break;
+	}
+	if((exit_status = mark_buf(bufsflag,bufsflagcnt,*thisbuf,longbitsize,dz))<0)	/* 7 */
+		return(exit_status);
+	return(FINISHED);
+}
+
+/*************************** ASSIGN_SCALING ***************************/
+/*RWD gulp! */
+#ifdef NOTDEF
+
+int assign_scaling(int here,double llevel,double rlevel,double lpan,double rpan,
+int *llscale,int *rrscale,int *lrscale,int *rlscale,dataptr dz)
+{
+	switch(dz->act[here]->val->stereo) {
+	case(MONO):
+		if(lpan < -1.0 - FLTERR)		*llscale = round(llevel * TWO_POW_15/(-lpan));
+		else if(lpan > 1.0 + FLTERR)	*llscale = round(llevel * TWO_POW_15/lpan);
+		else							*llscale = round(llevel * TWO_POW_15);
+		break;
+	case(MONO_TO_CENTRE):
+	case(STEREO_TO_CENTRE):				*llscale = round(llevel * TWO_POW_15);
+		break;
+	case(MONO_TO_LEFT):
+	case(STEREO_TO_LEFT):
+	case(STEREOLEFT_TO_LEFT):
+		if(lpan<(-1. - FLTERR))			*llscale = round(llevel * TWO_POW_15/(-lpan));
+		else							*llscale = round(llevel * TWO_POW_15);
+		break;
+	case(STEREORIGHT_TO_LEFT):
+		if(lpan<(-1. - FLTERR))			*llscale = round(rlevel * TWO_POW_15/(-lpan));
+		else							*llscale = round(rlevel * TWO_POW_15);
+		break;
+	case(MONO_TO_RIGHT):
+	case(STEREOLEFT_TO_RIGHT):
+		if(lpan>(1. + FLTERR))			*rrscale = round(llevel * TWO_POW_15/(lpan));
+		else 							*rrscale = round(llevel * TWO_POW_15);
+		break;
+	case(STEREO_TO_RIGHT):
+	case(STEREORIGHT_TO_RIGHT):
+		if(rpan>(1. + FLTERR))			*rrscale = round(rlevel * TWO_POW_15/rpan);
+		else							*rrscale = round(rlevel * TWO_POW_15);
+		break;
+	case(STEREO):
+		if(lpan < -1.0 - FLTERR)		*llscale = round(llevel * TWO_POW_15/(-lpan));
+		else							*llscale = round(llevel * TWO_POW_15);
+
+		if(rpan > 1.0 + FLTERR)			*rrscale = round(rlevel * TWO_POW_15/rpan);
+		else							*rrscale = round(rlevel * TWO_POW_15);
+		break;
+	case(STEREO_MIRROR):
+		if(lpan > 1.0 + FLTERR)			*llscale = round(llevel * TWO_POW_15/(lpan));
+		else							*llscale = round(llevel * TWO_POW_15);
+
+		if(rpan < -1.0 - FLTERR)		*rrscale = round(rlevel * TWO_POW_15/(-rpan));
+		else							*rrscale = round(rlevel * TWO_POW_15);
+		break;
+	case(MONO_TO_STEREO):
+	case(STEREOLEFT_PANNED):
+		if(lpan < -1.0 - FLTERR) {	/* VERY LEFT */
+			*llscale = round(llevel * TWO_POW_15/(-lpan));
+			*rrscale = 0;
+		} else if(lpan < 0.0) {		/* LEFTWARDS */
+			*llscale = round(llevel * TWO_POW_15);
+			*rrscale = round(llevel * (1.0+lpan) * TWO_POW_15);
+		} else if(lpan <= 1.0) {	/* RIGHTWARDS */
+			*llscale = round(llevel * (1.0-lpan) * TWO_POW_15);
+			*rrscale = round(llevel * TWO_POW_15);
+		} else {					/* VERY RIGHT */
+			*llscale = 0;
+			*rrscale = round(llevel * TWO_POW_15/(lpan));
+		}
+		break;
+	case(STEREORIGHT_PANNED):
+		if(rpan < -1.0) {			/* VERY LEFT */
+			*llscale = round(rlevel * TWO_POW_15/(-rpan));
+			*rrscale = 0;
+		} else if(rpan < 0.0) {		/* LEFTWARDS */
+			*llscale = round(rlevel * TWO_POW_15);
+			*rrscale = round(rlevel * (1.0+rpan) * TWO_POW_15);
+		} else if(rpan <= 1.0) {	/* RIGHTWARDS */
+			*llscale = round(rlevel * (1.0-rpan) * TWO_POW_15);
+			*rrscale = round(rlevel * TWO_POW_15);
+		} else {					/* VERY RIGHT */
+			*llscale = 0;
+			*rrscale = round(rlevel * TWO_POW_15/rpan);
+		}
+		break;
+	case(STEREO_PANNED):	
+		/* LEFT STEREO INPUT PANNED ... */
+		if(lpan < -1.0) {			/* VERY LEFT */
+			*llscale = round(llevel * TWO_POW_15/(-lpan));
+			*lrscale = 0;
+		} else if(lpan < 0.0) {		/* LEFTWARDS */
+			*llscale = round(llevel * TWO_POW_15);
+			*lrscale = round(llevel * (1.0+lpan) * TWO_POW_15);
+		} else if(lpan <= 1.0) {	/* RIGHTWARDS */
+			*llscale = round(llevel * (1.0-lpan) * TWO_POW_15);
+			*lrscale = round(llevel * TWO_POW_15);
+		} else {					/* VERY RIGHT */
+			*llscale = 0;
+			*lrscale = round(llevel * TWO_POW_15/(lpan));
+		}
+		/* RIGHT STEREO INPUT PANNED ... */
+		if(rpan < -1.0) {			/* VERY LEFT */
+			*rlscale = round(rlevel * TWO_POW_15/(-rpan));
+			*rrscale = 0;
+		} else if(rpan < 0.0) {		/* LEFTWARDS */
+			*rlscale = round(rlevel * TWO_POW_15);
+			*rrscale = round(rlevel * (1.0+rpan) * TWO_POW_15);
+		} else if(rpan <= 1.0) {	/* RIGHTWARDS */
+			*rlscale = round(rlevel * (1.0-rpan) * TWO_POW_15);
+			*rrscale = round(rlevel * TWO_POW_15);
+		} else {					/* VERY RIGHT */
+			*rlscale = 0;
+			*rrscale = round(rlevel * TWO_POW_15/(rpan));
+		}
+		break;
+	default:
+		sprintf(errstr,"Unknown case in assign_scaling()\n");
+		return(PROGRAM_ERROR);
+	}
+	return(FINISHED);
+}
+
+#else
+
+int d_assign_scaling(int here,double llevel,double rlevel,double lpan,double rpan,
+double *llscale,double *rrscale,double *lrscale,double *rlscale,dataptr dz)
+{
+	switch(dz->act[here]->val->stereo) {
+	case(MONO):
+		if(lpan < -1.0 - FLTERR)		*llscale = llevel/(-lpan);
+		else if(lpan > 1.0 + FLTERR)	*llscale = llevel/lpan;
+		else							*llscale = llevel;
+		break;
+	case(MONO_TO_CENTRE):
+	case(STEREO_TO_CENTRE):				*llscale = llevel;
+		break;
+	case(MONO_TO_LEFT):
+	case(STEREO_TO_LEFT):
+	case(STEREOLEFT_TO_LEFT):
+		if(lpan<(-1. - FLTERR))			*llscale = llevel/(-lpan);
+		else							*llscale = llevel;
+		break;
+	case(STEREORIGHT_TO_LEFT):
+		if(lpan<(-1. - FLTERR))			*llscale = rlevel/(-lpan);
+		else							*llscale = rlevel;
+		break;
+	case(MONO_TO_RIGHT):
+	case(STEREOLEFT_TO_RIGHT):
+		if(lpan>(1. + FLTERR))			*rrscale = llevel/lpan;
+		else 							*rrscale = llevel;
+		break;
+	case(STEREO_TO_RIGHT):
+	case(STEREORIGHT_TO_RIGHT):
+		if(rpan>(1. + FLTERR))			*rrscale = rlevel/rpan;
+		else							*rrscale = rlevel;
+		break;
+	case(STEREO):
+		if(lpan < -1.0 - FLTERR)		*llscale = llevel/(-lpan);
+		else							*llscale = llevel;
+
+		if(rpan > 1.0 + FLTERR)			*rrscale = rlevel/rpan;
+		else							*rrscale = rlevel;
+		break;
+	case(STEREO_MIRROR):
+		if(lpan > 1.0 + FLTERR)			*llscale = llevel/lpan;
+		else							*llscale = llevel;
+
+		if(rpan < -1.0 - FLTERR)		*rrscale = rlevel/(-rpan);
+		else							*rrscale = rlevel;
+		break;
+	case(MONO_TO_STEREO):
+	case(STEREOLEFT_PANNED):
+		if(lpan < -1.0 - FLTERR) {	/* VERY LEFT */
+			*llscale = llevel/(-lpan);
+			*rrscale = 0.0;
+		} else if(lpan < 0.0) {		/* LEFTWARDS */
+			*llscale = llevel;
+			*rrscale = llevel * (1.0+lpan);
+		} else if(lpan <= 1.0) {	/* RIGHTWARDS */
+			*llscale = llevel * (1.0-lpan);
+			*rrscale = llevel;
+		} else {					/* VERY RIGHT */
+			*llscale = 0.0;
+			*rrscale = llevel/lpan;
+		}
+		break;
+	case(STEREORIGHT_PANNED):
+		if(rpan < -1.0) {			/* VERY LEFT */
+			*llscale = rlevel/(-rpan);
+			*rrscale = 0.0;
+		} else if(rpan < 0.0) {		/* LEFTWARDS */
+			*llscale = rlevel;
+			*rrscale = rlevel * (1.0+rpan);
+		} else if(rpan <= 1.0) {	/* RIGHTWARDS */
+			*llscale = rlevel * (1.0-rpan);
+			*rrscale = rlevel;
+		} else {					/* VERY RIGHT */
+			*llscale = 0.0;
+			*rrscale = rlevel/rpan;
+		}
+		break;
+	case(STEREO_PANNED):	
+		/* LEFT STEREO INPUT PANNED ... */
+		if(lpan < -1.0) {			/* VERY LEFT */
+			*llscale = llevel /(-lpan);
+			*lrscale = 0.0;
+		} else if(lpan < 0.0) {		/* LEFTWARDS */
+			*llscale = llevel;
+			*lrscale = llevel * (1.0+lpan);
+		} else if(lpan <= 1.0) {	/* RIGHTWARDS */
+			*llscale = llevel * (1.0-lpan);
+			*lrscale = llevel;
+		} else {					/* VERY RIGHT */
+			*llscale = 0.0;
+			*lrscale = llevel/lpan;
+		}
+		/* RIGHT STEREO INPUT PANNED ... */
+		if(rpan < -1.0) {			/* VERY LEFT */
+			*rlscale = rlevel/(-rpan);
+			*rrscale = 0.0;
+		} else if(rpan < 0.0) {		/* LEFTWARDS */
+			*rlscale = rlevel;
+			*rrscale = rlevel * (1.0+rpan);
+		} else if(rpan <= 1.0) {	/* RIGHTWARDS */
+			*rlscale = rlevel * (1.0-rpan);
+			*rrscale = rlevel ;
+		} else {					/* VERY RIGHT */
+			*rlscale = 0.0;
+			*rrscale = rlevel/rpan;
+		}
+		break;
+	default:
+		sprintf(errstr,"Unknown case in assign_scaling()\n");
+		return(PROGRAM_ERROR);
+	}
+	return(FINISHED);
+}
+
+#endif
+
+
+
+/************************** CHECK_RIGHT_LEVEL ************************/
+
+int check_right_level(char *str,double *rlevel,int filecnt)
+{
+	if(is_dB(str)) {
+		if(!get_leveldb(str,rlevel)) {
+			sprintf(errstr,"Error1 scanning chan2 level: line %d\n",filecnt+1);
+			return(PROGRAM_ERROR);
+		}		
+	} else {
+		if(sscanf(str,"%lf",rlevel)!=1) {
+			sprintf(errstr,"Error2 scanning chan2 level: line %d\n",filecnt+1);
+			return(PROGRAM_ERROR);
+		}
+	}
+	if(*rlevel < 0.0) {
+		sprintf(errstr,"Error3 scanning chan2 level: line %d\n",filecnt+1);
+		return(PROGRAM_ERROR);
+	}
+	return(FINISHED);
+}
+
+/*********************** CHECK_RIGHT_PAN **********************/
+
+int check_right_pan(char *str,double *pan,int filecnt)
+{
+	switch(str[0]) {
+	case('L'): *pan = -1.0; break;
+	case('R'): *pan = 1.0; break;
+	case('C'): *pan = 0.5; break;
+	default:
+		if(sscanf(str,"%lf",pan)!=1) {
+			sprintf(errstr,"Error1 scanning chan2 pan: line %d\n",filecnt+1);
+			return(PROGRAM_ERROR);
+		}
+		if(*pan < MINPAN || *pan > MAXPAN)  {
+			sprintf(errstr,"Error2 scanning chan2 pan: line %d\n",filecnt+1);
+			return(PROGRAM_ERROR);
+		}
+		break;
+	}
+	return(FINISHED);
+}
+
+/************************** CHECK_LEFT_PAN ************************/
+
+int check_left_pan(char *str,double *pan,int filecnt)
+{
+	switch(str[0]) {
+	case('L'): *pan = -1.0; break;
+	case('R'): *pan = 1.0; break;
+	case('C'): *pan = 0.0; break;
+	default:
+		if(sscanf(str,"%lf",pan)!=1) {
+			sprintf(errstr,"Error1 scanning (chan1) pan: line %d\n",filecnt+1);
+			return(PROGRAM_ERROR);
+		}
+		if(*pan < MINPAN || *pan > MAXPAN)  {
+			sprintf(errstr,"Error2 scanning (chan1) pan: line %d\n",filecnt+1);
+			return(PROGRAM_ERROR);
+		}
+	}
+	return(FINISHED);
+}
+
+/*************** CHECK_LEFT_LEVEL ******************/
+
+int check_left_level(char *str,double *level,int filecnt)
+{
+	if(is_dB(str)) {
+		if(!get_leveldb(str,level)) {
+			sprintf(errstr,"Error1 scanning (chan1) level: line %d\n",filecnt+1);
+			return(PROGRAM_ERROR);
+		}		
+	} else {
+		if(sscanf(str,"%lf",level)!=1) {
+			sprintf(errstr,"Error2 scanning (chan1) level: line %d\n",filecnt+1);
+			return(PROGRAM_ERROR);
+		}
+	}
+	if(*level < 0.0) {
+		sprintf(errstr,"Error3 scanning (chan1) level: line %d\n",filecnt+1);
+		return(PROGRAM_ERROR);
+	}
+	return(FINISHED);
+}
+
+/************************** UNMARK_BUF ***************************/
+
+int unmark_buf(int **bufsflag,int *bufsflagcnt,int thisbuf,int longbitsize)
+{
+	int exit_status;
+	int mask = 1;	    
+	int z = thisbuf/longbitsize;
+/* 1998 --> */
+	if(z >= *bufsflagcnt) {
+		if((exit_status = reallocate_bufsflag(z,bufsflag,bufsflagcnt))<0)
+			return(exit_status);
+	}
+/* <-- 1998 */
+	thisbuf -= (z * longbitsize);
+	mask <<= thisbuf;
+	mask = ~mask;
+	(*bufsflag)[z] &= mask;
+	return(FINISHED);
+}
+
+/************************** MARK_BUF ***************************
+ *
+ * (1)	Which int is the appropriate byte in.
+ * (2)	What is it's index into this int.
+ * (3)	Move mask along the int.
+ * (4)	Set bit.
+ * (5)	Keep note of max number of bufs in use.
+ */
+
+int mark_buf(int **bufsflag,int *bufsflagcnt,int thisbuf,int longbitsize,dataptr dz)
+{
+	int exit_status;
+	int mask = 1;    
+	int z = thisbuf/longbitsize;	/* 1 */
+/* 1998 --> */
+	if(z >= *bufsflagcnt) {
+		if((exit_status = reallocate_bufsflag(z,bufsflag,bufsflagcnt))<0)
+			return(exit_status);
+	}
+/* <-- 1998 */
+	if(thisbuf > dz->bufcnt)
+		dz->bufcnt = thisbuf;
+	thisbuf -= (z * longbitsize);	/* 2 */
+	mask <<= thisbuf;				/* 3 */
+	(*bufsflag)[z] |= mask;			/* 4 */
+	return(FINISHED);
+}
+
+/**************************** REALLOCATE_BUFSFLAG ********************************/
+
+int reallocate_bufsflag(int z,int **bufsflag,int *bufsflagcnt)
+{
+	int n;
+	if(*bufsflagcnt==0) 
+	//	*bufsflag = (int *) malloc((z+1) * sizeof(int));
+	    *bufsflag = (int *) calloc((z+1),sizeof(int));  //RWD 2013 needs init values
+	else if((*bufsflag = (int *)realloc(*bufsflag,(z+1) * sizeof(int)))==NULL) {
+		sprintf(errstr,"INSUFFICIENT MEMORY for buffer flags store.\n");
+		return(MEMORY_ERROR);
+	}
+	for(n=*bufsflagcnt;n<z;n++) 
+		*bufsflag[n] = 0;		
+	*bufsflagcnt = z+1;
+	return(FINISHED);
+}
+
+/**************************** MIX_MODEL ********************************/
+
+int mix_model(dataptr dz)
+{
+	int n, m, k;
+	int total_words = 0,filestart;
+	char temp[200];
+	filestart = dz->itemcnt;
+	for(n=0,k=filestart;n<dz->linecnt;n++,k++) {
+		for(m = 0;m < dz->wordcnt[n];m++) {
+			if(m==0)
+				strcpy(temp,dz->wordstor[k]);
+			else {
+				strcat(temp," ");
+				strcat(temp,dz->wordstor[total_words]);
+			}
+			total_words++;
+		}
+		strcat(temp,"\n");
+		if(fputs(temp,dz->fp)<0) {
+			sprintf(errstr,"Failed to print new mixfile line %d to output file.\n",n+1);
+			return(SYSTEM_ERROR);
+		}
+	}
+	return FINISHED;
+}

+ 603 - 0
dev/submix/syncatt.c

@@ -0,0 +1,603 @@
+/*
+ * 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 <filetype.h>
+#include <arrays.h>
+#include <mix.h>
+#include <cdpmain.h>
+
+#include <sfsys.h>
+#ifdef unix
+#define round lround
+#endif
+
+static int  getenvpeak(int n,int samps_per_second,
+			int windows_per_sector,int sectors_per_window,int window_size,dataptr dz);
+static int  gettime_of_maxsamp(int k, /*int*/float *env,/*int*/float *envend,int *envpos,int *peak_sampno,int window_size);
+static int  create_envelope_arrays(int n,int numsects,int windows_per_sector,int sectors_per_window,
+			int **envpos,/*int*/float **env,dataptr dz);
+static int  count_sectors_to_scan(int *numsects,int lineno,int *skipsamps,int samps_per_second,dataptr dz);
+static int  get_envelope(int skipsamps,int **envpos,/*int*/float **env,int nbuff,int nsec, int window_size,dataptr dz);
+static void readenv_in_buffer(float *buf,int samps_to_process,int window_size,int **envpos,/*int*/float **env,int powflag);
+static void getmaxsamp_in_window(float *buf,int startsamp,int sample_cnt,int *envpos, /*int*/float *env,int powflag);
+static int  rescale_the_lines(double atten,dataptr dz);
+static int  attenuate_line(int total_words,double atten,int wordcnt,dataptr dz);
+static int  output_a_new_syncatt_file(double *timestor,double gain,dataptr dz);
+static int  output_a_syncatt_file(double *timestor,double gain,dataptr dz);
+static int  sum_maximum_samples(int n,double *total_maxval,dataptr dz);
+static int  get_filesearch_data(dataptr dz);
+static int  check_syncatt_window_factor(dataptr dz);
+
+/******************************** SYNCHRONISE_MIX_ATTACK ******************************/
+/* RWD crude hack to avoid SECSIZE abusage! */
+/* NB dz->lparray relaced with dz->lfarray for MSY_ENVEL amp stuff*/
+
+//TW WINSECSIZE replaced by global F_SECSIZE
+int synchronise_mix_attack(dataptr dz)
+{
+	int    exit_status;
+	double total_maxval = 0.0, attenuation = 1.0, *timestor;
+	int   sectors_per_window, n,  max_atk_time = 0, sampblok, window_size;
+	int    windows_per_sector, typefactor, inchans;
+	int   total_words = 0, srate =0, samps_per_second;	
+	int    textfile_filetype = dz->infile->filetype;
+	for(n=0;n<dz->linecnt;n++) {
+		windows_per_sector = 0;
+		if((exit_status = open_file_retrieve_props_open(n,dz->wordstor[total_words],&srate,dz))<0)
+			return(exit_status);
+		inchans = dz->iparray[MSY_CHANS][n];
+		samps_per_second = srate * inchans;
+		typefactor       = dz->iparam[MSY_SRFAC] * inchans;
+		sampblok         = (F_SECSIZE  * typefactor)/dz->iparam[MSY_WFAC];
+		
+		if((sectors_per_window = sampblok/F_SECSIZE)<=0)
+			windows_per_sector = F_SECSIZE/sampblok;
+		window_size = sampblok;
+
+		if((exit_status = getenvpeak(n,samps_per_second,windows_per_sector,sectors_per_window,window_size,dz))<0)
+			return(exit_status);
+		if((exit_status = sum_maximum_samples(n,&total_maxval,dz))<0)	/* read maxsample and add to running sum */
+			return(exit_status);
+		dz->lparray[MSY_PEAKSAMP][n] /= inchans;	 					/* convert to 'stereo'-sample count: TRUNCATES */
+		max_atk_time = max(max_atk_time,dz->lparray[MSY_PEAKSAMP][n]);	/* find attack time which is latest */
+		total_words += dz->wordcnt[n];
+		if(sndcloseEx(dz->ifd[0])<0) {
+			sprintf(errstr, "Failed to close input file %s: line %d: synchronise_mix_attack()\n",
+			dz->wordstor[total_words],n+1);
+			return(SYSTEM_ERROR);
+		}
+		dz->ifd[0] = -1;
+	}
+	if(total_maxval > (double)F_MAXSAMP)									/* calculate required attenuation */
+		attenuation = (double)F_MAXSAMP/total_maxval;
+
+	if((dz->parray[MSY_TIMESTOR] = (double *)malloc(dz->linecnt * sizeof(double)))==NULL) {
+		sprintf(errstr,"INSUFFICIENT MEMORY to store times.\n");
+		return(MEMORY_ERROR);
+	}
+	timestor = dz->parray[MSY_TIMESTOR];
+	for(n=0;n<dz->linecnt;n++)											/* calculate sndfile offsets */
+		timestor[n] = (double)(max_atk_time - dz->lparray[MSY_PEAKSAMP][n])/(double)srate;
+
+	dz->infile->filetype = textfile_filetype;
+	switch(dz->infile->filetype) {
+	case(SNDLIST):
+	case(SYNCLIST):
+		return output_a_new_syncatt_file(timestor,attenuation,dz);
+	case(MIXFILE):
+		return output_a_syncatt_file(timestor,attenuation,dz);
+	default:
+		sprintf(errstr,"Unknown case in synchronise_mix_attack()\n");
+		return(PROGRAM_ERROR);
+	}
+	return(FINISHED);	/* NOTREACHED */
+}
+
+/* RWD NB window_size is in samps */
+/* dz->lparray etc now floats */
+/******************************** GETENVPEAK ******************************/
+
+int getenvpeak(int lineno,int samps_per_second,int windows_per_sector,int sectors_per_window,int window_size,dataptr dz)
+{   
+	int exit_status;
+	int peak_sampno;
+	int skipsamps, numsects, searchsize, nbuff, nsec;
+	int  *envpos;
+	/*int*/float *env, *envend;
+	if((exit_status = count_sectors_to_scan(&numsects,lineno,&skipsamps,samps_per_second,dz))<0)
+		return(exit_status);
+	if((exit_status = create_envelope_arrays(lineno,numsects,windows_per_sector,sectors_per_window,&envpos,&env,dz))<0)
+		return(exit_status);
+	searchsize = numsects * F_SECSIZE;
+    nbuff      = searchsize/dz->buflen;	  			/* no. of whole buffs to srch   */
+    nsec       = (searchsize % dz->buflen)/F_SECSIZE;	/* no. of further secs to srch  */
+	if((exit_status = get_envelope(skipsamps,&envpos,&env,nbuff,nsec,window_size,dz))<0)
+		return(exit_status);
+    envend   = env;
+    env      = dz->lfarray[MSY_ENVEL];
+	envpos   = dz->iparray[MSY_ENVPOS];
+	if((exit_status = gettime_of_maxsamp(lineno,env,envend,envpos,&peak_sampno,window_size))<0)
+		return(exit_status);
+	dz->lparray[MSY_PEAKSAMP][lineno] = peak_sampno + skipsamps;
+	return(FINISHED);
+}
+
+/***************************** GETTIME_OF_MAXSAMP ***********************************/
+
+int gettime_of_maxsamp(int lineno, /*int*/float *env,/*int*/float *envend,int *envpos,int *peak_sampno,int window_size)
+{
+	float peak = 0.0f, *thismax = env, *loudest_place = NULL;
+	
+	int  blokno;
+	while(thismax < envend) {
+		if(*thismax > peak) {
+			peak = *thismax;
+			loudest_place = thismax;
+		}
+		thismax++;
+	}
+	if(loudest_place==NULL) {
+		fprintf(stdout,"WARNING: No peak found in file %d: Syncing to file start.\n",lineno+1);
+		fflush(stdout);
+		*peak_sampno = 0;
+		return(FINISHED);
+	}
+	blokno       = loudest_place - env;           								/* to nearest shrtblok */
+	*peak_sampno = (blokno * window_size) + envpos[blokno]; 					/* to nearest sample   */
+	return(FINISHED);
+}
+
+/********************** CREATE_ENVELOPE_ARRAYS ***********************/
+
+int create_envelope_arrays
+(int lineno,int numsects,int windows_per_sector,int sectors_per_window,int **envpos,/*int*/float **env,dataptr dz)
+{
+	int arraysize;
+	if(windows_per_sector > 0) {
+		arraysize = numsects * windows_per_sector;
+		arraysize += windows_per_sector;  /* Allow for a short buf at end */
+	} else {
+		arraysize = numsects/sectors_per_window;
+		arraysize++;		           /* round up + allow ditto */
+	}
+	if(lineno==0) {
+		if((dz->iparray[MSY_ENVPOS] = (int *)malloc(arraysize * sizeof(int)))==NULL) {
+			sprintf(errstr,"INSUFFICIENT MEMORY to store envelope positions.\n");
+			return(MEMORY_ERROR);
+		}
+		if((dz->lfarray[MSY_ENVEL] = (/*int*/float *)malloc(arraysize * sizeof(/*int*/float)))==NULL) {
+			sprintf(errstr,"INSUFFICIENT MEMORY to store envelope.\n");
+			return(MEMORY_ERROR);
+		}
+	} else {
+		free(dz->iparray[MSY_ENVPOS]);
+		free(dz->lparray[MSY_ENVEL]);
+		dz->iparray[MSY_ENVPOS] = NULL;
+		dz->lparray[MSY_ENVEL]  = NULL;
+		if((dz->iparray[MSY_ENVPOS] = (int *)realloc(dz->iparray[MSY_ENVPOS],arraysize * sizeof(int)))==NULL) {
+			sprintf(errstr,"INSUFFICIENT MEMORY to reallocate envelope positions.\n");
+			return(MEMORY_ERROR);
+		}
+		if((dz->lfarray[MSY_ENVEL] = (/*int*/float *)realloc(dz->lfarray[MSY_ENVEL],arraysize * sizeof(/*int*/float)))==NULL) {
+			sprintf(errstr,"INSUFFICIENT MEMORY to reallocate envelope.\n");
+			return(MEMORY_ERROR);
+		}
+	}
+	*envpos = dz->iparray[MSY_ENVPOS];
+	*env    = dz->lfarray[MSY_ENVEL];
+	return(FINISHED);
+}
+
+/****************************** COUNT_SECTORS_TO_SCAN *******************************/
+
+int count_sectors_to_scan(int *numsects,int lineno,int *skipsamps,int samps_per_second,dataptr dz)
+{
+	int endsamps, endsecs, skipsecs;
+	double *start = dz->parray[MSY_STARTSRCH];
+	double *end   = dz->parray[MSY_ENDSRCH];
+	int shsecsize = F_SECSIZE;
+	skipsecs   = 0;
+	/* RWD what is this doing? */
+	*skipsamps = round(start[lineno] * (double)samps_per_second);
+//TW SAFETY for the moment: matches up with secsize rounding  below
+// and secsize rounding in envelope-windowing and search
+	skipsecs   = *skipsamps/shsecsize;		/* TRUNCATE */
+	*skipsamps = skipsecs * shsecsize;   
+
+	if(end[lineno] < 0.0)						/* -1.0 flags ENDOFSNDFILE */
+		endsamps = dz->lparray[MSY_SAMPSIZE][lineno];
+	else
+		endsamps = round(end[lineno] * samps_per_second);
+	endsecs  = endsamps/shsecsize;
+	if(endsecs * shsecsize < endsamps)		/* CEILING */
+		endsecs++;
+	*numsects = max((int)1,endsecs - skipsecs);
+	return(FINISHED);
+}
+
+/************************** GET_ENVELOPE ***************************/
+
+int get_envelope(int skipsamps,int **envpos,/*int*/float **env,int nbuff,int nsec, int window_size,dataptr dz)
+{
+	int  exit_status;
+	int n, shrtstoget;
+	int shsecsize = F_SECSIZE;
+	float *buf = dz->sampbuf[0];
+	int powflag = dz->vflag[MSY_POWMETHOD];
+	if(sndseekEx(dz->ifd[0],skipsamps,0)<0) {
+		sprintf(errstr,"seek() failed in get_envelope()\n");
+		return(SYSTEM_ERROR);
+	}
+	if(nbuff > 0) {
+		for(n = 0; n < nbuff-1; n++)	{			/* 1ST PASS : WHOLE BUFFERS */
+			if((exit_status = read_samps(dz->bigbuf,dz))<0)
+				return(exit_status);
+			if(dz->ssampsread < dz->buflen) {
+				sprintf(errstr,"Error in buffer accounting: get_envelope()\n");
+				return(PROGRAM_ERROR);
+			}
+			readenv_in_buffer(buf,dz->buflen,window_size,envpos,env,powflag);
+		}
+												/* 2ND PASS : LAST WHOLE BUFFERS */
+		if((exit_status = read_samps(dz->bigbuf,dz))<0)
+			return(exit_status);
+		if(nsec > 0 && dz->ssampsread < dz->buflen) {
+			sprintf(errstr,"Error in buffer accounting: get_envelope()\n");
+			return(PROGRAM_ERROR);
+		}
+		readenv_in_buffer(buf,min(dz->ssampsread,dz->buflen),window_size,envpos,env,powflag);
+	}
+
+	if(nsec) {									/* 3RD PASS : REMAINING SECTORS */
+		shrtstoget = nsec * shsecsize;
+		if((exit_status = read_samps(dz->bigbuf,dz))<0)
+			return(exit_status);
+		readenv_in_buffer(buf,min(shrtstoget,dz->ssampsread),window_size,envpos,env,powflag);
+	}
+	return(FINISHED);
+}
+
+/************************* READENV_IN_BUFFER ******************************/
+
+void readenv_in_buffer(float *buf,int samps_to_process,int window_size,int **envpos,/*int*/float **env,int powflag)
+{
+	int  startsamp = 0;
+	int  *epos;
+	float *ev;
+	epos  = *envpos;
+	ev    = *env;
+	while(samps_to_process >= window_size) {
+		getmaxsamp_in_window(buf,startsamp,window_size,epos,ev,powflag);
+		epos++;
+		ev++;
+		startsamp 		 += window_size;
+		samps_to_process -= window_size;
+	}
+	if(samps_to_process) {	/* Handle any final short buffer */
+		getmaxsamp_in_window(buf,startsamp,samps_to_process,epos,ev,powflag);
+		epos++;
+		ev++;
+	}
+	*envpos = epos;
+	*env    = ev;
+}
+
+/*************************** GETMAXSAMP_IN_WINDOW ********************************/
+
+void getmaxsamp_in_window(float *buf,int startsamp,int sample_cnt,int *envpos, /*int*/float *env,int powflag)
+{
+	int   i, endsamp = startsamp + sample_cnt, maxpos = startsamp;
+	double rms_power = 0.0;
+	double maxval = 0, val;
+	
+
+	switch(powflag) {			
+	case(TRUE):
+		for(i = startsamp; i<endsamp; i++) {
+			val = fabs(buf[i]);
+			rms_power += (double)(val * val);
+			if(val > maxval) {
+				maxval = val;
+				maxpos = i;
+			}
+		}
+		rms_power /= (double)sample_cnt;
+		rms_power  = sqrt(rms_power);
+		*env       = (float) rms_power;
+		break;
+	case(FALSE):
+		for(i = startsamp; i<endsamp; i++) {
+			val = fabs(buf[i]);
+			if(val > maxval) {
+				maxval = val;
+				maxpos = i;
+			}
+		}
+		*env = (float)maxval;
+		break;
+	}
+	*envpos = (int)(maxpos - startsamp);
+}
+
+/*************************** RESCALE_THE_LINES ***************************/
+
+int rescale_the_lines(double atten,dataptr dz)
+{
+	int exit_status;
+	int lineno;
+	int total_words = 0;
+	for(lineno=0;lineno<dz->linecnt;lineno++) {
+		if((exit_status = attenuate_line(total_words,atten,dz->wordcnt[lineno],dz))<0)
+			return(exit_status);
+		total_words += dz->wordcnt[lineno];
+	}
+	return(FINISHED);
+}
+
+/************************** ATTENUATE_LINE ***************************/
+
+int attenuate_line(int total_words,double atten,int wordcnt,dataptr dz)
+{
+	int    exit_status;
+	int   wordno, newlen;
+	double level;
+	wordno = total_words + MIX_LEVELPOS;
+	if((exit_status = get_level(dz->wordstor[wordno],&level))<0)
+		return(exit_status);
+	sprintf(errstr,"%.5lf",level * atten);
+	if((newlen = (int)strlen(errstr)) > (int)strlen(dz->wordstor[wordno])) {
+		if((dz->wordstor[wordno] = (char *)realloc(dz->wordstor[wordno],(newlen+1) * sizeof(char)))==NULL) {
+			sprintf(errstr,"INSUFFICIENT MEMORY for wordstore %d\n",wordno+1);
+			return(MEMORY_ERROR);
+		}
+	}
+	strcpy(dz->wordstor[wordno],errstr);
+	if(wordcnt <= MIX_MIDLINE)
+		return(FINISHED);
+
+	wordno = total_words + MIX_RLEVELPOS;
+	if((exit_status = get_level(dz->wordstor[wordno],&level))<0)
+		return(exit_status);
+	sprintf(errstr,"%.5lf",level * atten);
+	if((newlen = (int)strlen(errstr)) > (int)strlen(dz->wordstor[wordno])) {
+		if((dz->wordstor[wordno] = (char *)realloc(dz->wordstor[wordno],(newlen+1) * sizeof(char)))==NULL) {
+			sprintf(errstr,"INSUFFICIENT MEMORY for wordstore %d\n",wordno+1);
+			return(MEMORY_ERROR);
+		}
+	}
+	strcpy(dz->wordstor[wordno],errstr);
+	return(FINISHED);
+}
+
+/************************** OUTPUT_A_NEW_SYNCATT_FILE ***************************/
+
+int output_a_new_syncatt_file(double *timestor,double gain,dataptr dz)
+{
+	int  exit_status;
+	int  max_timeword = 0;
+	int  max_namelen  = 0;
+	int total_words  = 0, n;
+	for(n=0;n<dz->linecnt;n++) {
+		max_namelen = max(max_namelen,(int)strlen(dz->wordstor[total_words]));
+		sprintf(errstr,"%.5lf",timestor[n]);
+		max_timeword = max(max_timeword,(int)strlen(errstr));
+		total_words += dz->wordcnt[n];
+	}							
+	total_words = 0;
+	for(n=0;n<dz->linecnt;n++) {						
+		if((exit_status = sync_and_output_mixfile_line
+		(n,dz->wordstor[total_words],max_namelen,max_timeword,timestor[n],gain,dz))<0)
+			return(exit_status);
+		total_words += dz->wordcnt[n];
+	}
+	return(FINISHED);
+}
+
+/************************** OUTPUT_A_SYNCATT_FILE ***************************/
+
+int output_a_syncatt_file(double *timestor,double gain,dataptr dz)
+{
+	int exit_status;
+	int *maxwordsize;
+	int postdec = DEFAULT_DECIMAL_REPRESENTATION;
+	if((exit_status = retime_the_lines(timestor,postdec,dz))<0)
+		return(exit_status);
+	if(gain < 1.0) {
+		if((exit_status = rescale_the_lines(gain,dz))<0)
+			return(exit_status);
+	}
+	if((exit_status = timesort_mixfile(timestor,dz))<0)
+		return(exit_status);
+	if((exit_status = get_maxwordsize(&maxwordsize,dz))<0)
+		return(exit_status);
+	if((exit_status = output_mixfile_lines(maxwordsize,dz))<0)
+		return(exit_status);
+	free(maxwordsize);
+	return(FINISHED);
+}
+
+/************************** SUM_MAXIMUM_SAMPLES ***************************/
+/* RWD: IS THIS ROUNDING FOR SFSEEK, OR ROUNDING FOR WINDOW SECTORS????? */
+
+int sum_maximum_samples(int n,double *total_maxval,dataptr dz)
+{
+	int   exit_status;
+	float *buf = dz->sampbuf[0];
+	int  shsecsize = F_SECSIZE;
+	int  peak_sampno = dz->lparray[MSY_PEAKSAMP][n];
+	int  sectorstart_of_maxsamp, sampstep;
+
+	sectorstart_of_maxsamp = (peak_sampno/shsecsize) * shsecsize;	 /* TRUNCATE */
+	sampstep  = peak_sampno - sectorstart_of_maxsamp;
+	if(sndseekEx(dz->ifd[0],sectorstart_of_maxsamp,0)<0) {
+		sprintf(errstr,"soundfile seek failed in sum_maximum_samples()\n");
+		return(SYSTEM_ERROR);
+	}
+	if((exit_status = read_samps(buf,dz))<0)
+		return(exit_status);
+	if(sampstep >= dz->ssampsread) {
+		sprintf(errstr,"Buffer accounting anomaly: sum_maximum_samples()\n");
+		return(PROGRAM_ERROR);
+	}
+	*total_maxval +=  fabs(buf[sampstep]);
+	return(FINISHED);
+}
+
+/************************* GET_FILESEARCH_DATA ************************/
+
+int get_filesearch_data(dataptr dz)
+{   
+	int    exit_status;
+	int   srate = 0, total_words, n;
+	int    *inchans;
+	int   shsecsize = F_SECSIZE, *samplen;
+	double filedur;
+	double minsyncscan;
+	double *start, *end;
+	int    textfile_filetype = dz->infile->filetype;
+
+	if(dz->linecnt > SF_MAXFILES) {
+		sprintf(errstr,"Maximum number of sndfiles [%d] exceeded.\n",SF_MAXFILES);
+		return(USER_ERROR);
+	} else if(dz->linecnt <= 0) {
+		sprintf(errstr,"No data in sync file.\n");
+		return(USER_ERROR);
+	}
+	if((dz->parray[MSY_STARTSRCH] = (double *)malloc(dz->linecnt * sizeof(double)))==NULL) {
+		sprintf(errstr,"INSUFFICIENT MEMORY to store startsearch array.\n");
+		return(MEMORY_ERROR);
+	}
+	start = dz->parray[MSY_STARTSRCH];
+	if((dz->parray[MSY_ENDSRCH] = (double *)malloc(dz->linecnt * sizeof(double)))==NULL) {
+		sprintf(errstr,"INSUFFICIENT MEMORY to store endsearch array.\n");
+		return(MEMORY_ERROR);
+	}
+	end = dz->parray[MSY_ENDSRCH];
+	if((dz->lparray[MSY_SAMPSIZE] = (int *)malloc(dz->linecnt * sizeof(int)))==NULL) {
+		sprintf(errstr,"gINSUFFICIENT MEMORY to store sizes in samples.\n");
+		return(MEMORY_ERROR);
+	}
+	samplen = dz->lparray[MSY_SAMPSIZE];
+	if((dz->iparray[MSY_CHANS] = (int *)malloc(dz->linecnt * sizeof(int)))==NULL) {
+		sprintf(errstr,"INSUFFICIENT MEMORY to store channel info.\n");
+		return(MEMORY_ERROR);
+	}
+	inchans = dz->iparray[MSY_CHANS];
+	if((dz->lparray[MSY_PEAKSAMP] = (int *)malloc(dz->linecnt * sizeof(int)))==NULL) {
+		sprintf(errstr,"INSUFFICIENT MEMORY to store peak information.\n");
+		return(MEMORY_ERROR);
+	}
+	if((exit_status = establish_file_data_storage_for_mix((int)1,dz))<0)
+		return(exit_status);
+	total_words = 0;
+	for(n=0;n<dz->linecnt;n++) {
+		if((exit_status = open_file_and_retrieve_props(n,dz->wordstor[total_words],&srate,dz))<0)
+			return(exit_status);
+		samplen[n]	= dz->insams[0];
+		inchans[n]	= dz->infile->channels;
+//REVISION TW July, 2004
+//		filedur = (double)(samplen[n]/inchans[n])/(double)srate;
+		total_words += dz->wordcnt[n];
+	}
+
+	if(srate > SAMPLE_RATE_DIVIDE)  dz->iparam[MSY_SRFAC]=2;
+	else							dz->iparam[MSY_SRFAC]=1;
+
+	minsyncscan = (double)((shsecsize * dz->iparam[MSY_SRFAC])/MAX_WINFAC)/(double)srate;
+
+	total_words = 0;
+	for(n=0;n<dz->linecnt;n++) {
+		switch(dz->wordcnt[n]) {
+		case(3):
+			if(dz->infile->filetype==MIXFILE) {
+				sprintf(errstr,"Anomalous line length [%d] in mixfile\n",dz->wordcnt[n]);
+				return(PROGRAM_ERROR);
+			}
+			if(sscanf(dz->wordstor[total_words+1],"%lf",&(start[n]))!=1) {
+				sprintf(errstr,"Failed to read starttime: line %d: get_filesearch_data()\n",n+1);
+				return(PROGRAM_ERROR);
+			}
+			if(sscanf(dz->wordstor[total_words+2],"%lf",&(end[n]))!=1) {
+				sprintf(errstr,"Failed to read endtime: line %d: get_filesearch_data()\n",n+1);
+				return(PROGRAM_ERROR);
+			}
+			if((start[n] < 0.0) || (end[n] < 0.0) || (start[n] + minsyncscan >= end[n])) {
+				sprintf(errstr,"Impossible or incompatible searchtimes [%.5lf to %.5lf]: line %d.\n",
+				start[n],end[n],n+1);
+				return(USER_ERROR);
+			}
+//REVISION TW July, 2004
+			filedur = (double)(samplen[n]/inchans[n])/(double)srate;
+			if(start[n] >= filedur - minsyncscan) {
+				sprintf(errstr,"starttime on line %d is beyond effective file end.\n",n+1);
+				return(DATA_ERROR);
+			}
+			if(end[n] >= filedur)
+				end[n] = -1.0;	/* flags END_OF_SNDFILE */
+			break;
+		default:
+			start[n] = 0.0;
+			end[n]   = -1.0;	/* flags END_OF_SNDFILE */
+			break;
+		}
+		total_words += dz->wordcnt[n];
+	}
+	dz->infile->filetype = textfile_filetype;
+	return(FINISHED);
+}
+
+/***************************** SYNCATT_PRESETS **************************/
+
+int syncatt_presets(dataptr dz)
+{
+	int exit_status;
+	if(!check_syncatt_window_factor(dz))
+		return(USER_ERROR);
+	if((exit_status= get_filesearch_data(dz))<0)
+		return(exit_status);
+	return(FINISHED);
+}
+
+/***************************** CHECK_SYNCATT_WINDOW_FACTOR **************************/
+
+int check_syncatt_window_factor(dataptr dz)
+{
+	int valid_value = MIN_WINFAC;
+	while(valid_value <= MAX_WINFAC) {
+		if(dz->iparam[MSY_WFAC]==valid_value)
+			return(TRUE);
+		valid_value *= 2;
+	}
+	return(FALSE);
+}

+ 20 - 0
dev/synth/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(synth main.c ap_synthesis.c mxfft.c pvoc_addon.c wave.c)
+
+target_link_libraries(synth cdp2k sfsys ${EXTRA_LIBRARIES})
+
+my_install(synth)
+

+ 1260 - 0
dev/synth/ap_synthesis.c

@@ -0,0 +1,1260 @@
+/*
+ * 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/TW 24/02/18: removed usage ref to "Outputs..." names */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <structures.h>
+#include <cdpmain.h>
+#include <tkglobals.h>
+#include <pnames.h>
+#include <synth.h>
+#include <processno.h>
+#include <modeno.h>
+#include <globcon.h>
+#include <logic.h>
+#include <filetype.h>
+#include <mixxcon.h>
+#include <speccon.h>
+#include <flags.h>
+#include <arrays.h>
+#include <formants.h>
+#include <sfsys.h>
+#include <osbind.h>
+#include <string.h>
+#include <math.h>
+#include <srates.h>
+//TW UPDATES
+#include <ctype.h>
+#include <special.h>
+
+#ifndef HUGE
+#define HUGE 3.40282347e+38F
+#endif
+
+/********************************************************************************************/
+/********************************** FORMERLY IN pconsistency.c ******************************/
+/********************************************************************************************/
+
+static int  synth_consistency(dataptr dz);
+static void init_specsynth(dataptr dz);
+static int specsynth_consistency(dataptr dz);
+//TW UPDATE: new functions
+static int read_clicktrack_data(char *,dataptr dz);
+static int gettempo(char *str,double *tempo,double *pulse_unit,double *accel,int linecnt,int *GP,int *is_abstime);
+static int getmeter(char *str,int *metre_num,int *metre_denom,int linecnt,int GP,int is_abstime,double *abstime,int *accent);
+static int getstyle(char *str,char *style,int metre_num,int linecnt,int GP,int is_abstime);
+static int getcount(char *str,int *barcnt,int linecnt,int GP,int is_abstime,double *timeincr);
+static int generate_clickdata(int init,int *arraysize,double tempo,double pulse_unit,int metre_num,int metre_denom,
+							  char *style,int barcnt,double accel,double *time,double *lasttime,
+							  int GP,int is_abstime,double abstime,int accent,double timeincr,int *tcnt,int *tarray,
+							  double *mintimestep,dataptr dz);
+static int default_style(char *style,int metre_num);
+static int generate_clicktable(dataptr dz);
+static int click_consistency(dataptr dz);
+static int getlineno(char *str,int tcnt,int linecnt);
+static int read_chord_data(char *str,dataptr dz);
+
+/***************************************************************************************/
+/****************************** FORMERLY IN aplinit.c **********************************/
+/***************************************************************************************/
+
+/***************************** ESTABLISH_BUFPTRS_AND_EXTRA_BUFFERS **************************/
+
+int establish_bufptrs_and_extra_buffers(dataptr dz)
+{
+	int exit_status;
+	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(SYNTH_SPEC):
+		is_spec = TRUE;			
+		dz->extra_bufcnt = 0;	dz->bptrcnt = 5;
+		break;
+	case(SYNTH_WAVE):		
+	case(MULTI_SYN):		
+	case(SYNTH_NOISE):	
+	case(SYNTH_SIL):			
+//TW UPDATE
+	case(CLICK):			
+		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);
+	}
+	if(is_spec)
+		return establish_spec_bufptrs_and_extra_buffers(dz);
+	else if((dz->process==HOUSE_SPEC && dz->mode==HOUSE_CONVERT) || dz->process==INFO_DIFF) {
+		if((exit_status = establish_spec_bufptrs_and_extra_buffers(dz))<0)
+			return(exit_status);
+	}
+	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) {
+//TW UPDATE
+	case(CLICK):		   dz->array_cnt=3; dz->iarray_cnt=0; dz->larray_cnt=0; dz->ptr_cnt= 0; dz->fptr_cnt = 0; break;
+	case(SYNTH_WAVE):
+	case(SYNTH_NOISE):	   dz->array_cnt=1; dz->iarray_cnt=0; dz->larray_cnt=0; dz->ptr_cnt= 0; dz->fptr_cnt = 0; break;
+	case(MULTI_SYN):	   dz->array_cnt=4; dz->iarray_cnt=0; dz->larray_cnt=1; dz->ptr_cnt= 0; dz->fptr_cnt = 0; break;	
+	case(SYNTH_SPEC):
+	case(SYNTH_SIL):	   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) {
+//TW UPDATE
+	case(CLICK):		   		setup_process_logic(NO_FILE_AT_ALL,	UNEQUAL_SNDFILE,	SNDFILE_OUT,	dz);	break;
+	case(MULTI_SYN):		
+	case(SYNTH_WAVE):	   		setup_process_logic(NO_FILE_AT_ALL,	UNEQUAL_SNDFILE,	SNDFILE_OUT,	dz);	break;
+	case(SYNTH_NOISE):	   		setup_process_logic(NO_FILE_AT_ALL,	UNEQUAL_SNDFILE,	SNDFILE_OUT,	dz);	break;
+	case(SYNTH_SIL):	   		setup_process_logic(NO_FILE_AT_ALL,	UNEQUAL_SNDFILE,	SNDFILE_OUT,	dz);	break;
+	case(SYNTH_SPEC):	   		setup_process_logic(NO_FILE_AT_ALL,	BIG_ANALFILE,		NO_OUTPUTFILE,	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) {
+//TW UPDATE
+	case(CLICK):			exit_status = set_internalparam_data("i",ap); 		break;
+	case(SYNTH_SPEC):
+	case(MULTI_SYN):		
+	case(SYNTH_WAVE):		exit_status = set_internalparam_data("",ap); 		break;
+	case(SYNTH_NOISE):		exit_status = set_internalparam_data("0",ap); 		break;
+	case(SYNTH_SIL):		exit_status = set_internalparam_data("00",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) {
+//TW UPDATE
+	case(CLICKTRACK):
+		dz->infile->srate = CLICK_SRATE;
+		return read_clicktrack_data(str,dz);
+	case(CHORD_SYN):
+		dz->infile->srate = CLICK_SRATE;
+		return read_chord_data(str,dz);
+	default:
+		sprintf(errstr,"Unknown special_data type: read_special_data()\n");
+		return(PROGRAM_ERROR);
+	}
+	return(FINISHED);	/* NOTREACHED */
+}
+
+/********************************************************************************************/
+/********************************** FORMERLY IN preprocess.c ********************************/
+/********************************************************************************************/
+
+/****************************** PARAM_PREPROCESS *********************************/
+
+int param_preprocess(dataptr dz)	
+{
+	int exit_status = FINISHED, n;
+//TW UPDATE
+	double x, convertor;
+
+	switch(dz->process) {
+//TW UPDATE
+	case(CLICK):
+		if((exit_status = generate_clicktable(dz))<0)
+			return(exit_status);
+		break;
+	case(SYNTH_WAVE):		
+	case(SYNTH_NOISE):		
+	case(SYNTH_SIL):
+		break;		
+	case(MULTI_SYN):
+		convertor = (double)dz->iparam[SYN_TABSIZE] / (double)dz->iparam[SYN_SRATE];
+		for(n = 0;n<dz->itemcnt;n++)
+			dz->parray[1][n] *= convertor;
+		break;
+	case(SYNTH_SPEC):
+		x = (dz->param[SS_FOCUS] * 4.0) - 2.0;
+		dz->param[SS_FOCUS] = pow(10,x);
+		x = (dz->param[SS_FOCUS2] * 4.0) - 2.0;
+		dz->param[SS_FOCUS2] = pow(10,x);
+		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) {
+//TW UPDATE
+	case(CLICK):		
+	case(SYNTH_WAVE):		
+	case(MULTI_SYN):		
+	case(SYNTH_NOISE):		
+	case(SYNTH_SIL):	
+		return do_synth(dz);
+	case(SYNTH_SPEC):
+		return do_stereo_specsynth(dz);
+	default:
+		sprintf(errstr,"Unknown case in process_file()\n");
+		return(PROGRAM_ERROR);
+	}
+	return(FINISHED);	/* NOTREACHED */
+}
+
+/********************************************************************************************/
+/********************************** FORMERLY IN pconsistency.c ******************************/
+/********************************************************************************************/
+
+/****************************** CHECK_PARAM_VALIDITY_AND_CONSISTENCY *********************************/
+
+int check_param_validity_and_consistency(dataptr dz)
+{
+	int exit_status;
+	handle_pitch_zeros(dz);
+	switch(dz->process) {
+	case(SYNTH_WAVE):	
+	case(MULTI_SYN):		
+	case(SYNTH_NOISE):	
+	case(SYNTH_SIL):	
+		if((exit_status = synth_consistency(dz))<0)
+			return exit_status;
+		dz->infile->channels = dz->iparam[SYN_CHANS];
+		dz->infile->srate    = dz->iparam[SYN_SRATE];
+		dz->infile->stype = SAMP_SHORT;
+		return create_sized_outfile(dz->wordstor[0],dz);
+	case(SYNTH_SPEC):	
+		init_specsynth(dz);
+//TW UPDATE
+		return specsynth_consistency(dz);
+	case(CLICK):	
+//TW UPDATE
+		if((exit_status = click_consistency(dz))<0)
+			return exit_status;
+		dz->infile->channels = 1;
+		dz->infile->srate    = 44100;
+		dz->infile->stype = SAMP_SHORT;
+		return create_sized_outfile(dz->wordstor[0],dz);
+	}
+	return(FINISHED);
+}
+
+/****************************** SYNTH_CONSISTENCY *********************************/
+
+int synth_consistency(dataptr dz)
+{
+	if(BAD_SR(dz->iparam[SYN_SRATE])) {
+		sprintf(errstr,"Invalid sample rate.\n");
+		return(DATA_ERROR);
+	}
+	dz->iparam[SYN_TABSIZE] /= 4;
+	dz->iparam[SYN_TABSIZE] *= 4;
+	
+	return(FINISHED);
+}
+
+
+/****************************** SPECSYNTH_CONSISTENCY *********************************/
+
+int specsynth_consistency(dataptr dz)
+{
+	if(dz->vflag[SS_PICHSPRD]) {
+		if(dz->param[SS_SPREAD] > dz->nyquist/SPEC_MINFRQ) {
+			sprintf(errstr,"SPREAD value is too large for pitch transposition (rather than frq) data.\n");
+			return(DATA_ERROR);
+		}
+	}
+	return(FINISHED);
+}
+
+/********************************************************************************************/
+/********************************** FORMERLY IN buffers.c ***********************************/
+/********************************************************************************************/
+
+/**************************** ALLOCATE_LARGE_BUFFERS ******************************/
+
+int allocate_large_buffers(dataptr dz)
+{
+	int exit_status, tempchans;
+	switch(dz->process) {
+//TW UPDATE
+	case(SYNTH_WAVE):		case(SYNTH_NOISE):	case(SYNTH_SIL):	case(CLICK):	case(MULTI_SYN):
+		tempchans = dz->infile->channels;
+		if(dz->process == CLICK)
+			dz->infile->channels = 1;
+		else
+			dz->infile->channels = dz->iparam[SYN_CHANS];
+		if((exit_status = create_sndbufs(dz))<0)
+			return exit_status;
+		dz->infile->channels = tempchans;
+		return FINISHED;
+	case(SYNTH_SPEC):
+		return allocate_triple_buffer(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,"wave"))		dz->process = SYNTH_WAVE;
+	else if(!strcmp(prog_identifier_from_cmdline,"noise"))		dz->process = SYNTH_NOISE;
+	else if(!strcmp(prog_identifier_from_cmdline,"silence"))	dz->process = SYNTH_SIL;
+	else if(!strcmp(prog_identifier_from_cmdline,"spectra"))	dz->process = SYNTH_SPEC;
+	else if(!strcmp(prog_identifier_from_cmdline,"clicks"))		dz->process = CLICK;
+	else if(!strcmp(prog_identifier_from_cmdline,"chord"))		dz->process = MULTI_SYN;
+	else {
+		sprintf(errstr,"Unknown program identification string '%s'\n",prog_identifier_from_cmdline);
+		return(USAGE_ONLY);
+	}
+//TW UPDATE
+	return(FINISHED);
+}
+
+/********************************************************************************************/
+/********************************** FORMERLY IN usage.c *************************************/
+/********************************************************************************************/
+
+/******************************** USAGE1 ********************************/
+
+int usage1(void)
+{
+	sprintf(errstr,
+	"USAGE: synth NAME (mode) outfile parameters\n"
+	"\n"
+	"where NAME can be any one of\n"
+	"\n"
+//TW UPDATE
+	"wave    noise   silence    spectra    clicks    chord\n"
+	"\n"
+	"Type 'synth wave'  for more info on synth wave option... ETC.\n");
+	return(USAGE_ONLY);
+}
+
+/******************************** USAGE2 ********************************/
+
+int usage2(char *str)
+{
+	if(!strcmp(str,"wave")) {
+    	sprintf(errstr,
+    	"GENERATE SIMPLE WAVEFORMS\n\n"
+		"USAGE: synth wave mode outfile sr chans dur freq [-aamp] [-ttabsize]\n\n"
+		"MODES ARE\n"
+		"1) sine wave\n"
+		"2) square wave\n"
+		"3) sawtooth wave\n"
+		"4) ramp wave\n\n"
+		"SR      (sample rate) can be 48000, 24000, 44100, 22050, 32000, or 16000\n"
+		"CHANS   can be 1, 2 or 4\n"
+		"DUR     is duration of output snd, in seconds.\n"
+		"FREQ    is frq of output sond, in Hz\n"
+		"AMP     is amplitude of output sound: 0.0 < Range <= 1.0 (max & default).\n"
+		"TABSIZE is size of table storing waveform.\n"
+		"        defaults to 256: input value always rounded to multiple of 4.\n\n"
+		"Frq and Amp may vary through time.\n");
+	} else if(!strcmp(str,"chord")) {
+    	sprintf(errstr,
+    	"GENERATE CHORD ON SIMPLE WAVEFORM\n\n"
+		"USAGE: synth chord mode outfile datafile sr chans dur  [-aamp] [-ttabsize]\n\n"
+		"MODES ARE\n"
+		"1) DATAFILE has list of midi data\n"
+		"2) DATAFILE has list of frequency data\n"
+		"SR      (sample rate) can be 48000, 24000, 44100, 22050, 32000, or 16000\n"
+		"CHANS   can be 1, 2 or 4\n"
+		"DUR     is duration of output snd, in seconds.\n"
+		"AMP     is amplitude of output sound: 0.0 < Range <= 1.0 (max & default).\n"
+		"TABSIZE is size of table storing waveform.\n"
+		"        defaults to 4096: input value always rounded to multiple of 4.\n\n");
+	} else if(!strcmp(str,"noise")) {
+    	sprintf(errstr,
+    	"GENERATE NOISE\n\n"
+		"USAGE: synth noise outfile sr chans dur [-aamp]\n\n"
+		"SR      (sample rate) can be 48000, 24000, 44100, 22050, 32000, or 16000\n"
+		"CHANS   can be 1, 2 or 4\n"
+		"DUR     is duration of output snd, in seconds.\n"
+		"AMP     is amplitude of output sound: 0.0 < Range <= 1.0 (max & default).\n\n"
+		"Amp may vary through time.\n");
+	} else if(!strcmp(str,"silence")) {
+    	sprintf(errstr,
+    	"MAKE SILENT SOUNDFILE\n\n"
+		"USAGE: synth silence outfile sr chans dur\n\n"
+		"SR      (sample rate) can be 48000, 24000, 44100, 22050, 32000, or 16000\n"
+		"CHANS   can be 1, 2 or 4\n"
+		"DUR     is duration of output snd, in seconds.\n");
+//TW UPDATE : new options
+	} else if(!strcmp(str,"spectra")) {
+    	sprintf(errstr,
+    	"GENERATE BOTH CHANNELS OF A STEREO SPECTRAL BAND\n\n"
+		"USAGE: synth spectra outfilename dur frq spread max-foc min-foc\n"
+		"                     timevar srate [-p]\n\n"
+		"DUR      duration of output snd, in seconds.\n"
+		"FRQ      centre frequency of the band.\n"
+		"SPREAD   width of band, in Hz (default) or as transposition ratio.\n"
+		"'Foc' = focus, degree to which band energy is concentrated at centre frequency.\n"
+		"MAX-FOC  range 0 1\n"
+		"MIN-FOC  range 0 1\n"
+		"TIMEVAR  Degree to which the band varies over time. Range 0-1.\n"
+		"SRATE    Sample rate of output audio file.\n\n"
+		"-p       If flag set, 'SPREAD' is a transposition ratio.\n\n");
+	} else if(!strcmp(str,"clicks")) {
+    	sprintf(errstr,
+    	"CLICKTRACK    USAGE: synth clicks mode outname clickfile [-sstart -eend -zzero]\n\n"
+		"      make clicktrack from 'start' to 'end'; music starting at dataline 'zero'.\n"
+		"      MODE 1: start and end are TIMES:    MODE 2: start & end are data linenos.\n"
+		"    CLICKFILE contains sequence of datalines. Each dataline has a line number \n"
+ 		"    followed by 2, 3 or 4 data items, separated by spaces, which can be....\n"
+		"TIME  141.52   (Set time to 141.52 secs: must be later than previous event)\n"
+		"GP  1  23.7    (Pause of 23.7sec, with accent [1] at start: '0' for no accent)\n"
+		"       OR the following set of items:-\n"
+ 		"1) TEMPO : in one of the forms (with no spaces around '='):-\n"
+ 		"       1=144         (crotchet = 144)   1.5=100    (dotted crotchet = 100)\n"
+ 		"       0.5=144to85.3 (tempo change from quaver = 144 to 85.3)\n"
+ 		"2) BARRING :  in the form 4:4 or 6:8 or 7:16 etc. (no spaces around the ':')\n"
+ 		"3) COUNT :  i.e. the (integer) number of bars in this format.\n"
+		"------- and, optionally ---------\n"
+ 		"4) ACCENT PATTERN  1.....  strong beat followed by 5 weak beats\n"
+ 		"                   1..1..  strong beat (start), secondary (at 4), weak between\n"
+ 		"                   100100  strong & secondary beats, but NO intermediate beats\n"
+		"IF THE ACCENT PATTERN IS OMITTED, default patterns are used. These are:-\n"
+		"An accent on the start of each bar PLUS\n"
+		"a) in 6:8, 9:8, 12:8, 15:8 etc, or 6:4, 6:16, 6:32, 9:4, 9:16 etc.\n"
+		"      sound on every unit (4,8,16,32 etc.), secondary accents every 3rd beat\n"
+		"b) in All other meters: NO secondary accents\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);
+}
+
+/******************************** INIT_SPECSYNTH (redundant)  ********************************/
+
+void init_specsynth(dataptr dz)
+{
+//TW Extensive rewrite
+	dz->outfile->origrate = dz->infile->origrate  = (int)round(dz->param[SS_SRATE]);
+	if(dz->floatsam_output) {
+		dz->outfile->stype = SAMP_FLOAT;
+		dz->infile->stype = SAMP_FLOAT;
+		dz->outfile->origstype = SAMP_FLOAT;
+		dz->infile->origstype  = SAMP_FLOAT;
+	} else {
+		dz->outfile->origstype = SAMP_SHORT;
+		dz->infile->origstype  = SAMP_SHORT;
+		dz->outfile->stype = SAMP_SHORT;
+		dz->infile->stype = SAMP_SHORT;
+	}
+	dz->wanted			  = SPECSYN_MLEN;
+	dz->outfile->channels = SPECSYN_MLEN;
+	dz->infile->channels  = SPECSYN_MLEN;
+	dz->outfile->Mlen	   = dz->infile->Mlen	   = (dz->outfile->channels-2);	
+	dz->wanted = dz->infile->channels;
+	dz->clength = dz->wanted/2;
+	dz->nyquist = dz->outfile->origrate / 2;		
+	dz->outfile->Dfac  = dz->infile->Dfac  = (dz->outfile->channels-2) / 8;
+	dz->outfile->arate = dz->infile->arate = (float) dz->outfile->origrate / (float)dz->outfile->Dfac;
+	dz->outfile->srate = dz->infile->srate = (int) dz->outfile->arate;
+	dz->frametime = (float)(1.0/dz->outfile->arate);
+	dz->wlength = (int)round(dz->param[SS_DUR] * dz->outfile->arate);
+	dz->chwidth = dz->nyquist/(double)dz->clength;
+	
+}
+
+//TW UPDATE : NEW FUNCTIONS below
+/******************************** READ_CLICKTRACK_DATA ********************************/
+
+#define CLICKLINE  (0)
+#define CLICKTEMPO (1)
+#define CLICKMETER (2)
+#define CLICKCOUNT (3)
+#define CLICKSTYLE (4)
+
+int read_clicktrack_data(char *str,dataptr dz)
+{
+	int exit_status, init = 1;
+	int cnt, linecnt = 0, GP, is_abstime, accent;
+	char temp[200], *q, *p;
+	int arraysize = BIGARRAY * 10, tarray = BIGARRAY * 10, tcnt = 0;/* ARRAYS V. BIG AS free() fails inside realloc() or on its own */
+	double tempo = -1.0, accel = -1.0, time = 0.0, pulse_unit = 0.0, timeincr, lasttime = -HUGE, abstime = 0.0;
+	int metre_num = -1, metre_denom = 1, barcnt = 0;
+	char style[200];
+	double  mintimestep = 0.0;
+	FILE *fp;
+
+	if((fp = fopen(str,"r"))==NULL) {			
+		sprintf(errstr,"Cannot open clicktrack data file %s\n",str);
+		return(DATA_ERROR);
+	}
+	while(fgets(temp,200,fp)!=NULL) {	 /* READ AND TEST BRKPNT VALS */
+		q = temp;
+		cnt = 0;
+		while(isspace(*q))
+			q++;
+		GP = 0;
+		is_abstime = 0;
+		accent = 0;
+		timeincr = 0.0;
+		if(*q == ENDOFSTR || *q == ';')	/* ignore blank lines and comments */
+			continue;
+		while(get_word_from_string(&q,&p)) {
+			switch(cnt) {
+			case(CLICKLINE):
+				if((exit_status = getlineno(p,tcnt+1,linecnt+1)) < 0)
+					return(exit_status);
+				break;
+			case(CLICKTEMPO):
+				if((exit_status = gettempo(p,&tempo,&pulse_unit,&accel,linecnt,&GP,&is_abstime)) < 0)
+					return(exit_status);
+				break;
+			case(CLICKMETER):
+				if((exit_status = getmeter(p,&metre_num,&metre_denom,linecnt,GP,is_abstime,&abstime,&accent)) < 0)
+					return(exit_status);
+				break;
+			case(CLICKCOUNT):
+				if((exit_status = getcount(p,&barcnt,linecnt,GP,is_abstime,&timeincr)) < 0)
+					return(exit_status);
+				break;
+			case(CLICKSTYLE):
+				if((exit_status = getstyle(p,style,metre_num,linecnt,GP,is_abstime)) < 0)
+					return(exit_status);
+				break;
+			default:
+				sprintf(errstr,"Too many data items on line %d\n",linecnt+1);
+				return(DATA_ERROR);
+			}
+			cnt++;
+		}
+		if(cnt < 5) {
+			switch(cnt) {
+			case(3):
+				if(!is_abstime) {
+					sprintf(errstr,"Too few data items on line %d\n",linecnt+1);
+					return(DATA_ERROR);
+				}
+				break;
+			case(4):
+				if(!GP && ((exit_status = default_style(style,metre_num)) < 0))
+					return(exit_status);
+				break;
+			default:
+				sprintf(errstr,"Too few data items on line %d\n",linecnt+1);
+				return(DATA_ERROR);
+			}
+		}
+		if ((exit_status = generate_clickdata(init,&arraysize,tempo,pulse_unit,metre_num,metre_denom,style,barcnt,
+				accel,&time,&lasttime,GP,is_abstime,abstime,accent,timeincr,&tcnt,&tarray,&mintimestep,dz)) < 0)
+			return(exit_status);
+		init = 0;
+		linecnt++;
+	}
+	dz->parray[2][tcnt] = lasttime;
+	dz->iparam[CLICKTIME] = linecnt;
+	dz->duration = (double)linecnt;	/* tells cdparams about range of param 3 */
+	return(FINISHED);
+}
+
+/******************************** READ_CHORD_DATA ********************************/
+
+int read_chord_data(char *str,dataptr dz)
+{
+	int cnt = 0, exit_status;
+	char temp[200], *q;
+	double maxmidi = 127.0, minmidi;
+	double maxfrq = miditohz(127);
+	double minfrq = 1.0/MAX_SYN_DUR;
+	double d;
+	FILE *fp;
+	if((exit_status = hztomidi(&minmidi,minfrq)) < 0)
+		return exit_status;
+
+	if((fp = fopen(str,"r"))==NULL) {			
+		sprintf(errstr,"Cannot open chord data file %s\n",str);
+		return(DATA_ERROR);
+	}
+	dz->ringsize = 1;
+	while(fgets(temp,200,fp)!=NULL) {	 /* READ AND TEST BRKPNT VALS */
+		q = temp;
+		while(get_float_from_within_string(&q,&d)) {
+			switch(dz->mode) {
+			case(0):	/* MIDI */
+				if(d < minmidi || d > maxmidi) {
+					sprintf(errstr,"Value %d (%lf) is out of range.\n",cnt+1,d);
+					return(DATA_ERROR);
+				}
+				break;
+			case(1):	/* FRQ */
+				if(d < minfrq || d > maxfrq) {
+					sprintf(errstr,"Value %d (%lf) is out of range.\n",cnt+1,d);
+					return(DATA_ERROR);
+				}
+				break;
+			case(2):	/* MIDI, CHORD SEQUENCE */
+				if(d < -99.0)
+					dz->ringsize++;
+				else if(d < minmidi || d > maxmidi) {
+					sprintf(errstr,"Value %d (%lf) is out of range.\n",cnt+1,d);
+					return(DATA_ERROR);
+				}
+				break;
+			}
+			cnt++;
+		}
+	}
+	if(cnt == 0) {
+		sprintf(errstr,"No data found in file.\n");
+		return(MEMORY_ERROR);
+	}
+	if((dz->parray[1] = (double *)malloc(cnt * sizeof(double)))==NULL) {
+		sprintf(errstr,"Insufficient memory to store MIDI values.\n");
+		return(MEMORY_ERROR);
+	}
+	if((dz->parray[2] = (double *)malloc(cnt * sizeof(double)))==NULL) {
+		sprintf(errstr,"Insufficient memory to store table step values.\n");
+		return(MEMORY_ERROR);
+	}
+	if((dz->parray[3] = (double *)malloc(cnt * sizeof(double)))==NULL) {
+		sprintf(errstr,"Insufficient memory to store sample interpolators.\n");
+		return(MEMORY_ERROR);
+	}
+	if((dz->lparray[0] = (int *)malloc(cnt * sizeof(int)))==NULL) {
+		sprintf(errstr,"Insufficient memory to store samplecounters.\n");
+		return(MEMORY_ERROR);
+	}
+	fseek(fp,0,0);
+	cnt = 0;
+	while(fgets(temp,200,fp)!=NULL) {	 /* READ AND TEST BRKPNT VALS */
+		q = temp;
+		while(get_float_from_within_string(&q,&d)) {
+			switch(dz->mode) {
+			case(0):
+				d = miditohz(d);
+				break;
+			case(2):
+				if(d < -99.0)
+					d = 0.0;
+				else
+					d = miditohz(d);
+				break;
+			}
+			dz->parray[1][cnt] = d;
+			cnt++;
+		}
+	}
+	dz->itemcnt = cnt;
+	for(cnt=0;cnt<dz->itemcnt;cnt++) {
+		dz->parray[2][cnt] = 0.0;	/* initialise all table increments and positions */
+		dz->parray[3][cnt] = 0.0;
+		dz->lparray[0][cnt] = 0;
+	}
+	return(FINISHED);
+}
+
+/*********************************** GETTEMPO ***********************************
+ *
+ * Expected format 1=144 OR 1.5=134.567 [or "G" (or "g") as part of "G P"]
+ */
+
+int gettempo(char *str,double *tempo,double *pulse_unit,double *accel,int linecnt,int *GP,int *is_abstime)
+{
+	char *p;
+	p = str;
+	if(!strcmp(str,"GP")) {
+		*GP = 1;
+		return(FINISHED);
+	} else if(!strcmp(str,"TIME")) {
+		if(linecnt == 0) {
+			sprintf(errstr,"'TIME' dataline too soon: You cannot reset the Absolute time before you start the clickdata.\n");
+			return(DATA_ERROR);
+		}
+		*is_abstime = 1;
+		return(FINISHED);
+	} else if(!strcmp(str,".")) {
+		if(*accel >= 0.0) {
+			sprintf(errstr,"Bad tempo data at line %d : Cannot use a DOT (for same tempo) when previous tempo was changing\n",linecnt+1);
+			return(DATA_ERROR);
+		} else if(*tempo < 0.0) {
+			sprintf(errstr,"Bad tempo data at line %d : Cannot use a DOT (for same tempo) when no previous tempo established\n",linecnt+1);
+			return(DATA_ERROR);
+		}
+		return(FINISHED);
+	}
+	if(!strgetfloat_within_string(&p,pulse_unit)) {
+		sprintf(errstr,"Bad tempo data at line %d : Cannot get length of pulse unit (e.g. 1 = crotchet)\n",linecnt+1);
+		return(DATA_ERROR);
+	}
+	if(!flteq(*pulse_unit,1.0) && !flteq(*pulse_unit,2.0) && !flteq(*pulse_unit,3.0) && !flteq(*pulse_unit,4.0) 
+	&& !flteq(*pulse_unit,1.5) && !flteq(*pulse_unit,0.75) && !flteq(*pulse_unit,0.375) && !flteq(*pulse_unit,0.1875)
+	&& !flteq(*pulse_unit,0.5) && !flteq(*pulse_unit,0.25) && !flteq(*pulse_unit,0.125))  {
+		sprintf(errstr,"Bad tempo data at line %d : Invalid pulse unit (%.3lf)\n",linecnt+1,*pulse_unit);
+		return(DATA_ERROR);
+	}
+	if(*p++ != '=') {
+		sprintf(errstr,"Bad tempo data at line %d : '=' missing, or spaces before '='\n",linecnt+1);
+		return(DATA_ERROR);
+	}
+	if(!strgetfloat_within_string(&p,tempo)) {
+		sprintf(errstr,"Bad tempo data at line %d : Failed to find metronome mark value\n",linecnt+1);
+		return(DATA_ERROR);
+	}
+	*accel = -1.0;
+	if(strlen(p) > 0) {
+		if(!strncmp(p,"to",2)) {
+			p += 2;
+			if(!strgetfloat_within_string(&p,accel)) {
+				sprintf(errstr,"Bad tempo data at line %d : Failed to find tempo at end of tempo-change\n",linecnt+1);
+				return(DATA_ERROR);
+			}
+		} else {
+			sprintf(errstr,"Bad tempo data at line %d : Spurious characters at end (can be 'to' followed by 2nd tempo only)\n",linecnt+1);
+			return(DATA_ERROR);
+		}
+	}
+	return(FINISHED);
+}
+
+/*********************************** GETMETER ***********************************
+ *
+ * Expected format 3:8,  [OR  P (or p) as part of "G P"]
+ */
+
+int getmeter(char *str,int *metre_num,int *metre_denom,int linecnt,int GP,int is_abstime,double *abstime,int *accent)
+{
+	char *q,*p = str;
+	int k, j;
+	if(GP) {
+		if(!strcmp(str,"1")) {
+			*accent = 1;
+			return(FINISHED);
+		} else if(!strcmp(str,"0"))
+			return(FINISHED);
+		else {
+			sprintf(errstr,"Bad GP data at line %d : no accent indicator (0 or 1)\n",linecnt+1);
+			return(DATA_ERROR);
+		}
+	} else if(is_abstime) {
+		if(sscanf(str,"%lf",abstime)!=1) {
+			sprintf(errstr,"Bad TIME data at line %d (found '%s')\n",linecnt+1,str);
+			return(DATA_ERROR);
+		}
+		return(FINISHED);
+	} else if(!strcmp(str,".")) {
+		if(*metre_num < 0) {
+			sprintf(errstr,"Bad meter data at line %d : Cannot use a DOT (for same meter) when no previous meter exists\n",linecnt+1);
+			return(DATA_ERROR);
+		}
+		return(FINISHED);
+	}
+	while(*p != ':') {
+		if(!isdigit(*p)) {
+			sprintf(errstr,"Bad meter data at line %d : no numerator, or non-numeric character or space in numerator before ':' or missing ':'\n",linecnt+1);
+			return(DATA_ERROR);
+		}
+		p++;
+	}
+	*p = ENDOFSTR;
+	if(sscanf(str,"%d",metre_num)!=1) {
+		sprintf(errstr,"Bad meter data at line %d : Failed to find numerator of meter\n",linecnt+1);
+		return(DATA_ERROR);
+	}
+	p++;
+	q = p;
+	while(*p != ENDOFSTR) {
+		if(!isdigit(*p)) {
+			sprintf(errstr,"Bad meter data at line %d : non-numeric (or no) characters after ':'\n",linecnt+1);
+			return(DATA_ERROR);
+		}
+		p++;
+	}
+	if(sscanf(q,"%d",metre_denom)!=1) {
+		sprintf(errstr,"Bad meter data at line %d : Failed to find denominator of meter (no spaces permitted after ':')\n",linecnt+1);
+		return(DATA_ERROR);
+	}
+	if((k = *metre_denom) < 2) {
+		sprintf(errstr,"Bad meter data at line %d : denominator of meter is not a multiple of 2\n",linecnt+1);
+		return(DATA_ERROR);
+	}
+	while(k > 2)  {
+		j = k/2;
+		if(k != j * 2) {
+			sprintf(errstr,"Bad meter data at line %d : denominator of meter is not a multiple of 2\n",linecnt+1);
+			return(DATA_ERROR);
+		}
+		k = j;
+	}
+	return(FINISHED);
+}
+
+/*********************************** GETSTYLE ***********************************************
+ *
+ * Expected format 1..... or 1..1.. or 100100  where number of chars = denominator of meter
+ */
+
+int getstyle(char *str,char *style,int metre_num,int linecnt,int GP,int is_abstime)
+{
+	char *p = str;
+	if(GP || is_abstime)
+		return(FINISHED);
+	while(*p != ENDOFSTR) {
+		if(*p != '1' && *p != '.' && *p != '0') {
+			sprintf(errstr,"Bad style data at line %d : Invalid character (%c) in style string (must be '1','0' or '.'\n",linecnt+1,*p);
+			return(DATA_ERROR);
+		}
+		p++;
+	}
+	
+	if((p - str) != metre_num) {
+		sprintf(errstr,"Bad style data at line %d : Wrong number of characters in style-string (must be %d in this meter)\n",linecnt+1,metre_num);
+		return(DATA_ERROR);
+	}
+	strcpy(style,str);
+	return(FINISHED);
+}
+
+/*********************************** GETLINENO ***********************************************
+ *
+ * Expected format = digit (increasing from 1)
+ */
+
+int getlineno(char *str,int tcnt,int linecnt)
+{
+	int lineno;
+	if(sscanf(str,"%d",&lineno)!=1) {
+		sprintf(errstr,"Failed to read line number, at line %d (found '%s')\n",linecnt,str);
+		return(DATA_ERROR);
+	}
+	if(lineno != linecnt) {
+		if(lineno == 0) {
+			sprintf(errstr,"Lines should be numbered from 1 upwards\n");
+			return(DATA_ERROR);
+		} else {
+			sprintf(errstr,"Line numbers are not in sequence, at line %d\n",linecnt);
+			return(DATA_ERROR);
+		}
+	}
+	if(lineno != tcnt) {
+		sprintf(errstr,"Anomaly in counting lines, at line %d\n",linecnt);
+		return(PROGRAM_ERROR);
+	}
+	return(FINISHED);
+}
+
+/*********************************** GETCOUNT ***********************************************
+ *
+ * Expected format is an INTEGER
+ */
+
+int getcount(char *str,int *barcnt,int linecnt,int GP,int is_abstime,double *timeincr)
+{
+	char *p = str;
+	if(is_abstime)
+		return(FINISHED);
+	else if(GP) {
+		if(sscanf(str,"%lf",timeincr)!=1) {
+			sprintf(errstr,"Failed to read duration of General Pause at line %d\n",linecnt+1);
+			return(DATA_ERROR);
+		} 
+		return(FINISHED);
+	}
+	while(*p != ENDOFSTR) {
+		if(!isdigit(*p)) {
+			sprintf(errstr,"Bad bar-count data at line %d : Non-numeric character encountered (must be whole number of bars)\n",linecnt+1);
+			return(DATA_ERROR);
+		}
+		p++;
+	}
+	if(sscanf(str,"%d",barcnt)!=1) {
+		sprintf(errstr,"Bad bar-count data at line %d : Failed to read bar-count\n",linecnt+1);
+		return(DATA_ERROR);
+	}
+	if(*barcnt < 1) {
+		sprintf(errstr,"Bad bar-count (%d) data at line %d\n",*barcnt,linecnt+1);
+		return(DATA_ERROR);
+	}
+	return(FINISHED);
+}
+
+/*********************************** GENERATE_CLICKDATA ***********************************************/
+
+#define ACCELPOW (0.6)
+#define RITPOW (1.0/ACCELPOW)
+
+int generate_clickdata
+(int init,int *arraysize,double tempo,double pulse_unit,int metre_num,int metre_denom,char *style,int barcnt,double accel,
+ double *time,double *lasttime,int GP,int is_abstime,double abstime,int accent,double timeincr,int *tcnt,int *tarray,
+ double *mintimestep,dataptr dz)
+{
+	int n, eventcnt;
+	double timestep, unit_tempo, *cliks, pulse_mutiplier;
+	double orig_timestep = 0.0, final_timestep, total_beats = 1.0, tstepinc = 0.0, thisincr;
+	char *p = style;
+	int do_accel, steptype = 1;
+	if(init) {
+		if((dz->parray[0] = (double *)malloc(*arraysize * sizeof(double)))==NULL) {
+			sprintf(errstr,"INSUFFICIENT MEMORY to make clicktrack data array.\n");
+			return(MEMORY_ERROR);
+		}
+		dz->itemcnt = 0;
+		*mintimestep = (double)((CLICKLEN + 1) + 4 /* safety */)/(double)dz->infile->srate;
+		if((dz->parray[2] = (double *)malloc(*tarray * sizeof(double)))==NULL) {
+			sprintf(errstr,"INSUFFICIENT MEMORY to store clicktrack data line times.\n");
+			return(MEMORY_ERROR);
+		}
+	}
+	cliks = dz->parray[0];
+	dz->parray[2][(*tcnt)++] = *time;
+	if(*tcnt > *tarray) {
+		*tarray += BIGARRAY;
+		if((dz->parray[2] = (double *)realloc((char *)dz->parray[2],(*tarray) * sizeof(double)))==NULL) {
+			sprintf(errstr,"INSUFFICIENT MEMORY to store clicktrack data line times.\n");
+			return(MEMORY_ERROR);
+		}
+	}
+	if(GP) {
+		if(accent) {
+			if(dz->itemcnt + 2 >= *arraysize) {
+				*arraysize += BIGARRAY;
+				if((dz->parray[0] = (double *)realloc((char *)dz->parray[0],*arraysize * sizeof(double)))==NULL) {
+					sprintf(errstr,"INSUFFICIENT MEMORY to make expand clicktrack data array.\n");
+					return(MEMORY_ERROR);
+				}
+				cliks = dz->parray[0];
+			}		
+			cliks[dz->itemcnt++] = *time;
+			cliks[dz->itemcnt++] = CLICKAMP1;
+		}
+		*lasttime = *time;
+		*time += timeincr;
+		return(FINISHED);
+	}
+	if(is_abstime) {
+		if(abstime < *lasttime) {
+			sprintf(errstr,"ABSOLUTE TIME %lf is OUT OF SEQUENCE.\n",abstime);	/*RWD 12:2003 added abstime arg */
+			return(DATA_ERROR);
+		}
+		*time = abstime;
+		return(FINISHED);
+	}
+	pulse_mutiplier = (double)metre_denom/4.0;	/* could be .5 if beats are minims */
+	unit_tempo = tempo * pulse_unit;			/* crotchets per minute */
+	unit_tempo *= pulse_mutiplier;				/* basic pulse-divisions per minute */
+	unit_tempo /= 60.0;							/* basic pulse-divisions per second */
+	if((timestep = (1.0/unit_tempo)) < *mintimestep) {
+		sprintf(errstr,"Tempo too fast to separate clicks in output, at time %lf secs.\n",*time);
+		return(DATA_ERROR);
+	}
+	eventcnt = 0;
+	if(accel > 0.0) {						/* in accel or rit case, change tempo logwise */
+		if((final_timestep = timestep * (tempo/accel)) < *mintimestep) {
+			sprintf(errstr,"Tempo too fast to separate clicks in output, at time %lf secs.\n",*time);
+			return(DATA_ERROR);
+		}
+		total_beats   = barcnt * metre_num;
+		if((tstepinc = final_timestep - timestep) < 0) {
+			steptype = -1;
+			tstepinc = -tstepinc;
+		}
+		orig_timestep = timestep;
+		do_accel = 1;
+	} else 
+		do_accel = 0;
+
+	for(n = 0; n < barcnt; n++) {			/* for each bar */
+		if(dz->itemcnt + (metre_num * 2) >= *arraysize) {
+			*arraysize += BIGARRAY;
+			if((dz->parray[0] = (double *)realloc((char *)dz->parray[0],*arraysize * sizeof(double)))==NULL) {
+				sprintf(errstr,"INSUFFICIENT MEMORY to make expand clicktrack data array.\n");
+				return(MEMORY_ERROR);
+			}
+			cliks = dz->parray[0];
+		}		
+		while(*p != ENDOFSTR) {				/* for each beat in specified pattern */
+			switch(*p) {
+			case('1'):					
+				cliks[dz->itemcnt++] = *time;
+				if(p == style)			/* stress first beat */
+					cliks[dz->itemcnt++] = CLICKAMP1;
+				else					/* half-stress subsidiary accents */
+					cliks[dz->itemcnt++] = CLICKAMP2;
+				break;
+			case('.'):					/* sound other beats with no stress */
+				cliks[dz->itemcnt++] = *time;
+				cliks[dz->itemcnt++] = CLICKAMP3;
+				break;
+			/* case('0'):				  ignore unsounded beats */
+			}
+			if(do_accel) {					/* if tempo changing, increment timestep logwise */
+				if(steptype < 0)
+					thisincr = pow(((double)eventcnt/(double)total_beats),ACCELPOW) * tstepinc * steptype;
+				else
+					thisincr = pow(((double)eventcnt/(double)total_beats),RITPOW) * tstepinc * steptype;
+				timestep = orig_timestep + thisincr;
+				eventcnt++;
+			}
+			*lasttime = *time;
+			*time += timestep;				/* advance absolute time to next beat */
+			p++;							/* advance along accent pattern */
+		}									
+		p = style;							/* at end of pattern, return to start of pattern */
+	}
+	return(FINISHED);
+}
+
+/*********************************** DEFAULT_STYLE ***********************************************/
+
+int default_style(char *style,int metre_num)
+{
+	char *p = style;
+	int triple = 0, n;
+	if((((metre_num/3) * 3) == metre_num)  && (metre_num > 3))
+		triple = 1;
+	*p++ = '1';
+	for(n = 1; n < metre_num;n++) {
+		if(triple & (n%3 == 0))
+			*p = '1';
+		else
+			*p = '.';
+		p++;
+	}
+	*p = ENDOFSTR;
+	return(FINISHED);
+}
+
+/*********************************** GENERATE_CLICKTABLE ***********************************************/
+
+int generate_clicktable(dataptr dz)
+{
+	int n;
+	double rand1, rand2, maxval;
+	if((dz->parray[1] = (double *)malloc((CLICKLEN +1) * sizeof(double)))==NULL) {
+		sprintf(errstr,"INSUFFICIENT MEMORY to store click table.\n");
+		return(MEMORY_ERROR);
+	}
+	initrand48();
+	maxval = 0.0;
+	for(n=0;n < CLICKLEN;n++) {
+		rand1 = (drand48() * 2.0) - 1.0;	/* in case I decide to modify it every time !! */
+		rand2 = (drand48() * .02) - .01;
+		dz->parray[1][n] = sqrt(sin(PI/(double)n)) * ((double)n * 2.0 * PI/(6.0+ rand1)) * rand2 * (MAXSHORT * .98);
+						/* 1/2 sin envel, steepened *    sin oscil every 6 or so samps    * noise *  maxsamp adjusted for noise wander */ 
+		maxval= max(maxval,fabs(dz->parray[1][n]));
+	}
+	maxval = MAXSHORT/maxval;
+	for(n=0;n < CLICKLEN;n++)
+		dz->parray[1][n] *= maxval;
+	dz->parray[1][n] = 0.0;
+	return(FINISHED);
+}
+
+/*********************************** CLICK_CONSISTENCY ***********************************************/
+
+int click_consistency(dataptr dz) 
+{
+	double lasttime;
+	switch(dz->mode) {
+	case(CLICK_BY_TIME):
+		if(dz->param[CLIKSTART] >= dz->param[CLIKEND]) {
+			sprintf(errstr,"Start time for Click Generation is beyond End time.\n");
+			return(DATA_ERROR);
+		}
+		lasttime = dz->parray[0][dz->itemcnt - 2];
+		if(dz->param[CLIKSTART] > lasttime - FLTERR) {
+			sprintf(errstr,"Start time for Click Generation is beyond end of your data.\n");
+			return(DATA_ERROR);
+		}
+		dz->param[CLIKEND] = min(dz->param[CLIKEND],lasttime);
+		break;
+	case(CLICK_BY_LINE):
+		if(dz->iparam[CLIKSTART] > dz->iparam[CLIKEND]) {
+			sprintf(errstr,"Start line for Click Generation is at or beyond End line.\n");
+			return(DATA_ERROR);
+		}
+		if(dz->iparam[CLIKSTART] > dz->iparam[CLICKTIME]) {
+			sprintf(errstr,"Start line for Click Generation is beyond end of your data.\n");
+			return(DATA_ERROR);
+		}
+		dz->iparam[CLIKSTART]--;
+		dz->iparam[CLIKEND]--;
+		dz->iparam[CLIKEND] = min(dz->iparam[CLIKEND],(dz->iparam[CLICKTIME] - 1));
+		break;
+	}
+	dz->iparam[CLIKOFSET]--;	/* convert from "1-N" to "0 to N-1" */
+	return(FINISHED);
+}

+ 226 - 0
dev/synth/main.c

@@ -0,0 +1,226 @@
+/*
+ * Copyright (c) 1983-2013 Trevor Wishart and Composers Desktop Project Ltd
+ * http://www.trevorwishart.co.uk
+ * http://www.composersdesktop.com
+ *
+ This file is part of the CDP System.
+
+    The CDP System is free software; you can redistribute it
+    and/or modify it under the terms of the GNU Lesser General Public
+    License as published by the Free Software Foundation; either
+    version 2.1 of the License, or (at your option) any later version.
+
+    The CDP System is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public
+    License along with the CDP System; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+    02111-1307 USA
+ *
+ */
+
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <structures.h>
+#include <tkglobals.h>
+#include <synth.h>
+#include <filetype.h>
+#include <processno.h>
+#include <modeno.h>
+#include <formants.h>
+#include <cdpmain.h>
+#include <special.h>
+#include <logic.h>
+#include <globcon.h>
+#include <cdpmain.h>
+#include <sfsys.h>
+#include <ctype.h>
+
+#include <string.h>
+char errstr[2400];
+
+int sloom = 0;
+int sloombatch = 0;
+int anal_infiles = 0;
+int is_converted_to_stereo = -1;
+
+/**************************************** MAIN *********************************************/
+
+/* RWD N0v 2011: removed bad call to sndsetbuf, caused synth spectra to fail */
+/* TODO: fix malloc of dz->ifd array - default is one channel, but this code tries to use two. */
+
+/* RWD 22/02/2018  fixed output interleave (glitch on ch 2),
+   replaced hamming with vonhann window in pvoc for clean frame transitions
+   bumped version number
+*/
+
+const char* cdp_version = "7.1.1";
+
+int main(int argc,char *argv[])
+{
+	int exit_status;
+//	FILE *fp   = NULL;
+	dataptr dz = NULL;
+	char **cmdline;
+	int  cmdlinecnt;
+	aplptr ap;
+	int *valid = NULL;
+	int is_launched = FALSE;
+	int  validcnt;
+
+						/* CHECK FOR SOUNDLOOM */
+//TW UPDATE
+	if((argc==2) && strcmp(argv[1],"--version")==0) {
+		fprintf(stdout,"%s\n",cdp_version);
+		fflush(stdout);
+		return 0;
+	}
+	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 = setup_param_ranges_and_defaults(dz))<0) {
+		print_messages_and_close_sndfiles(exit_status,is_launched,dz);
+		return(FAILED);
+	}
+
+/*********************************************************************************************************************
+		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);
+	/* RWD we MUST free all allocs */
+	/*free(dz);*/
+	superfree(dz);
+	return(SUCCEEDED);
+}
+

+ 804 - 0
dev/synth/mxfft.c

@@ -0,0 +1,804 @@
+/*
+ * Copyright (c) 1983-2013 Trevor Wishart and Composers Desktop Project Ltd
+ * http://www.trevorwishart.co.uk
+ * http://www.composersdesktop.com
+ *
+ This file is part of the CDP System.
+
+    The CDP System is free software; you can redistribute it
+    and/or modify it under the terms of the GNU Lesser General Public
+    License as published by the Free Software Foundation; either
+    version 2.1 of the License, or (at your option) any later version.
+
+    The CDP System is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public
+    License along with the CDP System; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+    02111-1307 USA
+ *
+ */
+
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <structures.h>
+#include <globcon.h>
+#include <pvoc.h>
+#include <math.h>			/*RWD*/
+
+int fft_(),fftmx(),reals_();
+
+/*
+ *-----------------------------------------------------------------------
+ * subroutine:  fft
+ * multivariate complex fourier transform, computed in place
+ * using mixed-radix fast fourier transform algorithm.
+ *-----------------------------------------------------------------------
+ *
+ *	this is the call from C:
+ *		fft_(anal,banal,&one,&N2,&one,&mtwo);
+ *	CHANGED TO:-
+ *		fft_(anal,banal,one,N2,one,mtwo);
+ */
+
+int fft_(float *a, float *b, int nseg, int n, int nspn, int isn)
+		/*  a: pointer to array 'anal'  */
+		/*  b: pointer to array 'banal' */
+{
+	int exit_status;
+	int nfac[16];		/*  These are one bigger than needed   */
+						/*  because wish to use Fortran array  */
+						/* index which runs 1 to n, not 0 to n */
+
+	int 	m = 0, nf, k, kt, ntot, j, jj, maxf, maxp=0;
+
+/* work space pointers */
+	float	*at, *ck, *bt, *sk;
+	int		*np;
+
+
+/* reduce the pointers to input arrays - by doing this, FFT uses FORTRAN
+   indexing but retains compatibility with C arrays */
+	a--;	b--;
+
+/*	
+ * determine the factors of n
+ */
+	k=nf=abs(n);
+   	if(nf==1) 
+		return(FINISHED);
+
+	nspn=abs(nf*nspn);
+	ntot=abs(nspn*nseg);
+
+	if(isn*ntot == 0){
+		sprintf(errstr,"zero in FFT parameters %d %d %d %d",nseg, n, nspn, isn);
+		return(DATA_ERROR);
+	}
+	for (m=0; !(k%16); nfac[++m]=4,k/=16);
+	for (j=3,jj=9; jj<=k; j+=2,jj=j*j)
+		for (; !(k%jj); nfac[++m]=j,k/=jj);
+
+      	if (k<=4){
+	      	kt = m;
+	      	nfac[m+1] = k;
+	      	if(k != 1) 
+			m++;
+	}
+	else{
+		if(k%4==0){
+		nfac[++m]=2;
+		k/=4;
+		}
+
+	 	kt = m;
+	       	maxp = max((kt+kt+2),(k-1));
+		for(j=2; j<=k; j=1+((j+1)/2)*2)
+			if(k%j==0){
+				nfac[++m]=j;
+				k/=j;
+			}
+	}
+	if(m <= kt+1) 
+		maxp = m + kt + 1;
+      	if(m+kt > 15) {
+			sprintf(errstr,"FFT parameter n has more than 15 factors : %d", n);
+	    	return(DATA_ERROR);
+	}
+      	if(kt!=0){
+	      	j = kt;
+		while(j)
+			nfac[++m]=nfac[j--];
+	}
+	maxf = nfac[m-kt];
+      	if(kt > 0) 
+		maxf = max(nfac[kt],maxf);
+
+/*  allocate workspace - assume no errors! */
+	at = (float *) calloc(maxf,sizeof(float));
+	ck = (float *) calloc(maxf,sizeof(float));
+	bt = (float *) calloc(maxf,sizeof(float));
+	sk = (float *) calloc(maxf,sizeof(float));
+	np = (int *) calloc(maxp,sizeof(int));
+
+/* decrement pointers to allow FORTRAN type usage in fftmx */
+	at--;	bt--;	ck--;	sk--;	np--;
+
+/* call fft driver */
+
+	if((exit_status = fftmx(a,b,ntot,nf,nspn,isn,m,&kt,at,ck,bt,sk,np,nfac))<0)
+		return(exit_status);
+
+/* restore pointers before releasing */
+	at++;	bt++;	ck++;	sk++;	np++;
+
+/* release working storage before returning - assume no problems */
+	(void) free(at);
+	(void) free(sk);
+	(void) free(bt);
+	(void) free(ck);
+	(void) free(np);
+    return(FINISHED);
+}
+
+/*
+ *-----------------------------------------------------------------------
+ * subroutine:  fftmx
+ * called by subroutine 'fft' to compute mixed-radix fourier transform
+ *-----------------------------------------------------------------------
+ */
+int fftmx(float *a,float *b,int ntot,int n,int nspan,int isn,int m,int *kt,
+			float *at,float *ck,float *bt,float *sk,int *np,int nfac[])
+{	
+	int	i,inc,
+		j,jc,jf, jj,
+		k, k1, k2, k3=0, k4,
+		kk,klim,ks,kspan, kspnn,
+		lim,
+		maxf,mm,
+		nn,nt;
+	double  aa, aj, ajm, ajp, ak, akm, akp,
+		bb, bj, bjm, bjp, bk, bkm, bkp,
+		c1, c2=0.0, c3=0.0, c72, cd,
+		dr,
+		rad, 
+		sd, s1, s2=0.0, s3=0.0, s72, s120;
+
+	double	xx;	/****** ADDED APRIL 1991 *********/
+	inc=abs(isn);
+	nt = inc*ntot;
+      	ks = inc*nspan;
+/******************* REPLACED MARCH 29: ***********************
+					rad = atan((double)1.0);
+**************************************************************/
+	rad = 0.785398163397448278900;
+/******************* REPLACED MARCH 29: ***********************
+			      		s72 = rad/0.625;
+			      		c72 = cos(s72);
+				      	s72 = sin(s72);
+**************************************************************/
+	c72 = 0.309016994374947451270;
+	s72 = 0.951056516295153531190;
+/******************* REPLACED MARCH 29: ***********************
+			      		s120 = sqrt((double)0.75);
+**************************************************************/
+      	s120 = 0.866025403784438707600;
+
+/* scale by 1/n for isn > 0 ( reverse transform ) */
+
+      	if (isn < 0){
+	      	s72 = -s72;
+	      	s120 = -s120;
+	      	rad = -rad;}
+	else{	ak = 1.0/(double)n;
+		for(j=1; j<=nt;j += inc){
+	        	a[j] = (float)(a[j] * ak);
+	        	b[j] = (float)(b[j] * ak);
+		}
+	}
+	kspan = ks;
+      	nn = nt - inc;
+      	jc = ks/n;
+
+/* sin, cos values are re-initialized each lim steps  */
+
+      	lim = 32;
+      	klim = lim * jc;
+      	i = 0;
+      	jf = 0;
+      	maxf = m - (*kt);
+      	maxf = nfac[maxf];
+      	if((*kt) > 0) 
+		maxf = max(nfac[*kt],maxf);
+
+/*
+ * compute fourier transform
+ */
+
+lbl40:
+	dr = (8.0 * (double)jc)/((double)kspan);
+/*************************** APRIL 1991 POW & POW2 not WORKING.. REPLACE *******
+	  	    cd = 2.0 * (pow2 ( sin((double)0.5 * dr * rad)) );
+*******************************************************************************/
+	xx =  sin((double)0.5 * dr * rad);
+      	cd = 2.0 * xx * xx;
+      	sd = sin(dr * rad);
+      	kk = 1;
+      	if(nfac[++i]!=2) goto lbl110;
+/*
+ * transform for factor of 2 (including rotation factor)
+ */
+      	kspan /= 2;
+      	k1 = kspan + 2;
+		do{	do{	k2 = kk + kspan;
+		      	ak = a[k2];
+		      	bk = b[k2];
+		      	a[k2] = (float)((a[kk]) - ak);
+		      	b[k2] = (float)((b[kk]) - bk);
+		      	a[kk] = (float)((a[kk]) + ak);
+		      	b[kk] = (float)((b[kk]) + bk);
+		      	kk = k2 + kspan;
+		} while(kk <= nn);
+	      	kk -= nn;
+	}while(kk <= jc);
+      	if(kk > kspan) goto lbl350;
+lbl60:  c1 = 1.0 - cd;
+      	s1 = sd;
+      	mm = min((k1/2),klim);
+      	goto lbl80;
+lbl70:	ak = c1 - ((cd*c1)+(sd*s1));
+      	s1 = ((sd*c1)-(cd*s1)) + s1;
+      	c1 = ak;
+lbl80:	do{	do{	k2 = kk + kspan;
+		      	ak = a[kk] - a[k2];
+		      	bk = b[kk] - b[k2];
+		      	a[kk] = a[kk] + a[k2];
+		      	b[kk] = b[kk] + b[k2];
+		      	a[k2] = (float)((c1 * ak) - (s1 * bk));
+		      	b[k2] = (float)((s1 * ak) + (c1 * bk));
+		      	kk = k2 + kspan;
+		}while(kk < nt);
+	      	k2 = kk - nt;
+	      	c1 = -c1;
+	      	kk = k1 - k2;
+	}while(kk > k2);
+      	kk += jc;
+      	if(kk <= mm) goto lbl70;
+      	if(kk < k2)  goto lbl90;
+      	k1 += (inc + inc);
+      	kk = ((k1-kspan)/2) + jc;
+      	if(kk <= (jc+jc)) goto lbl60;
+      	goto lbl40;
+lbl90: 	s1 = ((double)((kk-1)/jc)) * dr * rad;
+      	c1 = cos(s1);
+      	s1 = sin(s1);
+      	mm = min( k1/2, mm+klim);
+      	goto lbl80;
+/*
+ * transform for factor of 3 (optional code)
+ */
+
+
+lbl100:	k1 = kk + kspan;
+	k2 = k1 + kspan;
+	ak = a[kk];
+	bk = b[kk];
+      	aj = a[k1] + a[k2];
+      	bj = b[k1] + b[k2];
+      	a[kk] = (float)(ak + aj);
+      	b[kk] = (float)(bk + bj);
+      	ak += (-0.5 * aj);
+      	bk += (-0.5 * bj);
+      	aj = (a[k1] - a[k2]) * s120;
+      	bj = (b[k1] - b[k2]) * s120;
+      	a[k1] = (float)(ak - bj);
+      	b[k1] = (float)(bk + aj);
+      	a[k2] = (float)(ak + bj);
+      	b[k2] = (float)(bk - aj);
+      	kk = k2 + kspan;
+      	if(kk < nn)     goto lbl100;
+      	kk -= nn;
+      	if(kk <= kspan) goto lbl100;
+      	goto lbl290;
+
+/*
+ * transform for factor of 4
+ */
+
+lbl110:	if(nfac[i] != 4) goto lbl230;
+      	kspnn = kspan;
+      	kspan = kspan/4;
+lbl120:	c1 = 1.0;
+      	s1 = 0;
+      	mm = min( kspan, klim);
+      	goto lbl150;
+lbl130:	c2 = c1 - ((cd*c1)+(sd*s1));
+      	s1 = ((sd*c1)-(cd*s1)) + s1;
+/*
+ * the following three statements compensate for truncation
+ * error.  if rounded arithmetic is used, substitute
+ * c1=c2
+ *
+ * c1 = (0.5/(pow2(c2)+pow2(s1))) + 0.5;
+ * s1 = c1*s1;
+ * c1 = c1*c2;
+ */
+      	c1 = c2;
+lbl140:	c2 = (c1 * c1) - (s1 * s1);
+      	s2 = c1 * s1 * 2.0;
+      	c3 = (c2 * c1) - (s2 * s1);
+      	s3 = (c2 * s1) + (s2 * c1);
+lbl150:	k1 = kk + kspan;
+      	k2 = k1 + kspan;
+      	k3 = k2 + kspan;
+      	akp = a[kk] + a[k2];
+      	akm = a[kk] - a[k2];
+      	ajp = a[k1] + a[k3];
+      	ajm = a[k1] - a[k3];
+      	a[kk] = (float)(akp + ajp);
+       	ajp = akp - ajp;
+      	bkp = b[kk] + b[k2];
+      	bkm = b[kk] - b[k2];
+      	bjp = b[k1] + b[k3];
+      	bjm = b[k1] - b[k3];
+      	b[kk] = (float)(bkp + bjp);
+      	bjp = (float)(bkp - bjp);
+      	if(isn < 0) goto lbl180;
+      	akp = akm - bjm;
+      	akm = akm + bjm;
+      	bkp = bkm + ajm;
+      	bkm = bkm - ajm;
+      	if(s1 == 0.0) goto lbl190;
+lbl160:	a[k1] = (float)((akp*c1) - (bkp*s1));
+      	b[k1] = (float)((akp*s1) + (bkp*c1));
+      	a[k2] = (float)((ajp*c2) - (bjp*s2));
+      	b[k2] = (float)((ajp*s2) + (bjp*c2));
+      	a[k3] = (float)((akm*c3) - (bkm*s3));
+      	b[k3] = (float)((akm*s3) + (bkm*c3));
+      	kk = k3 + kspan;
+      	if(kk <= nt)   goto lbl150;
+lbl170: kk -= (nt - jc);
+      	if(kk <= mm)   goto lbl130;
+      	if(kk < kspan) goto lbl200;
+      	kk -= (kspan - inc);
+      	if(kk <= jc)   goto lbl120;
+      	if(kspan==jc)  goto lbl350;
+      	goto lbl40;
+lbl180:	akp = akm + bjm;
+      	akm = akm - bjm;
+      	bkp = bkm - ajm;
+      	bkm = bkm + ajm;
+      	if(s1 != 0.0)  goto lbl160;
+lbl190:	a[k1] = (float)akp;
+      	b[k1] = (float)bkp;
+      	a[k2] = (float)ajp;
+      	b[k2] = (float)bjp;
+      	a[k3] = (float)akm;
+      	b[k3] = (float)bkm;
+      	kk = k3 + kspan;
+      	if(kk <= nt) goto lbl150;
+      	goto lbl170;
+lbl200: s1 = ((double)((kk-1)/jc)) * dr * rad;
+      	c1 = cos(s1);
+      	s1 = sin(s1);
+      	mm = min( kspan, mm+klim);
+      	goto lbl140;
+
+/*
+ * transform for factor of 5 (optional code)
+ */
+
+lbl210:	c2 = (c72*c72) - (s72*s72);
+      	s2 = 2.0 * c72 * s72;
+lbl220:	k1 = kk + kspan;
+      	k2 = k1 + kspan;
+      	k3 = k2 + kspan;
+      	k4 = k3 + kspan;
+      	akp = a[k1] + a[k4];
+      	akm = a[k1] - a[k4];
+      	bkp = b[k1] + b[k4];
+      	bkm = b[k1] - b[k4];
+      	ajp = a[k2] + a[k3];
+      	ajm = a[k2] - a[k3];
+      	bjp = b[k2] + b[k3];
+      	bjm = b[k2] - b[k3];
+      	aa = a[kk];
+      	bb = b[kk];
+      	a[kk] = (float)(aa + akp + ajp);
+      	b[kk] = (float)(bb + bkp + bjp);
+      	ak = (akp*c72) + (ajp*c2) + aa;
+      	bk = (bkp*c72) + (bjp*c2) + bb;
+      	aj = (akm*s72) + (ajm*s2);
+      	bj = (bkm*s72) + (bjm*s2);
+      	a[k1] = (float)(ak - bj);
+      	a[k4] = (float)(ak + bj);
+      	b[k1] = (float)(bk + aj);
+      	b[k4] = (float)(bk - aj);
+      	ak = (akp*c2) + (ajp*c72) + aa;
+      	bk = (bkp*c2) + (bjp*c72) + bb;
+      	aj = (akm*s2) - (ajm*s72);
+	bj = (bkm*s2) - (bjm*s72);
+	a[k2] = (float)(ak - bj);
+      	a[k3] = (float)(ak + bj);
+      	b[k2] = (float)(bk + aj);
+      	b[k3] = (float)(bk - aj);
+      	kk = k4 + kspan;
+      	if(kk < nn)     goto lbl220;
+      	kk -= nn;
+      	if(kk <= kspan) goto lbl220;
+      	goto lbl290;
+
+/*
+ * transform for odd factors
+ */
+
+lbl230:	k = nfac[i];
+	kspnn = kspan;
+	kspan /= k;
+	if(k==3)   goto lbl100;
+	if(k==5)   goto lbl210;
+	if(k==jf)  goto lbl250;
+      	jf = k;
+      	s1 = rad/(((double)(k))/8.0);
+      	c1 = cos(s1);
+      	s1 = sin(s1);
+      	ck[jf] = 1.0f;
+	sk[jf] = 0.0f;
+	for(j=1; j<k ; j++){
+		ck[j] = (float)((ck[k])*c1 + (sk[k])*s1);
+	      	sk[j] = (float)((ck[k])*s1 - (sk[k])*c1);
+	      	k--;
+	      	ck[k] = ck[j];
+	      	sk[k] = -(sk[j]);
+	}
+lbl250:	k1 = kk;
+      	k2 = kk + kspnn;
+	aa = a[kk];
+	bb = b[kk];
+      	ak = aa;
+      	bk = bb;
+      	j = 1;
+      	k1 += kspan;
+		do{	k2 -= kspan;
+	      	j++;
+	      	at[j] = a[k1] + a[k2];
+	      	ak = at[j] + ak;	
+	      	bt[j] = b[k1] + b[k2];
+	      	bk = bt[j] + bk;	
+	      	j++;
+	      	at[j] = a[k1] - a[k2];
+	      	bt[j] = b[k1] - b[k2];
+	      	k1 += kspan;
+	}while(k1 < k2);
+      	a[kk] = (float)ak;
+      	b[kk] = (float)bk;
+      	k1 = kk;
+      	k2 = kk + kspnn;
+      	j = 1;
+lbl270:	k1 += kspan;
+      	k2 -= kspan;
+      	jj = j;
+      	ak = aa;
+      	bk = bb;
+      	aj = 0.0;
+      	bj = 0.0;
+      	k = 1;
+		do{	k++;
+	      	ak = (at[k] * ck[jj]) + ak;
+	      	bk = (bt[k] * ck[jj]) + bk;	
+	      	k++;
+	      	aj = (at[k] * sk[jj]) + aj;
+	      	bj = (bt[k] * sk[jj]) + bj;
+	      	jj += j;
+	      	if (jj > jf) 
+			jj -= jf;
+	}while(k < jf);
+      	k = jf - j;
+      	a[k1] = (float)(ak - bj);
+      	b[k1] = (float)(bk + aj);
+      	a[k2] = (float)(ak + bj);
+      	b[k2] = (float)(bk - aj);
+      	j++;
+      	if(j < k)     goto lbl270;
+      	kk += kspnn;
+      	if(kk <= nn)  goto lbl250;
+      	kk -= nn;
+      	if(kk<=kspan) goto lbl250;
+
+/*
+ * multiply by rotation factor (except for factors of 2 and 4)
+ */
+
+lbl290:	if(i==m) goto lbl350;
+      	kk = jc + 1;
+lbl300:	c2 = 1.0 - cd;
+      	s1 = sd;
+      	mm = min( kspan, klim);
+      	goto lbl320;
+lbl310:	c2 = c1 - ((cd*c1) + (sd*s1));
+      	s1 = s1 + ((sd*c1) - (cd*s1));
+lbl320:	c1 = c2;
+      	s2 = s1;
+      	kk += kspan;
+lbl330:	ak = a[kk];
+      	a[kk] = (float)((c2*ak) - (s2 * b[kk]));
+      	b[kk] = (float)((s2*ak) + (c2 * b[kk]));
+      	kk += kspnn;
+      	if(kk <= nt) goto lbl330;
+      	ak = s1*s2;
+      	s2 = (s1*c2) + (c1*s2);
+      	c2 = (c1*c2) - ak;
+      	kk -= (nt - kspan);
+     	if(kk <= kspnn) goto lbl330;
+      	kk -= (kspnn - jc);
+      	if(kk <= mm)   goto lbl310;
+      	if(kk < kspan) goto lbl340;
+      	kk -= (kspan - jc - inc);
+      	if(kk <= (jc+jc)) goto lbl300;
+      	goto lbl40;
+lbl340:	s1 = ((double)((kk-1)/jc)) * dr * rad;
+      	c2 = cos(s1);
+      	s1 = sin(s1);
+     	mm = min( kspan, mm+klim);
+      	goto lbl320;
+
+/*
+ * permute the results to normal order---done in two stages
+ * permutation for square factors of n
+ */
+
+lbl350:	np[1] = ks;
+      	if (!(*kt)) goto lbl440;
+      	k = *kt + *kt + 1;
+      	if(m < k) 
+		k--;
+	np[k+1] = jc;
+		for(j=1; j < k; j++,k--){
+		np[j+1] = np[j] / nfac[j];
+	      	np[k] = np[k+1] * nfac[j];
+	}
+      	k3 = np[k+1];
+      	kspan = np[2];
+      	kk = jc + 1;
+      	k2 = kspan + 1;
+      	j = 1;
+      	if(n != ntot) goto lbl400;
+/*
+ * permutation for single-variate transform (optional code)
+ */
+lbl370:	do{	ak = a[kk];
+	      	a[kk] = a[k2];
+	      	a[k2] = (float)ak;
+	      	bk = b[kk];
+	      	b[kk] = b[k2];
+	      	b[k2] = (float)bk;
+	      	kk += inc;
+	      	k2 += kspan;
+	}while(k2 < ks);
+lbl380:	do{	k2 -= np[j++];
+	      	k2 += np[j+1];
+	}while(k2 > np[j]);
+      	j = 1;
+lbl390:	if(kk < k2){
+		goto lbl370;
+	}
+      	kk += inc;
+      	k2 += kspan;
+      	if(k2 < ks) goto lbl390;
+      	if(kk < ks) goto lbl380;
+      	jc = k3;
+      	goto lbl440;
+/*
+ * permutation for multivariate transform
+ */
+lbl400:	do{	do{	k = kk + jc;
+				do{	ak = a[kk];
+			      	a[kk] = a[k2];
+			      	a[k2] = (float)ak;
+			      	bk = b[kk];
+			      	b[kk] = b[k2];
+			      	b[k2] = (float)bk;
+			      	kk += inc;
+			      	k2 += inc;
+			}while(kk < k);
+		      	kk += (ks - jc);
+		      	k2 += (ks - jc);
+		}while(kk < nt);
+	      	k2 -= (nt - kspan);
+	      	kk -= (nt - jc);
+	}while(k2 < ks);
+lbl420:	do{	k2 -= np[j++];
+	      	k2 += np[j+1];
+	}while(k2 > np[j]);
+      	j = 1;
+lbl430:	if(kk < k2) 	 goto lbl400;
+      	kk += jc;
+      	k2 += kspan;
+      	if(k2 < ks)      goto lbl430;
+      	if(kk < ks)      goto lbl420;
+      	jc = k3;
+lbl440:	if((2*(*kt))+1 >= m)
+		return(FINISHED);
+
+      	kspnn = *(np + *(kt) + 1);
+      	j = m - *kt;		
+      	nfac[j+1] = 1;
+lbl450:	nfac[j] = nfac[j] * nfac[j+1];
+      	j--;
+      	if(j != *kt) goto lbl450;
+      	*kt = *(kt) + 1;
+      	nn = nfac[*kt] - 1;
+      	jj = 0;
+      	j = 0;
+      	goto lbl480;
+lbl460:	jj -= k2;
+      	k2 = kk;
+      	kk = nfac[++k];
+lbl470:	jj += kk;
+      	if(jj >= k2) goto lbl460;
+      	np[j] = jj;
+lbl480:	k2 = nfac[*kt];
+      	k = *kt + 1;	
+      	kk = nfac[k];
+      	j++;
+      	if(j <= nn) goto lbl470;
+/* Determine permutation cycles of length greater than 1 */
+      	j = 0;
+      	goto lbl500;
+lbl490:	k = kk;
+     	kk = np[k];	
+      	np[k] = -kk;	
+      	if(kk != j) goto lbl490;
+      	k3 = kk;
+lbl500:	kk = np[++j];	
+      	if(kk < 0)  goto lbl500;
+      	if(kk != j) goto lbl490;
+      	np[j] = -j;
+      	if(j != nn) goto lbl500;
+      	maxf *= inc;
+/* Perform reordering following permutation cycles */
+      	goto lbl570;
+lbl510:	j--;
+      	if (np[j] < 0) goto lbl510;
+      	jj = jc;
+lbl520:	kspan = jj;
+      	if(jj > maxf) 
+		kspan = maxf;
+      	jj -= kspan;
+      	k = np[j];	
+      	kk = (jc*k) + i + jj;
+      	k1 = kk + kspan;
+      	k2 = 0;
+lbl530:	k2++;
+      	at[k2] = a[k1];
+      	bt[k2] = b[k1];
+      	k1 -= inc;
+      	if(k1 != kk) goto lbl530;
+lbl540:	k1 = kk + kspan;
+      	k2 = k1 - (jc * (k + np[k]));
+      	k = -(np[k]);
+lbl550:	a[k1] = a[k2];
+      	b[k1] = b[k2];
+      	k1 -= inc;
+      	k2 -= inc;
+      	if(k1 != kk) goto lbl550;
+      	kk = k2;
+      	if(k != j)   goto lbl540;
+      	k1 = kk + kspan;
+      	k2 = 0;
+lbl560:	k2++;
+      	a[k1] = at[k2];
+      	b[k1] = bt[k2];
+      	k1 -= inc;
+      	if(k1 != kk) goto lbl560;
+      	if(jj)       goto lbl520;
+      	if(j  != 1)  goto lbl510;
+lbl570:	j = k3 + 1;
+      	nt -= kspnn;
+      	i = nt - inc + 1;
+      	if(nt >= 0)  goto lbl510;
+      	return(FINISHED);; 
+}
+
+
+/*
+ *-----------------------------------------------------------------------
+ * subroutine:  reals
+ * used with 'fft' to compute fourier transform or inverse for real data
+ *-----------------------------------------------------------------------
+ *	this is the call from C:
+ *		reals_(anal,banal,N2,mtwo);
+ *	which has been changed from CARL call
+ *		reals_(anal,banal,&N2,&mtwo);
+ */
+
+int reals_(float *a, float *b, int n, int isn)
+
+			/* a refers to an array of floats 'anal'   */
+			/* b refers to an array of floats 'banal'  */
+/* See IEEE book for a long comment here on usage */
+
+{	int	inc,
+		j,
+		k,
+		lim,
+		mm,ml,
+		nf,nk,nh;
+ 
+	double	aa,ab,
+		ba,bb,
+		cd,cn,
+		dr,
+		em,
+		rad,re,
+		sd,sn;
+	double	xx;	/******* ADDED APRIL 1991 ******/
+/* adjust  input array pointers (called from C) */
+	a--;	b--;
+	inc=abs(isn);
+	nf=abs(n);
+      	if(nf*isn==0){
+			sprintf(errstr,"zero in reals parameters in FFT : %d : %d ",n,isn);
+	       	return(DATA_ERROR);;
+		}
+	 	nk = (nf*inc) + 2;
+      	nh = nk/2;
+/*****************************
+    	rad  = atan((double)1.0);
+******************************/
+	rad = 0.785398163397448278900;
+      	dr = -4.0/(double)(nf);
+/********************************** POW2 REMOVED APRIL 1991 *****************
+			      	cd = 2.0 * (pow2(sin((double)0.5 * dr * rad)));
+*****************************************************************************/
+	xx = sin((double)0.5 * dr * rad);
+      	cd = 2.0 * xx * xx;
+      	sd = sin(dr * rad);
+/*
+ * sin,cos values are re-initialized each lim steps
+ */
+      	lim = 32;
+      	mm = lim;
+      	ml = 0;
+      	sn = 0.0;
+	if(isn<0){
+		cn = 1.0;
+		a[nk-1] = a[1];
+		b[nk-1] = b[1]; }
+	else {
+		cn = -1.0;
+		sd = -sd;
+	}
+	 	for(j=1;j<=nh;j+=inc)	{
+        	k = nk - j;
+        	aa = a[j] + a[k];
+        	ab = a[j] - a[k];
+        	ba = b[j] + b[k];
+        	bb = b[j] - b[k];
+        	re = (cn*ba) + (sn*ab);
+        	em = (sn*ba) - (cn*ab);
+        	b[k] = (float)((em-bb)*0.5);
+        	b[j] = (float)((em+bb)*0.5);
+        	a[k] = (float)((aa-re)*0.5);
+		a[j] = (float)((aa+re)*0.5);
+        	ml++;
+		if(ml!=mm){
+			aa = cn - ((cd*cn)+(sd*sn));
+			sn = ((sd*cn) - (cd*sn)) + sn;
+			cn = aa;}
+		else {
+			mm +=lim;
+			sn = ((float)ml) * dr * rad;
+			cn = cos(sn);
+			if(isn>0)
+				cn = -cn;
+			sn = sin(sn);
+		}
+	}
+	return(FINISHED);
+}

+ 825 - 0
dev/synth/pvoc_addon.c

@@ -0,0 +1,825 @@
+/*
+ * Copyright (c) 1983-2020 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 22/02/2018  replaced hamming with vonhann window for smooth frame transition. */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <structures.h>
+#include <globcon.h>
+#include <tkglobals.h>
+#include <pnames.h>
+#include <processno.h>
+#include <modeno.h>
+#include <logic.h>
+#include <cdpmain.h>
+#include <pvoc.h>
+#include <string.h>
+#include <sfsys.h>
+#include <pvoc.h>
+
+static int  outfloats(float *nextOut, float *maxsampl,float *minsample,int *num_overflows,int todo, dataptr dz);
+static int  pvoc_float_array(int nnn,float **ptr);
+static int  sndwrite_header(float R,dataptr dz);
+static void hamming(float *win,int winLen,int even);
+static void vonhann(float *win,int winLen,int even);
+static int  pvoc_time_display(int nI,unsigned int samps_so_far,int srate,int *samptime,dataptr dz);
+
+static void reset_file_params_for_analout(int orig_proctype,int orig_srate,
+            int orig_chans,int orig_stype,dataptr dz);
+
+/****************************** PVOC_OUT *************************
+ *  
+ *  1) This code assumes there is an output analysis file from a previous process.
+ *  2) It assumes that the NAME of that file (orig_outfilename) is NOT the name of the new file being created.
+ *      In fact its name have a HIGHER numeric index, so when it is deleted there are no gaps
+ *      in the numbering of VALID outfiles (which run from 0 upwards).
+ *  3) root_outfname is the base outfilename, without its numeric add-on
+ *     'jj' is the humeric extension which will be added to that root name.
+ *  4) any INPUT file(s) to previous process MUST BE CLOSED before calling this function
+ *  5) floats_out = number of float samples in analysis file
+ *  6) samps_so_far is counter of TOTAL floats written out to any output files so far,
+ *      and is accumulated to the write-count sent to the timer-display bar by PVOC.
+ *      It does not affect counters in writing of file data.
+ *      Time-display for the process containing this function should be calculated as fraction of dz->tempsize,
+ *      which itself must hold the total of ALL the samps written out to ALL the files over the whole process.
+ *  7) the original analysis file (input to this function) is closed AND DELETED by this process.
+ *  8) mxfft() must be included in compilation, for this to work.
+ */
+
+int pvoc_out
+(int floats_out,unsigned int *samps_so_far,char *orig_outfilename, char *root_outname, int jj, dataptr dz)
+{
+    int exit_status;
+    int orig_proctype, orig_chans, orig_stype;
+    int orig_srate;
+    int orig_infilecnt  = dz->infilecnt;
+    int len = strlen(orig_outfilename);
+    char filename[256];
+    int stype;
+    /*RWD 2004 */
+    char pfname[_MAX_PATH];
+    //Create enough space to remember filename
+    if(dz->wordstor == NULL) {
+        if((dz->wordstor = (char **)malloc(sizeof(char *)))==NULL)
+            return(MEMORY_ERROR);
+        dz->wordstor[0] = NULL;
+        if((dz->wordstor[0] = (char *)malloc((len + 1) * sizeof(char *)))==NULL)
+            return(MEMORY_ERROR);
+    } else {
+        if(strlen(dz->wordstor[0]) < (unsigned int)len) {
+            if((dz->wordstor[0] = (char *)realloc((char *)dz->wordstor[0],(len + 1) * sizeof(char *)))==NULL)
+                return(MEMORY_ERROR);
+        }
+    }
+    strcpy(dz->wordstor[0],orig_outfilename);   /* save name of file in dz->wordstor[0]: in this case, no malloc reqd */
+
+    strcpy(filename,root_outname);              /* create new outfilename, for sound output */
+//TW REVISION new protocol : always pass outfile extension to cmdline
+    insert_new_number_at_filename_end(filename,jj,0);
+    dz->infilecnt = 2;                      /* tell system we have 1 inputfile */
+    /*RWD Feb 2004 write full anal props so we can inspect etc */
+#ifdef _DEBUG
+    if(sndputprop(dz->ofd,"original sampsize", (char *)&(dz->outfile->origstype), sizeof(int)) < 0){
+            sprintf(errstr,"Failure to write original sample size. headwrite()\n");
+            return(PROGRAM_ERROR);
+        }
+        if(sndputprop(dz->ofd,"original sample rate", (char *)&(dz->outfile->origrate), sizeof(int)) < 0){
+            sprintf(errstr,"Failure to write original sample rate. headwrite()\n");
+            return(PROGRAM_ERROR);
+        }
+        if(sndputprop(dz->ofd,"arate",(char *)&(dz->outfile->arate),sizeof(float)) < 0){
+            sprintf(errstr,"Failed to write analysis sample rate. headwrite()\n");
+            return(PROGRAM_ERROR);
+        }
+        if(sndputprop(dz->ofd,"analwinlen",(char *)&(dz->outfile->Mlen),sizeof(int)) < 0){
+            sprintf(errstr,"Failure to write analysis window length. headwrite()\n");
+            return(PROGRAM_ERROR);
+        }
+        if(sndputprop(dz->ofd,"decfactor",(char *)&(dz->outfile->Dfac),sizeof(int)) < 0){
+            sprintf(errstr,"Failure to write decimation factor. headwrite()\n");
+            return(PROGRAM_ERROR);
+        }
+#endif  
+/* set output file as input file */
+    sndcloseEx(dz->ofd);
+    dz->ofd = -1;
+    if(dz->ifd == NULL)
+        allocate_filespace(dz);
+    if((dz->ifd[0] = sndopenEx(orig_outfilename,0,CDP_OPEN_RDONLY)) < 0) {
+        sprintf(errstr,"Cannot reopen temporary analysis file '%s' to generate sound data:%s\n", orig_outfilename,sferrstr());
+        return(SYSTEM_ERROR);
+    }
+    *samps_so_far += dz->total_samps_written;
+    reset_file_params_for_sndout(&orig_proctype,&orig_srate,&orig_chans,&orig_stype,dz);
+
+    if(dz->floatsam_output==1)
+        stype = SAMP_FLOAT;
+    else
+        stype = SAMP_SHORT;
+    dz->true_outfile_stype = stype;
+    if((dz->ofd = sndcreat_formatted(filename,-1,stype,
+            1,(int)round(dz->param[SS_SRATE]),CDP_CREATE_NORMAL)) < 0) {
+        sprintf(errstr,"Cannot open output intermediate soundfile %s\n", filename);
+        return(DATA_ERROR);
+    }
+    dz->total_samps_written = 0L;
+    dz->insams[0] = floats_out;
+    /*RWD need retval - may run out of memory! */
+
+    if((exit_status = pvoc_process_addon(*samps_so_far,dz)) < 0)
+//TW Bare messages break sound Loom messaging system
+        return exit_status;
+    samps_so_far += dz->total_samps_written;
+
+    /*RWD Feb 2004 */
+    if(dz->ifd[0] >= 0){
+        strcpy(pfname,snd_getfilename(dz->ifd[0]));
+        if(sndcloseEx(dz->ifd[0]) < 0) {
+            sprintf(errstr,"Can't close intermediate analfile %s\n",orig_outfilename);
+            return(SYSTEM_ERROR);
+        }
+    }
+    dz->ifd[0] = -1;
+    if(remove(/*orig_outfilename*/pfname)<0) {
+        fprintf(stdout,"WARNING: Can't remove temporary analysis file %s\n",/*orig_outfilename*/pfname);
+        fflush(stdout);
+    }
+    sndcloseEx(dz->ofd);
+    reset_file_params_for_analout(orig_proctype,orig_srate,orig_chans,orig_stype,dz);
+    dz->infilecnt    = orig_infilecnt;
+    return(FINISHED);
+}
+
+/****************************** HAMMING ******************************/
+#if 0
+void hamming(float *win,int winLen,int even)
+{
+    float Pi,ftmp;
+    int i;
+
+/***********************************************************
+                    Pi = (float)((double)4.*atan((double)1.));
+***********************************************************/
+    Pi = (float)PI;
+    ftmp = Pi/winLen;
+
+    if (even) {
+        for (i=0; i<winLen; i++)
+        *(win+i) = (float)((double).54 + (double).46*cos((double)(ftmp*((float)i+.5))));
+        *(win+winLen) = 0.0f;}
+    else{   *(win) = 1.0f;
+        for (i=1; i<=winLen; i++)
+        *(win+i) =(float)((double).54 + (double).46*cos((double)(ftmp*(float)i)));
+    }
+    return;
+}
+#endif
+/*RWD 22/03/18 maybe need to use this? */
+void vonhann(float *win,int winLen,int even)
+{
+    float Pi,ftmp;
+    int i;
+
+    Pi = (float)PI;
+    ftmp = Pi/winLen;
+
+    if (even) {
+        for (i=0; i<winLen; i++)
+            *(win+i) = (float)(.5 + .5 *cos(ftmp*((double)i+.5)));
+        *(win+winLen) = 0.0f;
+    }
+    else{    *(win) = 1.0f;
+        for (i=1; i<=winLen; i++)
+            *(win+i) =(float)(.5 + .5 *cos(ftmp*(double)i));
+    }
+}
+
+
+/****************************** FLOAT_ARRAY ******************************/
+
+int pvoc_float_array(int nnn,float **ptr)
+{   /* set up a floating point array length nnn. */
+    *ptr = (float *) calloc(nnn,sizeof(float));
+    if(*ptr==NULL){
+        sprintf(errstr,"pvoc: insufficient memory\n");
+        return(MEMORY_ERROR);
+    }
+    return(FINISHED);
+}
+
+/****************************** PVOC_PROCESS_ADDON ******************************/
+
+int pvoc_process_addon(unsigned int samps_so_far,dataptr dz)
+{
+    int exit_status;
+    int num_overflows = 0;
+    int samptime = SAMP_TIME_STEP;
+    float   *input,         /* pointer to start of input buffer */
+            *output,        /* pointer to start of output buffer */
+            *anal,          /* pointer to start of analysis buffer */
+            *syn,           /* pointer to start of synthesis buffer */
+//          *banal,         /* pointer to anal[1] (for FFT calls) */
+            *bsyn,          /* pointer to syn[1]  (for FFT calls) */
+//          *nextIn,        /* pointer to next empty word in input */
+            *nextOut,       /* pointer to next empty word in output */
+            *analWindow,    /* pointer to center of analysis window */
+            *synWindow,     /* pointer to center of synthesis window */
+            *maxAmp,        /* pointer to start of max amp buffer */
+            *avgAmp,        /* pointer to start of avg amp buffer */
+            *avgFrq,        /* pointer to start of avg frq buffer */
+            *env,           /* pointer to start of spectral envelope */
+            *i0,            /* pointer to amplitude channels */
+            *i1,            /* pointer to frequency channels */
+            *oldInPhase,    /* pointer to start of input phase buffer */
+            *oldOutPhase,   /* pointer to start of output phase buffer */
+            maxsample = 0.0, minsample = 0.0, biggest;
+
+    int     M = 0,          /* length of analWindow impulse response */
+            D = 0,          /* decimation factor */
+            I = 0,          /* interpolation factor (default will be I=D)*/
+            pvoc_chans = dz->infile->channels - 2,
+            analWinLen,     /* half-length of analysis window */
+            synWinLen;      /* half-length of synthesis window */
+
+    int outCount,       /* number of samples written to output */
+            ibuflen,        /* length of input buffer */
+            obuflen,        /* length of output buffer */
+            nI = 0,         /* current input (analysis) sample */
+            nO,             /* current output (synthesis) sample */
+            nMaxOut;        /* last output (synthesis) sample */
+    int isr,            /* sampling rate */
+            endsamp = VERY_BIG_INT;
+
+    float   mag,            /* magnitude of analysis data */
+            phase,          /* phase of analysis data */
+            //RoverTwoPi,     /* R/D divided by 2*Pi */
+            TwoPioverR,     /* 2*Pi divided by R/I */
+            sum,            /* scale factor for renormalizing windows */
+            //rIn,            /* decimated sampling rate */
+            rOut,           /* pre-interpolated sampling rate */
+            R;              /* input sampling rate */
+
+    int     i,j,k,      /* index variables */
+            Dd,         /* number of new inputs to read (Dd <= D) */
+            Ii,         /* number of new outputs to write (Ii <= I) */
+            N2,         /* pvoc_chans/2 */
+            NO,         /* synthesis NO = pvoc_chans / P */
+            NO2,        /* NO/2 */
+            IO,         /* synthesis IO = I / P */
+            IOi,        /* synthesis IOi = Ii / P */
+            Mf = 0,     /* flag for even M */
+#ifdef SINGLE_SAMP
+            rv,         /* return value from fgetfloat */
+#endif
+            flag = 0;   /* end-of-input flag */
+    float   arate;      /* sample rate for header on stdout if -A */
+
+    /*RWD*/
+    float F = 0.0f;
+
+#if defined(__SC__) && defined(SOFT_FP)
+    extern int _8087;
+    _8087 = 0;
+#endif
+
+    {
+        char *mem;
+
+        if((mem = malloc(64*SECSIZE)) == 0
+//TW dz->snd_ifd no longer exists
+           /* RWD Nov 2011 not allowed to call sndsetbuf these days! */
+    /*  ||sndsetbuf(dz->ifd[0], mem, 64) < 0 */ ) {        /*RWD*/
+            sprintf(errstr, "pvoc: Can't set big input buffer\n");
+            return(MEMORY_ERROR);
+        }
+    }
+
+    isr      = dz->infile->origrate;
+    arate    = dz->infile->arate;
+    M        = dz->infile->Mlen;
+    D        = dz->infile->Dfac;
+    R        = ((float) D * arate);
+
+    if(flteq(R,0.0)) {
+        sprintf(errstr,"Problem: zero sampling rate\n");
+        return(DATA_ERROR);
+    }
+
+    N2 = pvoc_chans / 2;
+
+    F = /*(int)*/(R /(float)pvoc_chans);
+
+    Mf = 1 - M%2;
+
+    if (M < 7) {
+        fprintf(stdout,"WARNING: analWindow impulse response is too small\n");
+        fflush(stdout);
+    }
+    ibuflen = 4 * M;
+    obuflen = 4 * M;
+
+    I   = D;
+    NO  = pvoc_chans;   /* synthesis transform will be NO points */
+    NO2 = NO/2;
+    IO  = I;
+
+    if((exit_status = sndwrite_header(R,dz))<0)
+        return(exit_status);
+
+    /* set up analysis window: The window is assumed to be symmetric
+        with M total points.  After the initial memory allocation,
+        analWindow always points to the midpoint of the window
+        (or one half sample to the right, if M is even); analWinLen
+        is half the true window length (rounded down). Any low pass
+        window will work; a Hamming window is generally fine,
+        but a Kaiser is also available.  If the window duration is
+        longer than the transform (M > N), then the window is
+        multiplied by a sin(x)/x function to meet the condition:
+        analWindow[Ni] = 0 for i != 0.  In either case, the
+        window is renormalized so that the phase vocoder amplitude
+        estimates are properly scaled.  The maximum allowable
+        window duration is ibuflen/2. */
+
+    if((exit_status = pvoc_float_array(M+Mf,&analWindow))<0)
+        return(exit_status);
+    analWindow += (analWinLen = M/2);
+
+    //hamming(analWindow,analWinLen,Mf);
+    vonhann(analWindow,analWinLen,Mf);
+    
+    
+    for (i = 1; i <= analWinLen; i++)
+        *(analWindow - i) = *(analWindow + i - Mf);
+
+    if (M > pvoc_chans) {
+        if (Mf)
+        *analWindow *=(float)
+        ((double)pvoc_chans*sin((double)PI*.5/pvoc_chans)/(double)(PI*.5));
+        for (i = 1; i <= analWinLen; i++) 
+            *(analWindow + i) *=(float)
+            ((double)pvoc_chans * sin((double) (PI*(i+.5*Mf)/pvoc_chans)) / (PI*(i+.5*Mf)));  /*RWD*/
+        for (i = 1; i <= analWinLen; i++)
+            *(analWindow - i) = *(analWindow + i - Mf);
+    }
+
+    sum = 0.0f;
+    for (i = -analWinLen; i <= analWinLen; i++)
+        sum += *(analWindow + i);
+
+    sum = (float)(2.0/sum);     /*factor of 2 comes in later in trig identity*/
+
+    for (i = -analWinLen; i <= analWinLen; i++)
+        *(analWindow + i) *= sum;
+
+    /* set up synthesis window:  For the minimal mean-square-error
+        formulation (valid for N >= M), the synthesis window
+        is identical to the analysis window (except for a
+        scale factor), and both are even in length.  If N < M,
+        then an interpolating synthesis window is used. */
+
+    if((exit_status = pvoc_float_array(M+Mf,&synWindow))<0)
+        return(exit_status);
+    synWindow += (synWinLen = M/2);
+
+    if (M <= pvoc_chans){
+        //hamming(synWindow,synWinLen,Mf);
+        vonhann(synWindow,synWinLen,Mf);
+        for (i = 1; i <= synWinLen; i++)
+            *(synWindow - i) = *(synWindow + i - Mf);
+
+        for (i = -synWinLen; i <= synWinLen; i++)
+            *(synWindow + i) *= sum;
+
+        sum = 0.0f;
+        for (i = -synWinLen; i <= synWinLen; i+=I)
+            sum += *(synWindow + i) * *(synWindow + i);
+
+        sum = (float)(1.0/ sum);
+
+        for (i = -synWinLen; i <= synWinLen; i++)
+            *(synWindow + i) *= sum;
+    } else {
+        //hamming(synWindow,synWinLen,Mf);
+        vonhann(synWindow,synWinLen,Mf);
+        for (i = 1; i <= synWinLen; i++)
+            *(synWindow - i) = *(synWindow + i - Mf);
+
+        if (Mf)
+            *synWindow *= (float)((double)IO * sin((double) (PI*.5/IO)) / (double)(PI*.5));
+        for (i = 1; i <= synWinLen; i++) 
+            *(synWindow + i) *=(float)
+            ((double)IO * sin((double) (PI*(i+.5*Mf)/IO)) /(double) (PI*(i+.5*Mf)));
+        for (i = 1; i <= synWinLen; i++)
+            *(synWindow - i) = *(synWindow + i - Mf);
+
+        sum = (float)(1.0/sum);
+
+        for (i = -synWinLen; i <= synWinLen; i++)
+            *(synWindow + i) *= sum;
+    }
+
+    /* set up input buffer:  nextIn always points to the next empty
+        word in the input buffer (i.e., the sample following
+        sample number (n + analWinLen)).  If the buffer is full,
+        then nextIn jumps back to the beginning, and the old
+        values are written over. */
+
+    if((exit_status = pvoc_float_array(ibuflen,&input))<0)
+        return(exit_status);
+
+//  nextIn = input;
+
+    /* set up output buffer:  nextOut always points to the next word
+        to be shifted out.  The shift is simulated by writing the
+        value to the standard output and then setting that word
+        of the buffer to zero.  When nextOut reaches the end of
+        the buffer, it jumps back to the beginning.  */
+
+    if((exit_status = pvoc_float_array(obuflen,&output))<0)
+        return(exit_status);
+
+    nextOut = output;
+    /* set up analysis buffer for (N/2 + 1) channels: The input is real,
+        so the other channels are redundant. oldInPhase is used
+        in the conversion to remember the previous phase when
+        calculating phase difference between successive samples. */
+
+    if((exit_status = pvoc_float_array(pvoc_chans+2,&anal))<0)
+        return(exit_status);
+
+    if((exit_status = pvoc_float_array(N2+1,&oldInPhase))<0)
+        return(exit_status);
+    if((exit_status = pvoc_float_array(N2+1,&maxAmp))<0)
+        return(exit_status);
+    if((exit_status = pvoc_float_array(N2+1,&avgAmp))<0)
+        return(exit_status);
+    if((exit_status = pvoc_float_array(N2+1,&avgFrq))<0)
+        return(exit_status);
+    if((exit_status = pvoc_float_array(N2+1,&env))<0)
+        return(exit_status);
+
+    /* set up synthesis buffer for (pvoc_chans/2 + 1) channels: (This is included
+        only for clarity.)  oldOutPhase is used in the re-
+        conversion to accumulate angle differences (actually angle
+        difference per second). */
+
+    if((exit_status = pvoc_float_array(NO+2,&syn))<0)
+        return(exit_status);
+    bsyn = syn + 1;
+
+    if((exit_status = pvoc_float_array(NO2+1,&oldOutPhase))<0)
+        return(exit_status);
+
+    /* initialization: input time starts negative so that the rightmost
+        edge of the analysis filter just catches the first non-zero
+        input samples; output time is always T times input time. */
+
+    outCount = 0;
+    //rIn  = (float)(R/(float)D);
+    rOut = (float)(R/(float)I);
+    //RoverTwoPi = (float)(rIn/TWOPI);
+    TwoPioverR = (float)(TWOPI/rOut);
+    nI = -(analWinLen / D) * D; /* input time (in samples) */
+    nO = nI;                    /* output time (in samples) */
+    Dd = analWinLen + nI + 1;   /* number of new inputs to read */
+    Ii = 0;             /* number of new outputs to write */
+    IOi = 0;
+    flag = 1;
+
+    /* main loop:  If endsamp is not specified it is assumed to be very large
+        and then readjusted when fgetfloat detects the end of input. */
+
+    while(nI < (endsamp + analWinLen)){
+#ifdef SINGLE_SAMP
+        for (i = 0; i < pvoc_chans+2; i++){     /* synthesis only */
+            if ((rv = fgetfloat((anal+i),dz->ifd[0])) <= 0){
+                goto epilog;
+            }
+        }
+#else
+//TW snd_ibuf no longer exists
+        if((i = fgetfbufEx(anal, pvoc_chans+2, dz->ifd[0],0)) < 0) {       /*RWD*/
+            sfperror("pvoc: read error: ");
+            return(PROGRAM_ERROR);
+        }
+        if(i < pvoc_chans+2)
+            goto epilog;
+#endif
+
+    /* reconversion: The magnitude and angle-difference-per-second in syn
+        (assuming an intermediate sampling rate of rOut) are
+        converted to real and imaginary values and are returned in syn.
+        This automatically incorporates the proper phase scaling for
+        time modifications. */
+
+        if (NO <= pvoc_chans){
+            for (i = 0; i < NO+2; i++)
+                *(syn+i) = *(anal+i);
+        } else {
+            for (i = 0; i <= pvoc_chans+1; i++) 
+                *(syn+i) = *(anal+i);
+            for (i = pvoc_chans+2; i < NO+2; i++) 
+                *(syn+i) = 0.0f;
+        }
+        
+        for(i=0, i0=syn, i1=syn+1; i<= NO2; i++,i0+=2,i1+=2) {
+            mag = *i0;
+            *(oldOutPhase + i) += *i1 - ((float) i * F);
+            phase = *(oldOutPhase + i) * TwoPioverR;
+            *i0 = (float)((double)mag * cos((double)phase));
+            *i1 = (float)((double)mag * sin((double)phase));
+        }
+
+    /* synthesis: The synthesis subroutine uses the Weighted Overlap-Add
+        technique to reconstruct the time-domain signal.  The (pvoc_chans/2 + 1)
+        phase vocoder channel outputs at time n are inverse Fourier
+        transformed, windowed, and added into the output array.  The
+        subroutine thinks of output as a shift register in which 
+        locations are referenced modulo obuflen.  Therefore, the main
+        program must take care to zero each location which it "shifts"
+        out (to standard output). The subroutines reals and fft
+        together perform an efficient inverse FFT.  */
+
+        if((exit_status = reals_(syn,bsyn,NO2,2))<0)
+            return(exit_status);
+        if((exit_status = fft_(syn,bsyn,1,NO2,1,2))<0)
+            return(exit_status);
+
+        j = nO - synWinLen - 1;
+        while (j < 0)
+            j += obuflen;
+        j = j % obuflen;
+
+        k = nO - synWinLen - 1;
+        while (k < 0)
+            k += NO;
+        k = k % NO;
+
+        for (i = -synWinLen; i <= synWinLen; i++) { /*overlap-add*/
+            if (++j >= obuflen)
+                j -= obuflen;
+            if (++k >= NO)
+                k -= NO;
+            *(output + j) += *(syn + k) * *(synWindow + i);
+        }
+
+#ifdef SINGLE_SAMP
+        for (i = 0; i < IOi; i++) { /* shift out next IOi values */
+            fputfloat(nextOut,dz->ofd);
+            *(nextOut++) = 0.;
+            if (nextOut >= (output + obuflen))
+                nextOut -= obuflen;
+            outCount++;
+        }
+#else
+        for (i = 0; i < IOi;) { /* shift out next IOi values */
+            int j;
+            int todo = min(IOi-i, output+obuflen-nextOut);
+                if((exit_status = outfloats(nextOut,&maxsample,&minsample,&num_overflows,todo, dz))<0)
+                return(exit_status);
+            i += todo;
+            outCount += todo;
+            for(j = 0; j < todo; j++)
+                *nextOut++ = 0.0f;
+            if (nextOut >= (output + obuflen))
+                nextOut -= obuflen;
+        }
+#endif
+                    
+        if(flag                             /* flag means do this operation only once */
+        && (nI > 0) && (Dd < D)) {          /* EOF detected */
+            flag = 0;
+            endsamp = nI + analWinLen - (D - Dd);
+        }
+
+        nI += D;                /* increment time */
+        nO += IO;
+                                /* Dd = D except when the end of the sample stream intervenes */
+        Dd = min(D, max(0, D+endsamp-nI-analWinLen));
+
+        if (nO > (synWinLen + I))
+            Ii = I;
+        else if (nO > synWinLen)
+            Ii = nO - synWinLen;
+        else {
+            Ii = 0;
+            for (i=nO+synWinLen; i<obuflen; i++) {
+                if (i > 0)
+                    *(output+i) = 0.0f;
+            }
+        }
+        IOi = Ii;
+
+
+        if(nI > samptime && (exit_status = pvoc_time_display(nI,samps_so_far,isr,&samptime,dz))<0)
+            return(exit_status);
+    }   /* End of main while loop */
+
+    nMaxOut = endsamp;
+    while (outCount <= nMaxOut){
+#ifdef SINGLE_SAMP
+        outCount++;
+        fputfloat(nextOut++,dz->ofd);
+        if (nextOut >= (output + obuflen))
+            nextOut -= obuflen;
+#else
+        int todo = min(nMaxOut-outCount, output+obuflen-nextOut);
+        if(todo == 0)
+            break;
+        if((exit_status = outfloats(nextOut,&maxsample,&minsample,&num_overflows,todo, dz))<0)
+            return(exit_status);
+        outCount += todo;
+        nextOut += todo;
+        if (nextOut >= (output + obuflen))
+            nextOut -= obuflen;
+#endif
+    }
+    if((exit_status = pvoc_time_display((int)endsamp,samps_so_far,isr,&samptime,dz))<0)
+        return(exit_status);
+
+epilog:
+
+#ifndef NOOVERCHK
+    if(num_overflows > 0) {
+        biggest =  maxsample;
+        if(-minsample > maxsample)
+            biggest = -minsample;
+        fprintf(stdout, "WARNING: %d samples overflowed, and were clipped\n",num_overflows);
+        fprintf(stdout, "WARNING: maximum sample was %f  :  minimum sample was %f\n",maxsample,minsample);
+        fprintf(stdout, "WARNING: You should reduce source level to avoid clipping: use gain of <= %lf\n",1.0/biggest);
+        fflush(stdout);
+    }
+
+#endif
+    return(FINISHED);
+}
+
+/*MCA
+ *  Convert floats -> shorts explicitly, since we are compiled with
+ *  hardware FP(probably), and the sound filing system is not!
+ *  (even without this, it should be more efficient!)
+ */
+//TW NO CONVERSION TO FLOATS NEEDED 2002
+int outfloats(float *nextOut,float *maxsample,float *minsample,int *num_overflows,int todo, dataptr dz)
+{
+    static float *sbuf = 0;
+    static int sblen = 0;
+    float *sp;
+    int cnt;
+    float val;
+
+    if(sblen < todo) {
+        if(sbuf != 0)
+            free(sbuf);
+        if((sbuf = (float *)malloc(todo*sizeof(float))) == 0) {
+            sprintf(errstr, "pvoc: can't allocate output buffer\n");
+            return(MEMORY_ERROR);
+        }
+        sblen = todo;
+    }
+
+    sp = sbuf;
+#ifdef NOOVERCHK
+    for(cnt = 0; cnt < todo; cnt++)
+        *sp++ = *nextOut++;
+#else
+    for(cnt = 0; cnt < todo; cnt++) {
+        val = *nextOut++;
+        if(val >= 1.0 || val <= -1.0) {
+            (*num_overflows)++;
+            if(val > 0.0f) {
+                if(val > *maxsample)
+                    *maxsample = val;
+                val = 1.0f;
+            }
+            if(val < 0.0f) {
+                if(val < *minsample)
+                    *minsample = val;
+                val = -1.0f;
+            }
+        }
+        *sp++ = val;
+    }
+#endif
+
+//  if(fputfbufEx(sbuf, todo, ofd) < todo) {
+    if(todo > 0) {
+        if(write_samps(sbuf, todo, dz) < 0) {
+            sfperror("pvoc: write error");
+            return(SYSTEM_ERROR);;
+        }
+    }
+//TW UPDATE
+    return FINISHED;
+}
+
+/************************************ SNDWRITE_HEADER ************************************/
+ /*RWD changed dz->ofd to to dz->ofd */
+int sndwrite_header(float R,dataptr dz)
+{
+    int Nchans = 1;
+    int isr = (int)R;
+    if(sndputprop(dz->ofd,"sample rate",(char *)&isr,sizeof(int)) < 0 )
+        fprintf(stdout,"WARNING: failed to write sample rate\n");
+    if(sndputprop(dz->ofd,"channels",(char *)&Nchans,sizeof(int)) < 0 )
+        fprintf(stdout,"WARNING: failed to write channel data\n");
+    fflush(stdout);
+    return(FINISHED);
+}
+
+/*********************************** PVOC_TIME_DISPLAY ***********************************/
+
+int pvoc_time_display(int nI,unsigned int samps_so_far,int srate,int *samptime,dataptr dz)
+{
+    int true_chans, true_srate;
+    true_chans = dz->infile->channels;
+    true_srate = dz->infile->srate;
+    dz->infile->channels = 1;
+    dz->infile->srate    = srate;
+    display_virtual_time(nI + samps_so_far,dz); 
+    dz->infile->channels = true_chans;
+    dz->infile->srate    = true_srate;
+    *samptime += SAMP_TIME_STEP;
+    return(FINISHED);
+}
+
+/*void get_name_of_intermediate_file(char *filename,char *nufilename)
+{
+    char temp[256];
+    char *p;
+    strcpy(nufilename,filename);
+    p = nufilename + strlen(nufilename) - 1;
+    while(p > nufilename) {
+        if(*p == '/' || *p == '\\' || *p == ':') {
+            p = nufilename;
+            break;
+        }
+        if(*p == '.') {
+            p--;
+            c = *p;
+            c += 2;
+            *p = c;
+            return;
+        }
+        p--;
+    }
+    if(p == nufilename) {
+        p = nufilename + strlen(nufilename) - 1;
+        c = *p;
+        c += 2;
+        *p = c;
+    }
+}
+
+
+*/
+
+void reset_file_params_for_sndout
+(int *orig_proctype,int *orig_srate,int *orig_chans,int *orig_stype,dataptr dz) {
+    int stype;
+    if(dz->floatsam_output==1 )
+        stype= SAMP_FLOAT;
+    else
+        stype = SAMP_SHORT;
+    dz->true_outfile_stype = stype;
+    
+    *orig_proctype = dz->process_type;
+    *orig_srate    = dz->outfile->srate;
+    *orig_chans    = dz->outfile->channels;
+    *orig_stype   = dz->outfile->stype;
+    dz->process_type = UNEQUAL_SNDFILE;
+    dz->outfile->srate    = dz->infile->srate    = dz->iparam[SS_SRATE];
+    dz->outfile->channels = MONO;
+    dz->outfile->stype    = /*  dz->outfile->stype = */ stype;    /* RWD: should that be infile->stype? */
+}
+
+void reset_file_params_for_analout
+(int orig_proctype,int orig_srate,int orig_chans,int orig_stype,dataptr dz) {
+    dz->process_type = orig_proctype;
+    dz->outfile->srate    = dz->infile->srate    = orig_srate;
+    dz->outfile->channels = orig_chans;
+    dz->outfile->stype    = /* dz->outfile->stype = */ orig_stype;
+
+}

+ 997 - 0
dev/synth/wave.c

@@ -0,0 +1,997 @@
+/*
+ * 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 22/02/2018  changed sndfile interleave code to eliminate glitch on ch2
+   only suffix number to outfile name for sloom 
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <structures.h>
+#include <tkglobals.h>
+#include <globcon.h>
+#include <cdpmain.h>
+#include <synth.h>
+#include <processno.h>
+#include <modeno.h>
+#include <pnames.h>
+#include <flags.h>
+#include <arrays.h>
+#include <math.h>
+#include <logic.h>
+#include <speccon.h>
+#include <sfsys.h>
+#include <osbind.h>
+#include <string.h>			/*RWD*/
+//TW UPDATE
+#include <limits.h>
+#include <filetype.h>
+
+static int  gentable(int tabsize,dataptr dz);
+static int  gen_wave(int sampdur,double sr,dataptr dz);
+static int  gen_silence(int sampdur,dataptr dz);
+static int  gen_noise(int sampdur,double sr,dataptr dz);
+static int  update_wave_params(double *ampstep,double *frqstep,double *lastamp,double *lastfrq,double inverse_sr,
+			int *samptime, int *nextsamptime,int blokstep,dataptr dz);
+static double getval(double *tab,int i,double fracstep,double amp);
+static int advance_in_table(int *i,double convertor,double *step,double *fracstep,
+double *amp,double *frq,double dtabsize,double *ampstep,double *frqstep,int *samptime,int *nextsamptime,
+double *lastamp,double *lastfrq,double inverse_sr,int blokstep,dataptr dz);
+
+void set_band_limits(int clength,int *supertight, double *bwidth, int *minchan, int *centrchan,
+	double *hfbwidth, int *lo_n, int *hi_n, double *offset, double hfchwidth, dataptr dz);
+int do_stereo_specsynth(dataptr dz);
+//TW UPDATE
+static int gen_clicktrack(dataptr dz);
+static int gen_chord(int sampdur,dataptr dz);
+
+/******************************* DO_SYNTH ******************************/
+
+int do_synth(dataptr dz)
+{
+	int exit_status;
+	int sampdur = 0;
+	double sr = 0.0;
+
+//TW UPDATES
+	if(dz->process == CLICK)
+		dz->infile->channels = 1;
+	else {
+		dz->infile->channels = dz->iparam[SYN_CHANS];
+		dz->infile->srate    = dz->iparam[SYN_SRATE];
+		sr = (double)dz->infile->srate;
+		sampdur = round(sr * dz->param[SYN_DUR]) * dz->iparam[SYN_CHANS];
+		dz->tempsize = sampdur;
+	}
+	if(dz->floatsam_output)
+		dz->infile->stype = SAMP_FLOAT;
+	else
+		dz->infile->stype = SAMP_SHORT;
+
+	switch(dz->process) {
+	case(SYNTH_SIL):	return gen_silence(sampdur,dz);
+	case(SYNTH_NOISE):	return gen_noise(sampdur,sr,dz);
+//TW UPDATES
+	case(CLICK):		return gen_clicktrack(dz);
+ 	}
+	if((dz->parray[SYNTH_TAB] = (double *)malloc((dz->iparam[SYN_TABSIZE]+1) * sizeof(double)))==NULL) {
+		sprintf(errstr,"Insufficient memory for wave table.\n");
+		return(MEMORY_ERROR);
+	}
+	if(dz->process == MULTI_SYN)
+		dz->mode = 	WAVE_SINE;
+	if((exit_status = gentable(dz->iparam[SYN_TABSIZE],dz))<0)
+		return(exit_status);
+	if(dz->process == MULTI_SYN)
+		return gen_chord(sampdur,dz);
+	return gen_wave(sampdur,sr,dz);
+}
+
+/******************************* GENTABLE ******************************/
+
+int gentable(int tabsize,dataptr dz)
+{   
+	int n, m, k0, k1;
+	double minstep, step;
+	double *tab = dz->parray[SYNTH_TAB];
+	switch(dz->mode) {
+	case(WAVE_SINE):				
+		step = (2.0 * PI)/(double)tabsize;
+		for(n=0;n<tabsize;n++)
+			tab[n] = sin(step * (double)n) * F_MAXSAMP;
+		tab[tabsize] = 0.0;
+		break;
+	case(WAVE_SQUARE):				
+		k0 = tabsize/2;
+		for(n=0;n<k0;n++)
+			tab[n] = F_MAXSAMP;
+		for(n=k0;n<=tabsize;n++)
+			tab[n] = -F_MAXSAMP;
+		break;
+	case(WAVE_SAW):					
+		k0 = tabsize/4;
+		k1 = tabsize/2;
+		minstep = F_MAXSAMP/(double)k0;
+		tab[0] = 0.0;
+		for(n=1;n<=k0;n++)
+			tab[n] = tab[n-1] + minstep;
+		for(n=k0,m=k0-1;n<k1;n++,m--)
+			tab[n] = tab[m];
+		for(n=k1,m=0;n<tabsize;n++,m++)
+			tab[n] = -tab[m];
+		tab[n] = 0.0;
+		break;
+	case(WAVE_RAMP):					
+		k0 = tabsize/2;
+		minstep = F_MAXSAMP/(double)k0;
+		tab[0] = F_MAXSAMP;
+		for(n=1;n<k0;n++)
+			tab[n] = tab[n-1] - minstep;
+		tab[k0] = 0.0;
+		for(n=k0+1,m=k0-1;n<=tabsize;n++,m--)
+			tab[n] = -tab[m];
+		break;
+	default:
+		sprintf(errstr,"Unknown case in gentable()\n");
+		return(PROGRAM_ERROR);
+	}
+	return(FINISHED);
+}
+
+/****************************** GEN_WAVE *************************/
+
+int gen_wave(int sampdur,double sr,dataptr dz)
+{
+	int exit_status;
+	double inverse_sr = 1.0/sr;
+	double step;
+	double dtabsize = (double)dz->iparam[SYN_TABSIZE];
+	double convertor = dtabsize * inverse_sr;
+	int m, i, k;
+	int chans = dz->infile->channels;
+	double timestep = 10.0 * MS_TO_SECS, ampstep, frqstep, lastamp, lastfrq, amp, frq;
+	int blokstep   = round(timestep * sr);
+	int samptime = 0, nextsamptime = blokstep;
+	double *tab = dz->parray[SYNTH_TAB];
+	double fracstep = 0.0, val;
+	int do_start = 1;
+	int synth_splicelen = SYNTH_SPLICELEN * chans;
+	int total_samps = 0;
+	int startj = 0, endj = SYNTH_SPLICELEN;
+	int total_samps_left = sampdur;
+	int endsplicestart = sampdur - synth_splicelen;
+	int todo;
+	
+	step = 0.0;
+	i = 0;
+
+	if(sampdur < (synth_splicelen * 2) + chans) {
+		fprintf(stdout,"ERROR: Specified output duration is less then available splicing length.\n");
+		return(DATA_ERROR);
+	}
+
+	if((exit_status = read_values_from_all_existing_brktables(0.0,dz))<0)
+		return(exit_status);
+	if((exit_status = 
+	update_wave_params(&ampstep,&frqstep,&lastamp,&lastfrq,inverse_sr,&samptime,&nextsamptime,blokstep,dz))<0)
+		return(exit_status);
+	amp = lastamp;
+	frq = lastfrq;
+	while(total_samps_left > 0) {
+		if(total_samps_left/dz->buflen <= 0)
+			todo = total_samps_left;
+		else
+			todo = dz->buflen;
+		m = 0;
+		while(m < todo) {
+			val = getval(tab,i,fracstep,amp);
+			if(do_start) {
+				val *= (startj++/(double)SYNTH_SPLICELEN); 
+				if(startj >= SYNTH_SPLICELEN)
+					do_start = 0;
+			}
+			if(total_samps >= endsplicestart)
+				val *= (endj--/(double)SYNTH_SPLICELEN);
+			for(k=0;k<chans;k++) {
+//				dz->bigbuf[m++] = (short)round(val);
+				dz->bigbuf[m++] = (float)val;
+				total_samps++;
+			}
+			if((exit_status = advance_in_table(&i,convertor,&step,&fracstep,&amp,&frq,dtabsize,
+			&ampstep,&frqstep,&samptime,&nextsamptime,&lastamp,&lastfrq,inverse_sr,blokstep,dz))<0)
+				return(exit_status);
+		}
+		if(todo) {
+			if((exit_status = write_samps(dz->bigbuf,todo,dz))<0)
+				return(exit_status);
+		}
+		total_samps_left -= dz->buflen;
+	}
+	return(FINISHED);
+}
+  
+/****************************** GEN_SILENCE *************************/
+
+int gen_silence(int sampdur,dataptr dz)
+{
+	int exit_status;
+	int n, bufcnt = sampdur/dz->buflen;
+	int remain = sampdur - (bufcnt * dz->buflen);
+	for(n=0;n<dz->buflen;n++)
+		dz->bigbuf[n] = (float)0;
+	for(n=0;n<bufcnt;n++) {
+		if((exit_status = write_samps(dz->bigbuf,dz->buflen,dz))<0)
+			return(exit_status);
+	}
+	if(remain)
+		return write_samps(dz->bigbuf,remain,dz);
+	return FINISHED;
+}
+  
+/****************************** GEN_NOISE *************************/
+
+int gen_noise(int sampdur,double sr,dataptr dz)
+{
+	int exit_status;
+	int n;
+	int k, chans = dz->infile->channels;
+	double amp, lastamp,lastfrq,ampstep,frqstep;
+	double inverse_sr = 1.0/sr;
+	double timestep = 10.0 * MS_TO_SECS;
+	int blokstep = round(timestep * sr);
+	int samptime = 0, nextsamptime = blokstep;
+	int total_samps = 0;
+	int synth_splicelen = SYNTH_SPLICELEN * chans, startj = 0, endj = SYNTH_SPLICELEN;
+	int endsplicestart = sampdur - synth_splicelen;
+	int do_start = 1;
+	int total_samps_left = sampdur;
+	int todo;
+	double val;
+
+	if(sampdur < (synth_splicelen * 2) + chans) {
+		fprintf(stdout,"ERROR: Specified output duration is less then available splicing length.\n");
+		return(DATA_ERROR);
+	}
+
+	if((exit_status = read_values_from_all_existing_brktables(0.0,dz))<0)
+		return(exit_status);
+	if((exit_status = 
+	update_wave_params(&ampstep,&frqstep,&lastamp,&lastfrq,inverse_sr,&samptime,&nextsamptime,blokstep,dz))<0)
+		return(exit_status);
+	amp = lastamp;
+	while(total_samps_left > 0) {
+		if(total_samps_left/dz->buflen <= 0)
+			todo = total_samps_left;
+		else
+			todo = dz->buflen;
+		for(n=0;n<todo;n+=chans,total_samps += chans) {
+			val = ((drand48() * 2.0) - 1.0) * amp;
+			if(do_start) {
+				val *= startj++/(double)SYNTH_SPLICELEN; 
+				if(startj >= SYNTH_SPLICELEN)
+					do_start = 0;
+			}
+			if(total_samps >= endsplicestart)
+				val *= endj--/(double)SYNTH_SPLICELEN; 
+			for(k=0;k<chans;k++)
+				dz->bigbuf[n+k] = (float)val;
+			amp += ampstep;
+			if(++samptime >= nextsamptime) {
+				if((exit_status = update_wave_params
+				(&ampstep,&frqstep,&lastamp,&lastfrq,inverse_sr,&samptime,&nextsamptime,blokstep,dz))<0)
+					return(exit_status);
+				amp = lastamp;
+			}
+		}
+		if(todo) {
+			if((exit_status = write_samps(dz->bigbuf,todo,dz))<0)
+				return(exit_status);
+		}
+		total_samps_left -= dz->buflen;
+	}
+	return(FINISHED);
+}
+  
+/****************************** GETVAL *************************/
+
+double getval(double *tab,int i,double fracstep,double amp)
+{
+	double diff, val  = tab[i];
+	
+	diff = tab[i+1] - val;
+	val += diff * fracstep;
+	val *= amp;
+	return(val);
+}
+
+/****************************** UPDATE_WAVE_PARAMS *************************/
+
+int update_wave_params(double *ampstep,double *frqstep,double *lastamp,double *lastfrq,double inverse_sr,
+	int *samptime, int *nextsamptime,int blokstep,dataptr dz)
+{	
+	int exit_status;
+	double thistime = (double)(*nextsamptime) * inverse_sr;
+	double ratio;
+	*lastfrq = dz->param[SYN_FRQ];
+	*lastamp = dz->param[SYN_AMP];
+	*ampstep = 0.0;
+	*frqstep = 1.0;
+	if((exit_status = read_values_from_all_existing_brktables(thistime,dz))<0)
+		return(exit_status);
+	if(dz->brksize[SYN_AMP])
+		*ampstep = (dz->param[SYN_AMP] - *lastamp)/(double)blokstep;
+
+	if(dz->brksize[SYN_FRQ]) {
+		ratio    = dz->param[SYN_FRQ]/(*lastfrq);
+	 	*frqstep = pow(10.0,log10(ratio)/(double)blokstep);
+	}
+
+	*samptime      = *nextsamptime;
+	*nextsamptime += blokstep;
+	return(FINISHED);
+}
+
+/****************************** ADVANCE_IN_TABLE *************************/
+
+static int advance_in_table(int *i,double convertor,double *step,double *fracstep,
+double *amp,double *frq,double dtabsize,double *ampstep,double *frqstep,int *samptime,int *nextsamptime,
+double *lastamp,double *lastfrq,double inverse_sr,int blokstep,dataptr dz)
+{
+	int exit_status;
+
+	*step += *frq * convertor;
+	while(*step >= dtabsize)
+		*step -= dtabsize;
+	*i = (int)(*step); /* TRUNCATE */
+	*fracstep = *step - (double)(*i);
+	*amp += *ampstep;
+	*frq *= *frqstep;
+	if(++(*samptime) >= *nextsamptime) {
+		if((exit_status = update_wave_params
+		(ampstep,frqstep,lastamp,lastfrq,inverse_sr,samptime,nextsamptime,blokstep,dz))<0)
+			return(exit_status);
+		*amp = *lastamp;
+		*frq = *lastfrq;
+	}
+	return(FINISHED);
+}
+
+/****************************** DO_STEREO_SPECSYNTH *************************/
+
+#define SAFETY (10)
+
+//TW CONVERTED
+int do_stereo_specsynth(dataptr dz)
+{
+	int exit_status;
+	double hfchwidth = dz->chwidth/2.0;
+	float *bufend;
+	double focusrange = 0.0, basefrq, frq, *frqq, bwidth = 0.0, hfbwidth, offset = 0.0, totalamp;
+	double thisfocus, ampscaler, amp, wobble, dcf, hfchansprd;
+	int minchan = 0, supertight, lo_n = 0, hi_n = 0, wcnt, jj, n, m, k;
+	int remainder, samps_written;
+	int clength	= dz->wanted/2, centrchan = 0;
+	int orig_process_type;
+	char outfnam[256], outfilename[256];
+	unsigned int samps_so_far;
+	int floats_out =  dz->wlength * dz->wanted;
+	int samps_read1, samps_read2, samps_read;
+	int OK = 1;
+	int orig_process, orig_proctype, orig_chans, orig_stype;
+	int orig_srate;
+//TW UPDATE CORRECTION
+	int  overlap = (dz->infile->channels - 2)/dz->infile->Dfac;
+	int snd_floats_out = floats_out/overlap;
+	dz->tempsize = (floats_out + snd_floats_out) * 2;
+
+	if((frqq = (double *)malloc(clength * sizeof(double)))==NULL) {
+		sprintf(errstr,"No memory for initial-frequency storage-array.\n");
+		return(MEMORY_ERROR);
+	}
+	bufend = dz->bigfbuf + dz->big_fsize;
+
+	if(!dz->brksize[SS_FOCUS2] && !dz->brksize[SS_FOCUS])
+		focusrange = dz->param[SS_FOCUS2] - dz->param[SS_FOCUS];
+
+	/* SET BAND LIMITS */
+
+	if(!dz->brksize[SS_SPREAD] && !dz->brksize[SS_CENTRFRQ])
+		set_band_limits(clength,&supertight,&bwidth,&minchan,&centrchan,
+			&hfbwidth,&lo_n,&hi_n,&offset,hfchwidth,dz);
+
+	outfnam[0] = ENDOFSTR;
+	strcat(outfnam,dz->wordstor[0]);
+//TW REVISION for new protocol: always pass file-extension on cmdline
+	if(sloom)
+		delete_filename_lastchar(outfnam);	/* axe trailing zero on outfilename */
+	samps_so_far = 0;
+
+	for(jj=1;jj<3;jj++) {
+		strcpy(outfilename,outfnam);
+//TW REVISION for new protocol: always pass file-extension on cmdline
+		insert_new_number_at_filename_end(outfilename,jj+2,0);
+		orig_process_type = dz->process_type;
+		dz->process_type = BIG_ANALFILE;
+		dz->outfiletype = ANALFILE_OUT;
+		if((exit_status = create_sized_outfile(outfilename,dz)) < 0) {
+			sprintf(errstr,"Cannot open temporary analysis file '%s' to generate sound data:%s\n", outfilename,sferrstr());
+			return(SYSTEM_ERROR);
+		}
+		// dz->outfiletype = NO_OUTPUTFILE;  /* TW */ Thought I was, for safety, resetting to its original val (changed above) but did it wrongly, but not necessary.
+		dz->total_windows = 0;
+		dz->time = (float)0.0;
+		dz->flbufptr[0] = dz->bigfbuf;
+		for(wcnt = 0; wcnt < dz->wlength; wcnt++) {
+			memset((char *)dz->flbufptr[0],0,dz->wanted * sizeof(float));
+			if((exit_status = read_values_from_all_existing_brktables((double)dz->time,dz))<0)
+				return(exit_status);
+			if(dz->brksize[SS_FOCUS2] || dz->brksize[SS_FOCUS])
+				focusrange = dz->param[SS_FOCUS2] - dz->param[SS_FOCUS];
+			if(dz->brksize[SS_SPREAD] || dz->brksize[SS_CENTRFRQ])
+				set_band_limits(clength,&supertight,&bwidth,&minchan,&centrchan,
+					&hfbwidth,&lo_n,&hi_n,&offset,hfchwidth,dz);
+			hfchansprd = (hi_n - lo_n)/2.0;
+			totalamp = 0.0;
+			for(n=lo_n, m = minchan; n<hi_n; n++,m++) {
+				basefrq = ((double)n * bwidth) + offset;
+				if(dz->total_windows==0) {									/* for 1st window, establish a channel frq */
+					frq = (drand48() * bwidth) + basefrq;
+					frqq[n] = frq;
+				} else if(dz->param[SS_TRAND] > 0.0) {					/* if chan frq wobbles thro time, vary it */
+					wobble = ((drand48() * 2.0) - 1.0)/2.0;
+					frq = frqq[n] + (wobble * bwidth * dz->param[SS_TRAND]);
+				} else														/* if not, retain frq from first window */
+					frq = frqq[n];
+				dcf = (double)abs(centrchan - m)/hfchansprd;	/* fraction of chan-sprd we are away from centre */
+
+				thisfocus = (drand48() * focusrange) + dz->param[SS_FOCUS];
+				thisfocus = 1.0/thisfocus;
+				dcf = pow(dcf,thisfocus);									/* squeeze or unsqueeze cosin distrib */
+				amp = (cos(dcf * PI) + 1.0)/2.0;							/* cosin distrib */
+				totalamp += amp;
+				k = m * 2;
+				if(dz->total_windows)
+					dz->flbufptr[0][k] = (float)amp;
+				dz->flbufptr[0][++k]   = (float)frq;
+			}
+			if(dz->total_windows) {
+				ampscaler = (double)SPECSYN_MAXAMP/totalamp;
+				for(n=lo_n, k = minchan*2; n<hi_n; n++,k+=2)
+					dz->flbufptr[0][k] = (float)(dz->flbufptr[0][k] * ampscaler);
+			}
+			if((dz->flbufptr[0] += dz->wanted) >= bufend) {
+				if((exit_status = write_samps_no_report(dz->bigfbuf,dz->buflen,&samps_written,dz)) < 0)
+					return(exit_status);
+				display_virtual_time(dz->total_samps_written + samps_so_far,dz);
+				dz->flbufptr[0] = dz->bigfbuf;
+			}
+			dz->time = (float)(dz->time + dz->frametime);
+			dz->total_windows++;
+		}
+		if((remainder = dz->flbufptr[0] - dz->bigfbuf) > 0) {
+			if((exit_status = write_samps_no_report(dz->bigfbuf,remainder,&samps_written,dz)) < 0)
+				return(exit_status);
+			display_virtual_time(dz->total_samps_written + samps_so_far,dz);
+		}
+		dz->process_type = orig_process_type;
+
+/* SEE NOTES IN pvoc_addon.c in PVOC directory */
+		if((exit_status = pvoc_out(floats_out,&samps_so_far,outfilename,outfnam,jj,dz))<0)
+			return(exit_status);
+	}
+//TW NEW: merge the 2 output files
+	reset_file_params_for_sndout(&orig_proctype,&orig_srate,&orig_chans,&orig_stype,dz);
+	for(jj=0;jj<2;jj++) {
+		strcpy(outfilename,outfnam);
+		insert_new_number_at_filename_end(outfilename,jj+1,0);
+		if((dz->ifd[jj] = sndopenEx(outfilename,0,CDP_OPEN_RDONLY)) < 0) {
+			sprintf(errstr,"Cannot reopen mono file '%s' to convert to stereo :%s\n", outfilename,sferrstr());
+			return(SYSTEM_ERROR);
+		}
+	}
+	dz->insams[0] *= 2;
+	dz->process_type = EQUAL_SNDFILE;
+	dz->infile->channels = dz->outfile->channels = STEREO;
+	dz->infile->filetype = SNDFILE;	/* forces formatted sndfile creation */
+	strcpy(outfilename,outfnam);
+	if(dz->floatsam_output)
+		dz->infile->stype = SAMP_FLOAT;
+	else
+		dz->infile->stype = SAMP_SHORT;
+	dz->infile->srate = round(dz->param[SS_SRATE]);
+	dz->outfiletype = SNDFILE_OUT;
+	orig_process = dz->process;
+	dz->process = EDIT_CUT;	/* any process creating a standard sound outfile */
+	dz->infile->srate = (int)round(dz->param[SS_SRATE]);
+    if(sloom)                                                       /* TW 24/2/18 */
+        insert_new_number_at_filename_end(outfilename,0,0);
+	if((exit_status = create_sized_outfile(outfilename,dz)) < 0) {
+		sprintf(errstr,"Cannot open temporary soundfile '%s' to generate sound data:%s\n", outfilename,sferrstr());
+		return(SYSTEM_ERROR);
+	}
+	if((exit_status = reset_peak_finder(dz))<0)
+		return(exit_status);
+	dz->insams[0] /= 2;
+	OK = 1;
+	while(OK) {
+		memset((char *)dz->bigfbuf,0,dz->buflen * sizeof(float));
+		memset((char *)dz->flbufptr[2],0,dz->buflen * sizeof(float));
+		memset((char *)dz->flbufptr[3],0,dz->buflen * sizeof(float));
+		if((samps_read1 = fgetfbufEx(dz->flbufptr[2],dz->buflen,dz->ifd[0],0))<=0) {
+			if(samps_read1 < 0) {
+				sprintf(errstr,"Sample read failed: ");
+				for(jj=0;jj<2;jj++) {
+					char pfname[_MAX_PATH];
+					strcpy(pfname, snd_getfilename(dz->ifd[jj]));
+					sndcloseEx(dz->ifd[jj]);
+					if(remove(/*outfilename*/pfname)<0) {
+						fprintf(stdout,"WARNING: Tempfile %s not removed: ",outfilename);
+						fflush(stdout);
+					}
+				}
+				strcat(errstr,"\n");
+				return(SYSTEM_ERROR);
+			} else
+				break;
+		}
+		if((samps_read2 = fgetfbufEx(dz->flbufptr[3],dz->buflen,dz->ifd[1],0))<=0) {
+			if(samps_read2< 0) {
+				sprintf(errstr,"Sample read failed: ");
+				for(jj=0;jj<2;jj++) {
+					char pfname[_MAX_PATH];
+					strcpy(pfname, snd_getfilename(dz->ifd[jj]));
+					sndcloseEx(dz->ifd[jj]);
+					if(remove(/*outfilename*/pfname)<0) {
+						fprintf(stdout,"WARNING: Tempfile %s not removed: ",outfilename);
+						fflush(stdout);
+					}
+				}
+				strcat(errstr,"\n");
+				return(SYSTEM_ERROR);
+			} else
+				break;
+		}
+		if((samps_read = min(samps_read1,samps_read2)) <= 0)
+			break;
+#ifdef NOTDEF
+		for(n = 0,k=0; n < samps_read-1;n++,k+=2) {
+			dz->bigfbuf[k] = dz->flbufptr[2][n];
+			dz->bigfbuf[k+1] = dz->flbufptr[3][n];
+		}
+		dz->bigfbuf[k] = dz->flbufptr[2][n];
+#else
+        for(n = 0,k=0; n < samps_read;n++,k+=2) {
+            dz->bigfbuf[k] = dz->flbufptr[2][n];
+            dz->bigfbuf[k+1] = dz->flbufptr[3][n];
+        }
+#endif
+		/* last samp remains in situ */
+		if((exit_status = write_samps(dz->bigfbuf,samps_read * 2,dz))<0) {
+			sprintf(errstr,"Sample write failed: ");
+			for(jj=0;jj<2;jj++) {
+				char pfname[_MAX_PATH];
+				strcpy(pfname, snd_getfilename(dz->ifd[jj]));
+				sndcloseEx(dz->ifd[jj]);
+				if(remove(/*outfilename*/pfname)<0) {
+					fprintf(stdout,"WARNING: Tempfile %s not removed: ",outfilename);
+					fflush(stdout);
+				}
+			}
+			strcat(errstr,"\n");
+			return(SYSTEM_ERROR);
+		}
+	}
+	for(jj=0;jj<2;jj++) {
+		/*RWD Feb 2004 */
+		char pfname[_MAX_PATH];
+		strcpy(pfname, snd_getfilename(dz->ifd[jj]));
+		sndcloseEx(dz->ifd[jj]);
+		if(remove(/*outfilename*/pfname)<0) {
+			fprintf(stdout,"WARNING: Tempfile %s not removed: ",outfilename);
+			fflush(stdout);
+		}
+	}
+	dz->process = orig_process;	
+// In order to correctly write header, process_type should remain EQUAL_SNDFILE
+//	dz->process_type = OTHER_PROCESS;
+	return(FINISHED);
+}
+
+
+
+/****
+
+With cosinusoidal energy distribution
+-------------------------------------
+
+DCF(dist-from-centre-frq) = fabs(frq - centre-frq)			(range 0 - 1)
+							-------------------
+							half-interval-spread
+
+To focus energy towards centre, we squeeze values towards position 0
+--------------------------------------------------------------------
+
+DCF^focus
+
+if(focus > 1) squeezes
+if(focus < 1) braodens
+
+
+ampscaler = (cos(CDF*PI) + 1)/2.0;
+
+****/
+
+/****************************** SET_BAND_LIMITS *************************/
+
+void set_band_limits(int clength,int *supertight, double *bwidth, int *minchan, int *centrchan, 
+	double *hfbwidth, int *lo_n, int *hi_n, double *offset, double hfchwidth, dataptr dz)
+
+{
+	int chancnt;
+	double hifrq, lofrq, frqsprd;
+	int lochan, hichan, chanspreadmin;
+
+	if(dz->vflag[SS_PICHSPRD]) {
+		if(dz->param[SS_SPREAD] < 1.0)
+			dz->param[SS_SPREAD] = 1.0/dz->param[SS_SPREAD];
+		hifrq = min(dz->param[SS_CENTRFRQ] * dz->param[SS_SPREAD],dz->nyquist);
+		lofrq = max(dz->param[SS_CENTRFRQ] / dz->param[SS_SPREAD],SPEC_MINFRQ);
+	} else {
+		hifrq = min(dz->param[SS_CENTRFRQ] + dz->param[SS_SPREAD],dz->nyquist);
+		lofrq = max(dz->param[SS_CENTRFRQ] - dz->param[SS_SPREAD],SPEC_MINFRQ);
+	}
+	frqsprd = hifrq - lofrq;
+	/* ESTABLISH WHICH CHANS INVOLVED */
+
+	lochan = (int)floor((lofrq + hfchwidth)/dz->chwidth) - 1;
+	hichan = (int)floor((hifrq + hfchwidth)/dz->chwidth) - 1;
+//TW UPDATES
+	lochan = max(lochan,0);
+	hichan = max(hichan,0);
+
+	chancnt = hichan - lochan + 1;
+	chanspreadmin = (CHANUP * 2) + 1;
+	if (chancnt < chanspreadmin) {
+		chancnt = chanspreadmin;
+		*bwidth = frqsprd/chanspreadmin;
+		*centrchan = (int)floor((dz->param[SS_CENTRFRQ] + hfchwidth)/dz->chwidth) - 1;
+		if(*centrchan - CHANUP < 0)
+			*minchan = 0;
+		else if (*centrchan + CHANUP > clength)
+			*minchan = clength - chanspreadmin;
+		else
+			*minchan = *centrchan - CHANUP;
+		*centrchan = *minchan + CHANUP;
+		*supertight = 1;
+	} else {
+		*bwidth = dz->chwidth;
+		*minchan = lochan;
+		*supertight = 0;
+	}
+	*hfbwidth = (*bwidth)/2.0;
+
+	if(*supertight) {
+		*lo_n = 0;
+		*hi_n = chancnt;
+		*offset = lofrq;
+	} else {
+		*lo_n   = lochan;
+		*hi_n   = hichan;
+		*centrchan = (lochan + hichan)/2;
+		*offset = -(*hfbwidth);
+	}
+}
+
+//TW UPDATE: New Function
+/****************************** GEN_CLICKTRACK *************************/
+
+#define LINE_TIMES	(0)
+
+int gen_clicktrack(dataptr dz)
+{
+	double *clikdata = dz->parray[0], *clik = dz->parray[1];
+	double amp, tottime;
+	int n, m, j = 0, bufsamptime, bufsampendtime, samptime, tcnt = 0;
+	float *buf = dz->sampbuf[0];
+	int k, exit_status;
+	int from_start = 1;
+	int to_end = 1;
+	double click_ofset = 0.0, starttime_offset = 0.0;
+
+	if(dz->mode == CLICK_BY_LINE) {
+		if(dz->iparam[CLIKOFSET] > 0)
+			click_ofset = dz->parray[2][dz->iparam[CLIKOFSET]];
+		dz->param[CLIKSTART] = dz->parray[2][dz->iparam[CLIKSTART]] - click_ofset;
+		if(dz->iparam[CLIKEND] + 1 == dz->iparam[CLICKTIME])
+			dz->iparam[CLIKEND]++;
+		else
+			to_end = 0;
+		dz->param[CLIKEND]   = dz->parray[2][dz->iparam[CLIKEND]] - click_ofset;
+	}
+	if(sloom) {
+		tottime = dz->param[CLIKEND] - dz->param[CLIKSTART];
+		if((dz->tempsize = (int)round(tottime * CLICK_SRATE)) < 0) {
+			fprintf(stdout,"WARNING: File is too long to give accurate progress display on Progress Bar.\n");
+			fflush(stdout);
+			dz->tempsize = INT_MAX;
+		}
+	}
+	if(!flteq(dz->param[CLIKSTART],0.0))
+		from_start = 0;
+	if(dz->iparam[CLIKOFSET] > 0) {
+		click_ofset = dz->parray[2][dz->iparam[CLIKOFSET]];
+		if(!from_start)
+			starttime_offset = dz->param[CLIKSTART] + click_ofset;
+		dz->param[CLIKEND]   += click_ofset;
+		fprintf(stdout,"INFO: MUSIC STARTS %lf secs AFTER CLICKS\n",click_ofset);
+		fflush(stdout);
+	} else
+		starttime_offset = dz->param[CLIKSTART];
+	for(n=dz->itemcnt-2;n >=0;n-=2) {	/* throw away data beyond endtime of generating clicks */
+
+		if((dz->parray[0][n] < dz->param[CLIKEND]) || flteq(dz->parray[0][n],dz->param[CLIKEND])) {
+			dz->itemcnt = n+2;
+			break;
+		}
+	}
+	if(!to_end)
+		dz->itemcnt -= 2;
+	if(!from_start) {					/* throw away data before starttime of generating clicks */
+		while(dz->parray[0][0] < starttime_offset) {
+			dz->parray[0]+=2;
+			if((dz->itemcnt-=2) <= 0) {
+				sprintf(errstr,"No click data found between the specified times.\n");
+				return(DATA_ERROR);
+			}
+		}
+		for(n=0;n < dz->itemcnt;n+=2)	/* and adjust data time values so generation starts at outfile starttime 0.0 */
+			dz->parray[0][n] -= starttime_offset;
+	}
+	if(dz->vflag[LINE_TIMES]) {
+		tcnt = 0;						/* skip over times-of-lines prior to start of click-generation */
+		while(dz->parray[2][tcnt] < starttime_offset) {
+			if(++tcnt >= dz->iparam[CLICKTIME]) {
+				sprintf(errstr,"Anomaly in data about timing of data lines.\n");
+				return(PROGRAM_ERROR);
+			}
+		}
+	}
+	clikdata = dz->parray[0];
+	memset((char *)buf,0,dz->buflen * sizeof(float));
+	for(n=0,m=1;n<dz->itemcnt;n+=2,m+=2) {
+		samptime = (int)round(clikdata[n] * dz->infile->srate);
+		if(dz->vflag[LINE_TIMES] && (tcnt < dz->iparam[CLICKTIME])) {
+			if(flteq(dz->parray[2][tcnt],(clikdata[n] + starttime_offset))) {
+				fprintf(stdout,"INFO: LINE  %d  at  %lf\n",tcnt+1,(dz->parray[2][tcnt] - click_ofset));
+				fflush(stdout);
+				tcnt++;
+			} else if(dz->parray[2][tcnt] < (clikdata[n] + starttime_offset))
+				tcnt++;					/* skips lines which start with unaccented beat */
+		}
+		bufsamptime = samptime - dz->total_samps_written;
+		while(bufsamptime >= dz->buflen) {
+			if((exit_status = write_samps(dz->bigbuf,dz->buflen,dz))<0)
+				return(exit_status);
+			memset((char *)buf,0,dz->buflen * sizeof(float));
+			bufsamptime = samptime - dz->total_samps_written;
+		}
+		bufsampendtime = bufsamptime + CLICKLEN + 1;
+		amp = clikdata[m];
+		k = 0;
+		if(bufsampendtime <= dz->buflen) {
+			for(j = bufsamptime; j < bufsampendtime; j++)
+				buf[j] = (float)((double)clik[k++] * amp);
+		} else {
+			for(j = bufsamptime; j < dz->buflen; j++)
+				buf[j] = (float)((double)clik[k++] * amp);
+			if((exit_status = write_samps(dz->bigbuf,dz->buflen,dz))<0)
+				return(exit_status);
+			memset((char *)buf,0,dz->buflen * sizeof(float));
+			j = 0;
+			while(k <= CLICKLEN)
+				buf[j++] = (float)((double)clik[k++] * amp);
+		}
+	}
+	if(j > 0) {
+		if((exit_status = write_samps(dz->bigbuf,j,dz))<0)
+			return(exit_status);
+	}
+	return(FINISHED);
+}
+
+/****************************** GEN_CHORD *************************/
+
+#define JITTER_RANGE (1.0)
+#define JITTERSTEP (8)
+
+int gen_chord(int sampdur,dataptr dz)
+{
+	int exit_status;
+	double dtabsize = (double)dz->iparam[SYN_TABSIZE];
+	int m, n, k, kk;
+	int chans = dz->infile->channels;
+	double amp = dz->param[SYN_AMP];
+	double *tab = dz->parray[SYNTH_TAB];
+	double val;
+	int do_start = 1, jittercnt = 0;
+	int synth_splicelen = SYNTH_SPLICELEN * chans;
+	int total_samps = 0;
+	int startj = 0, endj = SYNTH_SPLICELEN, this_chordend, this_chordstart, thischord_notecnt;
+	int total_samps_left = sampdur;
+	int endsplicestart = sampdur - synth_splicelen;
+	int todo = 0, total_samps_done;
+	
+	double *step	 = dz->parray[1];
+	double *pos		 = dz->parray[2];
+	double *fracstep = dz->parray[3];
+	int   *samppos  = dz->lparray[0];
+
+	double *jitter=NULL, *lastjitter=NULL, *thisjitstep=NULL, *thisjitter=NULL;
+
+	if ((jitter = (double *)malloc(dz->itemcnt * sizeof(double)))==NULL) {
+		fprintf(stdout,"WARNING: Insufficient memory to add jitter.\n");
+		fflush(stdout);
+	} else if ((thisjitter = (double *)malloc(dz->itemcnt * sizeof(double)))==NULL) {
+		fprintf(stdout,"WARNING: Insufficient memory (2) to add jitter.\n");
+		fflush(stdout);
+	} else if ((lastjitter = (double *)malloc(dz->itemcnt * sizeof(double)))==NULL) {
+		fprintf(stdout,"WARNING: Insufficient memory (3) to add jitter.\n");
+		fflush(stdout);
+	} else if ((thisjitstep = (double *)malloc(dz->itemcnt * sizeof(double)))==NULL) {
+		fprintf(stdout,"WARNING: Insufficient memory (4) to add jitter.\n");
+		fflush(stdout);
+	} else {
+		for(n=0;n<dz->itemcnt;n++) {
+			jitter[n] = step[n] * (pow(SEMITONE_INTERVAL,JITTER_RANGE) - 1.0); /* Jitter within 0.5 of a semitone */
+			lastjitter[n] = 0.0;
+			thisjitter[n] = ((drand48() * 2.0) - 1.0) * jitter[n];	/* +- within jitter range */
+			thisjitstep[n] = thisjitter[n]/(double)JITTERSTEP;
+		}
+	}
+	if(sampdur < (synth_splicelen * 2) + chans) {
+		fprintf(stdout,"ERROR: Specified output duration is less then available splicing length.\n");
+		return(DATA_ERROR);
+	}
+	if(dz->ringsize > 1) {
+		total_samps_left = (int)round((double)(sampdur/chans)/(double)dz->ringsize) * chans;
+		total_samps_done = 0;
+		m = 0;
+		this_chordend = -1;
+		for(kk=0; kk < dz->ringsize; kk++) {
+			do_start = 1;
+			startj = 0;
+			endj = SYNTH_SPLICELEN;
+			if(kk == dz->ringsize - 1)
+				total_samps_left = sampdur - total_samps_done;
+			endsplicestart = total_samps_left - synth_splicelen;
+			this_chordend++;
+			this_chordstart = this_chordend;
+			while(step[this_chordend] > 0) {
+				if(++this_chordend >= dz->itemcnt)
+					break;
+			}
+			thischord_notecnt = this_chordend - this_chordstart;
+			todo = min(m + total_samps_left,dz->buflen);
+			total_samps = 0;
+			while(total_samps_left > 0) {
+				while(m < todo) {
+					val = 0.0;
+					for(n=this_chordstart;n < this_chordend;n++)
+						val += getval(tab,samppos[n],fracstep[n],amp);
+					val /= (double)thischord_notecnt;
+					if(do_start) {
+						val *= (startj++/(double)SYNTH_SPLICELEN); 
+						if(startj >= SYNTH_SPLICELEN)
+							do_start = 0;
+					}
+					if(total_samps >= endsplicestart)
+						val *= (endj--/(double)SYNTH_SPLICELEN);
+					for(k=0;k<chans;k++) {
+						dz->bigbuf[m++] = (float)val;
+						total_samps++;
+						total_samps_done++;
+					}
+					if(jitter != NULL) {
+						if(++jittercnt >= JITTERSTEP) {
+							for(n=this_chordstart;n<this_chordend;n++) {
+								lastjitter[n] = thisjitter[n];
+								thisjitter[n] = ((drand48() * 2.0) - 1.0) * jitter[n];	/* +- within jitter range */
+								thisjitstep[n] = (thisjitter[n] - lastjitter[n])/(double)JITTERSTEP;
+							}
+							jittercnt = 0;
+						}
+					}
+					for(n=this_chordstart;n<this_chordend;n++) {
+						pos[n] += step[n];
+						if(jitter != NULL)
+							pos[n] += thisjitstep[n];
+						while(pos[n] >= dtabsize)
+							pos[n] -= dtabsize;
+						samppos[n] = (int)pos[n];
+						fracstep[n] = pos[n] - (double)samppos[n];
+					}
+				}
+				total_samps_left -= todo;
+				if(m >= dz->buflen) {
+					if((exit_status = write_samps(dz->bigbuf,dz->buflen,dz))<0)
+						return(exit_status);
+					todo = min(total_samps_left,dz->buflen);
+					m = 0;
+				}
+			} 
+		}
+		if(todo > 0) {
+			if((exit_status = write_samps(dz->bigbuf,todo,dz))<0)
+				return(exit_status);
+		}
+	} else {
+		while(total_samps_left > 0) {
+			if(total_samps_left/dz->buflen <= 0)
+				todo = total_samps_left;
+			else
+				todo = dz->buflen;
+			m = 0;
+			while(m < todo) {
+				val = 0.0;
+				for(n=0;n < dz->itemcnt;n++)
+					val += getval(tab,samppos[n],fracstep[n],amp);
+				val /= (double)dz->itemcnt;
+				if(do_start) {
+					val *= (startj++/(double)SYNTH_SPLICELEN); 
+					if(startj >= SYNTH_SPLICELEN)
+						do_start = 0;
+				}
+				if(total_samps >= endsplicestart)
+					val *= (endj--/(double)SYNTH_SPLICELEN);
+				for(k=0;k<chans;k++) {
+					dz->bigbuf[m++] = (float)val;
+					total_samps++;
+				}
+				if(jitter != NULL) {
+					if(++jittercnt >= JITTERSTEP) {
+						for(n=0;n<dz->itemcnt;n++) {
+							lastjitter[n] = thisjitter[n];
+							thisjitter[n] = ((drand48() * 2.0) - 1.0) * jitter[n];	/* +- within jitter range */
+							thisjitstep[n] = (thisjitter[n] - lastjitter[n])/(double)JITTERSTEP;
+						}
+						jittercnt = 0;
+					}
+				}
+				for(n=0;n<dz->itemcnt;n++) {
+					pos[n] += step[n];
+					if(jitter != NULL)
+						pos[n] += thisjitstep[n];
+					while(pos[n] >= dtabsize)
+						pos[n] -= dtabsize;
+					samppos[n] = (int)pos[n];
+					fracstep[n] = pos[n] - (double)samppos[n];
+				}
+			}
+			if((exit_status = write_samps(dz->bigbuf,todo,dz))<0)
+				return(exit_status);
+			total_samps_left -= dz->buflen;
+		}
+	}
+	return(FINISHED);
+}