#include <stdio.h>
#include <stdlib.h>
#include <structures.h>
#include <tkglobals.h>
#include <pnames.h>
#include <filetype.h>
#include <processno.h>
#include <modeno.h>
#include <logic.h>
#include <globcon.h>
#include <cdpmain.h>
#include <math.h>
#include <mixxcon.h>
#include <osbind.h>
#include <standalone.h>
#include <ctype.h>
#include <sfsys.h>
#include <string.h>
#include <envlcon.h>
#include <srates.h>
#ifdef unix
#include <aaio.h>
#endif

#ifdef unix
#define round(x) lround((x))
#endif

#define envcnt	wlength
#define trofcnt rampbrksize
#define targetcnt ringsize
#define NEGATION 45

#define EXTSPEAK_PKSRCHWIDTH 3

#define XSPK_MAXLEVEL	0.9
char errstr[2400];

#define	PATN_ARRAY	0
#define	PERM_ARRAY	1
#define	TRGT_ARRAY	2

int anal_infiles = 1;
int	sloom = 0;
int sloombatch = 0;

const char* cdp_version = "6.1.0";

//CDP LIB REPLACEMENTS
static int check_extspeak_param_validity_and_consistency(int XSPK_RRND,int XSPK_ORISZ,dataptr dz);
static int setup_extspeak_application(dataptr dz);
static int parse_sloom_data(int argc,char *argv[],char ***cmdline,int *cmdlinecnt,dataptr dz);
static int parse_infile_and_check_type(char **cmdline,dataptr dz);
static int setup_extspeak_param_ranges_and_defaults(dataptr dz);
static int handle_the_outfile(int *cmdlinecnt,char ***cmdline,dataptr dz);
static int setup_and_init_input_param_activity(dataptr dz,int tipc);
static int setup_input_param_defaultval_stores(int tipc,aplptr ap);
static int establish_application(dataptr dz);
static int initialise_vflags(dataptr dz);
static int setup_parameter_storage_and_constants(int storage_cnt,dataptr dz);
static int initialise_is_int_and_no_brk_constants(int storage_cnt,dataptr dz);
static int mark_parameter_types(dataptr dz,aplptr ap);
static int assign_file_data_storage(int infilecnt,dataptr dz);
static int get_tk_cmdline_word(int *cmdlinecnt,char ***cmdline,char *q);
static int get_the_process_no(char *prog_identifier_from_cmdline,dataptr dz);
static int get_the_mode_from_cmdline(char *str,dataptr dz);
static int setup_and_init_input_brktable_constants(dataptr dz,int brkcnt);
static int precalculate_peaks_array_and_splice(dataptr dz);
static int extspeak(int XSPK_RRND,int XSPK_ORISZ,dataptr dz);
static int windows_in_sndfile(dataptr dz);
static int getenv_of_buffer(int samps_to_process,float **env,dataptr dz);
static double getmaxsamp(int startsamp, int sampcnt,float *buffer);
static int istrof(float *env,float *envend,float *q,int width);
static void randperm(int z,int setlen,dataptr dz);
static void hinsert(int z,int m,int t,int setlen,dataptr dz);
static void hprefix(int z,int m,int setlen,dataptr dz);
static void hshuflup(int z,int k,int setlen,dataptr dz);
static int handle_the_extra_infiles(int *cmdlinecnt,char ***cmdline,dataptr dz);
static int insert_new_syllable(int peaklen,int patno,int splicelen,double gain,double origlevel,double normaliser,
							   int *obufpos,float *obuf,float *ovflwbuf,dataptr dz);
static int store_patterndatafile_name(int *cmdlinecnt,char ***cmdline,dataptr dz);
static int handle_pattern_data(int patternsize,dataptr dz);
static int generate_xspk_pattern(int XSPK_RRND, int patternsize,dataptr dz);
static int create_sndbufs_for_extspeak(dataptr dz);
static int get_int_from_within_string(char **str,int *val, int minus_one_ok);
static int open_checktype_getsize_and_compare_header(char *filename,int fileno,fileptr *fp2,dataptr dz);
static int find_orig_syllab_maxima(int splicelen,dataptr dz);
static int find_normaliser(double *normaliser,int samps_per_sec,int splicelen,dataptr dz);
static double get_syllable_time(int thistrofat,int lasttrofat,int peaklen,int n,int samps_per_sec,dataptr dz);
static double dbtolevel(double val);
static int getcutdata(int *cmdlinecnt,char ***cmdline,dataptr dz);
static int get_cutpat_data(int *cmdlinecnt,char ***cmdline,dataptr dz);
static int expand_pattern_data(int patternsize,dataptr dz);
static int get_cuttapa_data(int *cmdlinecnt,char ***cmdline,dataptr dz);
static int get_cuttarg_data(int *cmdlinecnt,char ***cmdline,dataptr dz);
static int exttargetspeak(int XSPK_RRND,int XSPK_ORISZ,dataptr dz);
static int find_normaliser_target(double *normaliser,int samps_per_sec,int splicelen,dataptr dz);

/**************************************** MAIN *********************************************/

int main(int argc,char *argv[])
{
	int exit_status;
	dataptr dz = NULL;
	char **cmdline;
	int  cmdlinecnt, XSPK_RRND, XSPK_ORISZ;
	int n;
	aplptr ap;
	int is_launched = FALSE;
	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(sflinit("cdp")){
		sfperror("cdp: initialisation\n");
		return(FAILED);
	}
						  /* SET UP THE PRINCIPLE DATASTRUCTURE */
	if((exit_status = establish_datastructure(&dz))<0) {					// CDP LIB
		print_messages_and_close_sndfiles(exit_status,is_launched,dz);
		return(FAILED);
	}
	dz->trofcnt = 0;
	if(!sloom) {
		if(argc == 1) {
			usage1();	
			return(FAILED);
		} else if(argc == 2) {
			usage2(argv[1]);	
			return(FAILED);
		}
	}
	if(!sloom) {
		if((exit_status = make_initial_cmdline_check(&argc,&argv))<0) {		// CDP LIB
			print_messages_and_close_sndfiles(exit_status,is_launched,dz);
			return(FAILED);
		}
		cmdline    = argv;
		cmdlinecnt = argc;
		if((get_the_process_no(argv[0],dz))<0)
			return(FAILED);
		cmdline++;
		cmdlinecnt--;
		dz->maxmode = 18;
		if((exit_status = get_the_mode_from_cmdline(cmdline[0],dz))<0) {
			print_messages_and_close_sndfiles(exit_status,is_launched,dz);
			return(exit_status);
		}
		cmdline++;
		cmdlinecnt--;
		// setup_particular_application =
		if((exit_status = setup_extspeak_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) {		// CDP LIB
			print_messages_and_close_sndfiles(exit_status,is_launched,dz);
			return(FAILED);
		}
	} else {
		//parse_TK_data() =
		if((exit_status = parse_sloom_data(argc,argv,&cmdline,&cmdlinecnt,dz))<0) {
			exit_status = print_messages_and_close_sndfiles(exit_status,is_launched,dz);
			return(exit_status);		 
		}
	}
	ap = dz->application;

	// parse_infile_and_hone_type() = 
	if((exit_status = parse_infile_and_check_type(cmdline,dz))<0) {
		exit_status = print_messages_and_close_sndfiles(exit_status,is_launched,dz);
		return(FAILED);
	}
	// setup_param_ranges_and_defaults() =
	if((exit_status = setup_extspeak_param_ranges_and_defaults(dz))<0) {
		exit_status = print_messages_and_close_sndfiles(exit_status,is_launched,dz);
		return(FAILED);
	}
	// open_first_infile		CDP LIB
	if((exit_status = open_first_infile(cmdline[0],dz))<0) {	
		print_messages_and_close_sndfiles(exit_status,is_launched,dz);	
		return(FAILED);
	}
	cmdlinecnt--;
	cmdline++;

	if((dz->iparray = (int **)malloc(3 * sizeof(int *))) == NULL) {
		sprintf(errstr,"INSUFFICIENT MEMORY to store trof-locations and other data.\n");
		return(MEMORY_ERROR);
	}

//	handle_extra_infiles
	if((exit_status = handle_the_extra_infiles(&cmdlinecnt,&cmdline,dz))<0) {
		fprintf(stdout,"\n **** May be TOO MANY PARAMS on commandline ****\n\n");
		fflush(stdout);
		print_messages_and_close_sndfiles(exit_status,is_launched,dz);
		return(FAILED);
	}
	if(dz->infilecnt < 2) {
		sprintf(errstr,"ERROR: At least TWO input files required for this process.\n");
		exit_status = DATA_ERROR;
		print_messages_and_close_sndfiles(exit_status,is_launched,dz);
		return(FAILED);
	}

	// handle_outfile() = 
	if((exit_status = handle_the_outfile(&cmdlinecnt,&cmdline,dz))<0) {
		fprintf(stdout,"\n **** If the outfile does NOT already exist ****\n **** May be TOO FEW PARAMS on commandline ****\n\n");
		fflush(stdout);
		print_messages_and_close_sndfiles(exit_status,is_launched,dz);
		return(FAILED);
	}

//	handle_formants()			redundant
//	handle_formant_quiksearch()	redundant
	switch(dz->mode) {
	case(2):	//	fall thro
	case(5):
		if((exit_status = store_patterndatafile_name(&cmdlinecnt,&cmdline,dz))<0) {
			print_messages_and_close_sndfiles(exit_status,is_launched,dz);
			return(FAILED);
		}
		break;
	case(6):	//	fall thro
	case(7):	//	fall thro
	case(9):	//	fall thro
	case(10):
		if((exit_status = getcutdata(&cmdlinecnt,&cmdline,dz))<0) {
			print_messages_and_close_sndfiles(exit_status,is_launched,dz);
			return(FAILED);
		}
		break;
	case(8):	//	fall thro
	case(11):
		if((exit_status = get_cutpat_data(&cmdlinecnt,&cmdline,dz))<0) {
			print_messages_and_close_sndfiles(exit_status,is_launched,dz);
			return(FAILED);
		}
		break;
	case(12):	//	fall thro
	case(13):	//	fall thro
	case(15):	//	fall thro
	case(16):
		if((exit_status = get_cuttarg_data(&cmdlinecnt,&cmdline,dz))<0) {
			print_messages_and_close_sndfiles(exit_status,is_launched,dz);
			return(FAILED);
		}
		break;
	case(14):	//	fall thro
	case(17):
		if((exit_status = get_cuttapa_data(&cmdlinecnt,&cmdline,dz))<0) {
			print_messages_and_close_sndfiles(exit_status,is_launched,dz);
			return(FAILED);
		}
		break;
	}
	if((exit_status = read_parameters_and_flags(&cmdline,&cmdlinecnt,dz))<0) {		// CDP LIB
		print_messages_and_close_sndfiles(exit_status,is_launched,dz);
		return(FAILED);
	}
	if(dz->mode == 3 || dz->mode == 9)
		XSPK_RRND =	3;
	else if(dz->mode == 12)
		XSPK_RRND =	3;
	else if(dz->mode == 15)
		XSPK_RRND =	2;
	else
		XSPK_RRND = XSPK_RAND;
	if(dz->mode >=12 && dz->mode < 15)
		XSPK_ORISZ = 2;
	else
		XSPK_ORISZ = XSPK_ORIGSZ;

	is_launched = TRUE;
	dz->bufcnt = dz->infilecnt + 2;
	if((dz->sampbuf = (float **)malloc(sizeof(float *) * (dz->bufcnt+1)))==NULL) {
		sprintf(errstr,"INSUFFICIENT MEMORY establishing sample buffers.\n");
		return(MEMORY_ERROR);
	}
	if((dz->sbufptr = (float **)malloc(sizeof(float *) * dz->bufcnt))==NULL) {
		sprintf(errstr,"INSUFFICIENT MEMORY establishing sample buffer pointers.\n");
		return(MEMORY_ERROR);
	}
	for(n = 0;n <dz->bufcnt; n++)
		dz->sampbuf[n] = dz->sbufptr[n] = (float *)0;
	dz->sampbuf[n] = (float *)0;

	//	1 double array for splice, 1 for maxlevels of orig syllables & 1 for maxlevels of new syllables
	if((dz->parray = (double **)malloc(3 * sizeof(double *))) == NULL) {
		sprintf(errstr,"INSUFFICIENT MEMORY to create splice buffer (1).\n");
		return(MEMORY_ERROR);
	}
	//	2 float arrays for trofstore
	if((dz->fptr=(float **)malloc(2 * sizeof(float *)))==NULL) {
		sprintf(errstr,"INSUFFICIENT MEMORY to store envelope (1).\n");
		return(MEMORY_ERROR);
	}
//	create_sndbufs
	if((exit_status = create_sndbufs_for_extspeak(dz))<0) {
		print_messages_and_close_sndfiles(exit_status,is_launched,dz);
		return(FAILED);
	}
	if((exit_status = precalculate_peaks_array_and_splice(dz))<0) {
		print_messages_and_close_sndfiles(exit_status,is_launched,dz);
		return(FAILED);
	}
	if(dz->vflag[XSPK_ENV] || (dz->mode >= 3 && dz->mode < 6) || (dz->mode >= 9 && dz->mode < 12) || dz->mode >= 15) {
		if((dz->parray[2] = (double *)malloc(dz->infilecnt * sizeof(double))) == NULL) {//	Storage max levels of new input syllables
			sprintf(errstr,"INSUFFICIENT MEMORY to maximum levels of input syllables.\n");
			return(MEMORY_ERROR);
		}
	}
	//	check_param_validity_and_consistency....
	if((exit_status = check_extspeak_param_validity_and_consistency(XSPK_RRND,XSPK_ORISZ,dz))<0) {
		print_messages_and_close_sndfiles(exit_status,is_launched,dz);
		return(FAILED);
	}
	//param_preprocess()						redundant
	//spec_process_file =
	if(dz->mode >= 12)  {
		if((exit_status = exttargetspeak(XSPK_RRND,XSPK_ORISZ,dz))<0) {
			print_messages_and_close_sndfiles(exit_status,is_launched,dz);
			return(FAILED);
		}
	} else {
		if((exit_status = extspeak(XSPK_RRND,XSPK_ORISZ,dz))<0) {
			print_messages_and_close_sndfiles(exit_status,is_launched,dz);
			return(FAILED);
		}
	}
	if((exit_status = complete_output(dz))<0) {										// CDP LIB
		print_messages_and_close_sndfiles(exit_status,is_launched,dz);
		return(FAILED);
	}
	exit_status = print_messages_and_close_sndfiles(FINISHED,is_launched,dz);		// CDP LIB
	free(dz);
	return(SUCCEEDED);
}

/**********************************************
		REPLACED CDP LIB FUNCTIONS
**********************************************/


/****************************** SET_PARAM_DATA *********************************/

int set_param_data(aplptr ap, int special_data,int maxparamcnt,int paramcnt,char *paramlist)
{
	ap->special_data   = (char)special_data;	   
	ap->param_cnt      = (char)paramcnt;
	ap->max_param_cnt  = (char)maxparamcnt;
	if(ap->max_param_cnt>0) {
		if((ap->param_list = (char *)malloc((size_t)(ap->max_param_cnt+1)))==NULL) {	
			sprintf(errstr,"INSUFFICIENT MEMORY: for param_list\n");
			return(MEMORY_ERROR);
		}
		strcpy(ap->param_list,paramlist); 
	}
	return(FINISHED);
}

/****************************** SET_VFLGS *********************************/

int set_vflgs
(aplptr ap,char *optflags,int optcnt,char *optlist,char *varflags,int vflagcnt, int vparamcnt,char *varlist)
{
	ap->option_cnt 	 = (char) optcnt;			/*RWD added cast */
	if(optcnt) {
		if((ap->option_list = (char *)malloc((size_t)(optcnt+1)))==NULL) {
			sprintf(errstr,"INSUFFICIENT MEMORY: for option_list\n");
			return(MEMORY_ERROR);
		}
		strcpy(ap->option_list,optlist);
		if((ap->option_flags = (char *)malloc((size_t)(optcnt+1)))==NULL) {
			sprintf(errstr,"INSUFFICIENT MEMORY: for option_flags\n");
			return(MEMORY_ERROR);
		}
		strcpy(ap->option_flags,optflags); 
	}
	ap->vflag_cnt = (char) vflagcnt;		   
	ap->variant_param_cnt = (char) vparamcnt;
	if(vflagcnt) {
		if((ap->variant_list  = (char *)malloc((size_t)(vflagcnt+1)))==NULL) {
			sprintf(errstr,"INSUFFICIENT MEMORY: for variant_list\n");
			return(MEMORY_ERROR);
		}
		strcpy(ap->variant_list,varlist);		
		if((ap->variant_flags = (char *)malloc((size_t)(vflagcnt+1)))==NULL) {
			sprintf(errstr,"INSUFFICIENT MEMORY: for variant_flags\n");
			return(MEMORY_ERROR);
		}
		strcpy(ap->variant_flags,varflags);

	}
	return(FINISHED);
}

/***************************** APPLICATION_INIT **************************/

int application_init(dataptr dz)
{
	int exit_status;
	int storage_cnt;
	int tipc, brkcnt;
	aplptr ap = dz->application;
	if(ap->vflag_cnt>0)
		initialise_vflags(dz);	  
	tipc  = ap->max_param_cnt + ap->option_cnt + ap->variant_param_cnt;
	ap->total_input_param_cnt = (char)tipc;
	if(tipc>0) {
		if((exit_status = setup_input_param_range_stores(tipc,ap))<0)			  
			return(exit_status);
		if((exit_status = setup_input_param_defaultval_stores(tipc,ap))<0)		  
			return(exit_status);
		if((exit_status = setup_and_init_input_param_activity(dz,tipc))<0)	  
			return(exit_status);
	}
	brkcnt = tipc;
	if(brkcnt>0) {
		if((exit_status = setup_and_init_input_brktable_constants(dz,brkcnt))<0)			  
			return(exit_status);
	}
	if((storage_cnt = tipc + ap->internal_param_cnt)>0) {		  
		if((exit_status = setup_parameter_storage_and_constants(storage_cnt,dz))<0)	  
			return(exit_status);
		if((exit_status = initialise_is_int_and_no_brk_constants(storage_cnt,dz))<0)	  
			return(exit_status);
	}													   
 	if((exit_status = mark_parameter_types(dz,ap))<0)	  
		return(exit_status);
	
	// establish_infile_constants() replaced by
	dz->infilecnt = 1;
	//establish_bufptrs_and_extra_buffers():
	return(FINISHED);
}

/********************** SETUP_PARAMETER_STORAGE_AND_CONSTANTS ********************/
/* RWD mallo changed to calloc; helps debug verison run as release! */

int setup_parameter_storage_and_constants(int storage_cnt,dataptr dz)
{
	if((dz->param       = (double *)calloc(storage_cnt, sizeof(double)))==NULL) {
		sprintf(errstr,"setup_parameter_storage_and_constants(): 1\n");
		return(MEMORY_ERROR);
	}
	if((dz->iparam      = (int    *)calloc(storage_cnt, sizeof(int)   ))==NULL) {
		sprintf(errstr,"setup_parameter_storage_and_constants(): 2\n");
		return(MEMORY_ERROR);
	}
	if((dz->is_int      = (char   *)calloc(storage_cnt, sizeof(char)))==NULL) {
		sprintf(errstr,"setup_parameter_storage_and_constants(): 3\n");
		return(MEMORY_ERROR);
	}
	if((dz->no_brk      = (char   *)calloc(storage_cnt, sizeof(char)))==NULL) {
		sprintf(errstr,"setup_parameter_storage_and_constants(): 5\n");
		return(MEMORY_ERROR);
	}
	return(FINISHED);
}

/************** INITIALISE_IS_INT_AND_NO_BRK_CONSTANTS *****************/

int initialise_is_int_and_no_brk_constants(int storage_cnt,dataptr dz)
{
	int n;
	for(n=0;n<storage_cnt;n++) {
		dz->is_int[n] = (char)0;
		dz->no_brk[n] = (char)0;
	}
	return(FINISHED);
}

/***************************** MARK_PARAMETER_TYPES **************************/

int mark_parameter_types(dataptr dz,aplptr ap)
{
	int n, m;							/* PARAMS */
	for(n=0;n<ap->max_param_cnt;n++) {
		switch(ap->param_list[n]) {
		case('0'):	break; /* dz->is_active[n] = 0 is default */
		case('i'):	dz->is_active[n] = (char)1; dz->is_int[n] = (char)1;dz->no_brk[n] = (char)1; break;
		case('I'):	dz->is_active[n] = (char)1;	dz->is_int[n] = (char)1; 						 break;
		case('d'):	dz->is_active[n] = (char)1;							dz->no_brk[n] = (char)1; break;
		case('D'):	dz->is_active[n] = (char)1;	/* normal case: double val or brkpnt file */	 break;
		default:
			sprintf(errstr,"Programming error: invalid parameter type in mark_parameter_types()\n");
			return(PROGRAM_ERROR);
		}
	}						 		/* OPTIONS */
	for(n=0,m=ap->max_param_cnt;n<ap->option_cnt;n++,m++) {
		switch(ap->option_list[n]) {
		case('i'): dz->is_active[m] = (char)1; dz->is_int[m] = (char)1;	dz->no_brk[m] = (char)1; break;
		case('I'): dz->is_active[m] = (char)1; dz->is_int[m] = (char)1; 						 break;
		case('d'): dz->is_active[m] = (char)1; 							dz->no_brk[m] = (char)1; break;
		case('D'): dz->is_active[m] = (char)1;	/* normal case: double val or brkpnt file */	 break;
		default:
			sprintf(errstr,"Programming error: invalid option type in mark_parameter_types()\n");
			return(PROGRAM_ERROR);
		}
	}								/* VARIANTS */
	for(n=0,m=ap->max_param_cnt + ap->option_cnt;n < ap->variant_param_cnt; n++, m++) {
		switch(ap->variant_list[n]) {
		case('0'): break;
		case('i'): dz->is_active[m] = (char)1; dz->is_int[m] = (char)1;	dz->no_brk[m] = (char)1; break;
		case('I'): dz->is_active[m] = (char)1; dz->is_int[m] = (char)1;	 						 break;
		case('d'): dz->is_active[m] = (char)1; 							dz->no_brk[m] = (char)1; break;
		case('D'): dz->is_active[m] = (char)1; /* normal case: double val or brkpnt file */		 break;
		default:
			sprintf(errstr,"Programming error: invalid variant type in mark_parameter_types()\n");
			return(PROGRAM_ERROR);
		}
	}								/* INTERNAL */
	for(n=0,
	m=ap->max_param_cnt + ap->option_cnt + ap->variant_param_cnt; n<ap->internal_param_cnt; n++,m++) {
		switch(ap->internal_param_list[n]) {
		case('0'):  break;	 /* dummy variables: variables not used: but important for internal paream numbering!! */
		case('i'):	dz->is_int[m] = (char)1;	dz->no_brk[m] = (char)1;	break;
		case('d'):								dz->no_brk[m] = (char)1;	break;
		default:
			sprintf(errstr,"Programming error: invalid internal param type in mark_parameter_types()\n");
			return(PROGRAM_ERROR);
		}
	}
	return(FINISHED);
}

/************************ HANDLE_THE_OUTFILE *********************/

int handle_the_outfile(int *cmdlinecnt,char ***cmdline,dataptr dz)
{
	int exit_status;
	char *filename = (*cmdline)[0];

	if(filename[0]=='-' && filename[1]=='f') {
		dz->floatsam_output = 1;
		dz->true_outfile_stype = SAMP_FLOAT;
		filename+= 2;
	}
	if(!sloom) {
		if(file_has_invalid_startchar(filename) || value_is_numeric(filename)) {
			sprintf(errstr,"Outfile name %s has invalid start character(s) or looks too much like a number.\n",filename);
			return(DATA_ERROR);
		}
	}
	strcpy(dz->outfilename,filename);
	if((exit_status = create_sized_outfile(filename,dz))<0)
		return(exit_status);
	(*cmdline)++;
	(*cmdlinecnt)--;
	return(FINISHED);
}

/***************************** ESTABLISH_APPLICATION **************************/

int establish_application(dataptr dz)
{
	aplptr ap;
	if((dz->application = (aplptr)malloc(sizeof (struct applic)))==NULL) {
		sprintf(errstr,"establish_application()\n");
		return(MEMORY_ERROR);
	}
	ap = dz->application;
	memset((char *)ap,0,sizeof(struct applic));
	return(FINISHED);
}

/************************* INITIALISE_VFLAGS *************************/

int initialise_vflags(dataptr dz)
{
	int n;
	if((dz->vflag  = (char *)malloc(dz->application->vflag_cnt * sizeof(char)))==NULL) {
		sprintf(errstr,"INSUFFICIENT MEMORY: vflag store,\n");
		return(MEMORY_ERROR);
	}
	for(n=0;n<dz->application->vflag_cnt;n++)
		dz->vflag[n]  = FALSE;
	return FINISHED;
}

/************************* SETUP_INPUT_PARAM_DEFAULTVALS *************************/

int setup_input_param_defaultval_stores(int tipc,aplptr ap)
{
	int n;
	if((ap->default_val = (double *)malloc(tipc * sizeof(double)))==NULL) {
		sprintf(errstr,"INSUFFICIENT MEMORY for application default values store\n");
		return(MEMORY_ERROR);
	}
	for(n=0;n<tipc;n++)
		ap->default_val[n] = 0.0;
	return(FINISHED);
}

/***************************** SETUP_AND_INIT_INPUT_PARAM_ACTIVITY **************************/

int setup_and_init_input_param_activity(dataptr dz,int tipc)
{
	int n;
	if((dz->is_active = (char   *)malloc((size_t)tipc))==NULL) {
		sprintf(errstr,"setup_and_init_input_param_activity()\n");
		return(MEMORY_ERROR);
	}
	for(n=0;n<tipc;n++)
		dz->is_active[n] = (char)0;
	return(FINISHED);
}

/************************* SETUP_EXTSPEAK_APPLICATION *******************/

int setup_extspeak_application(dataptr dz)
{
	int exit_status;
	aplptr ap;
	if((exit_status = establish_application(dz))<0)		// GLOBAL
		return(FAILED);
	ap = dz->application;
	switch(dz->mode) {
	case(9):	//	fall thro
	case(10):	//	fall thro
	case(6):	//	fall thro
	case(7): exit_status = set_param_data(ap,XSPK_CUTS	  ,6,5,"0iiIDi");	break;
	case(11):	//	fall thro
	case(8): exit_status = set_param_data(ap,XSPK_CUTPAT  ,6,4,"0iiID0");	break;
	case(3):	//	fall thro
	case(4):	//	fall thro
	case(0):	//	fall thro
	case(1): exit_status = set_param_data(ap,0			  ,6,6,"iiiIDi");	break;
	case(5):	//	fall thro
	case(2): exit_status = set_param_data(ap,XSPK_PATTERN ,6,5,"iiiID0");	break;
	case(12):	//	fall thro
	case(13):	//	fall thro
	case(15):	//	fall thro
	case(16): exit_status = set_param_data(ap,XSPK_CUTARG ,6,3,"0i00Di");	break;
	case(14):	//	fall thro
	case(17): exit_status = set_param_data(ap,XSPK_CUPATA ,6,2,"0i00D0");	break;
	}
	if(exit_status < 0)
		return(FAILED);
	switch(dz->mode) {
	case(6):	//	fall thro
	case(0):
		exit_status = set_vflgs(ap,"",0,"","tekior",6,0,"000000");
		break;
	case(7):	//	fall thro
	case(8):	//	fall thro
	case(1):	//	fall thro
	case(2):
		exit_status = set_vflgs(ap,"",0,"","tekio" ,5,0,"00000");
		break;
	case(9):	//	fall thro
	case(3):
		exit_status = set_vflgs(ap,"",0,"","tekr"   ,4,0,"0000");
		break;
	case(10):	//	fall thro
	case(11):	//	fall thro
	case(4):	//	fall thro
	case(5):
		exit_status = set_vflgs(ap,"",0,"","tek"    ,3,0,"000");
		break;
	case(12):
		exit_status = set_vflgs(ap,"",0,"","teor"   ,4,0,"0000");
		break;
	case(15):	//	fall thro
		exit_status = set_vflgs(ap,"",0,"","ter"    ,3,0,"000");
		break;
	case(13):	//	fall thro
	case(14):
		exit_status = set_vflgs(ap,"",0,"","teo"    ,3,0,"000");
		break;
	case(16):	//	fall thro 
	case(17):
		exit_status = set_vflgs(ap,"",0,"","te"     ,2,0,"00");
		break;
	}
	if(exit_status < 0)
		return(FAILED);
	// set_legal_infile_structure -->
	dz->has_otherfile = FALSE;
	// assign_process_logic -->
	dz->input_data_type = MANY_SNDFILES;
	dz->process_type	= UNEQUAL_SNDFILE;	
	dz->outfiletype  	= SNDFILE_OUT;
	return application_init(dz);	//GLOBAL
}

/************************* PARSE_INFILE_AND_CHECK_TYPE *******************/

int parse_infile_and_check_type(char **cmdline,dataptr dz)
{
	int exit_status;
	infileptr infile_info;
	if(!sloom) {
		if((infile_info = (infileptr)malloc(sizeof(struct filedata)))==NULL) {
			sprintf(errstr,"INSUFFICIENT MEMORY for infile structure to test file data.");
			return(MEMORY_ERROR);
		} else if((exit_status = cdparse(cmdline[0],infile_info))<0) {
			sprintf(errstr,"Failed to parse input file %s\n",cmdline[0]);
			return(PROGRAM_ERROR);
		} else if(infile_info->filetype != SNDFILE)  {
			sprintf(errstr,"File %s is not of correct type\n",cmdline[0]);
			return(DATA_ERROR);
		} else if((exit_status = copy_parse_info_to_main_structure(infile_info,dz))<0) {
			sprintf(errstr,"Failed to copy file parsing information\n");
			return(PROGRAM_ERROR);
		}
		free(infile_info);
	}
	return(FINISHED);
}

/************************* SETUP_EXTSPEAK_PARAM_RANGES_AND_DEFAULTS *******************/

int setup_extspeak_param_ranges_and_defaults(dataptr dz)
{
	int exit_status;
	aplptr ap = dz->application;
	// set_param_ranges()
	ap->total_input_param_cnt = (char)(ap->max_param_cnt + ap->option_cnt + ap->variant_param_cnt);
	// NB total_input_param_cnt is > 0 !!!
	if((exit_status = setup_input_param_range_stores(ap->total_input_param_cnt,ap))<0)
		return(FAILED);
	if(dz->mode < 6) {
		ap->lo[XSPK_WINSZ]	= 5;			//	param 0
		ap->hi[XSPK_WINSZ]	= 1000;
		ap->default_val[XSPK_WINSZ]	= 50;
	}
	ap->lo[XSPK_SPLEN]	= 2;				//	param 1
	ap->hi[XSPK_SPLEN]	= 100;
	ap->default_val[XSPK_SPLEN]	= 5;
	if(dz->mode < 12) {
		ap->lo[XSPK_OFFST]	= 0;			//	param 2
		ap->hi[XSPK_OFFST]	= 100;
		ap->default_val[XSPK_OFFST]	= 0;
		ap->lo[XSPK_N]	= 0;				//	param 3
		ap->hi[XSPK_N]	= MAX_PATN;
		ap->default_val[XSPK_N]	= 1;
	}
	ap->lo[XSPK_GAIN]	= -96;				//	param 4
	ap->hi[XSPK_GAIN]	= 0;
	ap->default_val[XSPK_GAIN]	= 0;
	if(dz->mode != 2 && dz->mode != 5 && dz->mode != 8 && dz->mode != 11 && dz->mode != 14 && dz->mode != 17) {
		ap->lo[XSPK_SEED]	= 0;			//	param 5
		ap->hi[XSPK_SEED]	= 64;
		ap->default_val[XSPK_SEED]	= 0;
	}
	dz->maxmode = 18;
	if(!sloom)
		put_default_vals_in_all_params(dz);
	return(FINISHED);
}

/********************************* PARSE_SLOOM_DATA *********************************/

int parse_sloom_data(int argc,char *argv[],char ***cmdline,int *cmdlinecnt,dataptr dz)
{
	int exit_status;
	int cnt = 1, infilecnt;
	int filesize, insams, inbrksize;
	double dummy;
	int true_cnt = 0;
	aplptr ap;

	while(cnt<=PRE_CMDLINE_DATACNT) {
		if(cnt > argc) {
			sprintf(errstr,"Insufficient data sent from TK\n");
			return(DATA_ERROR);
		}
		switch(cnt) {
		case(1):	
			if(sscanf(argv[cnt],"%d",&dz->process)!=1) {
				sprintf(errstr,"Cannot read process no. sent from TK\n");
				return(DATA_ERROR);
			}
			break;

		case(2):	
			if(sscanf(argv[cnt],"%d",&dz->mode)!=1) {
				sprintf(errstr,"Cannot read mode no. sent from TK\n");
				return(DATA_ERROR);
			}
			if(dz->mode > 0)
				dz->mode--;
			//setup_particular_application() =
			if((exit_status = setup_extspeak_application(dz))<0)
				return(exit_status);
			ap = dz->application;
			break;

		case(3):	
			if(sscanf(argv[cnt],"%d",&infilecnt)!=1) {
				sprintf(errstr,"Cannot read infilecnt sent from TK\n");
				return(DATA_ERROR);
			}
			if(infilecnt < 1) {
				true_cnt = cnt + 1;
				cnt = PRE_CMDLINE_DATACNT;	/* force exit from loop after assign_file_data_storage */
			}
			if((exit_status = assign_file_data_storage(infilecnt,dz))<0)
				return(exit_status);
			break;
		case(INPUT_FILETYPE+4):	
			if(sscanf(argv[cnt],"%d",&dz->infile->filetype)!=1) {
				sprintf(errstr,"Cannot read filetype sent from TK (%s)\n",argv[cnt]);
				return(DATA_ERROR);
			}
			break;
		case(INPUT_FILESIZE+4):	
			if(sscanf(argv[cnt],"%d",&filesize)!=1) {
				sprintf(errstr,"Cannot read infilesize sent from TK\n");
				return(DATA_ERROR);
			}
			dz->insams[0] = filesize;	
			break;
		case(INPUT_INSAMS+4):	
			if(sscanf(argv[cnt],"%d",&insams)!=1) {
				sprintf(errstr,"Cannot read insams sent from TK\n");
				return(DATA_ERROR);
			}
			dz->insams[0] = insams;	
			break;
		case(INPUT_SRATE+4):	
			if(sscanf(argv[cnt],"%d",&dz->infile->srate)!=1) {
				sprintf(errstr,"Cannot read srate sent from TK\n");
				return(DATA_ERROR);
			}
			break;
		case(INPUT_CHANNELS+4):	
			if(sscanf(argv[cnt],"%d",&dz->infile->channels)!=1) {
				sprintf(errstr,"Cannot read channels sent from TK\n");
				return(DATA_ERROR);
			}
			break;
		case(INPUT_STYPE+4):	
			if(sscanf(argv[cnt],"%d",&dz->infile->stype)!=1) {
				sprintf(errstr,"Cannot read stype sent from TK\n");
				return(DATA_ERROR);
			}
			break;
		case(INPUT_ORIGSTYPE+4):	
			if(sscanf(argv[cnt],"%d",&dz->infile->origstype)!=1) {
				sprintf(errstr,"Cannot read origstype sent from TK\n");
				return(DATA_ERROR);
			}
			break;
		case(INPUT_ORIGRATE+4):	
			if(sscanf(argv[cnt],"%d",&dz->infile->origrate)!=1) {
				sprintf(errstr,"Cannot read origrate sent from TK\n");
				return(DATA_ERROR);
			}
			break;
		case(INPUT_MLEN+4):	
			if(sscanf(argv[cnt],"%d",&dz->infile->Mlen)!=1) {
				sprintf(errstr,"Cannot read Mlen sent from TK\n");
				return(DATA_ERROR);
			}
			break;
		case(INPUT_DFAC+4):	
			if(sscanf(argv[cnt],"%d",&dz->infile->Dfac)!=1) {
				sprintf(errstr,"Cannot read Dfac sent from TK\n");
				return(DATA_ERROR);
			}
			break;
		case(INPUT_ORIGCHANS+4):	
			if(sscanf(argv[cnt],"%d",&dz->infile->origchans)!=1) {
				sprintf(errstr,"Cannot read origchans sent from TK\n");
				return(DATA_ERROR);
			}
			break;
		case(INPUT_SPECENVCNT+4):	
			if(sscanf(argv[cnt],"%d",&dz->infile->specenvcnt)!=1) {
				sprintf(errstr,"Cannot read specenvcnt sent from TK\n");
				return(DATA_ERROR);
			}
			dz->specenvcnt = dz->infile->specenvcnt;
			break;
		case(INPUT_WANTED+4):	
			if(sscanf(argv[cnt],"%d",&dz->wanted)!=1) {
				sprintf(errstr,"Cannot read wanted sent from TK\n");
				return(DATA_ERROR);
			}
			break;
		case(INPUT_WLENGTH+4):	
			if(sscanf(argv[cnt],"%d",&dz->wlength)!=1) {
				sprintf(errstr,"Cannot read wlength sent from TK\n");
				return(DATA_ERROR);
			}
			break;
		case(INPUT_OUT_CHANS+4):	
			if(sscanf(argv[cnt],"%d",&dz->out_chans)!=1) {
				sprintf(errstr,"Cannot read out_chans sent from TK\n");
				return(DATA_ERROR);
			}
			break;
			/* RWD these chanegs to samps - tk will have to deal with that! */
		case(INPUT_DESCRIPTOR_BYTES+4):	
			if(sscanf(argv[cnt],"%d",&dz->descriptor_samps)!=1) {
				sprintf(errstr,"Cannot read descriptor_samps sent from TK\n");
				return(DATA_ERROR);
			}
			break;
		case(INPUT_IS_TRANSPOS+4):	
			if(sscanf(argv[cnt],"%d",&dz->is_transpos)!=1) {
				sprintf(errstr,"Cannot read is_transpos sent from TK\n");
				return(DATA_ERROR);
			}
			break;
		case(INPUT_COULD_BE_TRANSPOS+4):	
			if(sscanf(argv[cnt],"%d",&dz->could_be_transpos)!=1) {
				sprintf(errstr,"Cannot read could_be_transpos sent from TK\n");
				return(DATA_ERROR);
			}
			break;
		case(INPUT_COULD_BE_PITCH+4):	
			if(sscanf(argv[cnt],"%d",&dz->could_be_pitch)!=1) {
				sprintf(errstr,"Cannot read could_be_pitch sent from TK\n");
				return(DATA_ERROR);
			}
			break;
		case(INPUT_DIFFERENT_SRATES+4):	
			if(sscanf(argv[cnt],"%d",&dz->different_srates)!=1) {
				sprintf(errstr,"Cannot read different_srates sent from TK\n");
				return(DATA_ERROR);
			}
			break;
		case(INPUT_DUPLICATE_SNDS+4):	
			if(sscanf(argv[cnt],"%d",&dz->duplicate_snds)!=1) {
				sprintf(errstr,"Cannot read duplicate_snds sent from TK\n");
				return(DATA_ERROR);
			}
			break;
		case(INPUT_BRKSIZE+4):	
			if(sscanf(argv[cnt],"%d",&inbrksize)!=1) {
				sprintf(errstr,"Cannot read brksize sent from TK\n");
				return(DATA_ERROR);
			}
			if(inbrksize > 0) {
				switch(dz->input_data_type) {
				case(WORDLIST_ONLY):
					break;
				case(PITCH_AND_PITCH):
				case(PITCH_AND_TRANSPOS):
				case(TRANSPOS_AND_TRANSPOS):
					dz->tempsize = inbrksize;
					break;
				case(BRKFILES_ONLY):
				case(UNRANGED_BRKFILE_ONLY):
				case(DB_BRKFILES_ONLY):
				case(ALL_FILES):
				case(ANY_NUMBER_OF_ANY_FILES):
					if(dz->extrabrkno < 0) {
						sprintf(errstr,"Storage location number for brktable not established by CDP.\n");
						return(DATA_ERROR);
					}
					if(dz->brksize == NULL) {
						sprintf(errstr,"CDP has not established storage space for input brktable.\n");
						return(PROGRAM_ERROR);
					}
					dz->brksize[dz->extrabrkno]	= inbrksize;
					break;
				default:
					sprintf(errstr,"TK sent brktablesize > 0 for input_data_type [%d] not using brktables.\n",
					dz->input_data_type);
					return(PROGRAM_ERROR);
				}
				break;
			}
			break;
		case(INPUT_NUMSIZE+4):	
			if(sscanf(argv[cnt],"%d",&dz->numsize)!=1) {
				sprintf(errstr,"Cannot read numsize sent from TK\n");
				return(DATA_ERROR);
			}
			break;
		case(INPUT_LINECNT+4):	
			if(sscanf(argv[cnt],"%d",&dz->linecnt)!=1) {
				sprintf(errstr,"Cannot read linecnt sent from TK\n");
				return(DATA_ERROR);
			}
			break;
		case(INPUT_ALL_WORDS+4):	
			if(sscanf(argv[cnt],"%d",&dz->all_words)!=1) {
				sprintf(errstr,"Cannot read all_words sent from TK\n");
				return(DATA_ERROR);
			}
			break;
		case(INPUT_ARATE+4):	
			if(sscanf(argv[cnt],"%f",&dz->infile->arate)!=1) {
				sprintf(errstr,"Cannot read arate sent from TK\n");
				return(DATA_ERROR);
			}
			break;
		case(INPUT_FRAMETIME+4):	
			if(sscanf(argv[cnt],"%lf",&dummy)!=1) {
				sprintf(errstr,"Cannot read frametime sent from TK\n");
				return(DATA_ERROR);
			}
			dz->frametime = (float)dummy;
			break;
		case(INPUT_WINDOW_SIZE+4):	
			if(sscanf(argv[cnt],"%f",&dz->infile->window_size)!=1) {
				sprintf(errstr,"Cannot read window_size sent from TK\n");
					return(DATA_ERROR);
			}
			break;
		case(INPUT_NYQUIST+4):	
			if(sscanf(argv[cnt],"%lf",&dz->nyquist)!=1) {
				sprintf(errstr,"Cannot read nyquist sent from TK\n");
				return(DATA_ERROR);
			}
			break;
		case(INPUT_DURATION+4):	
			if(sscanf(argv[cnt],"%lf",&dz->duration)!=1) {
				sprintf(errstr,"Cannot read duration sent from TK\n");
				return(DATA_ERROR);
			}
			break;
		case(INPUT_MINBRK+4):	
			if(sscanf(argv[cnt],"%lf",&dz->minbrk)!=1) {
				sprintf(errstr,"Cannot read minbrk sent from TK\n");
				return(DATA_ERROR);
			}
			break;
		case(INPUT_MAXBRK+4):	
			if(sscanf(argv[cnt],"%lf",&dz->maxbrk)!=1) {
				sprintf(errstr,"Cannot read maxbrk sent from TK\n");
				return(DATA_ERROR);
			}
			break;
		case(INPUT_MINNUM+4):	
			if(sscanf(argv[cnt],"%lf",&dz->minnum)!=1) {
				sprintf(errstr,"Cannot read minnum sent from TK\n");
				return(DATA_ERROR);
			}
			break;
		case(INPUT_MAXNUM+4):	
			if(sscanf(argv[cnt],"%lf",&dz->maxnum)!=1) {
				sprintf(errstr,"Cannot read maxnum sent from TK\n");
				return(DATA_ERROR);
			}
			break;
		default:
			sprintf(errstr,"case switch item missing: parse_sloom_data()\n");
			return(PROGRAM_ERROR);
		}
		cnt++;
	}
	if(cnt!=PRE_CMDLINE_DATACNT+1) {
		sprintf(errstr,"Insufficient pre-cmdline params sent from TK\n");
		return(DATA_ERROR);
	}

	if(true_cnt)
		cnt = true_cnt;
	*cmdlinecnt = 0;		

	while(cnt < argc) {
		if((exit_status = get_tk_cmdline_word(cmdlinecnt,cmdline,argv[cnt]))<0)
			return(exit_status);
		cnt++;
	}
	return(FINISHED);
}

/********************************* GET_TK_CMDLINE_WORD *********************************/

int get_tk_cmdline_word(int *cmdlinecnt,char ***cmdline,char *q)
{
	if(*cmdlinecnt==0) {
		if((*cmdline = (char **)malloc(sizeof(char *)))==NULL)	{
			sprintf(errstr,"INSUFFICIENT MEMORY for TK cmdline array.\n");
			return(MEMORY_ERROR);
		}
	} else {
		if((*cmdline = (char **)realloc(*cmdline,((*cmdlinecnt)+1) * sizeof(char *)))==NULL)	{
			sprintf(errstr,"INSUFFICIENT MEMORY for TK cmdline array.\n");
			return(MEMORY_ERROR);
		}
	}
	if(((*cmdline)[*cmdlinecnt] = (char *)malloc((strlen(q) + 1) * sizeof(char)))==NULL)	{
		sprintf(errstr,"INSUFFICIENT MEMORY for TK cmdline item %d.\n",(*cmdlinecnt)+1);
		return(MEMORY_ERROR);
	}
	strcpy((*cmdline)[*cmdlinecnt],q);
	(*cmdlinecnt)++;
	return(FINISHED);
}


/****************************** ASSIGN_FILE_DATA_STORAGE *********************************/

int assign_file_data_storage(int infilecnt,dataptr dz)
{
	int exit_status;
	int no_sndfile_system_files = FALSE;
	dz->infilecnt = infilecnt;
	if((exit_status = allocate_filespace(dz))<0)
		return(exit_status);
	if(no_sndfile_system_files)
		dz->infilecnt = 0;
	return(FINISHED);
}



/************************* redundant functions: to ensure libs compile OK *******************/

int assign_process_logic(dataptr dz)
{
	return(FINISHED);
}

void set_legal_infile_structure(dataptr dz)
{}

int set_legal_internalparam_structure(int process,int mode,aplptr ap)
{
	return(FINISHED);
}

int setup_internal_arrays_and_array_pointers(dataptr dz)
{
	return(FINISHED);
}

int establish_bufptrs_and_extra_buffers(dataptr dz)
{
	return(FINISHED);
}

int read_special_data(char *str,dataptr dz)	
{
	return(FINISHED);
}

int inner_loop
(int *peakscore,int *descnt,int *in_start_portion,int *least,int *pitchcnt,int windows_in_buf,dataptr dz)
{
	return(FINISHED);
}

int get_process_no(char *prog_identifier_from_cmdline,dataptr dz)
{
	return(FINISHED);
}


/******************************** USAGE1 ********************************/

int usage1(void)
{
	usage2("extspeak");
	return(USAGE_ONLY);
}

/**************************** CHECK_EXTSPEAK_PARAM_VALIDITY_AND_CONSISTENCY *****************************/

int check_extspeak_param_validity_and_consistency(int XSPK_RRND,int XSPK_ORISZ,dataptr dz)
{
//	NEEDS TO BE DONE WHEN TROFCNT IS KNOWN AND SPLICELEN IN GPSAMPS KNOWN !!!!
	int lastsamp = 0, n, k, sampsize;
	int chans = dz->infile->channels, srate = dz->infile->srate;
	int offset = dz->iparam[XSPK_OFFST];
	int *trof = dz->lparray[0];
	int splicelen, minseg, bad;
	splicelen = dz->iparam[XSPK_SPLEN] * chans;
	minseg = (splicelen * 2) + chans;
	if(dz->trofcnt == 0) {
		sprintf(errstr,"Trof array not established before testing parameters.\n");
		return PROGRAM_ERROR;
	}
	if(offset >= dz->trofcnt - 2) {
		sprintf(errstr,"ERROR: Offset (%d) too large for number of peaks found (%d).\n",offset,dz->trofcnt);
		return DATA_ERROR;
	}
	bad = 0;
	for(n = 0; n <= dz->trofcnt; n++) {
		sampsize = trof[n] - lastsamp;
		if(sampsize < minseg) {
			bad = 1;
			if(n == 0)
				fprintf(stdout,"syllab %d too short (%d mS) for two Splices (%d mS)\nbetween times 0 and %lf\n",
				n+1,(int)round(((double)(sampsize/chans)/(double)srate) * SECS_TO_MS),(int)round(dz->param[XSPK_SPLEN] * 2),(double)trof[n]/(double)(srate * chans));
			else {
				sampsize -= splicelen;
				fprintf(stdout,"syllab %d too short (%d mS) for two Splices (%d mS)\nbetween times %lf and %lf\n",
				n+1,(int)round(((double)(sampsize/chans)/(double)srate) * SECS_TO_MS),(int)round(dz->param[XSPK_SPLEN] * 2),(double)(trof[n-1]/chans)/(double)srate,(double)(trof[n]/chans)/(double)srate);
			}
		}
		lastsamp = trof[n] - splicelen;
	}
	if(bad)
		return DATA_ERROR;
	if(dz->trofcnt <= 1) {
		sprintf(errstr,"Too few trofs found (%d) for this process and offset (%d)\n",dz->trofcnt,dz->iparam[2]);
		return DATA_ERROR;
	}
	if(dz->mode < 3 || (dz->mode >= 6  && dz->mode < 9)) {
		if(dz->vflag[XSPK_INJECT]) {
			if(dz->vflag[XSPK_ORISZ] || dz->vflag[XSPK_ENV] || dz->vflag[XSPK_TRANSPOSE] ) {
				if(dz->vflag[XSPK_ORISZ]) {
					if(dz->vflag[XSPK_ENV] && dz->vflag[XSPK_TRANSPOSE])
						fprintf(stdout,"WARNING: \"Original Size\" flag redundant : \"Envelope\" & \"Transpose\" Flags not operational when INSERTING the original syllables.\n"); 
					else if(dz->vflag[XSPK_ENV])
						fprintf(stdout,"WARNING: \"Original Size\" flag redundant : \"Envelope\" Flag not operational when INSERTING the original syllables.\n"); 
					else if(dz->vflag[XSPK_TRANSPOSE])
						fprintf(stdout,"WARNING: \"Original Size\" flag redundant : \"Transpose\" Flag not operational when INSERTING the original syllables.\n");
					else 
						fprintf(stdout,"WARNING: \"Original Size\" flag redundant when INSERTING the original syllables.\n");
				} else {
					if(dz->vflag[XSPK_ENV] && dz->vflag[XSPK_TRANSPOSE])
						fprintf(stdout,"WARNING: \"Envelope\" & \"Transpose\" Flags not operational when INSERTING the original syllables.\n"); 
					else if(dz->vflag[XSPK_ENV])
						fprintf(stdout,"WARNING: \"Envelope\" Flag not operational when INSERTING the original syllables.\n"); 
					else
						fprintf(stdout,"WARNING: \"Transpose\" Flag not operational when INSERTING the original syllables.\n"); 
				}
				fflush(stdout);
			}
			dz->vflag[XSPK_TRANSPOSE] = 0;
			dz->vflag[XSPK_ENV]       = 0;
			dz->vflag[XSPK_ORISZ]    = 1;
		}	
	}
	if(dz->mode < 3 || (dz->mode >= 6  && dz->mode < 9) || (dz->mode >= 12  && dz->mode < 15)) {
		if(dz->vflag[XSPK_ORISZ] && dz->vflag[XSPK_TRANSPOSE]) {
			fprintf(stdout,"WARNING: \"Keep original size\" Flag makes \"Transposition\" Flag redundant.\n"); 
			fflush(stdout);
		}
	}
	if((dz->mode==0 || dz->mode==3 || dz->mode==6 || dz->mode==9) && dz->vflag[XSPK_RRND] && dz->infilecnt < 3) {
		switch(dz->mode) {
		case(10):	//	fall thro
		case(7):	//	fall thro
		case(4):	//	fall thro
		case(1):
			sprintf(errstr,"INFO: No randomisation possible with less than 2 (extra) input file.\n");
			return DATA_ERROR;
		case(9):	//	fall thro
		case(6):	//	fall thro
		case(3):	//	fall thro
		case(0):
			if(dz->infilecnt < 3) {
				sprintf(errstr,"WARNING: No randomisation possible with only less than 2 (extra) input file.\n");
				return DATA_ERROR;
			}
			break;
		}
	}
	if(dz->brksize[XSPK_GAIN]) {
		for(n = 0,k = 1; n < dz->brksize[XSPK_GAIN];n++,k+=2)
			dz->brk[XSPK_GAIN][k] = dbtolevel(dz->brk[XSPK_GAIN][k]);
	} else
		dz->param[XSPK_GAIN] = dbtolevel(dz->param[XSPK_GAIN]);

	return FINISHED;
}

/********************************************************************************************/

int get_the_process_no(char *prog_identifier_from_cmdline,dataptr dz)
{
	if(!strcmp(prog_identifier_from_cmdline,"extspeak"))				dz->process = EXTSPEAK;
	else {
		sprintf(errstr,"Unknown program identification string '%s'\n",prog_identifier_from_cmdline);
		return(USAGE_ONLY);
	}
	return(FINISHED);
}

/******************************** SETUP_AND_INIT_INPUT_BRKTABLE_CONSTANTS ********************************/

int setup_and_init_input_brktable_constants(dataptr dz,int brkcnt)
{	
	int n;
	if((dz->brk      = (double **)malloc(brkcnt * sizeof(double *)))==NULL) {
		sprintf(errstr,"setup_and_init_input_brktable_constants(): 1\n");
		return(MEMORY_ERROR);
	}
	if((dz->brkptr   = (double **)malloc(brkcnt * sizeof(double *)))==NULL) {
		sprintf(errstr,"setup_and_init_input_brktable_constants(): 6\n");
		return(MEMORY_ERROR);
	}
	if((dz->brksize  = (int    *)malloc(brkcnt * sizeof(int)))==NULL) {
		sprintf(errstr,"setup_and_init_input_brktable_constants(): 2\n");
		return(MEMORY_ERROR);
	}
	if((dz->firstval = (double  *)malloc(brkcnt * sizeof(double)))==NULL) {
		sprintf(errstr,"setup_and_init_input_brktable_constants(): 3\n");
		return(MEMORY_ERROR);												  
	}
	if((dz->lastind  = (double  *)malloc(brkcnt * sizeof(double)))==NULL) {
		sprintf(errstr,"setup_and_init_input_brktable_constants(): 4\n");
		return(MEMORY_ERROR);
	}
	if((dz->lastval  = (double  *)malloc(brkcnt * sizeof(double)))==NULL) {
		sprintf(errstr,"setup_and_init_input_brktable_constants(): 5\n");
		return(MEMORY_ERROR);
	}
	if((dz->brkinit  = (int     *)malloc(brkcnt * sizeof(int)))==NULL) {
		sprintf(errstr,"setup_and_init_input_brktable_constants(): 7\n");
		return(MEMORY_ERROR);
	}
	for(n=0;n<brkcnt;n++) {
		dz->brk[n]     = NULL;
		dz->brkptr[n]  = NULL;
		dz->brkinit[n] = 0;
		dz->brksize[n] = 0;
	}
	return(FINISHED);
}

/******************************** USAGE2 ********************************/

int usage2(char *str)
{
	if(!strcmp(str,"extspeak")) {
		fprintf(stderr,
	    "\nUSAGE:  extspeak extspeak 1-18 infile0 infile1 [infile2..] outfile params\n"
		"PARAMS for each mode\n"
	    "1)          wsize splice offset N gain seed [-t] [-e] [-k] [-i] [-o] [-r]\n"
	    "2)          wsize splice offset N gain seed [-t] [-e] [-k] [-i] [-o] \n"
	    "3)  pattern wsize splice offset N gain      [-t] [-e] [-k] [-i] [-o] \n"
	    "4)          wsize splice offset N gain seed [-t] [-e] [-k]           [-r]\n"
	    "5)          wsize splice offset N gain seed [-t] [-e] [-k]\n"
	    "6)  pattern wsize splice offset N gain      [-t] [-e] [-k]\n"
	    "7)  cuts          splice offset N gain seed [-t] [-e] [-k] [-i] [-o] [-r]\n"
	    "8)  cuts          splice offset N gain seed [-t] [-e] [-k] [-i] [-o] \n"
	    "9)  cutspat       splice offset N gain      [-t] [-e] [-k] [-i] [-o] \n"
	    "10) cuts          splice offset N gain seed [-t] [-e] [-k]           [-r]\n"
	    "11) cuts          splice offset N gain seed [-t] [-e] [-k]\n"
	    "12) cutspat       splice offset N gain      [-t] [-e] [-k]\n"
	    "13) cuts+targets  splice          gain seed [-t] [-e]           [-o] [-r]\n"
	    "14) cuts+targets  splice          gain seed [-t] [-e]           [-o]\n"
	    "15) cuts+tgts+pat splice          gain      [-t] [-e]           [-o]\n"
	    "16) cuts+targets  splice          gain seed [-t] [-e]                [-r]\n"
	    "17) cuts+targets  splice          gain seed [-t] [-e]\n"
	    "18) cuts+tgts+pat splice          gain      [-t] [-e]\n"
		"MODES 1-3,6-9   REPLACE  - or INJECT BETWEEN - syllabs of infile0 ...\n"
		"MODES 12-15     REPLACE SPECIFIED syllabs of infile0 ...\n"
		"MODES 4-6,10-12 MIX INTO selected syllabs of infile0 ...\n"
		"MODES 16-18     MIX INTO SPECIFIED syllabs of infile0 ...\n"
		"      ... NEW SYLLABLES, each taken from one of the other input files.\n"
		"MODES 1/4/7/10/13/16  Select syllabs from each file in turn OR (-r) at random.\n"
		"MODES 2/5/8/11/14/17  Rand-permute order of syllabs. Once ALL used, permute again.\n"
		"MODES 3/6/9/12/15/18  Select infile following specified ordering-pattern.\n"
		"\n"
		"PATTERN Pattern in a Textfile : the specific sequence of syllables to be inserted.\n"
		"        e.g. \"1 5 2\" means, use infile1 infile5 infile2 in that order (then repeat).\n"
		"CUTS    Modes 7,8,10,11 List of Times, in a Textfile : location of syllable-starts\n"
		"        in infile0 (zero time, and time at very end of file, not required).\n"
		"CUTSPAT Modes 9 and 12 List of Times, in a Textfile : location of syllable-starts\n"
		"        FOLLOWED BY single line with \"#\", followed by PATTERN Data (see above).\n"
		"CUTS+TARGETS    List of Times, in a Textfile : location of syllable-starts\n"
		"        FOLLOWED BY single line with \"#\", followed by SYLLABLES TO TARGET Data.\n"
		"CUTS+TGTS+PAT   List of Times, in a Textfile : location of syllable-starts\n"
		"        FOLLOWED BY single line with \"#\", followed by SYLLABLES TO TARGET Data\n"
		"        FOLLOWED BY single line with \"#\", followed by PATTERN Data (see above).\n"
		"If there is NO CUTS/CUTSPAT, infile0 divided into \"syllables\" by automatic process.\n"
		"\n"
		"FOR MORE INFORMATION ----- hit any key on keyboard\n");
	} else {
		fprintf(stdout,"Unknown option '%s'\n",str);
		return USAGE_ONLY;
	}
	_getch();
	while(!kbhit())
		;
	if(kbhit()) {
		fprintf(stderr,
		"\n"
		"In \"Syllables to Target\" data, the COUNT OF SYLLABLES in infile0\n"
		"is ONE MORE than the number of edit-points you have listed\n"
		"(assuming there are no edits at zero or at the file end).\n"
		"\n"
		"       Each edit point marks the END of a syllable\n"
		"       and the final syllable is AFTER the last edit.\n"
		"\n"
		"To ensure to target the VERY LAST syllable, the value \"-1\" can be used.\n"
		"\n"
		"\n"
		"\n"
		"\n" 
		"PARAMETERS\n"
		"\n"
		"\n"
		"WSIZE   Size of envelope-search window to AUTOfind syllabs in file0, in mS (try 50).\n"
		"\n"
		"SPLICE  Splice length for extracting and joining syllables (try 15).\n"
		"\n"
		"OFFSET  Number of syllables at start of infile0 to output unchanged.\n"
		"\n" 
		"N       N means write 1 original (file0) syllable for every N new syllabs inserted\n"
		"\n" 
		"        ...... EXCEPT IF flag \"-k\" is set, when ......\n"
		"\n" 
		"        N means KEEP N original (file0) syllables for every 1 new syllab inserted.\n"
		"\n"
		"GAIN    Gain of inserted syllables (Range -96dB to 0dB).\n"
		"\n" 
		"SEED    Initialisation for random reorderings, or permutations.\n"
		"        If Seed > 0, using SAME seed AGAIN gives IDENTICAL random output.\n"
		"\n" 
		"Parameters N and GAIN may vary over time.\n"
		"\n" 
		"\n"
		"\n"
		"\n" 
		"\n"
		"\n"
		"\n"
		"FOR MORE INFORMATION ----- hit any key on keyboard\n"
		"\n" 
		"\n");
	}
	_getch();
	while(!kbhit())
		;
	if(kbhit()) {
		fprintf(stderr,
		"\n"
		"\n"
		"EXAMPLE USAGE:\n"
		"\n" 
		"          For N=2 (i.e. REPLACE or KEEP 2 in 3 syllables)\n"
		"          AND 9 Original Syllables =  ---------\n"
		"\n" 
		"No flags:      Keep 1, Replace (N=)2  -XX-XX-XX\n"
		"\n" 
		"-k flags:      Keep (N=)2, Replace 1  --X--X--X\n"
		"\n" 
		"-i flag:       Keep 1, Inject (N=)2   -XX-XX-XX-XX-XX-XX-XX-XX-XX\n"
		"\n" 
		"-i & -k flags: Keep (N=)2, Inject 1   --X--X--X--X-\n"
		"\n" 
		"\n" 
		"FLAGS.\n"
		"\n" 
		"-r      RAND: Select next inserted syllable ENTIRELY at random.\n"
		"\n" 
		"-k      KEEP:  N becomes count of syllabs to KEEP rather than to REPLACE or INJECT.\n"
		"\n" 
		"-i      INJECT new syllable(s) BETWEEN existing infile0 syllables.\n"
		"        Default : new syllabs OVERWRITE existing syllables, and are resized to fit.\n"
		"\n" 
		"FOLLOWING FLAG ONLY RELEVANT where you REPLACE the original syllables.\n"
		"\n" 
		"-o      ORIGINAL SIZE: Don't Resize new syllable to size of originals.\n"
		"        (Output file will therefore not be same length/rhythm as infile0).\n"
		"\n" 
		"FOLLOWING FLAGS ONLY RELEVANT where you REPLACE or MIX INTO the original syllables.\n"
		"\n" 
		"-t      TRANSPOSE: If Resizing, Transpose/Time-stretch new syllab to adjust length.\n"
		"        Default: Cut to Size or Pad with Silence.\n"
		"\n" 
		"-e      Follow the ENVELOPE of the the original syllables in file0\n"
		"        by scaling level of inserted syllab to that of replaced/mixed-into syllable.\n"
		"        This scaling is independent of the \"GAIN\" value (which is ALSO applied).\n" 
		"\n" 
		"\n" 
		"\n" 
		"\n" 
			"FOR MORE INFORMATION ----- hit any key on keyboard\n"
		"\n");
	}
	_getch();
	while(!kbhit())
		;
	if(kbhit()) {
		fprintf(stderr,
		"CONTOUR TYPES.\n"
		"\n"
		"                                        _\n"
		"                                     / | |    _\n"
		"      _ ................ Add ..... /   |_|   | |\n"
		"     | |                               | |   | |\n"
		"     | |                     _         | |   | |\n"
		"     | |    _               | |        | |   |_|\n"
		"     | |_  | |         _    | |        | |_  | |\n"
		"    _| | |_| |_   +   | |   | |   =   _| | |_| |_\n"	
		"   | | | | | | |     _| |___| |_     | | | | | | |\n"
		"\n"
		"\n"
		"\n"
		"\n"
		"                         Gain+          _\n"
		"      _ ................ Add ..... ../ |_|\n"
		"     | |                               | |    _\n"
		"     | |                   .....       | |   | |\n"
		"     | |    _                          | |   |_|\n"
		"     | |_  | |       .....  ._.        | |_  | |\n"
		"    _| | |_| |_   +   ._.   | |   =   _| | |_| |_\n"	
		"   | | | | | | |     _| |___| |_     | | | | | | |\n"
		"\n"
		"\n"
		"\n"
		"\n"
		"                                        _\n"
		"                                     / | |\n"
		"                                    /  | |\n"
		"                                   /   | |\n"
		"                                  /    | |\n"
		"                                 /     | |\n"
		"      _ .... -e ...... _ ..Add../      |_|    _\n"
		"     | |  Envelope    |^|              | |   | |\n"
		"     | |              |^|  .....       | |   | |\n"
		"     | |    _ ........|^|... _ ...     | |   |_|\n"
		"     | |_  | |        |^|   | |        | |_  | |\n"
		"    _| | |_| |_  +    |_|   | |   =   _| | |_| |_\n"	
		"   | | | | | | |     _| |___| |_     | | | | | | |\n"
		"\n");
	}
	return(USAGE_ONLY);
}

int usage3(char *str1,char *str2)
{
	fprintf(stderr,"Insufficient parameters on command line.\n");
	return(USAGE_ONLY);
}

/****************************** GET_MODE *********************************/

int get_the_mode_from_cmdline(char *str,dataptr dz)
{
	char temp[200], *p;
	if(sscanf(str,"%s",temp)!=1) {
		sprintf(errstr,"Cannot read mode of program.\n");
		return(USAGE_ONLY);
	}
	p = temp + strlen(temp) - 1;
	while(p >= temp) {
		if(!isdigit(*p)) {
			fprintf(stderr,"Invalid mode of program entered.\n");
			return(USAGE_ONLY);
		}
		p--;
	}
	if(sscanf(str,"%d",&dz->mode)!=1) {
		fprintf(stderr,"Cannot read mode of program.\n");
		return(USAGE_ONLY);
	}
	if(dz->mode <= 0 || dz->mode > dz->maxmode) {
		fprintf(stderr,"Program mode value [%d] is out of range [1 - %d].\n",dz->mode,dz->maxmode);
		return(USAGE_ONLY);
	}
	dz->mode--;		/* CHANGE TO INTERNAL REPRESENTATION OF MODE NO */
	return(FINISHED);
}

/****************************** EXTSPEAK *********************************/

int extspeak(int XSPK_RRND,int XSPK_ORISZ,dataptr dz) 
{
	int exit_status, chans = dz->infile->channels, srate = dz->infile->srate, orig, done;
	float *ibuf = dz->sampbuf[0], *obuf = dz->sampbuf[dz->infilecnt], *ovflwbuf = dz->sampbuf[dz->infilecnt + 1];
	int gpsplicelen = dz->iparam[XSPK_SPLEN];
	int splicelen = gpsplicelen * chans, upsplice;
	int obufpos = 0, lasttrofat = 0, thistrofat, peaklen, splicend;
	int *trof = dz->lparray[0];
	int mintrof;
	int n, m, j, k, z;
	double *splicebuf = dz->parray[0], time = 0, maxgain = 0.0, *origmax = dz->parray[1], *syllmax = dz->parray[2];
	int samps_per_sec = srate * chans;
	double val, gain, normaliser = 1.0;
	int *pattern;
	double Nmaxd, origlevel = 1.0;
	int max_inserts_per_orig, patternsize, patterncnt, patno, syllread, q;
	for(n = 1; n< dz->infilecnt;n++) {
		if((syllread = fgetfbufEx(dz->sampbuf[n], dz->insams[n],dz->ifd[n],0)) < 0) {
			sprintf(errstr,"Can't read samples from soundfile %d\n",n);      // RWD was %n
			return(SYSTEM_ERROR);
		}
		if(syllread != dz->insams[n]) {
			sprintf(errstr,"Fail to read all samples from soundfile %d\n",n);   // RWD ditto
			return(SYSTEM_ERROR);
		}
		if(dz->vflag[XSPK_ENV] || (dz->mode >= 3 && dz->mode < 6) || (dz->mode >= 9 && dz->mode < 12)|| dz->mode >= 15) {
			maxgain = 0.0;
			for(q = 0; q < dz->insams[n]; q++)
				maxgain = max(maxgain,fabs(dz->sampbuf[n][q]));
			syllmax[n] = maxgain;
		}
	}
	if(dz->mode != 2 && dz->mode != 5 && dz->mode != 8 && dz->mode != 11) {
		if(dz->iparam[XSPK_SEED] > 0)
			srand(dz->iparam[XSPK_SEED]);
		else
			initrand48();
	}
	mintrof = dz->iparam[XSPK_OFFST];
	if(dz->brksize[XSPK_N])  {
		if((exit_status = get_maxvalue_in_brktable(&Nmaxd,XSPK_N,dz))<0)
			return exit_status;
	} else
		Nmaxd = dz->param[XSPK_N];
	if(dz->vflag[XSPK_KEEP])								// One inserted item for every N origs
		max_inserts_per_orig = 1;							//	Max possible 1 for every 1
	else 
		max_inserts_per_orig = (int)ceil(Nmaxd);			//	Max possible = max_inserts_per_orig
	patternsize = (dz->trofcnt+1) * max_inserts_per_orig;	//	Max possible pattern size

	if((exit_status = generate_xspk_pattern(XSPK_RRND,patternsize,dz))<0)
		return exit_status;
	if((dz->mode >= 3 && dz->mode < 6) || dz->mode >= 9) {
		fprintf(stdout,"INFO: Calculating Normalisation.\n");
		fflush(stdout);
		if((exit_status = find_orig_syllab_maxima(splicelen,dz)) < 0)
			return exit_status;
		if((exit_status = find_normaliser(&normaliser,samps_per_sec,splicelen,dz)) < 0)
			return exit_status;
	}
	pattern = dz->iparray[PATN_ARRAY];
	orig = 0;
	done = 0;
	lasttrofat = 0;
	splicend = splicelen - 1;
	patterncnt = 0;
	m = mintrof - 1;
	if(m >= 0) {
		thistrofat = trof[m];
		peaklen = thistrofat;			//	We must be at start of file : therefore no obufpos baktrak & no upsplice
		for(k = 0, j = peaklen - 1; k < thistrofat; k++,j--) {
			if (j < splicelen) 
				obuf[obufpos] = (float)(ibuf[k] * splicebuf[splicend--] * normaliser);	//	do downslice
			else																	
				obuf[obufpos] = (float)(ibuf[k] * normaliser);							//  else copy input
			if(++obufpos >= dz->buflen * 2) {
				if((exit_status = write_samps(obuf,dz->buflen,dz))<0)
					return(exit_status);
				memcpy((char *)obuf,(char *)ovflwbuf,dz->buflen * sizeof(float));
				memset((char *)ovflwbuf,0,dz->buflen * sizeof(float));
				obufpos -= dz->buflen;
			}
		}
		lasttrofat = thistrofat;
	}
	m++;
	for(n = m; n <= dz->trofcnt; n++)  {
		if(n > 0)
			lasttrofat = trof[n-1];
		thistrofat  = trof[n];
		peaklen = thistrofat - lasttrofat;
		splicend = splicelen - 1;
		time = get_syllable_time(thistrofat,lasttrofat,peaklen,n,samps_per_sec,dz);
		if((exit_status = read_values_from_all_existing_brktables(time,dz))<0)
			return exit_status;
		gain = dz->param[XSPK_GAIN];
		if(lasttrofat > 0) {			//	If we're NOT at file start	
			obufpos -= splicelen;		//	baktrak to splice to end of last segment written
			peaklen += splicelen;		//	and length of peak is therefore one splicelen longer
			upsplice = splicelen;
		} else
			upsplice = 0;				//	Prevents initial splice on start of file-segment
		splicend = splicelen - 1;
		if(dz->vflag[XSPK_ENV])
			origlevel = origmax[n];
		switch(dz->vflag[XSPK_KEEP]) {
		case(0):						//	N  = the number of syllables to insert
										//	First Copy ONE original syllable
			for(k = 0, j = peaklen - 1, m = thistrofat - peaklen; k < peaklen; k++,m++,j--) {
				if(k < upsplice)
					val = ibuf[m] * splicebuf[k];							//	do upslice
				else if (j < splicelen) 
					val = ibuf[m] * splicebuf[splicend--];					//	do downslice
				else																	
					val = ibuf[m];											//  else as is
				obuf[obufpos] = (float)(obuf[obufpos] + (val * normaliser));//	then normalise and add to buffer
				if(++obufpos >= dz->buflen * 2) {
					if((exit_status = write_samps(obuf,dz->buflen,dz))<0)
						return(exit_status);
					memcpy((char *)obuf,(char *)ovflwbuf,dz->buflen * sizeof(float));
					memset((char *)ovflwbuf,0,dz->buflen * sizeof(float));
					obufpos -= dz->buflen;
				}
			}

			for(z = 0; z < dz->iparam[XSPK_N]; z++) {	//	Then Add N NEW syllables		
				if((dz->mode >= 3 && dz->mode < 6) || dz->mode >= 9 || !dz->vflag[XSPK_INJECT]) {
					if(++n > dz->trofcnt) {				//	Advance count of original syllables
						done = 1;						//	and If out of original syllables, quit
						break;
					}
					lasttrofat = thistrofat;
					thistrofat  = trof[n];
					peaklen = thistrofat - lasttrofat;
					peaklen += splicelen;
				}
				obufpos -= splicelen;
				upsplice = splicelen;
				patno = pattern[patterncnt++];
				if((dz->mode < 3 || (dz->mode >= 6 && dz->mode < 9)) && dz->vflag[XSPK_ORISZ])	//	IF not Resizing : write-in ALL of new syllable
					peaklen = dz->insams[patno];			//	ELSE it's truncated/extended to size of original syllable
				splicend = peaklen - 1; 
				if((exit_status = insert_new_syllable(peaklen,patno,splicelen,gain,origlevel,normaliser,&obufpos,obuf,ovflwbuf,dz))<0)
					return exit_status;
			}
			break;
		case(1):					//	N  = the number of syllables to keep
			if(orig < dz->iparam[XSPK_N]) {		//	Add an original syllable, Keeping count of how many added
				for(k = 0, j = peaklen - 1, m = thistrofat - peaklen; k < peaklen; k++,m++,j--) {
					if(k < upsplice)
						val = ibuf[m] * splicebuf[k];							//	do upslice
					else if (j < splicelen) 
						val = ibuf[m] * splicebuf[splicend--];					//	do downslice
					else																	
						val = ibuf[m];											//  else as is
					obuf[obufpos] = (float)(obuf[obufpos] + (val * normaliser));//	then normalise and add to buffer
					if(++obufpos >= dz->buflen * 2) {
						if((exit_status = write_samps(obuf,dz->buflen,dz))<0)
							return(exit_status);
						memcpy((char *)obuf,(char *)ovflwbuf,dz->buflen * sizeof(float));
						memset((char *)ovflwbuf,0,dz->buflen * sizeof(float));
						obufpos -= dz->buflen;
					}
				}
				orig++;									//	Count how many orig syllabs added
			} else {				//	If all N orig syllabs have already been added
				patno = pattern[patterncnt++];		//	Add JUST 1 NEW syllable
				if((dz->mode < 3 || (dz->mode >= 6 && dz->mode < 9)) && dz->vflag[XSPK_ORISZ])
					peaklen = dz->insams[patno];
				splicend = peaklen - 1;
				if((exit_status = insert_new_syllable(peaklen,patno,splicelen,gain,origlevel,normaliser,&obufpos,obuf,ovflwbuf,dz))<0)
					return exit_status;
				orig = 0;							//	Reset orig-syllabs counter
			}
			break;
		}				
		if(done)
			break;
	}
	if(obufpos) {
		if((exit_status = write_samps(obuf,obufpos,dz))<0)
			return(exit_status);
	}
	return FINISHED;
}
				
/****************************** EXTTARGETSPEAK *********************************/

int exttargetspeak(int XSPK_RRND,int XSPK_ORISZ,dataptr dz) 
{
	int exit_status, chans = dz->infile->channels, srate = dz->infile->srate;
	float *ibuf = dz->sampbuf[0], *obuf = dz->sampbuf[dz->infilecnt], *ovflwbuf = dz->sampbuf[dz->infilecnt + 1];
	int gpsplicelen = dz->iparam[XSPK_SPLEN];
	int splicelen = gpsplicelen * chans, upsplice;
	int obufpos = 0, lasttrofat = 0, thistrofat, peaklen, splicend;
	int *trof = dz->lparray[0];
	int n, m, j, k;
	double *splicebuf = dz->parray[0], time = 0, maxgain = 0.0, *origmax = dz->parray[1], *syllmax = dz->parray[2];
	int samps_per_sec = srate * chans;
	double val, gain, normaliser = 1.0;
	int *pattern, *target;
	double origlevel = 1.0;
	int patterncnt, target_cnt, patno, syllread, q;
	for(n = 1; n< dz->infilecnt;n++) {
		if((syllread = fgetfbufEx(dz->sampbuf[n], dz->insams[n],dz->ifd[n],0)) < 0) {
			sprintf(errstr,"Can't read samples from soundfile %d\n",n);      // RWD was %n
			return(SYSTEM_ERROR);
		}
		if(syllread != dz->insams[n]) {
			sprintf(errstr,"Fail to read all samples from soundfile %d\n",n); // RWD ditto
			return(SYSTEM_ERROR);
		}
		if(dz->vflag[XSPK_ENV] || dz->mode >= 15) {
			maxgain = 0.0;
			for(q = 0; q < dz->insams[n]; q++)
				maxgain = max(maxgain,fabs(dz->sampbuf[n][q]));
			syllmax[n] = maxgain;
		}
	}
	if(dz->mode != 14 && dz->mode != 17) {
		if(dz->iparam[XSPK_SEED] > 0)
			srand(dz->iparam[XSPK_SEED]);
		else
			initrand48();
		if((exit_status = generate_xspk_pattern(XSPK_RRND,dz->trofcnt+1,dz))<0)
			return exit_status;
	}
	if(dz->mode >= 15) {
		fprintf(stdout,"INFO: Calculating Normalisation.\n");
		fflush(stdout);
		if((exit_status = find_orig_syllab_maxima(splicelen,dz)) < 0)
			return exit_status;
		if((exit_status = find_normaliser_target(&normaliser,samps_per_sec,splicelen,dz)) < 0)
			return exit_status;
	}
	target  = dz->iparray[TRGT_ARRAY];
	pattern = dz->iparray[PATN_ARRAY];
	lasttrofat = 0;
	splicend = splicelen - 1;
	patterncnt = 0;
	target_cnt = 0;
	for(n = 0; n <= dz->trofcnt; n++)  {
		if(n > 0)
			lasttrofat = trof[n-1];
		thistrofat  = trof[n];
		peaklen = thistrofat - lasttrofat;
		splicend = splicelen - 1;
		if(dz->brksize[XSPK_GAIN]) {
			time = get_syllable_time(thistrofat,lasttrofat,peaklen,n,samps_per_sec,dz);
			if((exit_status = read_value_from_brktable(time,XSPK_GAIN,dz))<0)
				return exit_status;
		}
		gain = dz->param[XSPK_GAIN];
		if(lasttrofat > 0) {			//	If we're NOT at file start	
			obufpos -= splicelen;		//	baktrak to splice to end of last segment written
			peaklen += splicelen;		//	and length of peak is therefore one splicelen longer
			upsplice = splicelen;
		} else
			upsplice = 0;				//	Prevents initial splice on start of file-segment
		splicend = splicelen - 1;
		if(dz->vflag[XSPK_ENV])
			origlevel = origmax[n];
		if(target_cnt < dz->targetcnt && n == target[target_cnt]) {	
			patno = pattern[patterncnt++];
			if((dz->mode < 15) && dz->vflag[XSPK_ORISZ])	//	IF not Resizing : write-in ALL of new syllable
				peaklen = dz->insams[patno];			//	ELSE it's truncated/extended to size of original syllable
			splicend = peaklen - 1; 
			if((exit_status = insert_new_syllable(peaklen,patno,splicelen,gain,origlevel,normaliser,&obufpos,obuf,ovflwbuf,dz))<0)
				return exit_status;
			target_cnt++;
		} else {
			for(k = 0, j = peaklen - 1, m = thistrofat - peaklen; k < peaklen; k++,m++,j--) {
				if(k < upsplice)
					val = ibuf[m] * splicebuf[k];							//	do upslice
				else if (j < splicelen) 
					val = ibuf[m] * splicebuf[splicend--];					//	do downslice
				else																	
					val = ibuf[m];											//  else as is
				obuf[obufpos] = (float)(obuf[obufpos] + (val * normaliser));//	then normalise and add to buffer
				if(++obufpos >= dz->buflen * 2) {
					if((exit_status = write_samps(obuf,dz->buflen,dz))<0)
						return(exit_status);
					memcpy((char *)obuf,(char *)ovflwbuf,dz->buflen * sizeof(float));
					memset((char *)ovflwbuf,0,dz->buflen * sizeof(float));
					obufpos -= dz->buflen;
				}
			}
		}
	}
	if(obufpos) {
		if((exit_status = write_samps(obuf,obufpos,dz))<0)
			return(exit_status);
	}
	return FINISHED;
}
				
/*************************************** EXTRACT_ENV_FROM_SNDFILE **************************/

int extract_env_from_sndfile(dataptr dz)
{
	int exit_status;
	float *envptr;
	dz->envcnt = windows_in_sndfile(dz);
	if((dz->fptr[0]=(float *)malloc((dz->envcnt+20) * sizeof(float)))==NULL) {
		sprintf(errstr,"INSUFFICIENT MEMORY to store envelope (2).\n");
		return(MEMORY_ERROR);
	}
	envptr = dz->fptr[0];
	dz->ssampsread = 1;
	while(dz->ssampsread > 0)	{
		if((dz->ssampsread = fgetfbufEx(dz->sampbuf[0], dz->insams[0],dz->ifd[0],0)) < 0) {
			sprintf(errstr,"Can't read samples from soundfile 1: extract_env_from_sndfile()\n");
			return(SYSTEM_ERROR);
		}
		if(sloom)
			display_virtual_time(dz->total_samps_read,dz);		
		if((exit_status = getenv_of_buffer(dz->ssampsread,&envptr,dz))<0)
			return exit_status;
	}
	dz->fptr[1] = envptr;		//	envend
	if((exit_status = sndseekEx(dz->ifd[0],0,0))<0) {
		sprintf(errstr,"Failed to return to start of file.\n");
		return SYSTEM_ERROR;
	}
	dz->total_samps_read = 0;
	return(FINISHED);
}

/************************* GETENV_OF_BUFFER [READENV] *******************************/

int getenv_of_buffer(int samps_to_process,float **envptr,dataptr dz)
{
	int  start_samp = 0;
	int envwindow_sampsize = dz->iparam[XSPK_WINSZ];
	float *ibuf = dz->sampbuf[0];
	float *env = *envptr;
	double convertor = 1.0/F_ABSMAXSAMP;
	while(samps_to_process >= envwindow_sampsize) {
		*env++       = (float) (getmaxsamp(start_samp,envwindow_sampsize,ibuf) * convertor);
		start_samp  += envwindow_sampsize;
		samps_to_process -= envwindow_sampsize;
	}
	if(samps_to_process)	/* Handle any final short buffer */
		*env++ = (float)(getmaxsamp(start_samp,samps_to_process,ibuf) * convertor);
	*envptr = env;
	return FINISHED;
}

/****************************** WINDOWS_IN_SNDFILE [GET_ENVSIZE] ******************************/
 
int windows_in_sndfile(dataptr dz)
{
	int envcnt, winsize = dz->iparam[XSPK_WINSZ];
	if(((envcnt = dz->insams[0]/winsize) * winsize)!=dz->insams[0])
		envcnt++;
	return envcnt;
}

/*************************** GETMAXSAMP *****************************/

double getmaxsamp(int startsamp, int sampcnt,float *buffer)
{
	int  i, endsamp = startsamp + sampcnt;
	double thisval, thismaxsamp = 0.0;
	for(i = startsamp; i<endsamp; i++) {
		if((thisval =  fabs(buffer[i]))>thismaxsamp)		   
			thismaxsamp = thisval;
	}
	return thismaxsamp;
}

/*************************** EXTTROFSGET *************************/
 
int exttrofsget(dataptr dz)
{
 	int upwards, troffcnt = 0, thistrofat, lasttrofat, env_cnt, peaklen;
	int *trof;
 	float *p, *q, *ibuf = dz->sampbuf[0];
	double *maxarray, maxlevel;
	int envwindow_sampsize = dz->iparam[XSPK_WINSZ], n, k;
	int minseglen = (dz->iparam[XSPK_SPLEN] * 2) * dz->infile->channels;		//	Minimum segment to cut is larger than 2 splices.
	float *env, *envend;

	env = dz->fptr[0];
	envend = dz->fptr[1];
					//	 2 gpsplices     * chans;
	p = env+1;
 	q = env;    
	if (*p > *q)
 		upwards = TRUE;
 	else
 		upwards = FALSE;
	troffcnt  = 0;
	lasttrofat = 0;
	dz->envcnt = 0;
 	while(p < envend) {
 		if(upwards) {
 			if(*p < *q) {
 				upwards = FALSE;
 			}
 		} else {
			if(*p > *q) {												//	Peak-segments (separated by trofs)
				if(istrof(env,envend,q,EXTSPEAK_PKSRCHWIDTH)) {
					thistrofat = dz->envcnt * envwindow_sampsize;
					peaklen = thistrofat - lasttrofat;
					if(peaklen > minseglen) {							//	Peak-segments must be longer than 2 splices
						troffcnt++;										//	This also skips getting a trof AT 0 time
						lasttrofat = thistrofat;
					}
				}
 				upwards = TRUE;
 			}
		}
 		p++;
 		q++;
		dz->envcnt++;
 	}
	if((dz->lparray[0] = (int *)malloc((troffcnt + 1) * sizeof(int))) == NULL) {	//	Allow for trof at EOF
		sprintf(errstr,"INSUFFICIENT MEMORY to store peak-locations.\n");
		return(MEMORY_ERROR);
	}
	if(dz->mode == 1 || dz->mode == 4) {
		if((dz->iparray[PERM_ARRAY] = (int *)malloc((dz->infilecnt - 1) * sizeof(int))) == NULL) {	//	Storage for permed syllable order
			sprintf(errstr,"INSUFFICIENT MEMORY to store permutation array.\n");
			return(MEMORY_ERROR);
		}
	}
	trof = dz->lparray[0];
	dz->trofcnt = troffcnt;
 	p = env+1;
 	q = env;    
	env_cnt = 0;
	if (*p > *q)
 		upwards = TRUE;
 	else
 		upwards = FALSE;
	troffcnt = 0;
	lasttrofat = 0;
	while(env_cnt < dz->envcnt) {
 		if(upwards) {
 			if(*p < *q) {
 				upwards = FALSE;
 			}
 		} else {
			if(*p > *q) {													//	Peak-segments (separated by trofs)
				if(istrof(env,envend,q,EXTSPEAK_PKSRCHWIDTH)) {
					thistrofat = env_cnt * envwindow_sampsize;
					peaklen = thistrofat - lasttrofat;
					if(peaklen > minseglen) {
						trof[troffcnt++] = env_cnt * dz->iparam[XSPK_WINSZ];//	Peak-segments must be longer than 2 splices
						lasttrofat = thistrofat;							//	This also skips getting a trof AT 0 time
					}
				}
 				upwards = TRUE;
 			}
		}
 		p++;
 		q++;
		env_cnt++;
 	}
	trof[troffcnt] = dz->insams[0];		//	Add trof at EOF
													//Only get here if dz->mode < 6
	if(dz->vflag[XSPK_ENV] || dz->mode >= 3) {					//	Get syllable maxima on infile0
		if((dz->parray[1] = (double *)malloc((dz->trofcnt + 1) * sizeof(double))) == NULL) {
			sprintf(errstr,"INSUFFICIENT MEMORY to create splice buffer (2).\n");
			return(MEMORY_ERROR);
		}
		maxarray = dz->parray[1];
		n = 0;
		lasttrofat = 0;
		while(n <= dz->trofcnt) {
			thistrofat = trof[n];
			k = lasttrofat;
			maxlevel = -HUGE;
			while(k < thistrofat) {
				maxlevel = max(maxlevel,fabs(ibuf[k]));
				k++;
			}
			maxarray[n] = maxlevel;
			lasttrofat = thistrofat;
			n++;
		}
	}
	return(FINISHED);
}

/*************************** CREATE_SNDBUFS_FOR_EXTSPEAK **************************
 *
 *	Only AFTER params have been read.
 */

int create_sndbufs_for_extspeak(dataptr dz)
{
	int bigbufsize, minobufsize, safety = 16;
	int n, k,chans = dz->infile->channels;
	double srate = (double)dz->infile->srate;
	/* All other cases */
	if(dz->bufcnt == dz->infilecnt + 3);		//	includes end-of-all bufs pointer
	if(dz->sbufptr == 0 || dz->sampbuf == 0) {
		sprintf(errstr,"buffer pointers not allocated: create_sndbufs_for_extspeak()\n");
		return(PROGRAM_ERROR);
	}
	/* minobufsize = 2 * sizeof splice */
	minobufsize = ((int)ceil((dz->param[XSPK_SPLEN] * MS_TO_SECS) * 2.0 * srate) + safety) * chans;
	minobufsize = max(minobufsize,512 * chans); 
	bigbufsize  = 0;
	for(n = 0; n < dz->infilecnt; n++)
		bigbufsize += dz->insams[n];
	bigbufsize += minobufsize * 2;
	bigbufsize *=  sizeof(float);
	if((dz->bigbuf = (float *)malloc((bigbufsize))) == NULL) {
		sprintf(errstr,"INSUFFICIENT MEMORY to create sound buffers.\n");
		return(MEMORY_ERROR);
	}
	dz->sbufptr[0] = dz->sampbuf[0] = dz->bigbuf;
	for(n=0,k=1;n<dz->infilecnt;n++,k++)								//	Inbufs = size of infles
		dz->sbufptr[k] = dz->sampbuf[k] = dz->sampbuf[n] + dz->insams[n];
	dz->sbufptr[k] = dz->sampbuf[k] = dz->sampbuf[n] + minobufsize;		// outbuf and ovflwbuf are minobufsize length
	k++;											
	n++;
	dz->sbufptr[k] = dz->sampbuf[k] = dz->sampbuf[n] + minobufsize;
	dz->buflen = minobufsize;
	return(FINISHED);
}

/*************************** ISTROF **********************************/
 
int istrof(float *env,float *envend,float *q,int width)
{
 	int up, down;
 	float *upq, *downq, *r;
 	if(width<2)
 		return(TRUE);
 	down = up = width/2;
	if(EVEN(width))
 		down = up - 1;		/* set search params above and below q */
 	downq = q - down;
 	upq   = q + up;
 	upq   = min(envend-1,upq);	/* allow for ends of envelope table */
 	downq = max(env,downq);
 	for(r = downq; r<=upq; r++) {
 		if(*q > *r)
 			return(FALSE);		
 	}
 	return(TRUE);			/* if r is minimum of all in peak, return 1 */
 }
 
/*************************** PRECALCULATE_PEAKS_ARRAY_AND_SPLICE **********************************/
 
int precalculate_peaks_array_and_splice(dataptr dz)
{
	int exit_status, chans = dz->infile->channels;
	int gpsplicelen, splicelen, n, m, k;
	double splicincr, *splicebuf;
	int srate = dz->infile->srate;
	int *trof;
	double *maxarray, maxlevel;
	int thistrofat, lasttrofat;
	float *ibuf;

	dz->iparam[XSPK_SPLEN] = (int)round(dz->param[XSPK_SPLEN] * MS_TO_SECS * (double)srate);
	if(dz->mode < 6)
		dz->iparam[XSPK_WINSZ] = (int)round(dz->param[XSPK_WINSZ] * MS_TO_SECS * (double)srate) * chans;
	gpsplicelen = dz->iparam[XSPK_SPLEN];
	splicelen = gpsplicelen * chans;
	splicincr = 1.0/(double)gpsplicelen;
	if((dz->parray[0] = (double *)malloc((splicelen * sizeof(double)))) == NULL) {
		sprintf(errstr,"INSUFFICIENT MEMORY to create splice buffer (2).\n");
		return(MEMORY_ERROR);
	}
	splicebuf = dz->parray[0];
	for(n= 0, m = 0;n < gpsplicelen; n++, m += chans) {
		for(k = 0; k < chans; k++)
			splicebuf[m+k] = (double)n * splicincr;
	}
	if(dz->mode < 6) {
		if((exit_status = extract_env_from_sndfile(dz))< 0)
			return exit_status;
		if((dz->lparray=(int **)malloc(2 * sizeof(int *)))==NULL) {
			sprintf(errstr,"INSUFFICIENT MEMORY to store peaks.\n");
			return(MEMORY_ERROR);
		}
		if((dz->lparray[0]=(int *)malloc(dz->envcnt * sizeof(int)))==NULL) {
			sprintf(errstr,"INSUFFICIENT MEMORY to store peaks (2).\n");
			return(MEMORY_ERROR);
		}
		trof = dz->lparray[0];

		if((exit_status = exttrofsget(dz))< 0)
			return exit_status;
	} else {
		trof = dz->lparray[0];		//	Array was created when special-data file "cuts" was read
		ibuf = dz->sampbuf[0];
		if((dz->ssampsread = fgetfbufEx(dz->sampbuf[0],dz->insams[0],dz->ifd[0],0)) < 0) {
			sprintf(errstr,"Can't read samples from soundfile 1: precalculate_peaks_array_and_splice()\n");
			return(SYSTEM_ERROR);
		}
		if(dz->vflag[XSPK_ENV] || (dz->mode >= 9 && dz->mode < 12) || dz->mode >= 15) {			//	Get syllable maxima on infile0
			if((dz->parray[1] = (double *)malloc((dz->trofcnt + 1) * sizeof(double))) == NULL) {
				sprintf(errstr,"INSUFFICIENT MEMORY to create splice buffer (2).\n");
				return(MEMORY_ERROR);
			}
			maxarray = dz->parray[1];
			n = 0;
			lasttrofat = 0;
			while(n <= dz->trofcnt) {
				thistrofat = trof[n];
				k = lasttrofat;
				maxlevel = -HUGE;
				while(k < thistrofat) {
					maxlevel = max(maxlevel,fabs(ibuf[k]));
					k++;
				}
				maxarray[n] = maxlevel;
				lasttrofat = thistrofat;
				n++;
			}
		}
	}
	return FINISHED;
}

/********************************* RANDPERM *************************************/

void randperm(int z,int setlen,dataptr dz)
{
	int n, t;
	for(n=0;n<setlen;n++) {
		t = (int)floor(drand48() * (n+1));
		if(t>=n)
			hprefix(z,n,setlen,dz);
		else
			hinsert(z,n,t,setlen,dz);
	}
}

/***************************** HINSERT **********************************
 *
 * Insert the value m AFTER the T-th element in iparray[].
 */

void hinsert(int z,int m,int t,int setlen,dataptr dz)
{   
	hshuflup(z,t+1,setlen,dz);
	dz->iparray[z][t+1] = m;
}

/***************************** HPREFIX ************************************
 *
 * Insert the value m at start of the permutation iparray[].
 */

void hprefix(int z,int m,int setlen,dataptr dz)
{
	hshuflup(z,0,setlen,dz);
	dz->iparray[z][0] = m;
}

/****************************** HSHUFLUP ***********************************
 *
 * move set members in iparray[] upwards, starting from element k.
 */

void hshuflup(int z,int k,int setlen,dataptr dz)
{
	int n, *i;
	int y = setlen - 1;
	i = (dz->iparray[z]+y);
	for(n = y;n > k;n--) {
		*i = *(i-1);
		i--;
	}
}

/****************************** GENERATE_XSPK_PATTERN ***********************************/

int generate_xspk_pattern(int XSPK_RRND,int patternsize,dataptr dz)
{
	int exit_status, lastperm, firstperm, n, patterncnt, syllabcnt, done = 0;
	int *pattern, *permm;
	if(dz->mode != 8 && dz->mode != 11 && dz->mode != 14 && dz->mode != 17) {		//	In these modes, pattern has already been read
		if((dz->iparray[PATN_ARRAY] = (int *)malloc(patternsize  * sizeof(int))) == NULL) {//	Storage for permed or swapped syllable order
			sprintf(errstr,"INSUFFICIENT MEMORY to store pattern of new syllables.\n");
			return(MEMORY_ERROR);
		}
	}
	pattern = dz->iparray[PATN_ARRAY];
	syllabcnt = dz->infilecnt - 1;	//	Count of files with syllables-for-insertion
	patterncnt = 0;
	switch(dz->mode) {
	case(12):	//	fall thro
	case(15):	//	fall thro
	case(9):	//	fall thro
	case(6):	//	fall thro
	case(3):	//	fall thro
	case(0):						//	Syllable pattern is in original order, or entirely random
		if(dz->vflag[XSPK_RRND]) {	//	Entirely random
			while(patterncnt < patternsize)
				pattern[patterncnt++] = (int)floor(drand48() * syllabcnt) + 1;
		} else {					//	No flags set : seq of infiles, (repeated) e.g. for 3 files 1 2 3 1 2 3 ....
			while(patterncnt < patternsize) {
				for(n = 0; n < syllabcnt; n++) {
					pattern[patterncnt] = n + 1; 
					if(++patterncnt >= patternsize) {
							done = 1;
							break;
					}
				}
				if(done)
					break;
			}
		}
		break;
	case(16):	//	fall thro
	case(13):	//	fall thro
	case(10):	//	fall thro
	case(7):	//	fall thro
	case(4):	//	fall thro
	case(1):										//	Rand-permutation of ALL input syllables, then a different ditto, etc
		permm = dz->iparray[PERM_ARRAY];
		randperm(PERM_ARRAY,syllabcnt,dz);			//	For syllabcnt 3, perms values 0,1,2 into "permm"
		lastperm = permm[syllabcnt - 1];
		while(patterncnt < patternsize) {
			for(n = 0; n < syllabcnt; n++) {
				pattern[patterncnt] = permm[n] + 1;	//	Read permd value, but add 1 to index syllab buffers from 1 upwards
				if(++patterncnt >= patternsize) {
						done = 1;
						break;
				}
			}
			if(done)
				break;
			do {
				randperm(1,syllabcnt,dz);
				firstperm = permm[0];
			} while(firstperm == lastperm);
			lastperm = permm[syllabcnt - 1];		//	Ensure no syllable repeated betwren end of one perm & start of next
		}
		break;
	case(5):	//	fall thro
	case(2):						//	Syllable pattern is input as a file : read it, and expand to fill patternsize
		if((exit_status = handle_pattern_data(patternsize,dz))<0)
			return exit_status;
		break;
	case(8):	//	fall thro
	case(11):						//	Syllable pattern HAS ALREADY BEEN input as a file : expand it to fill patternsize
		if((exit_status = expand_pattern_data(patternsize,dz))<0)
			return exit_status;
		break;
	}
	return FINISHED;
}

/************************ HANDLE_PATTERN_DATA *********************/

int handle_pattern_data(int patternsize,dataptr dz)
{
	aplptr ap = dz->application;
	int patterncnt, linecnt, done, k, j;
	char temp[2000], *q, *filename = dz->wordstor[0];
	int *pattern = dz->iparray[PATN_ARRAY];
	int *p;
	ap->data_in_file_only = TRUE;
	ap->special_range 	  = TRUE;
	ap->min_special 	  = 1;
	ap->max_special 	  = dz->infilecnt - 1;

	if((dz->fp = fopen(filename,"r"))==NULL) {
		sprintf(errstr,"Cannot open pattern datafile %s\n",filename);
		return(DATA_ERROR);
	}
	p = pattern;
	done = 0;
	linecnt = 0;
	patterncnt = 0;
	while(fgets(temp,200,dz->fp)!=NULL) {
		q = temp;
		if(is_an_empty_line_or_a_comment(temp)) {
			linecnt++;
			continue;
		}
		while(get_int_from_within_string(&q,p,0)) {
			if(*p < ap->min_special || *p > ap->max_special) {
				sprintf(errstr,"Pattern number (%d) out of range (from %d to count of NEW syllables in infile list = %d) : file %s : line %d\n",
					(int)round(*p),(int)round(ap->min_special),dz->infilecnt - 1,filename,linecnt+1);
				return(DATA_ERROR);
			}
			if(++patterncnt >= patternsize) {
				done = 1;
				break;
			}
			p++;
		}
		if(done)
			break;
		linecnt++;
	}
	if(fclose(dz->fp)<0) {
		fprintf(stdout,"WARNING: Failed to close input textfile %s.\n",filename);
		fflush(stdout);
	}
	if(patterncnt == 0) {
		sprintf(errstr,"No data found in file %s\n",filename);
		return(DATA_ERROR);
	}
	if(patterncnt < patternsize) {			//	Repeat pattern to fill pattern array
		for(k = patterncnt, j = 0; k < patternsize; k++,j++)
			pattern[k] = pattern[j];
	}
	return(FINISHED);
}

/************************************ STORE_PATTERNDATAFILE_NAME ***************************
 *
 *	Store the NAME of the special-data file, to open later.
 */

int store_patterndatafile_name(int *cmdlinecnt,char ***cmdline,dataptr dz)
{
	int exit_status;
	char *filename = (*cmdline)[0];
	if(!sloom) {
		if(*cmdlinecnt <= 0) {
			sprintf(errstr,"Insufficient parameters on command line.\n");
			return(USAGE_ONLY);
		}
	}
	if((dz->fp = fopen(filename,"r"))==NULL) {
		sprintf(errstr,"Cannot open pattern datafile %s\n",filename);
		return(DATA_ERROR);
	}
	fclose(dz->fp);
	if(dz->wordstor!=NULL)
		free_wordstors(dz);
	dz->all_words = 0;
	if((exit_status = store_filename(filename,dz))<0)
		return(exit_status);
	(*cmdline)++;		
	(*cmdlinecnt)--;
	return(FINISHED);
}

/************************************ INSERT_NEW_SYLLABLE ***************************/

int insert_new_syllable(int peaklen,int patno,int splicelen,double gain,double origlevel,double normaliser,int *obufpos, float *obuf, float *ovflwbuf,dataptr dz)
{
	int exit_status, k, j, m, z, c, gpsmpcnt, chans = dz->infile->channels;
	double frac, diff, flincr, flpos, val;
	double *splicebuf = dz->parray[0];
	float *ibuf = dz->sampbuf[patno], *origibuf, ival;
	double *syllmax =  dz->parray[2];
	int ibufpos;
	int splicend = splicelen - 1;

	if(dz->vflag[XSPK_ENV])				//	Scale to level of original syllable
		gain *= origlevel/syllmax[patno];	//	pattern vals run from 1 (not from zero), and level also stored at 1 upwards

	if((dz->mode >= 3 && dz->mode < 6) || (dz->mode >= 9 && dz->mode < 12) || dz->mode >= 15) {
		origibuf = dz->sampbuf[0];
		ibufpos = dz->total_samps_written + *obufpos;
		switch(dz->vflag[XSPK_TRANSPOSE]) {
		case(0):						//	CUT OR PAD WITH ZEROS
			for(k = 0, j = peaklen - 1; k < peaklen; k++,j--) {
				if(k >= dz->insams[patno])												// add normalised orig into existing buffer
					ival = 0.0f;
				else
					ival = ibuf[k];
				if(k < splicelen)														//	do upslice of new syllab BUT ADD ~~NO~~ old syllab (its already there in downsplice)
					val = (origibuf[ibufpos++]  + (gain * ival)) * splicebuf[k];
				else if (j < splicelen)													//	do downslice of new syllab
					val = (origibuf[ibufpos++] + (gain * ival)) * splicebuf[splicend--];
				else																	//	just add, and normalise
					val = origibuf[ibufpos++] + (gain * ival);
				obuf[*obufpos] = (float)(obuf[*obufpos] + (val * normaliser));
				if(++(*obufpos) >= dz->buflen * 2) {
					if((exit_status = write_samps(obuf,dz->buflen,dz))<0)
						return(exit_status);
					memcpy((char *)obuf,(char *)ovflwbuf,dz->buflen * sizeof(float));
					memset((char *)ovflwbuf,0,dz->buflen * sizeof(float));
					*obufpos -= dz->buflen;
				}				
			}
			break;
		case(1):						//	TRANSPOSE
			flpos = 0.0;															//	Flincr increments as GPsampcnt		
			flincr = (double)(dz->insams[patno])/(double)peaklen;
			flpos = 0.0;															//	Flincr increments as GPsampcnt		
			for(k = 0,gpsmpcnt = 0,j = peaklen - chans;k < peaklen;gpsmpcnt++,k+=chans,j-=chans) { 
				flpos = ((double)k/(double)peaklen) * (double)(dz->insams[patno]/chans);
				m = (int)floor(flpos);											//	Find the fractional part of the GPchans-xnt
				frac = flpos - (double)m;										//	Convert to the (channel-base) in the true sampcnt;
				m *= chans;														
				for(c = 0; c < chans; c++) {									//	Do interp between ALL channels
					z = m + chans;
					val = ibuf[m];
					diff = ibuf[z] - ibuf[m];
					val +=  diff * frac;
					if(k < splicelen)											//	do upslice of new syllab
						val = (origibuf[ibufpos++]  + (gain * val)) * splicebuf[k];
					else if (j < splicelen)										//	do downslice of new syllab mixing with orig
						val = (origibuf[ibufpos++] + (gain * val)) * splicebuf[splicend--];
					else														//	just add, and normalise
						val = origibuf[ibufpos++] + (gain * val);
					obuf[*obufpos] = (float)(obuf[*obufpos] + (val * normaliser));
					m++;														
					(*obufpos)++;
				}
				if(*obufpos >= dz->buflen * 2) {
					if((exit_status = write_samps(obuf,dz->buflen,dz))<0)
						return(exit_status);
					memcpy((char *)obuf,(char *)ovflwbuf,dz->buflen * sizeof(float));
					memset((char *)ovflwbuf,0,dz->buflen * sizeof(float));
					*obufpos -= dz->buflen;
				}
			}
			break;
		}
		return FINISHED;
	}
	switch(dz->vflag[XSPK_TRANSPOSE]) {
	case(0):						//	CUT OR PAD WITH ZEROS
		for(k = 0, j = peaklen - 1; k < peaklen; k++,j--) {
			if(k >= dz->insams[patno])												// add nothing into existing buffer
				;															
			else if(k < splicelen)													//	do upslice
				obuf[*obufpos] = (float)(obuf[*obufpos] + (gain * (ibuf[k] * splicebuf[k])));
			else if (j < splicelen)													//	do downslice
				obuf[*obufpos] = (float)(obuf[*obufpos] + (gain * (ibuf[k] * splicebuf[splicend--])));
			else																
				obuf[*obufpos] = (float)(obuf[*obufpos] + (gain * ibuf[k]));		//	just copy
			if(++(*obufpos) >= dz->buflen * 2) {
				if((exit_status = write_samps(obuf,dz->buflen,dz))<0)
					return(exit_status);
				memcpy((char *)obuf,(char *)ovflwbuf,dz->buflen * sizeof(float));
				memset((char *)ovflwbuf,0,dz->buflen * sizeof(float));
				*obufpos -= dz->buflen;
			}				
		}
		break;
	case(1):						//	TRANSPOSE
		for(k = 0,gpsmpcnt = 0,j = peaklen - chans;k < peaklen;gpsmpcnt++,k+=chans,j-=chans) { 
			flpos = ((double)k/(double)peaklen) * (double)(dz->insams[patno]/chans);
			m = (int)floor(flpos);											//	Find the fractional part of the GPchans-xnt
			frac = flpos - (double)m;										//	Convert to the (channel-base) in the true sampcnt;
			m *= chans;														
			for(c = 0; c < chans; c++) {									//	Do interp between ALL channels
				z = m + chans;
				val = ibuf[m];
				diff = ibuf[z] - ibuf[m];
				val  += (diff * frac);
				if(k < splicelen) 
					obuf[*obufpos] = (float)(obuf[*obufpos] + (gain * val * splicebuf[k]));
				else if (j < splicelen)										//	do upslice
					obuf[*obufpos] = (float)(obuf[*obufpos] + (gain * val * splicebuf[splicend--]));
				else														//	do downslice
					obuf[*obufpos] = (float)(obuf[*obufpos] + (gain * val));
				m++;														//	just add in
				(*obufpos)++;
			}
			if(*obufpos >= dz->buflen * 2) {
				if((exit_status = write_samps(obuf,dz->buflen,dz))<0)
					return(exit_status);
				memcpy((char *)obuf,(char *)ovflwbuf,dz->buflen * sizeof(float));
				memset((char *)ovflwbuf,0,dz->buflen * sizeof(float));
				*obufpos -= dz->buflen;
			}
		}
		break;
	}
	return FINISHED;
}

/************************ HANDLE_EXTRA_INFILES *********************/

int handle_the_extra_infiles(int *cmdlinecnt,char ***cmdline,dataptr dz)
{
					/* OPEN ANY FURTHER INFILES, CHECK COMPATIBILITY, STORE DATA AND INFO */
	int  exit_status;
	int  n;
	char *filename;
	fileptr fp2 = NULL;
	for(n=1;n<dz->infilecnt;n++) {
		filename = (*cmdline)[0];
		if((exit_status = open_checktype_getsize_and_compare_header(filename,n,&fp2,dz))<0)
			return(exit_status);
		(*cmdline)++;
		(*cmdlinecnt)--;
	}
	return(FINISHED);
}

/************************** GET_INT_FROM_WITHIN_STRING **************************
 * takes a pointer TO A POINTER to a string. If it succeeds in finding 
 * aN INT it returns the int value (*val), and it's new position in the
 * string (*str).
 */

int get_int_from_within_string(char **str,int *val,int minus_one_ok)
{
	char *p, *valstart;
	int  has_digits = 0;
	p = *str;
	while(isspace(*p))
		p++;
	valstart = p;
	if(minus_one_ok) {
		if(*p == NEGATION) {
			p++;
			if(*p != 1 + INT_TO_ASCII)	//	Only neg number allowed is -1
				return(FALSE);
		}
	}
	if(!isdigit(*p))
		return(FALSE);
	has_digits = TRUE;
	p++;	
	while(!isspace(*p) && *p!=NEWLINE && *p!=ENDOFSTR) {
		if(isdigit(*p))
			has_digits = TRUE;
		p++;
	}
	if(!has_digits || sscanf(valstart,"%d",val)!=1)
		return(FALSE);
	*str = p;
	return(TRUE);
}

/************************** OPEN_CHECKTYPE_GETSIZE_AND_COMPARE_HEADER *****************************/

int open_checktype_getsize_and_compare_header(char *filename,int fileno,fileptr *fp2,dataptr dz)
{
	int exit_status;
	infileptr ifp;
	double maxamp, maxloc;
	int maxrep;
	int getmax = 0, getmaxinfo = 0;
	fileptr fp1 = dz->infile; 

	if((dz->ifd[fileno] = sndopenEx(filename,0,CDP_OPEN_RDONLY)) < 0) {
		sprintf(errstr,"cannot open input file %s to read data.\n",filename);
		return(DATA_ERROR);
	}
	if((ifp = (infileptr)malloc(sizeof(struct filedata)))==NULL) {
		sprintf(errstr,"INSUFFICIENT MEMORY to store data on later infile. (1)\n");
		return(MEMORY_ERROR);
	}
	if((*fp2 = (fileptr)malloc(sizeof(struct fileprops)))==NULL) {
		sprintf(errstr,"INSUFFICIENT MEMORY to store data on later infile. (2)\n");
		return(MEMORY_ERROR);
	}
	if((exit_status = readhead(ifp,dz->ifd[fileno],filename,&maxamp,&maxloc,&maxrep,getmax,getmaxinfo))<0)
		return(exit_status);
	copy_to_fileptr(ifp,*fp2);
	if((*fp2)->filetype != SNDFILE) {
		sprintf(errstr,"%s is not a sound file.\n",filename);
		return(DATA_ERROR);
	}
	if((*fp2)->filetype != fp1->filetype) {
		sprintf(errstr,"Incompatible file type in input file %s.\n",filename);
		return(DATA_ERROR);
	}
	if((*fp2)->srate != fp1->srate) {
		sprintf(errstr,"Incompatible sample-rate in input file %s.\n",filename);
		return(DATA_ERROR);
	}
	if((*fp2)->channels != fp1->channels) {
		sprintf(errstr,"Incompatible channel-count in input file %s.\n",filename);
		return(DATA_ERROR);
	}
	if((dz->insams[fileno] = sndsizeEx(dz->ifd[fileno]))<0) {	    /* FIND SIZE OF FILE */
		sprintf(errstr, "Can't read size of input file %s.\n");
		return(PROGRAM_ERROR);
	}
	return(FINISHED);
}

/***************************************** FIND_ORIG_SYLLAB_MAXIMA *******************************/

int find_orig_syllab_maxima(int splicelen,dataptr dz)
{
	int thistrofat, lasttrofat, n, k;
	int *trof = dz->lparray[0];
	double maxlevel, *origmax = dz->parray[1];
	float *ibuf = dz->sampbuf[0];
	lasttrofat = 0;
	for(n = 0; n <= dz->trofcnt;n++) {
		thistrofat = trof[n];
		lasttrofat = max(0,lasttrofat - splicelen);
		maxlevel = 0.0;
		for(k = lasttrofat; k < thistrofat; k++)
			maxlevel = max(maxlevel,ibuf[k]);
		origmax[n] = maxlevel;
		lasttrofat = thistrofat;
	}
	return FINISHED;
}

/***************************************** FIND_NORMALISER *******************************/

int find_normaliser(double *normaliser,int samps_per_sec,int splicelen,dataptr dz)
{
	int exit_status, patterncnt, patno, z, n, done, orig;
	double newmaxlevel, time = 0.0;
	int lasttrofat, thistrofat, peaklen;
	int *trof = dz->lparray[0];
	int  *pattern = dz->iparray[PATN_ARRAY];
	double thislevel, *origlevel = dz->parray[1], *syllmax = dz->parray[2];
	done = 0;
	orig = 0;
	patterncnt = 0;
	lasttrofat = 0;
	newmaxlevel = 0.0;
	z = 0;
	while(z < dz->iparam[XSPK_OFFST]) {
		newmaxlevel = max(newmaxlevel,origlevel[z]);
		z++;
	}
	for(n = z; n <= dz->trofcnt; n++)  {
		if(n > 0)
			lasttrofat = trof[n-1];
		lasttrofat = max(0,lasttrofat - splicelen);
		thistrofat = trof[n];
		peaklen = thistrofat - lasttrofat;
		time = get_syllable_time(thistrofat,lasttrofat,peaklen,n,samps_per_sec,dz);
		if((exit_status = read_values_from_all_existing_brktables(time,dz))<0)
			return exit_status;
		switch(dz->vflag[XSPK_KEEP]) {
		case(0):					//	N  = the number of syllables to insert
			newmaxlevel = max(newmaxlevel,origlevel[n]);	//	Just read level of file0 syllable
			for(z = 0; z < dz->iparam[XSPK_N]; z++) {		//	Then Consider N NEW syllables
				if(++n >= dz->trofcnt) {					//	Advance count of original syllables
					done = 1;								//	and If out of original syllables, quit
					break;
				}
				if(dz->brksize[XSPK_GAIN]) {
					lasttrofat = thistrofat;			//	Reset time to read any gain table
					thistrofat = trof[n];
					time = get_syllable_time(thistrofat,lasttrofat,peaklen,n,samps_per_sec,dz);
					if((exit_status = read_value_from_brktable(time,XSPK_GAIN,dz))<0)
						return exit_status;
				}
				patno = pattern[patterncnt++];
				if(dz->vflag[XSPK_ENV]) 
					thislevel = origlevel[n] + (origlevel[n] * dz->param[XSPK_GAIN]);					//	File0-level + (scaled fileN-level X gain)
				else
					thislevel = origlevel[n] + (syllmax[patno] * dz->param[XSPK_GAIN]);					//	File0-level + (fileN-level X gain)
				newmaxlevel = max(newmaxlevel,thislevel);
			}
			break;
		case(1):					//	N  = the number of syllables to keep
			if(orig < dz->iparam[XSPK_N]) {			//	Add an original syllable, Keeping count of how many added
				newmaxlevel = max(newmaxlevel,origlevel[n]);
				orig++;								//	Count how many orig syllabs added
			} else {								//	If all N orig syllabs have already been added
				if(++n >= dz->trofcnt) {			//	Advance count of original syllables
					done = 1;						//	and If out of original syllables, quit
					break;
				}
				if(dz->brksize[XSPK_GAIN]) {
					lasttrofat = thistrofat;
					thistrofat = trof[n];
					time = get_syllable_time(thistrofat,lasttrofat,peaklen,n,samps_per_sec,dz);
					if((exit_status = read_value_from_brktable(time,XSPK_GAIN,dz))<0)
						return exit_status;
				}
				patno = pattern[patterncnt++];		//	Add JUST 1 NEW syllable
				if(dz->vflag[XSPK_ENV]) 
					thislevel = origlevel[n] + (origlevel[n] * dz->param[XSPK_GAIN]);				//	File0-level + (scaled fileN-level X gain)
				else
					thislevel = origlevel[n] + (syllmax[patno] * dz->param[XSPK_GAIN]);				//	File0-level + (fileN-level X gain)
				newmaxlevel = max(newmaxlevel,thislevel);
				orig = 0;							//	Reset orig-syllabs counter
			}
			break;
		}				
		if(done)
			break;
	}
	if(newmaxlevel > XSPK_MAXLEVEL)
		*normaliser = XSPK_MAXLEVEL/newmaxlevel;
	return FINISHED;
}

/***************************************** FIND_NORMALISER_TARGET *******************************/

int find_normaliser_target(double *normaliser,int samps_per_sec,int splicelen,dataptr dz)
{
	int exit_status, patterncnt, patno, n;
	double newmaxlevel, time = 0.0;
	int lasttrofat, thistrofat, peaklen;
	int *trof = dz->lparray[0];
	int  target_cnt, *pattern = dz->iparray[PATN_ARRAY], *target = dz->iparray[TRGT_ARRAY];
	double thislevel, *origlevel = dz->parray[1], *syllmax = dz->parray[2];
	lasttrofat = 0;
	target_cnt = 0;
	patterncnt = 0;
	newmaxlevel = 0.0;
	for(n = 0; n <= dz->trofcnt; n++)  {
		if(n > 0)
			lasttrofat = trof[n-1];
		lasttrofat = max(0,lasttrofat - splicelen);
		thistrofat = trof[n];
		peaklen = thistrofat - lasttrofat;
		if(target_cnt < dz->targetcnt &&  n == target[target_cnt]) {
			if(dz->brksize[XSPK_GAIN]) {
				time = get_syllable_time(thistrofat,lasttrofat,peaklen,n,samps_per_sec,dz);
				if((exit_status = read_value_from_brktable(time,XSPK_GAIN,dz))<0)
					return exit_status;
			}
			patno = pattern[patterncnt++];
			if(dz->vflag[XSPK_ENV]) 
				thislevel = origlevel[n] + (origlevel[n] * dz->param[XSPK_GAIN]);					//	File0-level + (scaled fileN-level X gain)
			else
				thislevel = origlevel[n] + (syllmax[patno] * dz->param[XSPK_GAIN]);					//	File0-level + (fileN-level X gain)
			newmaxlevel = max(newmaxlevel,thislevel);
			target_cnt++;
		} else
			newmaxlevel = max(newmaxlevel,origlevel[n]);
	}
	if(newmaxlevel > XSPK_MAXLEVEL)
		*normaliser = XSPK_MAXLEVEL/newmaxlevel;
	return FINISHED;
}

/*************************************** GET_SYLLABLE_TIME ****************************************/

double get_syllable_time(int thistrofat,int lasttrofat,int peaklen,int n,int samps_per_sec,dataptr dz)
{
	double time;
	if(lasttrofat == 0)				//	time is zero at first syllab of file0
		time = 0,0;
	else if(n == dz->trofcnt)		//	time is EOF at last syllab of file0
		time = (double)thistrofat/(double)samps_per_sec;
	else							//	ELSE time is mid-point of syllable
		time = (double)(thistrofat + (peaklen/2))/(double)samps_per_sec;
	return time;
}

/******************************** DBTOLEVEL ***********************/

double dbtolevel(double val)
{
	int isneg = 0;
	if(flteq(val,0.0))
		return(1.0);
	if(val < 0.0) {
		val = -val;
		isneg = 1;
	}
	val /= 20.0;
	val = pow(10.0,val);
	if(isneg)
		val = 1.0/val;
	return(val);
}	

/******************************** GETCUTDATA ***********************/

int getcutdata(int *cmdlinecnt,char ***cmdline,dataptr dz)
{
	aplptr ap = dz->application;
	int troffcnt, linecnt, chans = dz->infile->channels, srate = dz->infile->srate;
	char temp[2000], *q, *filename = (*cmdline)[0];
	int *trof;
	double *p, dummy;
	ap->data_in_file_only = TRUE;
	ap->special_range 	  = TRUE;
	ap->min_special 	  = 0;
	ap->max_special 	  = dz->duration;

	if((dz->fp = fopen(filename,"r"))==NULL) {
		sprintf(errstr,"Cannot open pattern datafile %s\n",filename);
		return(DATA_ERROR);
	}
	p = &dummy;
	linecnt = 0;
	troffcnt = 0;
	while(fgets(temp,200,dz->fp)!=NULL) {
		q = temp;
		if(is_an_empty_line_or_a_comment(temp)) {
			linecnt++;
			continue;
		}
		while(get_float_from_within_string(&q,p)) {
			if(*p < ap->min_special || *p > ap->max_special) {
				sprintf(errstr,"Cut position (%lf) out of range (%lf to %lf): file %s : line %d\n",
					*p,ap->min_special,ap->max_special,filename,linecnt+1);
				return(DATA_ERROR);
			}
			troffcnt++;
		}
		linecnt++;
	}
	if(troffcnt == 0) {
		if(fclose(dz->fp)<0) {
			fprintf(stdout,"WARNING: Failed to close input textfile %s.\n",filename);
			fflush(stdout);
		}
		sprintf(errstr,"No data found in file %s\n",filename);
		return(DATA_ERROR);
	}
	if((dz->lparray=(int **)malloc(2 * sizeof(int *)))==NULL) {
		sprintf(errstr,"INSUFFICIENT MEMORY to store trofs (1).\n");
		return(MEMORY_ERROR);
	}
	if((dz->lparray[0] = (int *)malloc((troffcnt + 1) * sizeof(int))) == NULL) {		//	Storage for syllable edit-point data
		sprintf(errstr,"INSUFFICIENT MEMORY to store trofs (2).\n");
		return(MEMORY_ERROR);
	}
	if(dz->mode == 7 || dz->mode == 10) {
		if((dz->iparray[PERM_ARRAY] = (int *)malloc((dz->infilecnt - 1) * sizeof(int))) == NULL) {	//	Storage for permed syllable order
			sprintf(errstr,"INSUFFICIENT MEMORY to store permutation array.\n");
			return(MEMORY_ERROR);
		}
	}
	if(fseek(dz->fp,0,0)< 0) {
		sprintf(errstr,"Failed to return to start of file %s.\n",filename);
		return SYSTEM_ERROR;
	}
	troffcnt = 0;
	trof = dz->lparray[0];
	while(fgets(temp,200,dz->fp)!=NULL) {
		q = temp;
		if(is_an_empty_line_or_a_comment(temp))
			continue;
		while(get_float_from_within_string(&q,p))
			trof[troffcnt++] = (int)(*p * (double)srate) * chans;
	}
	if(fclose(dz->fp)<0) {
		fprintf(stdout,"WARNING: Failed to close input textfile %s.\n",filename);
		fflush(stdout);
	}
	if(trof[troffcnt - 1] >= dz->insams[0]-chans)	//	Ignore any splice at End-of-file
		troffcnt--;									//	by moving it to the troffcnt spot
	else
		trof[troffcnt] = dz->insams[0];
	dz->trofcnt = troffcnt;
	(*cmdline)++;		
	(*cmdlinecnt)--;
	return FINISHED;
}

/************************ GET_CUTPAT_DATA *********************/

int get_cutpat_data(int *cmdlinecnt,char ***cmdline,dataptr dz)
{
	aplptr ap = dz->application;
	int troffcnt, patterncnt, linecnt, gottrof, chans = dz->infile->channels, srate = dz->infile->srate;
	char temp[2000], *q, *filename = (*cmdline)[0];
	int maxpatternsize, *trof;
	double *dp, ddummy;
	int *ip, idummy, *pattern;
	ap->data_in_file_only = TRUE;
	ap->special_range 	  = TRUE;
	ap->min_special 	  = 0;
	ap->max_special		  = dz->duration;
	ap->min_special2	  = 1;
	ap->max_special2	  = dz->infilecnt - 1;

	if((dz->fp = fopen(filename,"r"))==NULL) {
		sprintf(errstr,"Cannot open splicing & pattern datafile %s\n",filename);
		return(DATA_ERROR);
	}
	dp = &ddummy;
	ip = &idummy;
	gottrof = 0;
	linecnt = 1;
	troffcnt = 0;
	patterncnt = 0;
	while(fgets(temp,200,dz->fp)!=NULL) {
		q = temp;
		if(temp[0] == '#') {
			if(gottrof) {
				sprintf(errstr,"Too many  \"#\" lines in the file\n");
				return(DATA_ERROR);
			}
			if(strlen(temp) != 1) {
				q++;
				while(*q != ENDOFSTR) {			//	Catch error like #1 1 2 3 4, with pattern item(s) on same line as #
					if(!isspace(*q)) {
						sprintf(errstr,"Spurious characters found on \"#\" line in file %s\n",filename);
						if(fclose(dz->fp)<0) {
							fprintf(stdout,"WARNING: Failed to close input textfile %s.\n",filename);
							fflush(stdout);
						}
						return DATA_ERROR;
					}
					q++;
				}
			}
			gottrof = 1;
			linecnt++;
			continue;
		}
		else if(is_an_empty_line_or_a_comment(temp)) {
			linecnt++;
			continue;
		}
		if(gottrof) {		//	Looking for pattern numbers
			while(get_int_from_within_string(&q,ip,0)) {
				if(*ip < ap->min_special2 || *ip > ap->max_special2) {
					sprintf(errstr,"Pattern number (%d) out of range (from %d to count of NEW syllables in infile list = %d) : file %s : line %d\n",
					*ip,(int)round(ap->min_special2),(int)round(ap->max_special2),filename,linecnt);
					return(DATA_ERROR);
				}
				patterncnt++;
			}
		} else {		//	Looking for file edit times
 			while(get_float_from_within_string(&q,dp)) {
				if(*dp < ap->min_special || *dp > ap->max_special) {
					sprintf(errstr,"Cut position (%lf) out of range (%lf to %lf): file %s : line %d\n",
						*dp,ap->min_special,ap->max_special,filename,linecnt);
					return(DATA_ERROR);
				}
				troffcnt++;
			}
		}
		linecnt++;
	}
	if(troffcnt == 0 || patterncnt == 0) {
		if(fclose(dz->fp)<0) {
			fprintf(stdout,"WARNING: Failed to close input textfile %s.\n",filename);
			fflush(stdout);
		}
		if(troffcnt == 0 && patterncnt == 0) {
			sprintf(errstr,"No data found in file %s\n",filename);
			return(DATA_ERROR);
		} else if(troffcnt == 0) {
			sprintf(errstr,"No file edit times found in file %s\n",filename);
			return(DATA_ERROR);
		} else {
			if(!gottrof) {
				sprintf(errstr,"No separator \"#\" found in file %s\n",filename);
				return(DATA_ERROR);
			} else {
				sprintf(errstr,"No pattern data found in file %s\n",filename);
				return(DATA_ERROR);
			}
		}
	}
	if((dz->lparray=(int **)malloc(2 * sizeof(int *)))==NULL) {
		sprintf(errstr,"INSUFFICIENT MEMORY to store cut times (1).\n");
		return(MEMORY_ERROR);
	}
	if((dz->lparray[0] = (int *)malloc((troffcnt + 1) * sizeof(int))) == NULL) {		//	Storage for syllable edit-point data
		sprintf(errstr,"INSUFFICIENT MEMORY to store source cut times (2).\n");
		return(MEMORY_ERROR);
	}
	if(dz->mode == 7 || dz->mode == 10) {
		if((dz->iparray[PERM_ARRAY] = (int *)malloc((dz->infilecnt - 1) * sizeof(int))) == NULL) {	//	Storage for permed syllable order
			sprintf(errstr,"INSUFFICIENT MEMORY to store permutation array.\n");
			return(MEMORY_ERROR);
		}
	}
	maxpatternsize = (troffcnt+1) * (1 + MAX_PATN);
	if((dz->iparray[PATN_ARRAY] = (int *)malloc(maxpatternsize  * sizeof(int))) == NULL) {	//	Storage for pattern of syllables
		sprintf(errstr,"INSUFFICIENT MEMORY to store pattern of new syllables.\n");
		return(MEMORY_ERROR);
	}
	if(fseek(dz->fp,0,0)< 0) {
		sprintf(errstr,"Failed to return to start of file %s.\n",filename);
		return SYSTEM_ERROR;
	}
	dp = &ddummy;
	ip = &idummy;
	gottrof = 0;
	linecnt = 0;
	trof = dz->lparray[0];
	pattern = dz->iparray[PATN_ARRAY];
	troffcnt = 0;
	patterncnt = 0;
	while(fgets(temp,200,dz->fp)!=NULL) {
		q = temp;
		if(temp[0] == '#') {
			gottrof = 1;
			continue;
		}
		if(is_an_empty_line_or_a_comment(temp))
			continue;
		if(gottrof) {		//	Looking for pattern numbers
			while(get_int_from_within_string(&q,ip,0))
				pattern[patterncnt++] = *ip;
		} else {		//	Looking for file edit times
 			while(get_float_from_within_string(&q,dp))
				trof[troffcnt++] = (int)(*dp * (double)srate) * chans;
		}
	}
	if(fclose(dz->fp)<0) {
		fprintf(stdout,"WARNING: Failed to close input textfile %s.\n",filename);
		fflush(stdout);
	}
	if(trof[troffcnt - 1] >= dz->insams[0]-chans)	//	Ignore any splice at End-of-file
		troffcnt--;									//	by moving it to the troffcnt spot
	else
		trof[troffcnt] = dz->insams[0];
	dz->trofcnt = troffcnt;
	dz->itemcnt = patterncnt;
	(*cmdline)++;		
	(*cmdlinecnt)--;
	return(FINISHED);
}

/************************ EXPAND_PATTERN_DATA *********************/

int expand_pattern_data(int patternsize,dataptr dz)
{
	int k, j;
	int *pattern = dz->iparray[PATN_ARRAY];
	if(dz->itemcnt < patternsize) {			//	Repeat pattern to fill pattern array : Array already has max possible size for patterns
		for(k = dz->itemcnt, j = 0; k < patternsize; k++,j++)
			pattern[k] = pattern[j % dz->itemcnt];
	}
	return FINISHED;
}

/************************ GET_CUTTARG_DATA *********************/

int get_cuttarg_data(int *cmdlinecnt,char ***cmdline,dataptr dz)
{
	aplptr ap = dz->application;
	int troffcnt, target_cnt, linecnt, gottrof, chans = dz->infile->channels, srate = dz->infile->srate;
	char temp[2000], *q, *filename = (*cmdline)[0];
	int *trof;
	double *dp, ddummy;
	int *ip, idummy, *target, n, m, k;
	ap->data_in_file_only = TRUE;
	ap->special_range 	  = TRUE;
	ap->min_special 	  = 0;
	ap->max_special		  = dz->duration;
	ap->min_special2	  = 1;
	ap->max_special2	  = dz->infilecnt - 1;

	if((dz->fp = fopen(filename,"r"))==NULL) {
		sprintf(errstr,"Cannot open splicing & target datafile %s\n",filename);
		return(DATA_ERROR);
	}
	dp = &ddummy;
	ip = &idummy;
	gottrof = 0;
	linecnt = 1;
	troffcnt = 0;
	target_cnt = 0;
	while(fgets(temp,200,dz->fp)!=NULL) {
		q = temp;
		if(temp[0] == '#') {
			if(gottrof) {
				sprintf(errstr,"Too many  \"#\" lines in the file\n");
				return(DATA_ERROR);
			}
			if(strlen(temp) != 1) {
				q++;
				while(*q != ENDOFSTR) {			//	Catch error like #1 1 2 3 4, with target item(s) on same line as #
					if(!isspace(*q)) {
						sprintf(errstr,"Spurious characters found on \"#\" line in file %s\n",filename);
						if(fclose(dz->fp)<0) {
							fprintf(stdout,"WARNING: Failed to close input textfile %s.\n",filename);
							fflush(stdout);
						}
						return DATA_ERROR;
					}
					q++;
				}
			}
			gottrof = 1;
			linecnt++;
			continue;
		}
		else if(is_an_empty_line_or_a_comment(temp)) {
			linecnt++;
			continue;
		}
		if(gottrof) {		//	Looking for target numbers
			while(get_int_from_within_string(&q,ip,1)) {
				if((*ip != -1) && (*ip == 0 || *ip > troffcnt+1)) {
					sprintf(errstr,"Target number (%d) out of range (from 1 to count of syllabs within file0 (%d)  = %d) OR -1 (for last syllab)le: file %s : line %d\n",
					*ip,troffcnt+1,filename,linecnt);
					return(DATA_ERROR);
				}
				target_cnt++;
			}
		} else {		//	Looking for file edit times
 			while(get_float_from_within_string(&q,dp)) {
				if(*dp < ap->min_special || *dp > ap->max_special) {
					sprintf(errstr,"Cut position (%lf) out of range (%lf to %lf): file %s : line %d\n",
						*dp,ap->min_special,ap->max_special,filename,linecnt);
					return(DATA_ERROR);
				}
				troffcnt++;
			}
		}
		linecnt++;
	}
	if(troffcnt == 0 || target_cnt == 0) {
		if(fclose(dz->fp)<0) {
			fprintf(stdout,"WARNING: Failed to close input textfile %s.\n",filename);
			fflush(stdout);
		}
		if(troffcnt == 0 && target_cnt == 0) {
			sprintf(errstr,"No data found in file %s\n",filename);
			return(DATA_ERROR);
		} else if(troffcnt == 0) {
			sprintf(errstr,"No file edit times found in file %s\n",filename);
			return(DATA_ERROR);
		} else {
			if(!gottrof) {
				sprintf(errstr,"No separator \"#\" found in file %s\n",filename);
				return(DATA_ERROR);
			} else {
				sprintf(errstr,"No target data found in file %s\n",filename);
				return(DATA_ERROR);
			}
		}
	}
	if((dz->lparray=(int **)malloc(2 * sizeof(int *)))==NULL) {
		sprintf(errstr,"INSUFFICIENT MEMORY to store source cut times (1).\n");
		return(MEMORY_ERROR);
	}
	if((dz->lparray[0] = (int *)malloc((troffcnt + 1) * sizeof(int))) == NULL) {		//	Storage for syllable edit-point data
		sprintf(errstr,"INSUFFICIENT MEMORY to store source cut times (2).\n");
		return(MEMORY_ERROR);
	}
	if((dz->iparray[TRGT_ARRAY] = (int *)malloc((troffcnt+1) * sizeof(int))) == NULL) {	//	Storage for targeted syllables
		sprintf(errstr,"INSUFFICIENT MEMORY to store target syllables.\n");
		return(MEMORY_ERROR);
	}
	if(dz->mode == 13 || dz->mode == 16) {
		if((dz->iparray[PERM_ARRAY] = (int *)malloc((dz->infilecnt - 1) * sizeof(int))) == NULL) {	//	Storage for permed syllable order
			sprintf(errstr,"INSUFFICIENT MEMORY to store permutation array.\n");
			return(MEMORY_ERROR);
		}
	}
	if(fseek(dz->fp,0,0)< 0) {
		sprintf(errstr,"Failed to return to start of file %s.\n",filename);
		return SYSTEM_ERROR;
	}
	dp = &ddummy;
	ip = &idummy;
	gottrof = 0;
	linecnt = 0;
	trof = dz->lparray[0];
	target  = dz->iparray[TRGT_ARRAY];
	troffcnt = 0;
	target_cnt = 0;
	while(fgets(temp,200,dz->fp)!=NULL) {
		q = temp;
		if(temp[0] == '#') {
			gottrof = 1;
			continue;
		}
		if(is_an_empty_line_or_a_comment(temp))
			continue;
		if(gottrof) {		//	Looking for target numbers
			while(get_int_from_within_string(&q,ip,1)) {
				if(*ip < 0)
					*ip = troffcnt + 1;
				target[target_cnt++] = *ip;
			}
		} else {		//	Looking for file edit times
 			while(get_float_from_within_string(&q,dp))
				trof[troffcnt++] = (int)(*dp * (double)srate) * chans;
		}
	}
	if(fclose(dz->fp)<0) {
		fprintf(stdout,"WARNING: Failed to close input textfile %s.\n",filename);
		fflush(stdout);
	}
	if(trof[troffcnt - 1] >= dz->insams[0]-chans)	//	Ignore any splice at End-of-file
		troffcnt--;									//	by moving it to the troffcnt spot
	else
		trof[troffcnt] = dz->insams[0];
	dz->trofcnt = troffcnt;
	for(n = 0; n < target_cnt-1;n++) {				//	Sort targets to ascending order, and erase duplicates
		for(m = n+1; m < target_cnt; m++) {
			if(target[n] == target[m]) {
				fprintf(stdout,"syllable %d targeted more than once.\n",target[n]);
				fflush(stdout);
				if(m < target_cnt - 1) {
					for(k = m+1;k < target_cnt;k++)
						target[k-1] = target[k];	//	Erase by shufldown
				}
				target_cnt--;
				m--;
			} else if(target[m] < target[n]) {
				k = target[m];
				target[m] = target[n];
				target[n] = k;
			}
		}
	}
	for(n = 0; n < target_cnt;n++)					//	Make targets count from zero
		target[n]--;
	dz->targetcnt = target_cnt;
	(*cmdline)++;		
	(*cmdlinecnt)--;
	return(FINISHED);
}

/************************ GET_CUTTAPA_DATA *********************/

int get_cuttapa_data(int *cmdlinecnt,char ***cmdline,dataptr dz)
{
	aplptr ap = dz->application;
	int troffcnt, target_cnt, patterncnt, linecnt, gothash, chans = dz->infile->channels, srate = dz->infile->srate;
	char temp[2000], *q, *filename = (*cmdline)[0];
	int *trof;
	double *dp, ddummy;
	int *ip, idummy, *pattern, *target, n, m, k;
	ap->data_in_file_only = TRUE;
	ap->special_range 	  = TRUE;
	ap->min_special 	  = 0;
	ap->max_special		  = dz->duration;
	ap->min_special2	  = 1;
	ap->max_special2	  = dz->infilecnt - 1;

	if((dz->fp = fopen(filename,"r"))==NULL) {
		sprintf(errstr,"Cannot open splicing,pattern and targeting datafile %s\n",filename);
		return(DATA_ERROR);
	}
	dp = &ddummy;
	ip = &idummy;
	gothash = 0;
	linecnt = 1;
	troffcnt = 0;
	target_cnt = 0;
	patterncnt = 0;
	while(fgets(temp,200,dz->fp)!=NULL) {
		q = temp;
		if(temp[0] == '#') {
			if(gothash == 2) {
				sprintf(errstr,"Too many \"#\" signs in datafile %s\n",filename);
				return(DATA_ERROR);
			}
			if(strlen(temp) != 1) {
				q++;
				while(*q != ENDOFSTR) {			//	Catch error like #1 1 2 3 4, with pattern item(s) on same line as #
					if(!isspace(*q)) {
						if(gothash)
							sprintf(errstr,"Spurious characters found on second \"#\" line in file %s\n",filename);
						else 
							sprintf(errstr,"Spurious characters found on first \"#\" line in file %s\n",filename);
						if(fclose(dz->fp)<0) {
							fprintf(stdout,"WARNING: Failed to close input textfile %s.\n",filename);
							fflush(stdout);
						}
						return DATA_ERROR;
					}
					q++;
				}
			}
			gothash++;
			linecnt++;
			continue;
		}
		else if(is_an_empty_line_or_a_comment(temp)) {
			linecnt++;
			continue;
		}
		if(gothash == 2) {		//	Looking for target numbers
			while(get_int_from_within_string(&q,ip,1)) {
				if((*ip != -1) && (*ip == 0 || *ip > troffcnt+1)) {
					sprintf(errstr,"Target number (%d) out of range (from 1 to count of syllabs within file0 = %d) OR -1 for last syllable: file %s : line %d\n",
					*ip,troffcnt+1,filename,linecnt);
					return(DATA_ERROR);
				}
				target_cnt++;
			}
		} else if(gothash == 1) {		//	Looking for pattern
			while(get_int_from_within_string(&q,ip,0)) {
				if(*ip < ap->min_special2 || *ip > ap->max_special2) {
					sprintf(errstr,"Pattern number (%d) out of range (from %d to count of NEW syllables (%d) in infile list = %d) : file %s : line %d\n",
					*ip,dz->infilecnt-1,(int)round(ap->min_special2),(int)round(ap->max_special2),filename,linecnt);
					return(DATA_ERROR);
				}
				patterncnt++;
			}
		} else {		//	Looking for file edit times
 			while(get_float_from_within_string(&q,dp)) {
				if(*dp < ap->min_special || *dp > ap->max_special) {
					sprintf(errstr,"Cut position (%lf) out of range (%lf to %lf): file %s : line %d\n",
						*dp,ap->min_special,ap->max_special,filename,linecnt);
					return(DATA_ERROR);
				}
				troffcnt++;
			}
		}
		linecnt++;
	}
	if(troffcnt == 0 || patterncnt == 0 || target_cnt == 0) {
		if(fclose(dz->fp)<0) {
			fprintf(stdout,"WARNING: Failed to close input textfile %s.\n",filename);
			fflush(stdout);
		}
		if(troffcnt == 0 && patterncnt == 0 && target_cnt == 0) {
			sprintf(errstr,"No data found in file %s\n",filename);
			return(DATA_ERROR);
		} else if(troffcnt == 0) {
			sprintf(errstr,"No file edit times found in file %s\n",filename);
			return(DATA_ERROR);
		} else {
			if(gothash == 0) {
				sprintf(errstr,"No separator \"#\" found in file %s\n",filename);
				return(DATA_ERROR);
			} else if(gothash == 1) {
				sprintf(errstr,"No 2nd separator \"#\" found in file %s\n",filename);
				return(DATA_ERROR);
			} else if(target_cnt == 0) {
				sprintf(errstr,"No target data found in file %s\n",filename);
				return(DATA_ERROR);
			} else {
				sprintf(errstr,"No pattern data found in file %s\n",filename);
				return(DATA_ERROR);
			}
		}
	}
	if((dz->lparray=(int **)malloc(2 * sizeof(int *)))==NULL) {
		sprintf(errstr,"INSUFFICIENT MEMORY to store cut times (1).\n");
		return(MEMORY_ERROR);
	}
	if((dz->lparray[0] = (int *)malloc((troffcnt + 1) * sizeof(int))) == NULL) {		//	Storage for syllable edit-point data
		sprintf(errstr,"INSUFFICIENT MEMORY to store source cut times (2).\n");
		return(MEMORY_ERROR);
	}
	if((dz->iparray[PATN_ARRAY] = (int *)malloc((troffcnt+1) * sizeof(int))) == NULL) {	//	Storage for pattern of syllables
		sprintf(errstr,"INSUFFICIENT MEMORY to store target syllables.\n");
		return(MEMORY_ERROR);
	}
	if((dz->iparray[TRGT_ARRAY] = (int *)malloc((troffcnt+1) * sizeof(int))) == NULL) {	//	Storage for target syllables
		sprintf(errstr,"INSUFFICIENT MEMORY to store target syllables.\n");
		return(MEMORY_ERROR);
	}
	if(fseek(dz->fp,0,0)< 0) {
		sprintf(errstr,"Failed to return to start of file %s.\n",filename);
		return SYSTEM_ERROR;
	}
	dp = &ddummy;
	ip = &idummy;
	gothash = 0;
	linecnt = 0;
	trof = dz->lparray[0];
	pattern = dz->iparray[PATN_ARRAY];
	target  = dz->iparray[TRGT_ARRAY];
	troffcnt = 0;
	patterncnt = 0;
	target_cnt = 0;
	while(fgets(temp,200,dz->fp)!=NULL) {
		q = temp;
		if(temp[0] == '#') {
			gothash++;
			continue;
		}
		if(is_an_empty_line_or_a_comment(temp))
			continue;
		if(gothash == 2) {			//	Looking for target list
			while(get_int_from_within_string(&q,ip,1)) {
				if(*ip < 0)
					*ip = troffcnt+1;
				target[target_cnt++] = *ip;
			}
		} else if(gothash == 1) {		//	Looking for pattern numbers
			while(get_int_from_within_string(&q,ip,0))
				pattern[patterncnt++] = *ip;
		} else {		//	Looking for file edit times
 			while(get_float_from_within_string(&q,dp))
				trof[troffcnt++] = (int)(*dp * (double)srate) * chans;
		}
	}
	if(fclose(dz->fp)<0) {
		fprintf(stdout,"WARNING: Failed to close datafile %s.\n",filename);
		fflush(stdout);
	}
	if(trof[troffcnt - 1] >= dz->insams[0]-chans)	//	Ignore any splice at End-of-file
		troffcnt--;									//	by moving it to the troffcnt spot
	else
		trof[troffcnt] = dz->insams[0];
	dz->trofcnt = troffcnt;
	for(n = 0; n < target_cnt-1;n++) {				//	Sort targets to ascending order, and erase duplicates
		for(m = n+1; m < target_cnt; m++) {
			if(target[n] == target[m]) {
				fprintf(stdout,"syllable %d targeted more than once.\n",target[n]);
				fflush(stdout);
				if(m < target_cnt - 1) {
					for(k = m+1;k < target_cnt;k++)
						target[k-1] = target[k];	//	Erase by shufldown
				}
				target_cnt--;
				m--;
			} else if(target[m] < target[n]) {		//	Swap out-of-order targets
				k = target[m];
				target[m] = target[n];
				target[n] = k;
			}
		}
	}
	for(n = 0; n < target_cnt;n++)					//	Make targets count from zero
		target[n]--;
	dz->targetcnt = target_cnt;
	if(patterncnt < dz->trofcnt + 1) {				//	Expand pattern to max possible size
		for(n = 0, k = patterncnt; k < dz->trofcnt+1;n++,k++)
			pattern[k] = pattern[n % patterncnt];
	}
	(*cmdline)++;		
	(*cmdlinecnt)--;
	return(FINISHED);
}
