Bladeren bron

initial commit

richarddobson 3 jaren geleden
bovenliggende
commit
72e17252d0
4 gewijzigde bestanden met toevoegingen van 6164 en 0 verwijderingen
  1. 20 0
      dev/repitch/CMakeLists.txt
  2. 2178 0
      dev/repitch/ap_repitch.c
  3. 236 0
      dev/repitch/main.c
  4. 3730 0
      dev/repitch/repitch.c

+ 20 - 0
dev/repitch/CMakeLists.txt

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

+ 2178 - 0
dev/repitch/ap_repitch.c

@@ -0,0 +1,2178 @@
+/*
+ * Copyright (c) 1983-2013 Trevor Wishart and Composers Desktop Project Ltd
+ * http://www.trevorwishart.co.uk
+ * http://www.composersdesktop.com
+ *
+ This file is part of the CDP System.
+
+    The CDP System is free software; you can redistribute it
+    and/or modify it under the terms of the GNU Lesser General Public
+    License as published by the Free Software Foundation; either
+    version 2.1 of the License, or (at your option) any later version.
+
+    The CDP System is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public
+    License along with the CDP System; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+    02111-1307 USA
+ *
+ */
+
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <structures.h>
+#include <cdpmain.h>
+#include <tkglobals.h>
+#include <pnames.h>
+#include <repitch.h>
+#include <processno.h>
+#include <modeno.h>
+#include <globcon.h>
+#include <logic.h>
+#include <filetype.h>
+#include <mixxcon.h>
+#include <flags.h>
+#include <speccon.h>
+#include <arrays.h>
+#include <special.h>
+#include <formants.h>
+#include <sfsys.h>
+#include <osbind.h>
+#include <string.h>
+#include <math.h>
+#include <srates.h>
+#include <pvoc.h>
+
+//TW UPDATES
+#include <vowels.h>
+#include <ctype.h>
+
+
+/********************************************************************************************/
+/********************************** FORMERLY IN pconsistency.c ******************************/
+/********************************************************************************************/
+
+static int 	check_consistency_of_pitch_params(dataptr dz);
+static int 	check_consistency_of_track_params(dataptr dz);
+static void establish_datareduction(int k,dataptr dz);
+static int	check_compatibility_pinvert_params(dataptr dz);
+static int 	check_validity_of_prandomise_params(dataptr dz);
+static int 	check_consistency_of_pcut_params(dataptr dz);
+static int	check_compatibility_of_pfix_smoothing_flags(dataptr dz);
+static int  check_for_valid_transposition_ratios(double,double,dataptr);
+
+/********************************************************************************************/
+/********************************** FORMERLY IN preprocess.c ********************************/
+/********************************************************************************************/
+
+static int  specpitch_preprocess(dataptr dz);
+static int  adjust_parameters_for_specpitch(dataptr dz);
+static int  establish_internal_arrays_for_pitchwork(dataptr dz);
+static int  establish_arrays_for_pitchwork(dataptr dz);
+static int  track_preprocess(dataptr dz);
+static int  convert_track_params(dataptr dz);
+static int  setup_internal_params_and_arrays_for_track(dataptr dz);
+static int  papprox_preprocess(dataptr dz);
+static int  pexag_preprocess(dataptr dz);
+static int  pinvert_preprocess(dataptr dz);
+static int  pquantise_preprocess(dataptr dz);
+static int  adjust_params_and_setup_internal_params_for_prandomise(dataptr dz);
+static int  adjust_params_and_setup_internal_params_for_psmooth(dataptr dz);
+static int  adjust_params_for_ptranspose(dataptr dz);
+static int  pvibrato_preprocess(dataptr dz);
+static int  pfix_preprocess(dataptr dz);
+static int  repitchb_preprocess(dataptr dz);
+
+/********************************************************************************************/
+/********************************** FORMERLY IN specialin.c *********************************/
+/********************************************************************************************/
+
+static int  get_transposition_value(double val,int datatype,dataptr dz);
+static int  convert_constant_to_transposition_table(double val,dataptr dz);
+static int  getsize_and_getdata_from_transpos_brkfile
+			(char *filename,double minval, double maxval,int which_type, dataptr dz);
+static int  read_pquantise_set(char *filename,dataptr dz);
+static int  sort_quantising_set(dataptr dz);
+static int  generate_octave_duplicates(dataptr dz);
+static int  eliminate_duplicates_in_quantising_set(dataptr dz);
+static int  read_interval_mapping(char *str,dataptr dz);
+static int  get_mapping(char *filename,dataptr dz);
+static int  sort_mapping(dataptr dz);
+static int  get_and_count_data_from_textfile(char *filename,double **brktable,int *brksize);
+static int get_and_count_timedata_from_textfile(char *filename,int **brktable1,int **brktable2,int *brksize,dataptr dz);
+//TW UPDATES
+static int  get_the_pitches(char *filename,double **times,double **pitch,int *pcnt);
+static int  get_pitch(char *str,double *pitch);
+
+/***************************************************************************************/
+/****************************** FORMERLY IN aplinit.c **********************************/
+/***************************************************************************************/
+
+/***************************** ESTABLISH_BUFPTRS_AND_EXTRA_BUFFERS **************************/
+
+int establish_bufptrs_and_extra_buffers(dataptr dz)
+{
+	dz->extra_bufcnt = -1;	/* ENSURE EVERY CASE HAS A PAIR OF ENTRIES !! */
+	dz->bptrcnt = 0;
+	dz->bufcnt  = 0;
+	switch(dz->process) {
+	case(PITCH):      		dz->extra_bufcnt =  3; dz->bptrcnt = 2; 	break;
+	case(TRACK):      		dz->extra_bufcnt =  3; dz->bptrcnt = 2; 	break;
+	case(P_APPROX):   		dz->extra_bufcnt =  0; dz->bptrcnt = 0; 	break;
+	case(P_EXAG): 	  		dz->extra_bufcnt =  0; dz->bptrcnt = 0; 	break;
+	case(P_INVERT):   		dz->extra_bufcnt =  0; dz->bptrcnt = 0; 	break;
+	case(P_QUANTISE): 		dz->extra_bufcnt =  0; dz->bptrcnt = 0; 	break;
+	case(P_RANDOMISE):		dz->extra_bufcnt =  0; dz->bptrcnt = 0; 	break;
+	case(P_SMOOTH):   		dz->extra_bufcnt =  0; dz->bptrcnt = 0; 	break;
+	case(P_TRANSPOSE):		dz->extra_bufcnt =  0; dz->bptrcnt = 0; 	break;
+	case(P_VIBRATO):  		dz->extra_bufcnt =  0; dz->bptrcnt = 0; 	break;
+	case(P_CUT): 	  		dz->extra_bufcnt =  0; dz->bptrcnt = 0; 	break;
+	case(P_FIX):      		dz->extra_bufcnt =  0; dz->bptrcnt = 0; 	break;
+	case(REPITCH):    		dz->extra_bufcnt =  0; dz->bptrcnt = 0; 	break;
+	case(REPITCHB):   		dz->extra_bufcnt =  0; dz->bptrcnt = 0; 	break;
+	case(TRNSP):      		dz->extra_bufcnt =  1; dz->bptrcnt = 1; 	break;
+	case(TRNSF):      		dz->extra_bufcnt =  1; dz->bptrcnt = 1; 	break;
+//TW UPDATES
+	case(P_SYNTH): 			dz->extra_bufcnt =  0; dz->bptrcnt = 2; 	break;
+	case(P_VOWELS): 		dz->extra_bufcnt =  0; dz->bptrcnt = 2; 	break;
+	case(P_GEN): 			dz->extra_bufcnt =  0; dz->bptrcnt = 0; 	break;
+	case(P_INTERP): 		dz->extra_bufcnt =  0; dz->bptrcnt = 0; 	break;
+	case(P_INSERT):			dz->extra_bufcnt =  0; dz->bptrcnt = 0; 	break;
+	case(P_SINSERT):		dz->extra_bufcnt =  0; dz->bptrcnt = 0; 	break;
+	case(P_PTOSIL):			dz->extra_bufcnt =  0; dz->bptrcnt = 0; 	break;
+	case(P_NTOSIL):			dz->extra_bufcnt =  0; dz->bptrcnt = 0; 	break;
+	case(ANALENV):			dz->extra_bufcnt =  0; dz->bptrcnt = 4; 	break;
+	case(P_BINTOBRK):		dz->extra_bufcnt =  0; dz->bptrcnt = 0; 	break;
+
+	default:
+		sprintf(errstr,"Unknown program type [%d] in establish_bufptrs_and_extra_buffers()\n",dz->process);
+		return(PROGRAM_ERROR);
+	}
+
+	if(dz->extra_bufcnt < 0) {
+		sprintf(errstr,"bufcnts have not been set: establish_bufptrs_and_extra_buffers()\n");
+		return(PROGRAM_ERROR);
+	}
+	return establish_spec_bufptrs_and_extra_buffers(dz);
+}
+
+/***************************** SETUP_INTERNAL_ARRAYS_AND_ARRAY_POINTERS **************************/
+
+int setup_internal_arrays_and_array_pointers(dataptr dz)
+{
+	int n;		 
+	dz->ptr_cnt    = -1;		/* base constructor...process */
+	dz->array_cnt  = -1;
+	dz->iarray_cnt = -1;
+	dz->larray_cnt = -1;
+	switch(dz->process) {
+	case(PITCH):  	dz->array_cnt =2;  dz->iarray_cnt = 0; dz->larray_cnt = 0; dz->ptr_cnt = 0; dz->fptr_cnt = 0;	break;
+	case(TRACK):  	dz->array_cnt =2;  dz->iarray_cnt = 0; dz->larray_cnt = 0; dz->ptr_cnt = 0; dz->fptr_cnt = 0;	break;
+	case(P_APPROX): dz->array_cnt =1;  dz->iarray_cnt =1;  dz->larray_cnt = 0; dz->ptr_cnt = 0; dz->fptr_cnt = 0;	break;
+	case(P_EXAG): 	dz->array_cnt = 0; dz->iarray_cnt = 0; dz->larray_cnt = 0; dz->ptr_cnt = 0; dz->fptr_cnt = 0;	break;
+	case(P_INVERT): dz->array_cnt =1;  dz->iarray_cnt = 0; dz->larray_cnt = 0; dz->ptr_cnt = 0; dz->fptr_cnt = 0;	break;
+	case(P_QUANTISE): dz->array_cnt =1;	 dz->iarray_cnt = 0; dz->larray_cnt = 0; dz->ptr_cnt = 0; dz->fptr_cnt = 0;	break;
+	case(P_RANDOMISE):dz->array_cnt = 0; dz->iarray_cnt = 0; dz->larray_cnt = 0; dz->ptr_cnt = 0; dz->fptr_cnt = 0;	break;
+	case(P_SMOOTH): dz->array_cnt = 0; dz->iarray_cnt = 0; dz->larray_cnt = 0; dz->ptr_cnt = 0; dz->fptr_cnt = 0;	break;
+	case(P_TRANSPOSE):dz->array_cnt = 0; dz->iarray_cnt = 0; dz->larray_cnt = 0; dz->ptr_cnt = 0; dz->fptr_cnt = 0;	break;
+	case(P_VIBRATO):  dz->array_cnt =1;	 dz->iarray_cnt = 0; dz->larray_cnt = 0; dz->ptr_cnt = 0; dz->fptr_cnt = 0;	break;
+	case(P_CUT): 	dz->array_cnt = 0; dz->iarray_cnt = 0; dz->larray_cnt = 0; dz->ptr_cnt = 0; dz->fptr_cnt = 0;	break;
+	case(P_FIX):    dz->array_cnt = 0; dz->iarray_cnt = 0; dz->larray_cnt = 0; dz->ptr_cnt = 0; dz->fptr_cnt = 0;	break;
+	case(REPITCH): 	dz->array_cnt =1;  dz->iarray_cnt = 0; dz->larray_cnt = 0; dz->ptr_cnt = 0; dz->fptr_cnt = 0;	break;
+	case(REPITCHB):	dz->array_cnt =1;  dz->iarray_cnt = 0; dz->larray_cnt = 0; dz->ptr_cnt = 0; dz->fptr_cnt = 0;	break;
+	case(TRNSP):  	dz->array_cnt = 0; dz->iarray_cnt = 0; dz->larray_cnt = 0; dz->ptr_cnt = 0; dz->fptr_cnt = 0;	break;
+	case(TRNSF):  	dz->array_cnt = 0; dz->iarray_cnt = 0; dz->larray_cnt = 0; dz->ptr_cnt = 0; dz->fptr_cnt = 0;	break;
+//TW UPDATES
+	case(P_SYNTH):  dz->array_cnt = 1; dz->iarray_cnt = 0; dz->larray_cnt = 0; dz->ptr_cnt = 0; dz->fptr_cnt = 0;	break;
+	case(P_VOWELS): dz->array_cnt = 1; dz->iarray_cnt = 1; dz->larray_cnt = 0; dz->ptr_cnt = 0; dz->fptr_cnt = 0;	break;
+	case(P_GEN): 	dz->array_cnt = 2; dz->iarray_cnt = 0; dz->larray_cnt = 0; dz->ptr_cnt = 0; dz->fptr_cnt = 0;	break;
+	case(P_INSERT): dz->array_cnt = 0; dz->iarray_cnt = 0; dz->larray_cnt = 2; dz->ptr_cnt = 0; dz->fptr_cnt = 0;	break;
+	case(P_SINSERT): dz->array_cnt = 0; dz->iarray_cnt = 0; dz->larray_cnt = 2; dz->ptr_cnt = 0; dz->fptr_cnt = 0;	break;
+	case(P_PTOSIL):	dz->array_cnt = 0; dz->iarray_cnt = 0; dz->larray_cnt = 0; dz->ptr_cnt = 0; dz->fptr_cnt = 0;	break;
+	case(P_NTOSIL):	dz->array_cnt = 0; dz->iarray_cnt = 0; dz->larray_cnt = 0; dz->ptr_cnt = 0; dz->fptr_cnt = 0;	break;
+	case(ANALENV):	dz->array_cnt = 0; dz->iarray_cnt = 0; dz->larray_cnt = 0; dz->ptr_cnt = 0; dz->fptr_cnt = 0;	break;
+	case(P_BINTOBRK): dz->array_cnt=1; dz->iarray_cnt = 0; dz->larray_cnt = 0; dz->ptr_cnt = 0; dz->fptr_cnt = 0;	break;
+	case(P_INTERP):	dz->array_cnt = 0; dz->iarray_cnt = 0; dz->larray_cnt = 0; dz->ptr_cnt = 0; dz->fptr_cnt = 0;	break;
+
+	}
+
+/*** WARNING ***
+ANY APPLICATION DEALING WITH A NUMLIST INPUT: MUST establish AT LEAST 1 double array: i.e. dz->array_cnt = at least 1
+**** WARNING ***/
+
+
+	if(dz->array_cnt < 0 || dz->iarray_cnt < 0 || dz->larray_cnt < 0 || dz->ptr_cnt < 0 || dz->fptr_cnt < 0) {
+		sprintf(errstr,"array_cnt not set in setup_internal_arrays_and_array_pointers()\n");	   
+		return(PROGRAM_ERROR);
+	}
+
+	if(dz->array_cnt > 0) {  
+		if((dz->parray  = (double **)malloc(dz->array_cnt * sizeof(double *)))==NULL) {
+			sprintf(errstr,"INSUFFICIENT MEMORY for internal double arrays.\n");
+			return(MEMORY_ERROR);
+		}
+		for(n=0;n<dz->array_cnt;n++)
+			dz->parray[n] = NULL;
+	}
+	if(dz->iarray_cnt > 0) {
+		if((dz->iparray = (int     **)malloc(dz->iarray_cnt * sizeof(int *)))==NULL) {
+			sprintf(errstr,"INSUFFICIENT MEMORY for internal int arrays.\n");
+			return(MEMORY_ERROR);
+		}
+		for(n=0;n<dz->iarray_cnt;n++)
+			dz->iparray[n] = NULL;
+	}
+	if(dz->larray_cnt > 0) {	  
+		if((dz->lparray = (int    **)malloc(dz->larray_cnt * sizeof(int *)))==NULL) {
+			sprintf(errstr,"INSUFFICIENT MEMORY for internal long arrays.\n");
+			return(MEMORY_ERROR);
+		}
+		for(n=0;n<dz->larray_cnt;n++)
+			dz->lparray[n] = NULL;
+	}
+	if(dz->ptr_cnt > 0)   {  	  
+		if((dz->ptr    	= (double  **)malloc(dz->ptr_cnt  * sizeof(double *)))==NULL) {
+			sprintf(errstr,"INSUFFICIENT MEMORY for internal pointer arrays.\n");
+			return(MEMORY_ERROR);
+		}
+		for(n=0;n<dz->ptr_cnt;n++)
+			dz->ptr[n] = NULL;
+	}
+	if(dz->fptr_cnt > 0)   {  	  
+		if((dz->fptr = (float  **)malloc(dz->fptr_cnt * sizeof(float *)))==NULL) {
+			sprintf(errstr,"INSUFFICIENT MEMORY for internal float-pointer arrays.\n");
+			return(MEMORY_ERROR);
+		}
+		for(n=0;n<dz->fptr_cnt;n++)
+			dz->fptr[n] = NULL;
+	}
+	return(FINISHED);
+}
+
+/****************************** ASSIGN_PROCESS_LOGIC *********************************/
+
+int assign_process_logic(dataptr dz)
+{						 
+	switch(dz->process) {
+	case(PITCH):		setup_process_logic(ANALFILE_ONLY,		  	EQUAL_ANALFILE,		ANALFILE_OUT,	dz);	break;
+	case(TRACK):		setup_process_logic(ANALFILE_ONLY,		  	EQUAL_ANALFILE,		ANALFILE_OUT,	dz);	break;
+	case(P_APPROX):	  	setup_process_logic(PITCHFILE_ONLY,		  	PITCH_TO_BIGPITCH,	PITCH_OUT,		dz);	break;
+	case(P_EXAG):	  	setup_process_logic(PITCHFILE_ONLY,		  	PITCH_TO_PITCH,		PITCH_OUT,		dz);	break;
+	case(P_INVERT):	  	setup_process_logic(PITCHFILE_ONLY,		  	PITCH_TO_PITCH,		PITCH_OUT,		dz);	break;
+	case(P_QUANTISE): 	setup_process_logic(PITCHFILE_ONLY,		  	PITCH_TO_PITCH,		PITCH_OUT,		dz);	break;
+	case(P_RANDOMISE):	setup_process_logic(PITCHFILE_ONLY,		  	PITCH_TO_PITCH,		PITCH_OUT,		dz);	break;
+	case(P_SMOOTH):	  	setup_process_logic(PITCHFILE_ONLY,		  	PITCH_TO_PITCH,		PITCH_OUT,		dz);	break;
+	case(P_TRANSPOSE):	setup_process_logic(PITCHFILE_ONLY,		  	PITCH_TO_PITCH,		PITCH_OUT,		dz);	break;
+	case(P_VIBRATO):  	setup_process_logic(PITCHFILE_ONLY,		  	PITCH_TO_PITCH,		PITCH_OUT,		dz);	break;
+	case(P_CUT):	  	setup_process_logic(PITCHFILE_ONLY,		  	PITCH_TO_BIGPITCH,	PITCH_OUT,		dz);	break;
+//TW UPDATES
+	case(P_SYNTH):		setup_process_logic(PITCHFILE_ONLY,		  	PITCH_TO_ANAL,		ANALFILE_OUT,	dz);	break;
+	case(P_VOWELS):		setup_process_logic(PITCHFILE_ONLY,		  	PITCH_TO_ANAL,		ANALFILE_OUT,	dz);	break;
+	case(P_INTERP):		setup_process_logic(PITCHFILE_ONLY,		  	PITCH_TO_PITCH,		PITCH_OUT,		dz);	break;
+	case(P_GEN):		setup_process_logic(NO_FILE_AT_ALL,		  	PITCH_TO_BIGPITCH,	PITCH_OUT,		dz);	break;
+	case(P_INSERT):		setup_process_logic(PITCHFILE_ONLY,		  	PITCH_TO_PITCH,		PITCH_OUT,		dz);	break;
+	case(P_SINSERT):	setup_process_logic(PITCHFILE_ONLY,		  	PITCH_TO_PITCH,		PITCH_OUT,		dz);	break;
+	case(P_PTOSIL):		setup_process_logic(PITCHFILE_ONLY,		  	PITCH_TO_PITCH,		PITCH_OUT,		dz);	break;
+	case(P_NTOSIL):		setup_process_logic(PITCHFILE_ONLY,		  	PITCH_TO_PITCH,		PITCH_OUT,		dz);	break;
+	case(ANALENV):		setup_process_logic(ANALFILE_ONLY,		  	UNEQUAL_ENVFILE,	ENVFILE_OUT,	dz);	break;
+
+	case(P_BINTOBRK):	setup_process_logic(PITCHFILE_ONLY,		  	TO_TEXTFILE,		TEXTFILE_OUT,	dz);	break;
+	case(P_FIX):	  	setup_process_logic(PITCHFILE_ONLY,		  	PITCH_TO_PITCH,		PITCH_OUT,		dz);	break;
+	case(REPITCH):
+		switch(dz->mode) {
+		case(PPT): 		setup_process_logic(PITCH_AND_PITCH,	  	PITCH_TO_BIGPITCH,	PITCH_OUT,		dz);	break;
+		case(PTP): 		setup_process_logic(PITCH_AND_TRANSPOS,	  	PITCH_TO_BIGPITCH,	PITCH_OUT,		dz);	break;
+		case(TTT): 		setup_process_logic(TRANSPOS_AND_TRANSPOS,	PITCH_TO_BIGPITCH,	PITCH_OUT,		dz);	break;
+		}
+		break;
+	case(REPITCHB):
+		switch(dz->mode) {
+		case(PPT): 		setup_process_logic(PITCH_AND_PITCH,	  	TO_TEXTFILE,		TEXTFILE_OUT,	dz);	break;
+		case(PTP): 		setup_process_logic(PITCH_AND_TRANSPOS,	  	TO_TEXTFILE,		TEXTFILE_OUT,	dz);	break;
+		case(TTT): 		setup_process_logic(TRANSPOS_AND_TRANSPOS,	TO_TEXTFILE,		TEXTFILE_OUT,	dz);	break;
+		}
+		break;
+	case(TRNSP):
+	case(TRNSF):
+		switch(dz->mode) {
+		case(TRNS_BIN):	setup_process_logic(ANAL_WITH_TRANSPOS,   	EQUAL_ANALFILE,		ANALFILE_OUT,	dz);	break;
+		default:		setup_process_logic(ANALFILE_ONLY,	  	  	EQUAL_ANALFILE,		ANALFILE_OUT,	dz);	break;
+		}
+		break;
+	default:
+		sprintf(errstr,"Unknown process: assign_process_logic()\n");
+		return(PROGRAM_ERROR);
+		break;
+	}
+	if(dz->has_otherfile) {
+		switch(dz->input_data_type) {
+		case(ALL_FILES):
+		case(TWO_SNDFILES):
+		case(SNDFILE_AND_ENVFILE):
+		case(SNDFILE_AND_BRKFILE):
+		case(SNDFILE_AND_UNRANGED_BRKFILE):
+		case(SNDFILE_AND_DB_BRKFILE):
+			break;
+		case(MANY_SNDFILES):
+			if(dz->process==INFO_TIMELIST)
+				break;
+			/* fall thro */
+		default:
+			sprintf(errstr,"Most processes accepting files with different properties\n"
+						   "can only take 2 sound infiles.\n");
+			return(PROGRAM_ERROR);
+		}
+	}
+	return(FINISHED);
+}
+
+/***************************** SET_LEGAL_INFILE_STRUCTURE **************************
+ *
+ * Allows 2nd infile to have different props to first infile.
+ */
+
+void set_legal_infile_structure(dataptr dz)
+{
+	switch(dz->process) {
+	default:
+		dz->has_otherfile = FALSE;
+		break;
+	}
+}
+
+/***************************************************************************************/
+/****************************** FORMERLY IN internal.c *********************************/
+/***************************************************************************************/
+
+/****************************** SET_LEGAL_INTERNALPARAM_STRUCTURE *********************************/
+
+int set_legal_internalparam_structure(int process,int mode,aplptr ap)
+{
+	int exit_status = FINISHED;
+	switch(process) {
+	case(PITCH):
+		switch(mode) {																	   
+		case(PICH_TO_BIN):	exit_status = set_internalparam_data("0d",ap);				break;
+		case(PICH_TO_BRK):	exit_status = set_internalparam_data( "d",ap);				break;
+		}
+		break;
+	case(TRACK):
+		switch(mode) {																	   
+		case(TRK_TO_BIN): 	exit_status = set_internalparam_data("0d",ap);				break;
+		case(TRK_TO_BRK): 	exit_status = set_internalparam_data( "d",ap);				break;
+		}
+		break;
+	case(P_APPROX):   	return(FINISHED);
+	case(P_EXAG): 	  	return(FINISHED);
+	case(P_INVERT):   	return(FINISHED);
+	case(P_QUANTISE): 	return(FINISHED);
+	case(P_RANDOMISE):	exit_status = set_internalparam_data("i",ap);					break;
+	case(P_SMOOTH):   	return(FINISHED);
+	case(P_TRANSPOSE):	return(FINISHED);
+	case(P_VIBRATO):  	return(FINISHED);
+	case(P_CUT): 	  	return(FINISHED);
+	case(P_FIX): 	  	exit_status = set_internalparam_data("iiii",ap);				break;
+	case(REPITCH):    	return(FINISHED);
+	case(REPITCHB):   	return(FINISHED);
+	case(TRNSP):	  	return(FINISHED);
+	case(TRNSF):	  	return(FINISHED);
+//TW UPDATES
+	case(P_SYNTH):		return(FINISHED);
+	case(P_VOWELS):		return(FINISHED);
+	case(P_GEN):		return(FINISHED);
+	case(P_INSERT):		return(FINISHED);
+	case(P_SINSERT):	return(FINISHED);
+	case(P_PTOSIL):		return(FINISHED);
+	case(P_NTOSIL):		return(FINISHED);
+	case(ANALENV):		return(FINISHED);
+	case(P_BINTOBRK):	return(FINISHED);
+	case(P_INTERP):		return(FINISHED);
+
+	default:
+		sprintf(errstr,"Unknown process in set_legal_internalparam_structure()\n");
+		return(PROGRAM_ERROR);
+	}
+	return(exit_status);		
+}
+
+/********************************************************************************************/
+/********************************** FORMERLY IN specialin.c *********************************/
+/********************************************************************************************/
+
+/********************** READ_SPECIAL_DATA ************************/
+
+int read_special_data(char *str,dataptr dz)	   
+{
+	int exit_status = FINISHED;
+//TW UPDATE
+	int n;
+
+	aplptr ap = dz->application;
+	double dummy = 0.0,  is_numeric = 0;
+	switch(ap->special_data) {
+	case(TRANSPOS_RATIO_OR_CONSTANT):
+	case(TRANSPOS_OCTAVE_OR_CONSTANT):
+ 	case(TRANSPOS_SEMIT_OR_CONSTANT):
+		if(!sloom) {
+//TW NEW FILENAME CONVENTION
+			if(!value_is_numeric(str) && file_has_invalid_startchar(str)) {
+    			sprintf(errstr,"Filename has an invalid start-character [%s]\n",str);
+				return(USER_ERROR);
+			}
+			if(value_is_numeric(str)) {
+				if(sscanf(str,"%lf",&dummy)!=1) {
+					sprintf(errstr,"Invalid data: read_special_data()\n");
+					return(DATA_ERROR);
+				}
+				is_numeric = 1;
+			}
+		} else {
+			if(str[0]==NUMERICVAL_MARKER) {				/* TK convention: values preceded by an extra '@' */
+				str++;
+				if(strlen(str)<=0 || sscanf(str,"%lf",&dummy)!=1) {
+					sprintf(errstr,"Invalid transposition data: read_special_data()\n");
+					return(DATA_ERROR);
+				}
+				is_numeric = 1;
+			}
+		}
+		if(is_numeric)
+			return get_transposition_value(dummy,(int)ap->special_data,dz);
+		else	
+			return getsize_and_getdata_from_transpos_brkfile
+			(str,(double)MIN_TRANSPOS,(double)MAX_TRANSPOS,(int)ap->special_data,dz);
+		break;
+	case(PITCHQUANTISE_SET):  	return read_pquantise_set(str,dz);
+	case(INTERVAL_MAPPING):	  	return read_interval_mapping(str,dz);
+ 	case(OUT_PFILE):
+		if(!sloom) {
+			if((dz->other_file=sndcreat_formatted(str,(dz->insams[0]/dz->wanted),SAMP_FLOAT,
+			1,dz->infile->srate,CDP_CREATE_NORMAL)) < 0) {
+				sprintf(errstr,"Cannot open output pitch file %s\n",str);
+				return(DATA_ERROR);
+			}
+			dz->needpeaks = 0;
+		}
+		break;
+	case(OUT_PBRKFILE):		  
+		if(!sloom) {
+			if((dz->fp = fopen(str,"w"))==NULL) {
+				sprintf(errstr,"Cannot open file %s for output.\n",str);
+				return(DATA_ERROR);
+			}
+		}
+		break;
+//TW UPDATES
+	case(PITCH_SPECTRUM):		  
+		if((exit_status = get_and_count_data_from_textfile(str,&dz->parray[PICH_SPEC],&dz->itemcnt)) < 0)
+			return(exit_status);
+		for(n=0;n<dz->itemcnt;n++) {
+			if(dz->parray[PICH_SPEC][n] < ap->min_special || dz->parray[PICH_SPEC][n] > ap->max_special) {
+				sprintf(errstr,"Partial amplitude[%d] = %lf is out of range (%lf - %lf)\n",
+				n+1,dz->parray[PICH_SPEC][n],ap->min_special,ap->max_special);
+				return(DATA_ERROR);
+			}
+		}
+		break;
+	case(ZERO_INSERTTIMES):
+		if((exit_status = get_and_count_timedata_from_textfile(str,&dz->lparray[0],&dz->lparray[1],&dz->itemcnt,dz)) < 0)
+			return(exit_status);
+		break;
+	case(PITCH_VOWELS):
+		if((exit_status = get_the_vowels(str,&dz->parray[0],&dz->iparray[0],&dz->itemcnt,dz)) < 0)
+			return(exit_status);
+		break;
+	case(PITCH_CREATE):
+		if((exit_status = get_the_pitches(str,&dz->parray[0],&dz->parray[1],&dz->itemcnt)) < 0)
+			return(exit_status);
+		break;
+
+	default:
+		sprintf(errstr,"Unknown special_data type: read_special_data()\n");
+		return(PROGRAM_ERROR);
+	}
+	return(FINISHED);
+}
+
+/********************** GET_TRANSPOSITION_VALUE ************************/
+
+int get_transposition_value(double val,int datatype,dataptr dz)
+{
+	switch(datatype) {
+	case(TRANSPOS_SEMIT_OR_CONSTANT):	val *= OCTAVES_PER_SEMITONE;		/* semitones -> octaves */
+	/* fall thro */
+	case(TRANSPOS_OCTAVE_OR_CONSTANT):	val = (float)pow(2.0,val);	break;	/* octaves -> frqratios */
+	}
+	if(val < MIN_TRANSPOS || val > MAX_TRANSPOS) {	 /* graphics - range could be preset */
+		sprintf(errstr,"Transposition [%lf] out of range %lf - %lf semitones\n",val,MIN_TRANSPOS,MAX_TRANSPOS);
+		return(DATA_ERROR);
+	}
+	return convert_constant_to_transposition_table(val,dz);
+}
+
+/****************************** CONVERT_CONSTANT_TO_TRANSPOSITION_TABLE *********************************
+ *
+ * convert constant to transposition table.
+ */
+
+int convert_constant_to_transposition_table(double val,dataptr dz)
+{   int n = 0, arraysize = BIGARRAY;
+    double ttime = 0.0;
+    double infiletime  = (double)dz->wlength * dz->frametime;
+    if((dz->transpos = (float *)malloc(arraysize * sizeof(float)))==NULL) {
+		sprintf(errstr,"INSUFFICIENT MEMORY for transpostion array.\n");
+		return(MEMORY_ERROR);
+	}
+    while(n < dz->wlength) {
+        (dz->transpos)[n] = (float)val;
+		if(++n >= arraysize) {
+	    	arraysize += BIGARRAY;
+    	    if((dz->transpos = (float *)realloc((char *)dz->transpos,arraysize*sizeof(float)))==NULL) {
+				sprintf(errstr,"INSUFFICIENT MEMORY to reallocate transpostion array.\n");
+				return(MEMORY_ERROR);
+			}
+		}
+		ttime += dz->frametime;
+    }
+    while(ttime < infiletime) {
+		(dz->transpos)[n] = (float)val;
+		if(++n >= arraysize) {
+	    	arraysize += BIGARRAY;
+    	    if((dz->transpos = (float *)realloc((char *)dz->transpos,arraysize*sizeof(float)))==NULL) {
+				sprintf(errstr,"INSUFFICIENT MEMORY to reallocate transpostion array.\n");
+				return(MEMORY_ERROR);
+			}
+		}
+		ttime += dz->frametime;
+    }
+    if((dz->transpos = (float *)realloc((char *)dz->transpos,n * sizeof(float)))==NULL) {
+		sprintf(errstr,"INSUFFICIENT MEMORY to reallocate transpostion array.\n");
+		return(MEMORY_ERROR);
+	}
+	return(FINISHED);
+}
+
+/********************** GETSIZE_AND_GETDATA_FROM_TRANSPOS_BRKFILE *******************/
+
+int getsize_and_getdata_from_transpos_brkfile(char *filename,double minval, double maxval,int which_type, dataptr dz)
+{
+	FILE *fp;
+	int exit_status;
+	int brksize;
+	if((fp = fopen(filename,"r"))==NULL) {
+		sprintf(errstr,	"Can't open brkpntfile %s to read data.\n",filename);
+		return(DATA_ERROR);
+	}
+	if((exit_status = 
+	read_and_test_pitch_or_transposition_brkvals(fp,filename,&(dz->temp),&brksize,which_type,minval,maxval))<0)
+		return(exit_status);
+	if(fclose(fp)<0) {
+		fprintf(stdout,"WARNING: Failed to close output textfile %s.\n",filename);
+		fflush(stdout);
+	}
+	if((exit_status = 
+	convert_brkpntdata_to_window_by_window_array(dz->temp,brksize,&(dz->transpos),dz->wlength,dz->frametime))<0)
+		return(exit_status);
+	return(FINISHED);
+}
+
+/********************************* READ_PQUANTISE_SET ********************************/
+
+int read_pquantise_set(char *filename,dataptr dz)
+{
+	int exit_status;
+	double *p;
+	int n;
+	if((exit_status = get_and_count_data_from_textfile(filename,&(dz->parray[PQ_QSET]),&(dz->itemcnt)))<0)
+		return(exit_status);
+	p = dz->parray[PQ_QSET];
+	for(n=0;n<dz->itemcnt;n++) {
+		if(*p < MIDIMIN || *p > MIDIMAX) {
+			sprintf(errstr,"Pitch value out of range (%d.0 - %d.0) in quantisation set\n",MIDIMIN,MIDIMAX);
+		return(DATA_ERROR);
+		}
+		p++;
+	}
+	return FINISHED;
+}
+
+/************************* SORT_QUANTISING_SET *****************************/
+
+int sort_quantising_set(dataptr dz)
+{
+	int n, m;
+	double thisval;
+	for(n=1;n<dz->itemcnt;n++) {
+		thisval = dz->parray[PQ_QSET][n];
+		m = n-1;
+		while(m >= 0 && dz->parray[PQ_QSET][m] > thisval) {
+			dz->parray[PQ_QSET][m+1]  = dz->parray[PQ_QSET][m];
+			m--;
+		}
+		dz->parray[PQ_QSET][m+1]  = thisval;
+	}
+	return(FINISHED);
+}
+
+/************************* GENERATE_OCTAVE_DUPLICATES *****************************/
+
+int generate_octave_duplicates(dataptr dz)
+{
+	int n, m;
+	double thisval, octval;
+	int duplicated;
+	int orig_itemcnt = dz->itemcnt;
+	for(n=0;n<orig_itemcnt;n++) {
+		thisval = dz->parray[PQ_QSET][n];
+		octval = thisval;
+		while((octval -= SEMITONES_PER_OCTAVE) >= MIDIMIN) {
+			duplicated = FALSE;
+		   	for(m=0;m<dz->itemcnt;m++) {
+				if(flteq(dz->parray[PQ_QSET][m],octval)) {
+					duplicated = TRUE;
+					break;
+				}
+			}		
+			if(!duplicated) {
+				dz->itemcnt++;
+				if((dz->parray[PQ_QSET] = (double *)realloc((char *)dz->parray[PQ_QSET],dz->itemcnt * sizeof(double)))==NULL) {
+					sprintf(errstr,"INSUFFICIENT MEMORY for quantisation set array.\n");
+					return(MEMORY_ERROR);
+				}
+				dz->parray[PQ_QSET][dz->itemcnt - 1] = octval;
+			}
+		}
+		octval = thisval;
+		while((octval += SEMITONES_PER_OCTAVE) <= MIDIMAX) {
+			duplicated = FALSE;
+		   	for(m=0;m<dz->itemcnt;m++) {
+				if(flteq(dz->parray[PQ_QSET][m],octval)) {
+					duplicated = TRUE;
+					break;
+				}
+			}		
+			if(!duplicated) {
+				dz->itemcnt++;
+				if((dz->parray[PQ_QSET] = (double *) realloc((char *)dz->parray[PQ_QSET],dz->itemcnt * sizeof(double)))==NULL) {
+					sprintf(errstr,"INSUFFICIENT MEMORY to reallocate quantisation set array.\n");
+					return(MEMORY_ERROR);
+				}
+				dz->parray[PQ_QSET][dz->itemcnt - 1] = octval;
+			}
+		}
+	}
+	return(FINISHED);
+}
+
+/************************* ELIMINATE_DUPLICATES_IN_QUANTISING_SET *****************************/
+
+int eliminate_duplicates_in_quantising_set(dataptr dz)
+{
+	int n, m, k;
+	for(n=1,m=0;n<dz->itemcnt;n++,m++) { /* eliminate DUPLICATE vals */
+		if(flteq(dz->parray[PQ_QSET][n],dz->parray[PQ_QSET][m])) {
+			for(k=n;k<dz->itemcnt;k++)
+				dz->parray[PQ_QSET][k-1] = dz->parray[PQ_QSET][k];
+			n--;
+			m--;
+			dz->itemcnt--;
+		}
+	}
+	return(FINISHED);
+}
+
+/************************** READ_INTERVAL_MAPPING ********************************/
+
+int read_interval_mapping(char *str,dataptr dz)
+{
+	int exit_status;
+
+	if(!strcmp(str,"0"))
+		dz->is_mapping = FALSE;
+	else { 
+		if((exit_status = get_mapping(str,dz))<0)
+			return(exit_status);
+		dz->is_mapping = TRUE;
+	} 
+	return(FINISHED);
+}
+
+/********************************* GET_MAPPING ********************************/
+
+int get_mapping(char *filename,dataptr dz)
+{
+	int exit_status;
+	double *p;
+	int n;
+	if((exit_status = get_and_count_data_from_textfile(filename,&(dz->parray[PI_INTMAP]),&(dz->itemcnt)))<0)
+		return(exit_status);
+	p = dz->parray[PI_INTMAP];
+	for(n=0;n<dz->itemcnt;n++) {
+		if(*p < -MAXINTRANGE || *p > MAXINTRANGE) {
+			sprintf(errstr,
+			"Mapping val (%lf) out of range (%.0lf to -%.0lf semitones) (8 8vas up or down).\n",
+			*p,MAXINTRANGE,MAXINTRANGE);
+			return(DATA_ERROR);
+		}
+		p++;
+	}
+	if(ODD(dz->itemcnt)) {
+		sprintf(errstr,"Data not paired correctly in mapping file\n");
+		return(DATA_ERROR);
+	}
+	dz->itemcnt /= 2;
+	return sort_mapping(dz);
+}
+
+/************************* SORT_MAPPING *****************************
+ *
+ * sort interval mapping into ascending size of src_interval.
+ */
+
+int sort_mapping(dataptr dz)
+{
+	int n, m, j, k;
+	double src_interval, goal_interval;
+	for(n=1;n<dz->itemcnt;n++) {
+		k = n*2;
+		src_interval  = dz->parray[PI_INTMAP][k];
+		goal_interval = dz->parray[PI_INTMAP][k+1];
+		m = n-1;
+		while(m >= 0 && dz->parray[PI_INTMAP][m*2] > src_interval) {
+			k = (m+1)* 2;
+			j =  m   * 2;
+			dz->parray[PI_INTMAP][k]   = dz->parray[PI_INTMAP][j];
+			dz->parray[PI_INTMAP][k+1] = dz->parray[PI_INTMAP][j+1];
+			m--;
+		}
+		k = (m+1)*2;
+		dz->parray[PI_INTMAP][k]   = src_interval;
+		dz->parray[PI_INTMAP][k+1] = goal_interval;
+	}
+	return(FINISHED);
+}
+
+/*************************** GET_AND_COUNT_DATA_FROM_TEXTFILE ******************************
+ *
+ * (1)	Gets double table data from a text file.
+ * (2)	counts ALL items (not pairing them).
+ * (3)	Does NOT check for in-range.
+ */
+
+int get_and_count_data_from_textfile(char *filename,double **brktable,int *brksize)
+{
+	FILE *fp;
+	double *p;
+	int arraysize = BIGARRAY;
+	char temp[200], *q;
+	int n = 0;
+	if((fp = fopen(filename,"r"))==NULL) {
+		sprintf(errstr,	"Can't open textfile %s to read data.\n",filename);
+		return(DATA_ERROR);
+	}
+	if((*brktable = (double *)malloc(arraysize * sizeof(double)))==NULL) {
+		sprintf(errstr,"INSUFFICIENT MEMORY for data.\n");
+		return(MEMORY_ERROR);
+	}
+	p = *brktable;
+	while(fgets(temp,200,fp)==temp) {
+		q = temp;
+		while(get_float_from_within_string(&q,p)) {
+			p++;
+			if(++n >= arraysize) {
+				arraysize += BIGARRAY;
+				if((*brktable = (double *)realloc((char *)(*brktable),arraysize * sizeof(double)))==NULL) {
+					sprintf(errstr,"INSUFFICIENT MEMORY to reallocate data table.\n");
+					return(MEMORY_ERROR);
+				}
+				p = *brktable + n;		
+			}
+		}
+	}	    
+	if(n == 0) {
+		sprintf(errstr,"No data in textdata file %s\n",filename);
+		return(DATA_ERROR);
+	}
+	if((*brktable = (double *)realloc((char *)(*brktable),n * sizeof(double)))==NULL) {
+		sprintf(errstr,"INSUFFICIENT MEMORY to reallocate data table.\n");
+		return(MEMORY_ERROR);
+	}
+	if(fclose(fp)<0) {
+		fprintf(stdout,"WARNING: Failed to close input textfile %s.\n",filename);
+		fflush(stdout);
+	}
+	*brksize = n;
+	return(FINISHED);
+}
+
+
+/*************************** GET_AND_COUNT_TIMEDATA_FROM_TEXTFILE ******************************
+ *
+ * (1)	Gets double table data from a text file.
+ * (2)	counts ALL items (not pairing them).
+ * (3)	Does NOT check for in-range.
+ */
+
+int get_and_count_timedata_from_textfile(char *filename,int **brktable1,int **brktable2,int *brksize,dataptr dz)
+{
+	FILE *fp;
+	double dummy[2];
+	int *p[2];
+	int arraysize = BIGARRAY;
+	char temp[200], *q;
+	int n = 0;
+	int thistable;
+	aplptr ap = dz->application;
+
+	if((fp = fopen(filename,"r"))==NULL) {
+		sprintf(errstr,	"Can't open textfile %s to read data.\n",filename);
+		return(DATA_ERROR);
+	}
+	if((*brktable1 = (int *)malloc(arraysize * sizeof(int)))==NULL) {
+		sprintf(errstr,"INSUFFICIENT MEMORY for data.\n");
+		return(MEMORY_ERROR);
+	}
+	if((*brktable2 = (int *)malloc(arraysize * sizeof(int)))==NULL) {
+		sprintf(errstr,"INSUFFICIENT MEMORY for data.\n");
+		return(MEMORY_ERROR);
+	}
+	p[0] = *brktable1;
+	p[1] = *brktable2;
+	thistable = 0;
+	while(fgets(temp,200,fp)==temp) {
+		q = temp;
+		while(get_float_from_within_string(&q,&(dummy[thistable]))) {
+			if(thistable) {
+				if(dummy[0] < ap->min_special || dummy[0] > ap->max_special) {
+					sprintf(errstr,"Time (%lf) in datafile out of range (%lf %lf)\n",
+					dummy[0],ap->min_special,ap->max_special);
+					return(DATA_ERROR);
+				}
+				if(dummy[1] < ap->min_special || dummy[1] > ap->max_special) {
+					sprintf(errstr,"Time (%lf) in datafile out of range (%lf %lf)\n",
+					dummy[1],ap->min_special,ap->max_special);
+					return(DATA_ERROR);
+				}
+				if(flteq(dummy[0],dummy[1])) {
+					sprintf(errstr,"Times in datafile equivalent (%lf %lf)\n",dummy[0],dummy[1]);
+					return(DATA_ERROR);
+				}
+				if(dummy[0] > dummy[1]) {
+					sprintf(errstr,"Times in datafile reversed (%lf %lf)\n",dummy[0],dummy[1]);
+					return(DATA_ERROR);
+				}
+				
+				if(dz->mode == 1) {	/* info as sample-cnt, convert to time */
+					dummy[0] /= (double)dz->infile->origrate;
+					dummy[1] /= (double)dz->infile->origrate;
+				}
+				*(p[0]) = (int)round(dummy[0] * dz->infile->arate);	/* convert from time to window number */
+				*(p[1]) = (int)round(dummy[1] * dz->infile->arate);
+				p[0]++;
+				p[1]++;
+				if(++n >= arraysize) {
+					arraysize += BIGARRAY;
+					if((*brktable1 = (int *)realloc((char *)(*brktable1),arraysize * sizeof(int)))==NULL) {
+						sprintf(errstr,"INSUFFICIENT MEMORY to reallocate data table.\n");
+						return(MEMORY_ERROR);
+					}
+					if((*brktable2 = (int *)realloc((char *)(*brktable2),arraysize * sizeof(int)))==NULL) {
+						sprintf(errstr,"INSUFFICIENT MEMORY to reallocate data table.\n");
+						return(MEMORY_ERROR);
+					}
+					p[0] = *brktable1 + n;		
+					p[1] = *brktable2 + n;		
+				}
+			}
+			thistable = !thistable;
+		}
+	}	    
+	if(n == 0) {
+		sprintf(errstr,"No data in textdata file %s\n",filename);
+		return(DATA_ERROR);
+	}
+	if(thistable) {
+		sprintf(errstr,"data in textdata file %s not paired correctly\n",filename);
+		return(DATA_ERROR);
+	}
+	if((*brktable1 = (int *)realloc((char *)(*brktable1),n * sizeof(int)))==NULL) {
+		sprintf(errstr,"INSUFFICIENT MEMORY to reallocate data table.\n");
+		return(MEMORY_ERROR);
+	}
+	if((*brktable2 = (int *)realloc((char *)(*brktable2),n * sizeof(int)))==NULL) {
+		sprintf(errstr,"INSUFFICIENT MEMORY to reallocate data table.\n");
+		return(MEMORY_ERROR);
+	}
+	if(fclose(fp)<0) {
+		fprintf(stdout,"WARNING: Failed to close input textfile %s.\n",filename);
+		fflush(stdout);
+	}
+	*brksize = n;
+	return(FINISHED);
+}
+
+//TW UPDATE : NEW FUNCTION
+/******************************** GET_THE_PITCHES ********************************/
+
+int get_the_pitches(char *filename,double **times,double **pitch,int *pcnt)
+{
+	FILE *fp;
+	double *t, lasttime = 0.0;
+	double *pitchval;
+	int non_zero_start = 0;
+	int arraysize = BIGARRAY, n = 0;
+	char temp[200], *q, *p;
+	int istime;
+
+	if((fp = fopen(filename,"r"))==NULL) {
+		sprintf(errstr,	"Can't open textfile %s to read pitch data.\n",filename);
+		return(DATA_ERROR);
+	}
+	if((*times = (double *)malloc(arraysize * sizeof(double)))==NULL) {
+		sprintf(errstr,"INSUFFICIENT MEMORY for time data.\n");
+		return(MEMORY_ERROR);
+	}
+	if((*pitch = (double *)malloc(arraysize * sizeof(double)))==NULL) {
+		sprintf(errstr,"INSUFFICIENT MEMORY for vowels data.\n");
+		return(MEMORY_ERROR);
+	}
+	t = *times;
+	pitchval = *pitch;
+	istime = 1;
+	while(fgets(temp,200,fp)==temp) {
+		q = temp;
+		while(get_word_from_string(&q,&p)) {
+			if(istime) {
+				if(sscanf(p,"%lf",t)!=1) {
+					sprintf(errstr,"No time for time-pitch pair %d\n",n+1);
+					return(DATA_ERROR);
+				}
+				if(n==0) {
+					if(*t < 0.0) {
+						sprintf(errstr,"First time is less than zero in pitch data\n");
+						return(DATA_ERROR);
+					} else if(*t > 0.0) {
+						print_outwarning_flush("FIRST TIME in pitch data IS NOT ZERO : assuming first pitch runs from time zero\n");
+						non_zero_start = 1;
+						t++;
+						*t = *(t-1);
+						*(t-1) = 0.0;
+					}
+				} else {
+					if (*t <= lasttime) {
+						sprintf(errstr,"Times do not advance (from %lf to %lf at pair %d) in pitch data\n",
+						lasttime,*t,n+1);
+						return(DATA_ERROR);
+					}
+				}
+				lasttime = *t++;
+			} else {
+				if(get_pitch(p,pitchval)<0) {
+					strcat(errstr,p);
+					sprintf(temp,"'  is a bad pitch value at item %d\n",n+1);
+					strcat(errstr,temp);
+					return(DATA_ERROR);
+				}
+				if((n==0) && non_zero_start) {
+					pitchval++;
+					*pitchval = *(pitchval-1);
+					n++;
+				}
+				pitchval++;
+				if(++n >= arraysize) {
+					arraysize += BIGARRAY;
+					if((*times = (double *)realloc((char *)(*times),arraysize * sizeof(double)))==NULL) {
+						sprintf(errstr,"INSUFFICIENT MEMORY to reallocate table of pitch-times.\n");
+						return(MEMORY_ERROR);
+					}
+					if((*pitch = (double *)realloc((char *)(*pitch),arraysize * sizeof(double)))==NULL) {
+						sprintf(errstr,"INSUFFICIENT MEMORY to reallocate table of pitches.\n");
+						return(MEMORY_ERROR);
+					}
+					t = *times + n;		
+					pitchval = *pitch + n;		
+				}
+			}
+			istime = !istime;
+		}
+	}
+	if(n < 2) {
+		sprintf(errstr,"Insufficient data in pitch datafile %s\n",filename);
+		return(DATA_ERROR);
+	}
+	if(!istime) {
+		sprintf(errstr,"data in  pitch datafile %s not paired correctly\n",filename);
+		return(DATA_ERROR);
+	}
+	if((*times = (double *)realloc((char *)(*times),n * sizeof(double)))==NULL) {
+		sprintf(errstr,"INSUFFICIENT MEMORY to reallocate vowel-time table.\n");
+		return(MEMORY_ERROR);
+	}
+	if((*pitch = (double *)realloc((char *)(*pitch),n * sizeof(double)))==NULL) {
+		sprintf(errstr,"INSUFFICIENT MEMORY to reallocate vowels table.\n");
+		return(MEMORY_ERROR);
+	}
+	if(fclose(fp)<0) {
+		fprintf(stdout,"WARNING: Failed to close input textfile %s.\n",filename);
+		fflush(stdout);
+	}
+	*pcnt = n;
+	return(FINISHED);
+}
+
+/********************************************************************************************/
+/********************************** FORMERLY IN preprocess.c ********************************/
+/********************************************************************************************/
+
+/****************************** PARAM_PREPROCESS *********************************/
+
+int param_preprocess(dataptr dz)	
+{
+	switch(dz->process) {
+	case(PITCH):		return specpitch_preprocess(dz);
+	case(TRACK):		return track_preprocess(dz);
+	case(P_APPROX):		return papprox_preprocess(dz);
+	case(P_EXAG):		return pexag_preprocess(dz);
+	case(P_INVERT):		return pinvert_preprocess(dz);
+	case(P_QUANTISE): 	return pquantise_preprocess(dz);
+	case(P_RANDOMISE):	return adjust_params_and_setup_internal_params_for_prandomise(dz);
+	case(P_SMOOTH):		return adjust_params_and_setup_internal_params_for_psmooth(dz);
+	case(P_TRANSPOSE):	return adjust_params_for_ptranspose(dz);
+	case(P_VIBRATO):	return pvibrato_preprocess(dz);
+	case(P_FIX):		return pfix_preprocess(dz);
+	case(REPITCHB):	    return repitchb_preprocess(dz);
+	case(P_CUT):	case(REPITCH):	case(TRNSP):	case(TRNSF):
+//TW UPDATES
+	case(P_SYNTH):
+	case(P_VOWELS):
+	case(P_GEN):
+	case(P_INSERT):
+	case(P_SINSERT):
+	case(P_PTOSIL):
+	case(P_NTOSIL):
+	case(ANALENV):
+	case(P_BINTOBRK):
+	case(P_INTERP):
+
+		return(FINISHED);
+	default:
+		sprintf(errstr,"PROGRAMMING PROBLEM: Unknown process in param_preprocess()\n");
+		return(PROGRAM_ERROR);
+	}
+	return(FINISHED);	/* NOTREACHED */
+}
+
+/************************** SPECPITCH_PREPROCESS ******************************/
+
+int specpitch_preprocess(dataptr dz)
+{
+	int exit_status;
+	if((exit_status = adjust_parameters_for_specpitch(dz))<0)
+		return(exit_status);
+	if(dz->mode == PICH_TO_BRK) {
+		if((dz->parray[PICH_PBRK] = (double *)malloc(dz->wlength * 2 * sizeof(double)))==NULL) {
+			sprintf(errstr,"INSUFFICIENT MEMORY for pitchbrk array.\n");
+			return(MEMORY_ERROR);
+		}
+	}
+	if((exit_status = establish_internal_arrays_for_pitchwork(dz))<0)
+		return(exit_status);
+	initrand48();		
+	dz->param[PICH_PICH] = 0.0;
+	return setup_ring(dz);
+}
+
+/************ ADJUST_PARAMETERS_FOR_SPECPITCH *************/
+
+int adjust_parameters_for_specpitch(dataptr dz)
+{
+	/* convert semitone to ratio */
+   	dz->param[PICH_RNGE] = pow(SEMITONE_INTERVAL,fabs(dz->param[PICH_RNGE])); 
+	/* convert dB to gain */		
+	dz->param[PICH_SRATIO] /= 20.0;
+	dz->param[PICH_SRATIO] = pow(10.0,dz->param[PICH_SRATIO]);
+	dz->param[PICH_SRATIO] = 1.0/dz->param[PICH_SRATIO];
+	return(FINISHED);
+}
+
+/************ ESTABLISH_INTERNAL_ARRAYS_FOR_PITCHWORK *************/
+
+int establish_internal_arrays_for_pitchwork(dataptr dz)
+{
+	int exit_status;
+	if((exit_status = establish_arrays_for_pitchwork(dz))<0)
+		return(exit_status);
+	if((exit_status = establish_bottom_frqs_of_channels(dz))<0)
+		return(exit_status);
+	return establish_testtone_amps(dz);
+}
+
+/***************************** ESTABLISH_ARRAYS_FOR_PITCHWORK *************************/
+
+int establish_arrays_for_pitchwork(dataptr dz)
+{
+	int i;
+	if((dz->parray[PICH_PRETOTAMP] = (double *)malloc(dz->wlength * sizeof(double)))==NULL) {
+		sprintf(errstr,"INSUFFICIENT MEMORY for amp totalling array.\n");
+		return(MEMORY_ERROR);
+	}
+//RWD NOV97	 quick solution to unassigned value somewhere in spec pitch!
+	for(i = 0; i < dz->wlength;i++)
+		dz->parray[PICH_PRETOTAMP][i] = 0.0;
+
+	if((dz->pitches = (float *)malloc(dz->wlength * sizeof(float)))==NULL) {
+		sprintf(errstr,"INSUFFICIENT MEMORY for pitches array.\n");
+		return(MEMORY_ERROR);
+	}
+	return(FINISHED);
+}
+
+/************************** TRACK_PREPROCESS ******************************/
+
+int track_preprocess(dataptr dz)
+{
+	int exit_status;
+	if((exit_status = convert_track_params(dz))<0)
+		return(exit_status);
+	if((exit_status = setup_internal_params_and_arrays_for_track(dz))<0)
+		return(exit_status);
+	initrand48();		
+	return establish_internal_arrays_for_pitchwork(dz);
+}
+
+/************ CONVERT_TRACK_PARAMS *************/
+
+int convert_track_params(dataptr dz)
+{	/* convert semitone to ratio */
+   	dz->param[TRAK_RNGE] = pow(SEMITONE_INTERVAL,fabs(dz->param[TRAK_RNGE]));
+	/* convert dB to gain */		
+	dz->param[TRAK_SRATIO] /= 20.0;
+	dz->param[TRAK_SRATIO] = pow(10.0,dz->param[TRAK_SRATIO]);
+	dz->param[TRAK_SRATIO] = 1.0/dz->param[TRAK_SRATIO];
+	return(FINISHED);
+}
+
+/************ SETUP_INTERNAL_PARAMS_AND_ARRAYS_FOR_TRACK *************/
+
+int setup_internal_params_and_arrays_for_track(dataptr dz)
+{		/* setup internal arrays */
+	dz->param[TRAK_LOLM] = MINPITCH;
+	if(dz->mode == TRK_TO_BRK)	{
+		if((dz->parray[PICH_PBRK] = (double *)malloc(dz->wlength * 2 * sizeof(double)))==NULL) {
+			sprintf(errstr,"INSUFFICIENT MEMORY for pitch brk array.\n");
+			return(MEMORY_ERROR);
+		}
+	}
+	return(FINISHED);
+}
+
+/************************** PAPPROX_PREPROCESS ******************************/
+
+int papprox_preprocess(dataptr dz)
+{
+	int exit_status;
+	if(dz->mode==TRANSP_OUT)
+		dz->is_transpos = TRUE;
+	if((exit_status = convert_msecs_to_secs(PA_TRANG,dz))<0)
+		return(exit_status);
+	return convert_msecs_to_secs(PA_SRANG,dz);
+}
+
+/************************** PEXAG_PREPROCESS ******************************/
+
+int pexag_preprocess(dataptr dz)
+{
+	if(dz->mode == RANGE_ONLY_TO_T 
+	|| dz->mode == CONTOUR_ONLY_TO_T 
+	|| dz->mode == R_AND_C_TO_T)
+		dz->is_transpos = TRUE;
+	return(FINISHED);
+}
+
+/************************** PINVERT_PREPROCESS ******************************/
+
+int pinvert_preprocess(dataptr dz)
+{
+	if(dz->mode==TRANSP_OUT)
+		dz->is_transpos = TRUE;
+	return(FINISHED);
+}
+
+/************************** PQUANTISE_PREPROCESS ******************************/
+
+int pquantise_preprocess(dataptr dz)
+{
+	if(dz->mode==TRANSP_OUT)
+		dz->is_transpos = TRUE;
+	if(dz->vflag[PQ_OCTDUPL])
+		generate_octave_duplicates(dz);
+	eliminate_duplicates_in_quantising_set(dz);
+	return sort_quantising_set(dz);
+}
+
+/************ ADJUST_PARAMS_AND_SETUP_INTERNAL_PARAMS_FOR_PRANDOMISE *************/
+
+int adjust_params_and_setup_internal_params_for_prandomise(dataptr dz)
+{
+	int exit_status;
+	if((exit_status = convert_msecs_to_secs(PR_TSTEP,dz))<0)
+		return(exit_status);
+	if(dz->mode==TRANSP_OUT)
+		dz->is_transpos = TRUE;
+	if(dz->vflag[PR_IS_SLEW]) {
+		if(dz->param[PR_SLEW] < 0.0)
+			dz->iparam[PR_NEGATIV_SLEW] = TRUE;
+		dz->param[PR_SLEW] = -1.0/dz->param[PR_SLEW];
+	}
+	return(FINISHED);
+}
+
+/************ ADJUST_PARAMS_AND_SETUP_INTERNAL_PARAMS_FOR_PSMOOTH *************/
+
+int adjust_params_and_setup_internal_params_for_psmooth(dataptr dz)
+{
+	int exit_status;
+	if((exit_status = convert_msecs_to_secs(PS_TFRAME,dz))<0)
+		return(exit_status);
+	if(dz->mode==TRANSP_OUT)
+		dz->is_transpos = TRUE;
+	return(FINISHED);
+}
+
+/************ ADJUST_PARAMS_FOR_PTRANSPOSE *************/
+
+int adjust_params_for_ptranspose(dataptr dz)
+{
+ 	dz->param[PT_TVAL] /= 12.0;
+	dz->param[PT_TVAL] = pow(2.0,dz->param[PT_TVAL]);
+	return(FINISHED);
+}
+
+/************************** PVIBRATO_PREPROCESS ******************************/
+
+int pvibrato_preprocess(dataptr dz)
+{
+	int n;
+	double scaling = (PI * 2.0)/P_TABSIZE;
+	if(dz->mode==TRANSP_OUT)
+		dz->is_transpos = TRUE;
+	if((dz->parray[PV_SIN] = (double *)malloc((P_TABSIZE + 1) * sizeof(double)))==NULL) {
+		sprintf(errstr,"INSUFFICIENT MEMORY for vibrato sine table.\n");
+		return(MEMORY_ERROR);
+	}
+	for(n=0;n<P_TABSIZE;n++)
+		dz->parray[PV_SIN][n] = sin((double)n * scaling);
+	dz->parray[PV_SIN][n] = 0.0;
+	return(FINISHED);
+}
+
+/************************** PFIX_PREPROCESS ******************************/
+
+int pfix_preprocess(dataptr dz)
+{
+	dz->iparam[PF_ISFILTER] = 0;	/* establish pfix filtertype */		
+	if(dz->vflag[PF_HIPASS])
+		dz->iparam[PF_ISFILTER] |= IS_HIPASS;
+	if(dz->vflag[PF_LOPASS])
+		dz->iparam[PF_ISFILTER] |= IS_LOPASS;
+
+	if(dz->vflag[PF_STARTCUT]) { 	/* establish_pfix_cutpoints */
+	  if(!dz->vflag[PF_ENDCUT])
+			dz->iparam[PF_ECUTW] = dz->wlength;
+		else
+			dz->iparam[PF_ECUTW] = round(dz->param[PF_ECUT]/dz->frametime);
+	}
+	if(dz->vflag[PF_ENDCUT]) {
+		if(!dz->vflag[PF_STARTCUT])
+			dz->iparam[PF_SCUTW] = 0;
+		else
+			dz->iparam[PF_SCUTW] = round(dz->param[PF_SCUT]/dz->frametime);
+	}
+	if(dz->vflag[PF_ENDCUT] || dz->vflag[PF_STARTCUT]) {
+		dz->iparam[PF_ISCUT] = 1;
+		if(dz->iparam[PF_SCUTW] >= dz->iparam[PF_ECUTW]) {
+			sprintf(errstr,"Remove-pitch times incompatible.\n");
+			return(USER_ERROR);
+		}
+	}
+	return(FINISHED);
+}
+
+/************************** REPITCHB_PREPROCESS ******************************/
+
+int repitchb_preprocess(dataptr dz)
+{
+	dz->mode += 3;	/* converts to higher (brkpnt) mode inside the option 'repitch' */
+
+	dz->param[RP_DRED] /= 12.0;
+	dz->param[RP_DRED]  = pow(2.0,dz->param[RP_DRED]);
+	dz->is_sharp = dz->param[RP_DRED];
+	if(dz->is_sharp==0.0) {
+		sprintf(errstr,"parameter not set: repitchb_preprocess()\n");
+		return(PROGRAM_ERROR);
+	}
+	dz->is_flat  = 1.0/dz->is_sharp;
+	return(FINISHED);
+}
+
+/********************************************************************************************/
+/********************************** FORMERLY IN procspec.c **********************************/
+/********************************************************************************************/
+
+/**************************** SPEC_PROCESS_FILE ****************************/
+
+int spec_process_file(dataptr dz)
+{	
+	dz->total_windows = 0;
+
+	display_virtual_time(0L,dz);
+
+	switch(dz->process) {
+	case(TRNSP):		return outer_loop(dz);
+	case(TRNSF):		return outer_loop(dz);
+	case(PITCH):		return outer_pitch_loop(dz);
+	case(TRACK):		return outer_pitch_loop(dz);
+	case(P_APPROX):		return outer_pichpich_loop(dz);
+	case(P_EXAG):		return outer_pichpich_loop(dz);
+	case(P_INVERT):		return outer_pichpich_loop(dz);
+	case(P_QUANTISE): 	return outer_pichpich_loop(dz);
+	case(P_RANDOMISE):	return outer_pichpich_loop(dz);
+	case(P_SMOOTH):	  	return outer_pichpich_loop(dz);
+	case(P_TRANSPOSE):	return outer_pichpich_loop(dz);
+	case(P_VIBRATO):  	return outer_pichpich_loop(dz);
+	case(P_CUT):		return outer_pichpich_loop(dz);
+//TW UPDATES
+	case(P_SYNTH):		return outer_pichpich_loop(dz);
+	case(P_VOWELS):		return outer_pichpich_loop(dz);
+	case(P_INSERT):		return outer_pichpich_loop(dz);
+	case(P_SINSERT):	return outer_pichpich_loop(dz);
+	case(P_PTOSIL):		return outer_pichpich_loop(dz);
+	case(P_NTOSIL):		return outer_pichpich_loop(dz);
+	case(P_INTERP):		return outer_pichpich_loop(dz);
+	case(ANALENV):		return get_anal_envelope(dz);
+	case(P_BINTOBRK):	return convert_pitch_from_binary_to_text(dz);
+	case(P_GEN):		return generate_pitch(dz);
+
+	case(P_FIX):		return specpfix(dz);
+	case(REPITCH):		return specrepitch(dz);
+	case(REPITCHB):		return specrepitch(dz);
+	default:
+		sprintf(errstr,"Unknown process in procspec()\n");
+		return(PROGRAM_ERROR);
+	}
+	return(FINISHED);	/* NOTREACHED */
+}
+
+/**************************** INNER_LOOP ****************************/
+
+int inner_loop
+(int *peakscore,int *descnt,int *in_start_portion,int *least,int *pitchcnt,int windows_in_buf,dataptr dz)
+{
+	int exit_status;
+	int local_zero_set = FALSE;
+	int wc;
+ 
+   	for(wc=0; wc<windows_in_buf; wc++) {
+		if(dz->total_windows==0) {
+			if((exit_status = skip_or_special_operation_on_window_zero(dz))<0)
+				return(exit_status);
+			if(exit_status==TRUE) {
+				dz->flbufptr[0] += dz->wanted;
+				dz->total_windows++;
+				dz->time = (float)(dz->time + dz->frametime);
+				continue;
+			}
+		}
+		if((exit_status = read_values_from_all_existing_brktables((double)dz->time,dz))<0)
+			return(exit_status);
+
+		switch(dz->process) {
+		case(TRNSF):	exit_status = spectrnsf(dz);  						break;
+		case(TRNSP):	exit_status = spectrnsp(dz);  						break;
+		default:
+			sprintf(errstr,"unknown process in inner_loop()\n");
+			return(PROGRAM_ERROR);
+		}
+		if(exit_status<0)
+			return(exit_status);
+		dz->flbufptr[0] += dz->wanted;
+		dz->total_windows++;
+		dz->time = (float)(dz->time + dz->frametime);
+	}
+	if(!dz->zeroset && local_zero_set==TRUE) {
+		fprintf(stdout,"WARNING: Zero-amp spectral window(s) encountered: orig window(s) substituted.\n"); 
+		fflush(stdout);
+		dz->zeroset = TRUE;
+	}
+	return(FINISHED);
+}
+
+/***************** SKIP_OR_SPECIAL_OPERATION_ON_WINDOW_ZERO ************/
+
+int skip_or_special_operation_on_window_zero(dataptr dz)
+{
+	int vc;
+	switch(dz->process) {
+	case(TRNSF):
+	case(TRNSP):
+		for(vc = 0; vc < dz->wanted; vc += 2)
+			dz->windowbuf[0][FREQ] = dz->flbufptr[0][FREQ];
+		break;
+	}
+	return(TRUE);
+}
+
+/********************************************************************************************/
+/********************************** FORMERLY IN pconsistency.c ******************************/
+/********************************************************************************************/
+
+/****************************** CHECK_PARAM_VALIDITY_AND_CONSISTENCY *********************************/
+
+int check_param_validity_and_consistency(dataptr dz)
+{
+	int exit_status;
+	int chans;
+	int srate;
+	int win_overlap;
+	int chancnt;
+	handle_pitch_zeros(dz);
+	switch(dz->process) {
+	case(PITCH):	   return check_consistency_of_pitch_params(dz);
+	case(TRACK):	   return check_consistency_of_track_params(dz);
+	case(P_INVERT):	   return check_compatibility_pinvert_params(dz);
+	case(P_RANDOMISE): return check_validity_of_prandomise_params(dz);
+	case(P_CUT):	   return check_consistency_of_pcut_params(dz);
+	case(P_FIX):	   return check_compatibility_of_pfix_smoothing_flags(dz);
+	case(TRNSF):	   return check_for_valid_transposition_ratios(MINPITCH/dz->nyquist,dz->nyquist/MINPITCH,dz);
+	case(TRNSP):	   return check_for_valid_transposition_ratios(MINPITCH/dz->nyquist,dz->nyquist/MINPITCH,dz);
+
+	case(P_SYNTH):
+	case(P_VOWELS):
+		chans = dz->infile->channels;
+		dz->infile->channels = dz->infile->origchans;
+		if((exit_status = create_sized_outfile(dz->wordstor[0],dz))<0)
+			return(exit_status);
+		dz->infile->channels = chans;
+		break;
+	case(ANALENV):
+		chans = dz->infile->channels;
+		srate = dz->infile->srate;
+// JULY 2005 OLD 
+		dz->infile->srate    = round(1.0/dz->frametime);
+// NEW 
+		dz->infile->srate    = (int)(1.0/dz->frametime);
+		dz->infile->channels = 1;
+		if((exit_status = create_sized_outfile(dz->wordstor[0],dz))<0)
+			return(exit_status);
+		dz->infile->channels = chans;
+		dz->infile->srate    = srate;
+		break;
+	case(P_GEN):
+		if(dz->floatsam_output)
+			dz->infile->origstype = SAMP_FLOAT;
+		else
+			dz->infile->origstype = SAMP_SHORT;
+		dz->infile->origrate  = dz->iparam[PGEN_SRATE];
+		dz->infile->stype     = SAMP_FLOAT;
+		win_overlap = dz->iparam[PGEN_WINOVLP_INPUT]-1;
+		chancnt = dz->iparam[PGEN_CHANS_INPUT];
+		chancnt = chancnt + (chancnt%2);
+		switch(win_overlap) {
+			case 0:	dz->infile->Mlen = 4*chancnt;	break;
+			case 1:	dz->infile->Mlen = 2*chancnt;	break;
+			case 2: dz->infile->Mlen = chancnt;		break;
+			case 3: dz->infile->Mlen = chancnt / 2;	break;
+			default:
+				sprintf(errstr,"pvoc: Invalid window overlap factor.\n");
+				return(PROGRAM_ERROR);
+		}
+		if((dz->infile->Dfac = (int)(dz->infile->Mlen/PVOC_CONSTANT_A)) == 0){
+			fprintf(stdout,"WARNING: Decimation too low: adjusted.\n");
+			fflush(stdout);
+			dz->infile->Dfac = 1;
+		}
+		dz->infile->origchans = dz->iparam[PGEN_CHANS_INPUT] + 2;
+		dz->wanted = dz->infile->origchans;
+		dz->clength = dz->wanted/2;
+		dz->nyquist = dz->infile->origrate / 2;		
+		dz->infile->arate = (float) dz->infile->origrate / (float)dz->infile->Dfac;
+		dz->infile->srate = (int) dz->infile->arate;
+		dz->frametime = (float)(1.0/dz->infile->arate);
+		dz->wlength = (int)round(dz->param[SS_DUR] * dz->infile->arate);
+		dz->chwidth = dz->nyquist/(double)dz->clength;
+		dz->infile->channels = 1;
+		if((exit_status = create_sized_outfile(dz->outfilename,dz))<0)
+			return(exit_status);
+		break;
+	}
+	return(FINISHED);
+}
+
+/************ CHECK_CONSISTENCY_OF_PITCH_PARAMS *************/
+
+int check_consistency_of_pitch_params(dataptr dz)
+{
+	if(dz->param[PICH_HILM] <= dz->param[PICH_LOLM]) {
+		sprintf(errstr,"Impossible pitch range specified.\n");
+		return(USER_ERROR);
+	}
+	if(dz->mode==PICH_TO_BRK) {
+		if(dz->vflag==NULL) {
+			sprintf(errstr,"Problem in setting up redundant flag for PITCH.\n");
+			return(PROGRAM_ERROR);
+		}
+		if((dz->vflag = (char *)realloc((char *)dz->vflag,2 * sizeof(char)))==NULL) {
+			sprintf(errstr,"INSUFFICIENT MEMORY for extra internal flags.\n");
+			return(MEMORY_ERROR);
+		}
+		dz->vflag[KEEP_PITCH_ZEROS] = FALSE;
+		establish_datareduction(PICH_DATAREDUCE,dz);
+	}
+	return(FINISHED);
+}
+
+/************ CHECK_CONSISTENCY_OF_TRACK_PARAMS *************/
+
+int check_consistency_of_track_params(dataptr dz)
+{
+	if(dz->vflag!=NULL) {
+		sprintf(errstr,"Problem in setting up redundant flag for TRACK.\n");
+		return(PROGRAM_ERROR);
+	}
+	if((dz->vflag = (char *)malloc(2 * sizeof(char)))==NULL) {
+		sprintf(errstr,"INSUFFICIENT MEMORY for extra internal flags.\n");
+		return(MEMORY_ERROR);
+	}
+	dz->vflag[KEEP_PITCH_ZEROS] = FALSE;
+	establish_datareduction(TRAK_DATAREDUCE,dz);
+//TW UPDATE
+	return(FINISHED);
+}
+
+/************************** ESTABLISH_DATAREDUCTION ********************************/
+
+void establish_datareduction(int paramno,dataptr dz)
+{
+	double datareduction = dz->param[paramno] * OCTAVES_PER_SEMITONE;
+	datareduction = pow(2.0,datareduction);
+	dz->is_sharp  = datareduction;
+	dz->is_flat   = 1.0/dz->is_sharp;
+}
+
+/************ CHECK_COMPATIBILITY_PINVERT_PARAMS *************/
+
+int check_compatibility_pinvert_params(dataptr dz)
+{
+	int exit_status;
+	int n;
+	double maxmean, minmean;
+	if((dz->vflag[PI_IS_TOP] || dz->vflag[PI_IS_BOT]) && dz->vflag[PI_IS_MEAN]) {
+		if(dz->brksize[PI_MEAN]) {
+			maxmean = MIDIMIN;
+			if((exit_status = hztomidi(&minmean,dz->nyquist))<0)
+				return(exit_status);
+			for(n=0;n<dz->itemcnt*2; n+=2) {
+				if(dz->brk[PI_MEAN][n] > maxmean)
+					maxmean = dz->brk[PI_MEAN][n];
+				if(dz->brk[PI_MEAN][n] < minmean)
+					minmean = dz->brk[PI_MEAN][n];
+			}	 
+		} else
+			maxmean = minmean = dz->param[PI_MEAN];	
+		if(dz->vflag[PI_IS_TOP] && (dz->param[PI_TOP] < maxmean)) {
+			if(dz->brksize[PI_MEAN])
+				sprintf(errstr,
+				"top midipitch value must be ABOVE all mean values in brkpntfile.\n");
+			else
+				sprintf(errstr,"top midipitch value must be ABOVE mean value.\n");
+			return(USER_ERROR);
+
+		}
+		if(dz->vflag[PI_IS_BOT] && (dz->param[PI_BOT] > minmean)) {
+			if(dz->brksize[PI_MEAN])
+				sprintf(errstr,"bot midipitch value must be BELOW all mean values in brkpntfile.\n");
+			else
+				sprintf(errstr,"bot midipitch value must be BELOW mean value.\n");
+			return(USER_ERROR);
+		}
+   	}
+	return(FINISHED);
+}
+
+/************ CHECK_VALIDITY_OF_PRANDOMISE_PARAMS *************/
+
+int check_validity_of_prandomise_params(dataptr dz)
+{
+	if(dz->vflag[PR_IS_SLEW] && fabs(dz->param[PR_SLEW])<=1.0) {
+		sprintf(errstr,"slew out of range: slew must be >1 or <-1\n");
+		return(USER_ERROR);
+	}
+	return(FINISHED);
+}
+
+/********************** CHECK_CONSISTENCY_OF_PCUT_PARAMS **********************/
+
+int check_consistency_of_pcut_params(dataptr dz)
+{
+	if(dz->mode==PCUT_BOTH && (dz->param[PC_STT] >= dz->param[PC_END])) {
+		sprintf(errstr,"Start and end cut-times incompatible.\n");
+		return(USER_ERROR);
+	}
+	return(FINISHED);
+}
+
+/***************************** CHECK_COMPATIBILITY_OF_PFIX_SMOOTHING_FLAGS ******/
+
+int check_compatibility_of_pfix_smoothing_flags(dataptr dz)
+{
+	if(dz->vflag[PF_TWOW] && !dz->vflag[PF_IS_SMOOTH]) {
+		sprintf(errstr,"-w flag cannot be used without -s flag.\n");
+		return(USER_ERROR);
+	}
+	return(FINISHED);
+}
+
+/********************* CHECK_FOR_VALID_TRANSPOSITION_RATIOS **********************/
+
+int check_for_valid_transposition_ratios(double mintrans,double maxtrans,dataptr dz)
+{
+	int n;
+	for(n=0;n<dz->wlength;n++) {
+		if(dz->transpos[n] < mintrans || dz->transpos[n] > maxtrans) {
+			sprintf(errstr,
+				"Invalid transposition ratio (%f) encountered.\n(MIN %lf MAX %lf)\n",
+				dz->transpos[n],mintrans,maxtrans);
+			return(DATA_ERROR);
+		}
+	}
+	return(FINISHED);
+}
+
+
+/********************************************************************************************/
+/********************************** FORMERLY IN buffers.c ***********************************/
+/********************************************************************************************/
+
+/**************************** ALLOCATE_LARGE_BUFFERS ******************************/
+
+int allocate_large_buffers(dataptr dz)
+{
+	switch(dz->process) {
+	case(TRNSP):	case(TRNSF):
+		return allocate_single_buffer(dz);
+
+	case(PITCH):	case(TRACK):
+//TW UPDATES
+	case(P_SYNTH):
+	case(P_VOWELS):
+
+		return allocate_single_buffer_plus_extra_pointer(dz);
+
+	case(P_APPROX):		case(P_EXAG): 	  case(P_INVERT):	  
+	case(P_QUANTISE): 	case(P_RANDOMISE):case(P_SMOOTH):	  
+	case(P_TRANSPOSE):	case(P_VIBRATO):  case(P_CUT): 	  
+	case(P_FIX): 	  	case(REPITCH):	  case(REPITCHB):	  
+		return(FINISHED);
+//TW UPDATES
+	case(P_INSERT):
+	case(P_SINSERT):
+	case(P_PTOSIL):
+	case(P_NTOSIL):
+	case(P_GEN):
+	case(P_INTERP):
+	case(P_BINTOBRK):
+		return(FINISHED);
+	case(ANALENV):
+		return allocate_double_buffer(dz);
+
+	default:
+		sprintf(errstr,"Unknown program no. in allocate_large_buffers()\n");
+		return(PROGRAM_ERROR);
+	}
+	return(FINISHED);	/* NOTREACHED */
+}
+
+/********************************************************************************************/
+/********************************** FORMERLY IN cmdline.c ***********************************/
+/********************************************************************************************/
+
+int get_process_no(char *prog_identifier_from_cmdline,dataptr dz)
+{
+	if     (!strcmp(prog_identifier_from_cmdline,"getpitch"))     	dz->process = PITCH;
+	else if(!strcmp(prog_identifier_from_cmdline,"track"))     		dz->process = TRACK;
+	else if(!strcmp(prog_identifier_from_cmdline,"approx"))   		dz->process = P_APPROX;
+	else if(!strcmp(prog_identifier_from_cmdline,"exag"))     		dz->process = P_EXAG;
+	else if(!strcmp(prog_identifier_from_cmdline,"invert"))   		dz->process = P_INVERT;
+	else if(!strcmp(prog_identifier_from_cmdline,"quantise")) 		dz->process = P_QUANTISE;
+	else if(!strcmp(prog_identifier_from_cmdline,"randomise")) 		dz->process = P_RANDOMISE;
+	else if(!strcmp(prog_identifier_from_cmdline,"smooth"))   		dz->process = P_SMOOTH;
+	else if(!strcmp(prog_identifier_from_cmdline,"pchshift")) 		dz->process = P_TRANSPOSE;
+	else if(!strcmp(prog_identifier_from_cmdline,"vibrato"))  		dz->process = P_VIBRATO;
+	else if(!strcmp(prog_identifier_from_cmdline,"cut"))  	   		dz->process = P_CUT;
+	else if(!strcmp(prog_identifier_from_cmdline,"fix"))  	   		dz->process = P_FIX;
+	else if(!strcmp(prog_identifier_from_cmdline,"combine"))   		dz->process = REPITCH;
+	else if(!strcmp(prog_identifier_from_cmdline,"combineb"))  		dz->process = REPITCHB;
+	else if(!strcmp(prog_identifier_from_cmdline,"transpose"))	   	dz->process = TRNSP;
+	else if(!strcmp(prog_identifier_from_cmdline,"transposef"))	   	dz->process = TRNSF;
+//TW UPDATES (or definite instatements)
+	else if(!strcmp(prog_identifier_from_cmdline,"synth"))  	   	dz->process = P_SYNTH;
+	else if(!strcmp(prog_identifier_from_cmdline,"vowels"))  	   	dz->process = P_VOWELS;
+	else if(!strcmp(prog_identifier_from_cmdline,"insertzeros"))  	dz->process = P_INSERT;
+	else if(!strcmp(prog_identifier_from_cmdline,"insertsil"))  	dz->process = P_SINSERT;
+	else if(!strcmp(prog_identifier_from_cmdline,"pitchtosil"))  	dz->process = P_PTOSIL;
+	else if(!strcmp(prog_identifier_from_cmdline,"noisetosil"))  	dz->process = P_NTOSIL;
+	else if(!strcmp(prog_identifier_from_cmdline,"analenv"))  		dz->process = ANALENV;
+	else if(!strcmp(prog_identifier_from_cmdline,"generate"))  	   	dz->process = P_GEN;
+	else if(!strcmp(prog_identifier_from_cmdline,"interp"))  	   	dz->process = P_INTERP;
+	else if(!strcmp(prog_identifier_from_cmdline,"pchtotext"))  	dz->process = P_BINTOBRK;
+	else {
+		sprintf(errstr,"Unknown program identification string '%s'\n",prog_identifier_from_cmdline);
+		return(USAGE_ONLY);
+	}
+//TW UPDATE
+	return(FINISHED);
+}
+
+/********************************************************************************************/
+/********************************** FORMERLY IN usage.c *************************************/
+/********************************************************************************************/
+
+/******************************** USAGE1 ********************************/
+
+int usage1(void)
+{
+	fprintf(stdout,
+	"\nREPITCHING OPERATIONS ON SPECTRAL AND PITCH FILES\n\n"
+	"USAGE: repitch NAME (mode) infile (infile2) outfile parameters: \n"
+	"\n"
+	"where NAME can be any one of\n"
+	"\n"
+	"getpitch\n"
+	"approx      exag     invert    quantise    randomise    smooth\n"
+	"vibrato     cut      fix       combine     combineb\n"
+//TW UPDATES
+	"synth    vowels   insertzeros   insertsil   pitchtosil    noisetosil   analenv\n"
+	"generate interp   pchtotext\n"
+	"pchshift   transpose   transposef\n\n"
+	"Type 'repitch getpitch' for more info on repitch getpitch..ETC.\n");
+	return(USAGE_ONLY);
+}
+
+/******************************** USAGE2 ********************************/
+
+int usage2(char *str)
+{
+	if(!strcmp(str,"getpitch")) {
+		fprintf(stdout,
+		"repitch getpitch 1 infile outfile pfil \n\t [-tR] [-gM] [-sS] [-nH] [-lL] [-hT] [-a] [-z]\n"
+		"repitch getpitch 2 infile outfile bfil \n\t [-tR] [-gM] [-sS] [-nH] [-lL] [-hT] [-di] [-a]\n\n" 
+		"ATTEMPT TO EXTRACT PITCH FROM SPECTRAL DATA.\n\n" 
+		"outfile  If resynthesized, produces tone at detected (possibly varying) pitch.\n\n"
+		"pfil     (MODE 1) Binary output file containing pitch information.\n"
+		"bfil     (MODE 2) breakpoint (text) outfile of pitch info (as time/Hz pairs).\n"
+		"         Either of these may be reused in other pitch-manipulating options.\n\n"
+		"-t R     R = Tuning range(semitones) within which harmonics accepted as in tune\n"
+		"         (Default 1)\n"
+		"-g M     M = minimum number of adjacent windows that must be pitched,\n"
+		"         for a pitch-value to be registered (Default %d).\n"
+		"-s S     S = signal to noise ratio, in decibels. (Default %.0lfdB)\n"
+		"         Windows which are more than SdB below maximum level in sound, are\n"
+		"         assumed to be noise, & any detected pitchvalue is assumed spurious.\n"
+		"-n H     H = how many of the %d loudest peaks in spectrum must be harmonics\n"
+		"         to confirm sound is pitched: Default %d.\n"
+		"-l L     L = frequency of LOWEST acceptable pitch (Default min: %.0lfHz).\n"
+		"-h T     T = frequency of TOPMOST acceptable pitch (Default max: nyquist/%d).\n"
+		"-d i     i = acceptable pitch-ratio error in data reduction. (semitones)\n"
+		"         Default 1/8 tone = %lf\n"
+		"-a       Alternative pitch-finding algorithm (avoid N<2).\n"
+		"-z       Retain unpitched windows (set them to -1)\n"
+		"         Default: Set pitch by interpolation between adjacent pitched windows.\n",
+		BLIPLEN,SILENCE_RATIO,MAXIMI,ACCEPTABLE_MATCH,MINPITCH,MAXIMI,LOG2(EIGHTH_TONE)*SEMITONES_PER_OCTAVE);
+	} else if(!strcmp(str,"approx")) {
+		fprintf(stdout,
+    	"repitch approx mode pitchfile outfile [-pprange] [-ttrange] [-ssrange]\n\n"
+		"MAKE AN APPROXIMATE COPY OF A PITCHFILE.\n\n"
+		"PRANGE  Interval (semitones) over which pitch +- randomly varies from orig.\n"
+		"        Range > 0.0\n"
+		"TRANGE  Time-interval (msecs) by which pitchval can stray from orig time.\n"
+		"        Applied to turning-points in pitch-contour.\n"
+		"        Range: from duration of 1 analysis window to duration of entire file.\n"
+		"SRANGE  Time-interval (msecs) over which pitch contour scanned.\n"
+		"        Pitchshift by a semitone within srange, indicates pitch rise or fall.\n"
+		"        Range: from duration of %d analwindows to (approx) dur of infile.\n\n"
+    	"MODES....\n"
+    	"(1) Gives a pitchfile as ouput.\n"
+    	"(2) Gives a transposition file as output.\n\n"
+    	"Prange, trange and srange may vary over time.\n",2*BLOKCNT);
+	} else if(!strcmp(str,"exag")) {
+		fprintf(stdout,
+    	"repitch exag 1-2 pitchfile outfile meanpch range\n"
+    	"repitch exag 3-4 pitchfile outfile meanpch       contour\n"
+    	"repitch exag 5-6 pitchfile outfile meanpch range contour\n\n"
+		"EXAGGERATE PITCH CONTOUR.\n\n"
+		"MEANPITCH pitch (MIDI) around which intervals stretched.\n"
+		"RANGE     exagg pitch-range (multiply semitone-intvl). >0.\n"
+		"CONTOUR   exagg pitch-contour. Values (0-1).\n\n"
+    	"MODES....\n"
+    	"(1,3,5) Give a pitchfile as ouput.\n"
+    	"(2,4,6) Give a transposition file as output.\n\n"
+    	"Meanpitch, range and contour may all vary over time.\n");
+	} else if(!strcmp(str,"invert")) {
+		fprintf(stdout,
+    	"repitch invert mode pitchfile outfile map [-mmeanpch] [-bbot] [-ttop]\n\n"
+		"INVERT PITCH CONTOUR OF A PITCH DATA FILE.\n\n"
+		"MAP	   Set map to ZERO if no mapping is required..OTHERWISE\n"
+		"          map is a file of paired values showing how intervals\n"
+		"          (in, possibly fractional, SEMITONES)\n"
+		"          are to be mapped onto their inversions.\n"
+		"          Range -%.0lf to %.0lf.\n"
+		"MEANPCH   pitch (MIDI) around which pitchline inverted.\n"
+		"          Range: MIDI equivalents of %.0lfHz to nyquist.\n"
+		"BOT       bottom pitch (MIDI) permissible (default 0).\n"
+		"          Range: MIDI equivalents of %.0lfHz to nyquist.\n"
+ 		"TOP       top pitch (MIDI) permissible (default 127).\n"
+		"          Range: MIDI equivalents of %.0lfHz to nyquist.\n"
+   		"MODES.\n"
+    	"(1) Gives a pitchfile as ouput.\n"
+    	"(2) Gives a transposition file as output.\n\n"
+    	"Meanpitch may vary over time.\n",MAXINTRANGE,MAXINTRANGE,MINPITCH,MINPITCH,MINPITCH);		   
+	} else if(!strcmp(str,"quantise")) {
+		fprintf(stdout,
+    	"repitch quantise mode pitchfile outfile q-set [-o]\n\n"
+		"QUANTISE PITCHES IN A PITCH DATA FILE.\n\n"
+		"q_set   a file of (possibly fractional) MIDI pitchvals\n"
+		"        over which pitch to be quantised.\n"
+		"-o		 duplicates q_set in all octave transpositions\n\n"
+    	"MODES....\n"
+    	"(1) Gives a pitchfile as ouput.\n"
+    	"(2) Gives a transposition file as output.\n\n");
+	} else if(!strcmp(str,"randomise")) {
+		fprintf(stdout,
+		"repitch randomise mode pitchfile outfile maxinterval timestep [-sslew]\n\n"
+		"RANDOMISE PITCH LINE.\n\n"
+		"MAXINTERVAL (semitones) over which pitches can +- randomvary.\n"
+		"            Range 0 to %.0lf: Value or brkpnt file.\n"
+		"TIMESTEP    maximum timestep between random pitch fluctuations (milliseconds).\n"
+		"            Timesteps are random values less than this.\n"
+		"            Range: duration of 1 anal window to dur of entire file.\n" 
+		"SLEW	    e.g. 2:  upward variation range twice that of downward.\n"
+		"    	    e.g -3: downward variation range 3 times that of upward.\n"
+		"    	    Range >1 || <-1.\n\n"
+    	"MODES....\n"
+    	"(1) Gives a pitchfile as ouput.\n"
+    	"(2) Gives a transposition file as output.\n\n"
+    	"Maxinterval and timestep may vary over time.\n",MAXINTRANGE);
+	} else if(!strcmp(str,"smooth")) {
+		fprintf(stdout,
+    	"repitch smooth mode pitchfile outfile timeframe [-pmeanpch] [-h]\n\n"
+		"SMOOTH PITCH CONTOUR IN A PITCH DATA FILE.\n\n"
+		"TIMEFRAME (millisecs) over which to interpolate pitch values.\n"
+		"          Range: duration of 1 anal window to dur of entire file.\n" 
+		"-p        interp between PEAK value in each timeframe block of pitch values.\n"
+		"          MEANPITCH is pitch from which peaks measured\n"
+		"          (and must be within pitch range, in every timeframe block).\n"
+		"          Peak is maximum displacement from mean (up or down).\n"
+		"-h        At end of file, hold last interpolated pitchvalue calculated.\n"
+		"          Default: interpolate thence to last actual value in input.\n"
+    	"MODES....\n"
+    	"(1) Gives a pitchfile as ouput.\n"
+    	"(2) Gives a transposition file as output.\n\n"
+    	"Timeframe and meanpitch may vary over time.\n");
+	} else if(!strcmp(str,"pchshift")) {
+		fprintf(stdout,
+    	"repitch pchshift pitchfile outpitchfile transposition\n\n"
+		"SHIFTS PITCHES IN PITCHDATA FILE BY CONSTANT NO OF SEMITONES.\n\n"
+		"(To transpose pitch of spectrum in time-varying way,'repitch transpose[f]')\n");
+	} else if(!strcmp(str,"vibrato")) {
+		fprintf(stdout,
+		"repitch vibrato mode pitchfile outfile vibfreq vibrange\n\n"
+		"ADD VIBRATO TO PITCH IN A PITCH DATA FILE.\n\n"
+		"VIBFREQ   frequency of vibrato itself (Hz). Values >0.\n"
+		"VIBRANGE  max interval vibrato moves away from central pitch (semitones).\n"
+		"          Values >0.\n\n"
+    	"MODES....\n"
+    	"(1) Gives a pitchfile as ouput.\n"
+    	"(2) Gives a transposition file as output.\n\n"
+    	"Vibfreq and vibrange may vary over time.\n");
+	} else if(!strcmp(str,"cut")) {
+		fprintf(stdout,
+		"repitch cut 1 pitchfile outpitchfile starttime\n"
+		"repitch cut 2 pitchfile outpitchfile endtime\n"
+		"repitch cut 3 pitchfile outpitchfile starttime endtime\n\n"
+		"CUT OUT AND KEEP A SEGMENT OF A BINARY PITCH-DATAFILE.\n");
+	} else if(!strcmp(str,"fix")) {
+		fprintf(stdout,
+		"repitch fix pitchfile outpitchfile\n"
+		"       [-rt1] [-xt2] [-lbf] [-htf] [-sN] [-bf1] [-ef2] [-w] [-i]\n\n"
+		"MASSAGE PITCH DATA IN A BINARY PITCHFILE.\n"
+		"Pitchdata may be viewed by running pitchinfo see, and viewing output in viewsf.\n\n"
+		"PITCHFILE & OUTPITCHFILE:binary pitchdata files generated by 'spec pitch' etc.\n\n"
+		"-r t1  Starttime:  remove pitch from time 't1' (default 0.0).\n"
+		"-x t2  Endtime:    end pitch removal at time 't2' (default, end of file).\n"
+		"-l bf  Bottom_frq: remove pitch below frequency 'bf'.\n"
+		"-h tf  Top_frq:    remove pitch above frequency 'tf'.\n"
+		"-s N   Smoothcnt:  smooth onset errors & glitches in pitchdata, N times.\n"
+		"-b f1  Startfrq:   force start frequency to be 'f1'.\n"
+		"-e f2  Endfrq:     force end frequency to be 'f2'.\n"
+		"-w     removes 2-window glitches (Default: 1-window) (Use ONLY with -s)\n"
+		"-i     interpolate through ALL non-pitch windows in pitch_data,\n"
+		"       producing pitch everywhere.\n"
+		"RULES.........\n"
+		"(1) AT LEAST ONE flag must be used.\n"
+		"(2) When pitches are removed they are replaced by a 'no-pitch' indicator.\n"
+    	"    These (and any already existing unpitched windows in the file) can be\n"
+		"    converted to pitch-data (by interpolation between adjacent pitches)\n"
+		"    using the -i flag.\n"
+		"(3) With multiple flags, ORDER of operations inside program is....\n"
+    	"    REMOVE-TIMEWISE(rx),REMOVE-FRQWISE(lh),SMOOTH(sw),SET-ENDVALS(be),INTERP(i)\n");
+	} else if(!strcmp(str,"combine")) {
+		fprintf(stdout,
+		"repitch combine 1 pitchfile    pitchfile2    outtransposfile\n" 
+		"repitch combine 2 pitchfile    transposfile  outpitchfile\n" 
+		"repitch combine 3 transposfile transposfile2 outtransposfile\n\n" 
+		"       GENERATE TRANSPOSITION DATA FROM 2 SETS OF PITCH DATA,\n" 
+		"          OR TRANSPOSE PITCH DATA WITH TRANSPOSITION DATA,\n" 
+		"OR COMBINE 2 SETS OF TRANSPOSITION DATA TO FORM NEW TRANSPOSITION DATA,\n"
+		"                 PRODUCING BINARY DATAFILE OUTPUT.\n\n"
+		"PITCHFILE       binary pitchdatafile OR time/pitch(frq) brkpnt file\n"
+		"TRANSPOSFILE    binary transposition file OR time/transpos(ratio) brkpnt file\n"
+		"OUTPITCHFILE    binary pitchdatafile\n"
+		"OUTTRANSPOSFILE binary transpositionfile\n\n"
+		"NB: It's IMPOSSIBLE to generate binary outfile from exclusively brkpnt infiles.\n");
+	} else if(!strcmp(str,"combineb")) {
+		fprintf(stdout,
+		"repitch combineb 1 pitchfile    pitchfile2    outtbrkfile [-dI]\n" 
+		"repitch combineb 2 pitchfile    transposfile  outpbrkfile [-dI]\n" 
+		"repitch combineb 3 transposfile transposfile2 outtbrkfile [-dI]\n\n" 
+		"       GENERATE TRANSPOSITION DATA FROM 2 SETS OF PITCH DATA,\n" 
+		"          OR TRANSPOSE PITCH DATA WITH TRANSPOSITION DATA,\n" 
+		"OR COMBINE 2 SETS OF TRANSPOSITION DATA TO FORM NEW TRANSPOSITION DATA,\n"
+		"              PRODUCING A TIME/VAL BRKPNT FILE OUTPUT.\n\n"
+		"PITCHFILE    binary pitchdatafile OR time/pitch(frq) brkpnt file\n"
+		"TRANSPOSFILE binary transposition file OR time/transpos(ratio) brkpnt file\n"
+		"OUTPBRKFILE  time/pitch(frq) brkpnt file\n"
+		"OUTTBRKFILE  time/transposition(ratio) brkpnt file\n\n"
+		"-d  I = acceptable pitch error in brkpntfile data-reduction.\n"
+   		"    Range > 1.0 : Default: eighth_tone = %lf\n",LOG2(EIGHTH_TONE)*SEMITONES_PER_OCTAVE);
+	} else if(!strcmp(str,"transposef")) {
+		fprintf(stdout,
+		"repitch transposef 1-3 infile outfile -fN|-pN [-i] transpos [-lminf][-hmaxf][-x]\n"
+		"repitch transposef 4   infile transpos outfile -fN|-pN [-i] [-lminf][-hmaxf][-x]\n"
+		"\n"
+		"TRANSPOSE SPECTRUM : BUT RETAIN ORIGINAL SPECTRAL ENVELOPE\n"
+		"\n"
+		"MODES\n"
+		"1    transposition as a frq ratio.\n"
+		"2    transposition in (fractions of) octaves.\n"
+		"3    transposition in (fractions of) semitones.\n"
+		"4    transposition as a binary data file.\n"
+		"\n"
+		"-f   extract formant envelope linear frqwise,\n"
+		"     using 1 point for every N equally-spaced frequency-channels.\n"
+		"-p   extract formant envelope linear pitchwise,\n"
+		"     using N equally-spaced pitch-bands per octave.\n"
+		"-i   quicksearch for formants (less accurate).\n"
+		"\n"
+		"-l     MINF = minimum frq, below which data is filtered out.\n"
+		"-h     MAXF = maximum frq, above which data is filtered out.\n"
+		"-x     Fuller spectrum.\n"
+		"\n"
+		"frq-ratio, octave or semitone transpositions may vary over time.\n"
+		"maxfrq and minfrq may vary over time.\n");
+	} else if(!strcmp(str,"transpose")) {
+		fprintf(stdout,
+		"repitch transpose 1-3 infile          outfile transpos [-lminfrq][-hmaxfrq][-x]\n"
+		"repitch transpose 4   infile transpos outfile          [-lminfrq][-hmaxfrq][-x]\n"
+		"\n"
+		"TRANSPOSE SPECTRUM (SPECTRAL ENVELOPE ALSO MOVES)\n"
+		"\n"
+		"MODES\n"
+		"1    transposition as a frq ratio.\n"
+		"2    transposition in (fractions of) octaves.\n"
+		"3    transposition in (fractions of) semitones.\n"
+		"4    transposition as a binary data file.\n"
+		"\n"
+		"-l     MINFRQ = minimum frq, below which data is filtered out.\n"
+		"-h     MAXFRQ = maximum frq, above which data is filtered out.\n"
+		"-x     Fuller spectrum.\n"
+		"\n"
+		"frq-ratio, octave or semitone transpositions may vary over time.\n");
+//TW UPDATES
+	} else if(!strcmp(str,"synth")) {
+		fprintf(stdout,
+		"repitch synth binarypitchfile outanalfile harmonics-data\n"
+		"\n"
+		"CREATE SPECTRUM OF A SOUND FOLLOWING THE PITCH CONTOUR IN THE PITCH FILE\n"
+		"\n"
+		"HARMONICS-DATA is a list of the amplitude of each harmonic in sequence, from 1 upwards\n"
+		"Amplitudes must lie in the range 0-1\n");
+	} else if(!strcmp(str,"generate")) {
+		fprintf(stdout,
+		"repitch generate outpitchdatafile midipitch-data srate  [-cpoints] [-ooverlap]\n"
+		"\n"
+		"CREATE BINARY PITCHDATA FILE FROM A TEXTFILE OF TIME-MIDI VALUE PAIRS\n"
+		"\n"
+		"MIDIPITCH-DATA is a list of paired time and midi-note-values\n"
+		"     where times must start at zero and increase,\n"
+		"     and note values may be numeric MIDI values (possibly fractional)\n"
+		"     OR note names (A,B,C,D,E,F or G)\n"
+		"     possibly followed by '#'(sharp) or 'b'(flat)\n"
+		"     followed by an octave number between -5 and 5\n"
+		"     where 0 corresponds to the octave starting at middle C.\n\n"
+		"SRATE is the sample rate of the soundfile that might later be generated\n"
+		"     from the binary pitch data.\n"
+		"POINTS   No of analysis points (2-32768 (power of 2)): default 1024\n"
+		"         More points give better freq resolution but worse time-resolution.\n"
+		"OVERLAP  Filter overlap factor (1-4): default 3\n");
+	} else if(!strcmp(str,"vowels")) {
+		fprintf(stdout,
+		"repitch vowels infile outfile vowel-data halfwidth curve pk_range fweight foffset\n"
+		"\n"
+		"CREATE SPECTRUM OF VOWEL SOUND(S) FOLLOWING PITCH CONTOUR IN PITCH FILE\n"
+		"\n"
+		"VOWEL-DATA is a vowel, OR a file of paired time/vowel values\n"
+		"where vowel is one of the following strings\n"
+		"     ee : as in 'heat'\n"        
+		"     i  : as in 'hit'\n"
+		"     ai : as in 'hate'\n"
+		"     aii: as in scottish 'e'\n"
+		"     e  : as in 'pet'\n"
+		"     a  : as in 'pat'\n"
+		"     ar : as in 'heart'\n"
+		"     o  : as in 'hot'\n"
+		"     or : as in 'taught'\n"
+		"     u  : as in 'hood'\n"
+		"     uu : as in scottish 'you'\n"
+		"     ui : as in scottish 'could'\n"
+		"     x  : neutral vowel as in 'herb', or 'a'\n"
+		"     xx : as in Southern English 'hub'\n"
+		"     n  : as in mean, can, done\n"
+		"\n"
+		"In brkpnt files, times must start at zero, and increase.\n"
+		"\n"
+		"HALFWIDTH is half-width of formant, in Hz, as fraction of formant centre-frq (range .01 - 10)\n"
+		"CURVE     is the steepness of the formant peak (range 0.1 to 10.0)\n"
+		"PK_RANGE  ratio of (max) amplitude range of formant peaks to (max) total range (range 0 to 1)\n"
+		"FWEIGHT   is amplitude weighting of fundamental (range 0 to 1)\n"
+		"FOFFSET   is amount of scattering of frqs of harmonics from their true value (range 0 to 1)\n"
+		"\n");
+	} else if(!strcmp(str,"insertzeros")) {
+		fprintf(stdout,
+		"repitch insertzeros mode infile outfile zeros-data\n"
+		"\n"
+		"MARK AREAS AS UNPITCHED IN A PITCHDATA FILE\n"
+		"\n"
+		"MODES\n"
+		"1  data as times.\n"
+		"2  data as (grouped) sample count: Count samples in mono, pairs in stereo etc\n"
+		"\n"
+		"ZEROS-DATA\n"
+		"is a list of pairs of times between which unpitched data to be indicated.\n");
+	} else if(!strcmp(str,"insertsil")) {
+		fprintf(stdout,
+		"repitch insertsil mode infile outfile silence-data\n"
+		"\n"
+		"MARK AREAS AS SILENT IN A PITCHDATA FILE\n"
+		"\n"
+		"MODES\n"
+		"1  data as times.\n"
+		"2  data as (grouped) sample count: Count samples in mono, pairs in stereo etc\n"
+		"\n"
+		"SILENCE-DATA\n"
+		"is a a list of pairs of times between which silence is to be indicated.\n");
+	} else if(!strcmp(str,"pitchtosil")) {
+		fprintf(stdout,
+		"repitch pitchtosil infile outfile\n"
+		"\n"
+		"REPLACE PITCHED WINDOWS BY SILENCE\n");
+	} else if(!strcmp(str,"noisetosil")) {
+		fprintf(stdout,
+		"repitch noisetosil infile outfile\n"
+		"\n"
+		"REPLACE UNPITCHED WINDOWS BY SILENCE\n");
+	} else if(!strcmp(str,"analenv")) {
+		fprintf(stdout,
+		"repitch analenv inanalfile outenvfile\n"
+		"\n"
+		"EXTRACT THE WINDOW-LOUDNESS ENVELOPE OF AN ANALYSIS FILE\n"
+		"\n"
+		"Extracts loudness of each window of analysis file.\n"
+		"Output data synchronous with pitch or formant data from same analfile\n");
+	} else if(!strcmp(str,"interp")) {
+		fprintf(stdout,
+		"repitch interp 1-2 infile outfile\n"
+		"\n"
+		"REPLACE NOISE OR SILENCE BY PITCH INTERPOLATED FROM EXISTING PITCHES\n"
+		"\n"
+		"Mode 1 glides from previous valid pitch to next vaild pitch.\n"
+		"Mode 2 sustains previous valid pitch until next vaild pitch appears.\n");
+	} else if(!strcmp(str,"pchtotext")) {
+		fprintf(stdout,
+		"repitch pchtotext infile outfile\n"
+		"\n"
+		"CONVERT BINARY PITCH DATA TO TEXTFILE\n");
+
+	} else
+		fprintf(stdout,"Unknown option '%s'\n",str);
+	return(USAGE_ONLY);
+}
+
+/******************************** USAGE3 ********************************/
+
+int usage3(char *str1,char *str2)
+{
+	sprintf(errstr,"Insufficient parameters on command line.\n");
+	return(USAGE_ONLY);
+}
+
+//TW UPDATE : NEW FUNCTION
+/******************************** GET_PITCH ********************************/
+
+int get_pitch(char *str,double *midi)
+{
+	char *p = str;
+	int oct, intmidi = 0, is_noteval = 0;
+	switch(*p) {
+	case('c'):	case('C'):	intmidi = 0; 	is_noteval = 1; break;
+	case('d'):	case('D'):	intmidi = 2; 	is_noteval = 1; break;	
+	case('e'):	case('E'):	intmidi = 4; 	is_noteval = 1; break;
+	case('f'):	case('F'):	intmidi = 5; 	is_noteval = 1; break;	
+	case('g'):	case('G'):	intmidi = 7;	is_noteval = 1; break;
+	case('a'):	case('A'):	intmidi = 9;	is_noteval = 1; break;
+	case('b'):	case('B'):	intmidi = 11;	is_noteval = 1; break;
+	}
+	if(is_noteval) {
+		p++;	
+		switch(*p) {
+		case('#'):	intmidi++;	p++; break;
+		case('b'):	intmidi--;	p++; break;
+		}
+		if(sscanf(p,"%d",&oct)!=1) {
+			sprintf(errstr,"No (valid) octave value given : '");
+			return(-1);
+		}
+		if(oct < -5 || oct > 5) {
+			sprintf(errstr,"Octave value (%d) out of range : '",oct);
+			return(-1);
+		}
+		oct += 5;
+		oct *= 12;
+		intmidi += oct;
+		*midi = (double)intmidi;
+	} else if(sscanf(str,"%lf",midi)!=1) {
+		sprintf(errstr,"'");
+		return(-1);
+	}
+	if(*midi < 0.0 || *midi >= 132.0) {
+		sprintf(errstr,"Midi value (%lf) out of range : '",*midi);
+		return(-1);
+	}
+	return FINISHED;
+}
+

+ 236 - 0
dev/repitch/main.c

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

+ 3730 - 0
dev/repitch/repitch.c

@@ -0,0 +1,3730 @@
+/*
+ * Copyright (c) 1983-2013 Trevor Wishart and Composers Desktop Project Ltd
+ * http://www.trevorwishart.co.uk
+ * http://www.composersdesktop.com
+ *
+ This file is part of the CDP System.
+
+    The CDP System is free software; you can redistribute it
+    and/or modify it under the terms of the GNU Lesser General Public
+    License as published by the Free Software Foundation; either
+    version 2.1 of the License, or (at your option) any later version.
+
+    The CDP System is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public
+    License along with the CDP System; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+    02111-1307 USA
+ *
+ */
+
+
+
+/* flotsam version */
+#include <stdio.h>
+#include <stdlib.h>
+#include <structures.h>
+#include <tkglobals.h>
+#include <pnames.h>
+#include <globcon.h>
+#include <processno.h>
+#include <modeno.h>
+#include <special.h>
+#include <logic.h>
+#include <arrays.h>
+#include <flags.h>
+#include <repitch.h>
+#include <cdpmain.h>
+#include <formants.h>
+#include <speccon.h>
+#include <sfsys.h>
+#include <osbind.h>
+#include <repitch.h>
+#include <pvoc.h>
+
+#include <vowels.h>
+#include <vowels2.h>
+
+
+#if defined unix || defined __GNUC__
+#define round(x) lround((x))
+#endif
+
+#define	GLARG		 (0.1)	/* 2nd-derivative maximum, for smoothing */
+#define SLOPE_FUDGE  (0.2)
+
+
+static int  specpitch(dataptr dz);
+static int  spectrack(dataptr dz);
+static int  tranpose_within_formant_envelope(int vc,dataptr dz);
+static int  reposition_partials_in_appropriate_channels(int with_body,dataptr dz);
+static int  zero_outofrange_channels(double *totalamp,double lofrq_limit,double hifrq_limit,dataptr dz);
+static int  close_to_frq_already_in_ring(chvptr *there,double frq1,dataptr dz);
+static int  substitute_in_ring(int vc,chvptr here,chvptr there,dataptr dz);
+static int  insert_in_ring(int vc, chvptr here, dataptr dz);
+static int  put_ring_frqs_in_ascending_order(chvptr **partials,float *minamp,dataptr dz);
+static int  found_pitch(chvptr *partials,double lo_loud_partial,double hi_loud_partial,float minamp,dataptr dz);
+static int  found_pitch_1(chvptr *partials,double lo_loud_partial,double hi_loud_partial,float minamp,dataptr dz);
+static int  found_pitch_2(chvptr *partials,dataptr dz);
+static int  smooth_spurious_octave_leaps(int pitchno,float minamp,dataptr dz);
+static int  equivalent_pitches(double frq1, double frq2, dataptr dz);
+static int  is_peak_at(double frq,int window_offset,float minamp,dataptr dz);
+static int  enough_partials_are_harmonics(chvptr *partials,dataptr dz);
+static int  is_a_harmonic(double frq1,double frq2,dataptr dz);
+static int	do_pitch_cut(dataptr dz);
+static int	do_pitch_filter(dataptr dz);
+static int	do_pitch_smoothing(dataptr dz);
+static int	skip_to_first_pitch(int *first_pitch,dataptr dz);
+static int	calc_slopechanges(int m, double *slopechange,dataptr dz);
+static int	is_start_of_glitch(int n,double *slopechange,dataptr dz);
+static int	do_onset_smooth(int n, double *slopechange,dataptr dz);
+static int	do_double_onset_smooth(int n, double *slopechange,dataptr dz);
+static int	do_smooth(int n, double *slopechange,dataptr dz);
+static int	get_max_and_min_pitches(double *maxpitch,double *minpitch,dataptr dz);
+static int	write_remaining_pitch_or_transpos_data(int final_length_in_windows,dataptr dz);
+static int	specpapprox(int *,double *,dataptr dz);
+static int	specpcut(int *,dataptr dz);
+static int	specpexag(dataptr dz);
+static int 	specpinvert(dataptr dz);
+static int 	specpquantise(dataptr dz);
+static int	specprand(dataptr dz);
+static int	specpsmooth(dataptr dz);
+static int 	specptranspose(dataptr dz);
+static int	specpvib(dataptr dz);
+static int	get_midimean(double *midimean,dataptr dz);
+static int 	set_pval(double midivalue,int n,dataptr dz);
+static int	do_tail(int n, double lastmidi,dataptr dz);
+static int	get_pitchapprox_averages(int *avcnt,dataptr dz);
+static int	get_rand_interval(double *thisintv,dataptr dz);
+static int	approx_func1(int *,int *,double *,int *,int n,dataptr dz);
+static int	approx_func2(int *newlength_of_data,double lastmidi,int lastpos,int avcnt,dataptr dz);
+static int	interval_mapping(double *thisint,double thismidi,dataptr dz);
+static int	peak_interp(int pitchno,int last_validpitch_no,int *lastmaxpos,double meanpich,
+		double minint,double maxint,double *lastmidi,dataptr dz);
+
+static int  tidy_up_pitch_data(dataptr dz);
+static int  generate_tone(dataptr dz);
+static int  anti_noise_smoothing(int wlength,float *pitches,float frametime);
+static int  is_smooth_from_both_sides(int n,double max_pglide,float *pitches);
+static int  is_initialpitch_smooth(char *smooth,double max_pglide,float *pitches);
+static int  is_finalpitch_smooth(char *smooth,double max_pglide,int wlength,float *pitches);
+static int  is_smooth_from_before(int n,char *smooth,double max_pglide,float *pitches);
+static int  is_smooth_from_after(int n,char *smooth,double max_pglide,float *pitches);
+static int  test_glitch_sets(char *smooth,double max_pglide,int wlength,float *pitches);
+static void remove_unsmooth_pitches(char *smooth,int wlength,float *pitches);
+static int  test_glitch_forwards(int gltchstart,int gltchend,char *smooth,double max_pglide,float *pitches);
+static int  test_glitch_backwards(int gltchstart,int gltchend,char *smooth,
+				double max_pglide,int wlength,float *pitches);
+
+/* RWD NB: changes outfile header properties - rejigging required! */
+
+
+static int  write_pitch_outheader_from_analysis_inheader_to_second_outfile(int ofd,dataptr dz);
+
+static int  local_peak(int thiscc,double frq, float *thisbuf, dataptr dz);
+static int  interpolate_pitch(float *floatbuf,int skip_silence,dataptr dz);
+static double hz_to_pitchheight(double frqq);
+static double pitchheight_to_hz(double pitch_height);
+static int    eliminate_blips_in_pitch_data(dataptr dz);
+static int    mark_zeros_in_pitchdata(dataptr dz);
+static int    pitch_found(dataptr dz);
+static int    do_interpolating(int *pitchno,float *floatbuf,int skip_silence,dataptr dz);
+static void   check_transpos(float *t,dataptr dz);
+static void   check_pitch(float *t,dataptr dz);
+static int 	  trap_junk(int final_length_in_windows,dataptr dz);
+static int 	  write_pitch_or_transpos_data(int final_length_in_windows,dataptr dz);
+static int	  pitch_insert(int is_sil,dataptr dz);
+static int	  pitch_to_silence(dataptr dz);
+static int	  unpitch_to_silence(dataptr dz);
+static int 	  generate_vowels(dataptr dz);
+static int 	  generate_vowel_spectrum(double frq,double formant1,double formant2,double formant3,
+				double f2atten,double f3atten,double *sensitivity,int senslen,int is_offset,dataptr dz);
+static int 	  get_formant_frqs(int vowel,double *formant1,double *formant2,double *formant3,
+				double *f2atten,double *f3atten);
+static int 	  define_sensitivity_curve(double **sensitivity,int *senslen);
+static int 	  adjust_for_sensitivity(double *amp,double frq,double *sensitivity,int senslen);
+static int 	  remove_pitch_zeros(dataptr dz);
+
+static int convert_single_window_pch_or_transpos_data_to_brkpnttable
+			(int *brksize,float *floatbuf,float frametime,int array_no,dataptr dz);
+
+int are_pitch_zeros = 0;
+
+/********************************** SPECTRNSF **********************************
+ *
+ * transpose spectrum, but retain original spectral envelope.
+ */
+
+int spectrnsf(dataptr dz)
+{
+	int exit_status;
+	double pre_totalamp, post_totalamp;
+	double lofrq_limit, hifrq_limit;
+	int cc, vc;
+	rectify_window(dz->flbufptr[0],dz);
+	if((exit_status = extract_specenv(0,0,dz))<0)
+		return(exit_status);
+	if((exit_status = get_totalamp(&pre_totalamp,dz->flbufptr[0],dz->wanted))<0)
+		return(exit_status);
+	for(cc = 0, vc = 0; cc < dz->clength; cc++, vc += 2) {
+		if((exit_status = tranpose_within_formant_envelope(vc,dz))<0)
+			return(exit_status);
+	}
+	if((exit_status = reposition_partials_in_appropriate_channels(TRNSF_BODY,dz))<0)
+		return(exit_status);
+	if(dz->vflag[TRNSF_FBOT] || dz->vflag[TRNSF_FTOP]) {
+		lofrq_limit = dz->param[TRNSF_LOFRQ];
+		hifrq_limit = dz->param[TRNSF_HIFRQ];
+		if(hifrq_limit <  lofrq_limit)
+			swap(&hifrq_limit,&lofrq_limit);
+		if((exit_status = zero_outofrange_channels(&post_totalamp,lofrq_limit,hifrq_limit,dz))<0)
+			return(exit_status);
+	} else {
+		if((exit_status = get_totalamp(&post_totalamp,dz->flbufptr[0],dz->wanted))<0)
+			return(exit_status);
+	}
+	return normalise(pre_totalamp,post_totalamp,dz);
+}
+
+
+/********************************** SPECTRNSP **********************************
+ *
+ * transpose spectrum, (spectral envelope also moves).
+ */
+int spectrnsp(dataptr dz)
+{
+	int exit_status;
+	double pre_totalamp, post_totalamp;
+	double lofrq_limit, hifrq_limit;
+	int cc, vc;
+	rectify_window(dz->flbufptr[0],dz);
+	if((exit_status = get_totalamp(&pre_totalamp,dz->flbufptr[0],dz->wanted))<0)
+		return(exit_status);
+	for(cc = 0, vc = 0; cc < dz->clength; cc++, vc += 2)
+		dz->flbufptr[0][FREQ] = (float)(dz->flbufptr[0][FREQ]*dz->transpos[dz->total_windows]);
+	if((exit_status = reposition_partials_in_appropriate_channels(TRNSP_BODY,dz))<0)
+		return(exit_status);
+	if(dz->vflag[TRNSP_FBOT] || dz->vflag[TRNSP_FTOP]) {
+		lofrq_limit = dz->param[TRNSP_LOFRQ];
+		hifrq_limit = dz->param[TRNSP_HIFRQ];
+		if(hifrq_limit <  lofrq_limit)
+			swap(&hifrq_limit,&lofrq_limit);
+		if((exit_status = zero_outofrange_channels(&post_totalamp,lofrq_limit,hifrq_limit,dz))<0)
+			return(exit_status);
+	} else {
+		if((exit_status = get_totalamp(&post_totalamp,dz->flbufptr[0],dz->wanted))<0)
+			return(exit_status);
+	}
+	return normalise(pre_totalamp,post_totalamp,dz);
+}
+
+/************************** TRANPOSE_WITHIN_FORMANT_ENVELOPE *****************************/
+
+int tranpose_within_formant_envelope(int vc,dataptr dz)
+{
+	int exit_status;
+	double thisspecamp, newspecamp, thisamp, formantamp_ratio; 
+	if((exit_status = getspecenvamp(&thisspecamp,(double)dz->flbufptr[0][FREQ],0,dz))<0)
+		return(exit_status);
+	dz->flbufptr[0][FREQ] = (float)(fabs(dz->flbufptr[0][FREQ])*dz->transpos[dz->total_windows]);
+	if(dz->flbufptr[0][FREQ] < dz->nyquist) {
+		if(thisspecamp < VERY_TINY_VAL)
+			dz->flbufptr[0][AMPP] = 0.0f;
+		else {
+			if((exit_status = getspecenvamp(&newspecamp,(double)dz->flbufptr[0][FREQ],0,dz))<0)
+				return(exit_status);
+			if(newspecamp < VERY_TINY_VAL)
+				dz->flbufptr[0][AMPP] = 0.0f;
+			else {
+				formantamp_ratio = newspecamp/thisspecamp;
+				if((thisamp = dz->flbufptr[0][AMPP] * formantamp_ratio) < VERY_TINY_VAL)
+					dz->flbufptr[0][AMPP] = 0.0f;
+				else
+					dz->flbufptr[0][AMPP] = (float)thisamp;
+			}
+		}
+	}
+	return(FINISHED);
+}
+
+/************************ REPOSITION_PARTIALS_IN_APPROPRIATE_CHANNELS *************************
+ *
+ * (1)	At each pass, preset store-buffer channel amps to zero.
+ * (2)	Move frq data into appropriate channels, carrying the
+ *		amplitude information along with them.
+ *		Work down spectrum 	for upward transposition, and
+ * (3)	up spectrum for downward transposition,
+ *		so that we do not overwrite transposed data before we move it.
+ * (4)	Put new frqs back into src buff.
+ */
+
+int reposition_partials_in_appropriate_channels(int with_body,dataptr dz)
+{
+	int exit_status;
+	int truecc,truevc;
+	int cc, vc;
+	for(vc = 0; vc < dz->wanted; vc+=2)						/* 1 */
+		dz->windowbuf[0][vc] = 0.0f;
+	if(dz->transpos[dz->total_windows] > 1.0f) {			/* 2 */
+		for(cc=dz->clength-1,vc = dz->wanted-2; cc>=0; cc--, vc-=2) {
+			if(dz->flbufptr[0][FREQ] < dz->nyquist && dz->flbufptr[0][AMPP] > 0.0f) {
+				if((exit_status = get_channel_corresponding_to_frq(&truecc,(double)dz->flbufptr[0][FREQ],dz))<0)
+					return(exit_status);
+				truevc = truecc * 2;
+				switch(dz->vflag[with_body]) {			
+				case(FALSE): 
+					if((exit_status = move_data_into_appropriate_channel(vc,truevc,dz->flbufptr[0][AMPP],dz->flbufptr[0][FREQ],dz))<0)
+						return(exit_status);
+					break;
+				case(TRUE):  
+					if((exit_status = move_data_into_some_appropriate_channel(truevc,dz->flbufptr[0][AMPP],dz->flbufptr[0][FREQ],dz))<0)
+						return(exit_status);
+					break;
+				default:
+					sprintf(errstr,"Unknown case for vflag[with_body]: reposition_partials_in_appropriate_channels()\n");
+					return(PROGRAM_ERROR);
+				}								/* upward transpos, chandata tends to thin */
+			}									/* case(TRUE) tries for fuller spectrum    */
+		}
+		for(vc = 0; vc < dz->wanted; vc++)
+			dz->flbufptr[0][vc] = dz->windowbuf[0][vc];	
+	} else if(dz->transpos[dz->total_windows] < 1.0f){		/* 3 */
+		for(cc=0,vc = 0; cc < dz->clength; cc++, vc+=2) {
+			if(dz->flbufptr[0][FREQ] < dz->nyquist && dz->flbufptr[0][FREQ]>0.0) {
+				if((exit_status = get_channel_corresponding_to_frq(&truecc,(double)dz->flbufptr[0][FREQ],dz))<0)
+					return(exit_status);
+				truevc = truecc * 2;
+				if((exit_status = move_data_into_appropriate_channel(vc,truevc,dz->flbufptr[0][AMPP],dz->flbufptr[0][FREQ],dz))<0)
+					return(exit_status);
+			}
+		}
+		for(vc = 0; vc < dz->wanted; vc++)
+			dz->flbufptr[0][vc] = dz->windowbuf[0][vc];		/* 4 */
+	}
+	return(FINISHED);
+}
+
+/******************* ZERO_OUTOFRANGE_CHANNELS *****************/
+
+int zero_outofrange_channels(double *totalamp,double lofrq_limit,double hifrq_limit,dataptr dz)
+{
+	int cc, vc;
+	*totalamp = 0.0;
+	for(cc = 0,vc = 0; cc < dz->clength; cc++, vc += 2) {
+		if(dz->flbufptr[0][FREQ] < lofrq_limit || dz->flbufptr[0][FREQ] > hifrq_limit)
+			dz->flbufptr[0][AMPP] = 0.0f;
+		else
+			*totalamp += dz->flbufptr[0][AMPP];
+	}
+	return(FINISHED);
+}
+
+/***************************** OUTER_PITCH_LOOP ***********************/
+
+int outer_pitch_loop(dataptr dz)
+{
+	int exit_status;
+	int samps_read, wc, windows_in_buf, brklen;
+	double totalamp;
+	int thismode = 0;
+	while((samps_read = fgetfbufEx(dz->bigfbuf,dz->big_fsize,dz->ifd[0],0)) > 0) {
+		dz->flbufptr[0] = dz->bigfbuf;
+		windows_in_buf = samps_read/dz->wanted;    
+		for(wc=0; wc<windows_in_buf; wc++, dz->total_windows++) {
+			if(dz->total_windows==0 && dz->wlength > 1) {
+				dz->pitches[0] = (float)NOT_PITCH;
+				dz->flbufptr[0] += dz->wanted;
+				continue;
+			}
+			if((exit_status = get_totalamp(&totalamp,dz->flbufptr[0],dz->wanted))<0)
+				return(exit_status);
+			dz->parray[PICH_PRETOTAMP][dz->total_windows] = totalamp;
+			switch(dz->process) {
+			case(PITCH):
+				if((exit_status = specpitch(dz))<0)
+					return(exit_status);
+				break;
+			case(TRACK):	
+				if((exit_status = spectrack(dz))<0)
+					return(exit_status);
+				break;
+			default:
+				sprintf(errstr,"Unknown case in outer_pitch_loop()\n");
+				return(PROGRAM_ERROR);
+			}
+			dz->flbufptr[0] += dz->wanted;
+		}
+	}  
+	if(samps_read<0) {
+		sprintf(errstr,"Sound read error.\n");
+		return(SYSTEM_ERROR);
+	}
+	if((exit_status = tidy_up_pitch_data(dz))<0)
+		return(exit_status);
+	if((exit_status = generate_tone(dz))<0)
+		return(exit_status);
+
+	dz->total_samps_written = 0;
+
+	switch(dz->process) {
+	case(PITCH):	if(dz->mode == PICH_TO_BRK)	thismode = 1;	break;	
+	case(TRACK):	if(dz->mode == TRK_TO_BRK)	thismode = 1;	break;	
+	default:
+		sprintf(errstr,"Unknown mode in outer_pitch_loop().\n");
+		return(PROGRAM_ERROR);
+	}
+
+	switch(thismode) {
+	case(0):
+
+		if((exit_status = write_samps_to_elsewhere(dz->other_file,dz->pitches,dz->wlength,dz))<0)
+			return(exit_status);
+		if((exit_status = write_pitch_outheader_from_analysis_inheader_to_second_outfile
+		(dz->other_file,dz))<0)
+			return(exit_status);
+		break;
+	case(1):
+/* MAY 2001 BRKPNT OUTPUT ELIMINATES PITCH ZEROS */
+		if((exit_status = interpolate_pitch(dz->pitches,0,dz))<0)
+			return(exit_status);
+		if(dz->wlength == 1) {
+			if((exit_status = convert_single_window_pch_or_transpos_data_to_brkpnttable
+			(&brklen,dz->pitches,dz->frametime,PICH_PBRK,dz))<0)
+				return(exit_status);
+		} else {
+			if((exit_status = convert_pch_or_transpos_data_to_brkpnttable
+			(&brklen,dz->pitches,dz->frametime,PICH_PBRK,dz))<0)
+				return(exit_status);
+		}
+		if((exit_status = write_brkfile(dz->fp,brklen,PICH_PBRK,dz))<0)
+			return(exit_status);
+		if(fclose(dz->fp)<0) {
+			fprintf(stdout, "WARNING: Failed to close output brkpntfile.\n");
+			fflush(stdout);
+		}
+		break;
+	default:
+		sprintf(errstr,"unknown output case in outer_pitch_loop()\n");
+		return(PROGRAM_ERROR);
+	}
+	return(FINISHED);
+}
+
+/****************************** SPECPITCH *******************************
+ *
+ * (1)	Ignore partials below low limit of pitch.
+ * (2)  If this channel data is louder than any existing piece of data in ring.
+ *		(Ring data is ordered loudness-wise)...
+ * (3)	If this freq is too close to an existing frequency..
+ * (4)	and if it is louder than that existing frequency data..
+ * (5)	Substitute in in the ring.
+ * (6)	Otherwise, (its a new frq) insert it into the ring.
+ */
+ 
+int specpitch(dataptr dz)
+{
+	int exit_status;
+	int vc;
+	chvptr here, there, *partials;
+	float minamp;
+	double loudest_partial_frq, nextloudest_partial_frq, lo_loud_partial, hi_loud_partial;	
+	if((partials = (chvptr *)malloc(MAXIMI * sizeof(chvptr)))==NULL) {
+		sprintf(errstr,"INSUFFICIENT MEMORY for partials array.\n");
+		return(MEMORY_ERROR);
+	}
+	if((exit_status = initialise_ring_vals(MAXIMI,-1.0,dz))<0)
+		return(exit_status);
+	if((exit_status = rectify_frqs(dz->flbufptr[0],dz))<0)
+		return(exit_status);
+	for(vc=0;vc<dz->wanted;vc+=2) {
+		here = dz->ringhead;
+		if(dz->flbufptr[0][FREQ] > dz->param[PICH_LOLM]) {  			/* 1 */
+			do {								
+				if(dz->flbufptr[0][AMPP] > here->val) {			   	/* 2 */
+					if((exit_status = close_to_frq_already_in_ring(&there,(double)dz->flbufptr[0][FREQ],dz))<0)
+						return(exit_status);
+					if(exit_status==TRUE) {
+						if(dz->flbufptr[0][AMPP] > there->val) {		/* 4 */
+							if((exit_status = substitute_in_ring(vc,here,there,dz))<0) /* 5 */
+								return(exit_status);
+						}
+					} else	{										/* 6 */
+						if((exit_status = insert_in_ring(vc,here,dz))<0)
+							return(exit_status);
+					}				
+					break;
+				}
+			} while((here = here->next)!=dz->ringhead);
+		}
+	}
+	loudest_partial_frq     = dz->flbufptr[0][dz->ringhead->loc + 1];
+	nextloudest_partial_frq = dz->flbufptr[0][dz->ringhead->next->loc + 1];
+	if(loudest_partial_frq < nextloudest_partial_frq) {
+		lo_loud_partial = loudest_partial_frq;
+		hi_loud_partial = nextloudest_partial_frq;
+	} else {
+		lo_loud_partial = nextloudest_partial_frq;
+		hi_loud_partial = loudest_partial_frq;
+	}
+	if((exit_status = put_ring_frqs_in_ascending_order(&partials,&minamp,dz))<0)
+		return(exit_status);
+	if((exit_status = found_pitch(partials,lo_loud_partial,hi_loud_partial,minamp,dz))<0)
+		return(exit_status);
+	if(exit_status==TRUE && dz->param[PICH_PICH]>=MINPITCH)
+		dz->pitches[dz->total_windows] = (float)dz->param[PICH_PICH];
+	else
+		dz->pitches[dz->total_windows] = (float)NOT_PITCH;
+	return smooth_spurious_octave_leaps(dz->total_windows,minamp,dz);
+}
+
+/**************************** CLOSE_TO_FRQ_ALREADY_IN_RING *******************************/
+
+int close_to_frq_already_in_ring(chvptr *there,double frq1,dataptr dz)
+{
+#define EIGHT_OVER_SEVEN	(1.142857143)
+
+	double frq2, frqratio;
+	*there = dz->ringhead;
+	do {
+		if((*there)->val > 0.0) {
+			frq2 = dz->flbufptr[0][(*there)->loc + 1];
+			if(frq1 > frq2)
+				frqratio = frq1/frq2;
+			else
+			    frqratio = frq2/frq1;
+			if(frqratio < EIGHT_OVER_SEVEN)
+				return(TRUE);
+		}
+	} while((*there = (*there)->next) != dz->ringhead);
+	return(FALSE);
+}
+
+/******************************* SUBSITUTE_IN_RING **********************/
+
+int substitute_in_ring(int vc,chvptr here,chvptr there,dataptr dz)
+{
+	chvptr spare, previous;
+	if(here!=there) {
+		if(there==dz->ringhead) {
+			sprintf(errstr,"IMPOSSIBLE! in substitute_in_ring()\n");
+			return(PROGRAM_ERROR);
+		}
+		spare = there;
+		there->next->last = there->last; /* SPLICE REDUNDANT STRUCT FROM RING */
+		there->last->next = there->next;
+		previous = here->last;
+		previous->next = spare;			/* SPLICE ITS ADDRESS-SPACE BACK INTO RING */
+		spare->last = previous;			/* IMMEDIATELY BEFORE HERE */
+		here->last = spare;
+		spare->next = here;
+		if(here==dz->ringhead)			/* IF HERE IS RINGHEAD, MOVE RINGHEAD */
+			dz->ringhead = spare;
+		here = spare;					/* POINT TO INSERT LOCATION */
+	}
+	here->val = dz->flbufptr[0][AMPP]; 	/* IF here==there */
+	here->loc = vc;	    				/* THIS WRITES OVER VAL IN EXISTING RING LOCATION */
+	return(FINISHED);
+}
+
+/*************************** INSERT_IN_RING ***************************/
+
+int insert_in_ring(int vc, chvptr here, dataptr dz)
+{
+	chvptr previous, newend, spare;
+	if(here==dz->ringhead) {
+		dz->ringhead = dz->ringhead->last;
+		spare = dz->ringhead;
+	} else {
+		if(here==dz->ringhead->last)
+			spare = here;
+		else {
+			spare  = dz->ringhead->last;
+			newend = dz->ringhead->last->last; 	/* cut ENDADR (spare) out of ring */
+			dz->ringhead->last = newend;
+			newend->next = dz->ringhead;
+			previous = here->last;
+			here->last = spare;					/* reuse spare address at new loc by */ 
+			spare->next = here;  				/* inserting it back into ring before HERE */
+			previous->next = spare;
+			spare->last = previous;
+		}
+	}
+	spare->val = dz->flbufptr[0][vc];			/* Store new val in spare ring location */
+	spare->loc = vc;
+	return(FINISHED);
+}
+
+/************************** PUT_RING_FRQS_IN_ASCENDING_ORDER **********************/
+
+int put_ring_frqs_in_ascending_order(chvptr **partials,float *minamp,dataptr dz)
+{
+	int k;
+	chvptr start, ggot, here = dz->ringhead;
+	float minpitch;
+	*minamp = (float)MAXFLOAT;
+	for(k=0;k<MAXIMI;k++) {
+		if((*minamp = min(dz->flbufptr[0][here->loc],*minamp))>=(float)MAXFLOAT) {
+			sprintf(errstr,"Problem with amplitude out of range: put_ring_frqs_in_ascending_order()\n");
+			return(PROGRAM_ERROR);
+		}
+		(here->loc)++;		/* CHANGE RING TO POINT TO FRQS, not AMPS */
+		here->val = dz->flbufptr[0][here->loc];
+		here = here->next;
+	}
+	here = dz->ringhead;
+	minpitch = dz->flbufptr[0][here->loc];
+	for(k=1;k<MAXIMI;k++) {
+		start = ggot = here;
+		while((here = here->next)!=start) {		/* Find lowest frq */
+			if(dz->flbufptr[0][here->loc] < minpitch) {	
+				minpitch = dz->flbufptr[0][here->loc];
+				ggot = here;
+			}
+		}
+		(*partials)[k-1] = ggot;				/* Save its address */
+		here = ggot->next;						/* Move to next ring site */
+		minpitch = dz->flbufptr[0][here->loc];	/* Preset minfrq to val there */
+		ggot->last->next = here;				/* Unlink ringsite ggot */
+		here->last = ggot->last;
+	}
+	(*partials)[k-1] = here;	     			/* Remaining ringsite is maximum */
+
+	here = dz->ringhead = (*partials)[0];   	/* Reconstruct ring */
+	for(k=1;k<MAXIMI;k++) {
+		here->next = (*partials)[k];
+		(*partials)[k]->last = here;
+		here = here->next;
+	}
+	here->next = dz->ringhead;					/* Close up ring */
+	dz->ringhead->last = here;
+	return(FINISHED);
+}
+
+/******************************	 FIND_PITCH **************************/
+
+int found_pitch(chvptr *partials,double lo_loud_partial,double hi_loud_partial,float minamp,dataptr dz)
+{
+	switch(dz->vflag[PICH_ALTERNATIVE_METHOD]) {
+	case(FALSE): return(found_pitch_1(partials,lo_loud_partial,hi_loud_partial,minamp,dz));
+	case(TRUE):	 return(found_pitch_2(partials,dz));
+	default:
+		sprintf(errstr,"Unknown case in found_pitch()\n");
+		return(PROGRAM_ERROR);
+	}
+}
+
+/******************************	 FIND_PITCH_1 **************************/
+
+#define MAXIMUM_PARTIAL (64)
+
+int found_pitch_1(chvptr *partials,double lo_loud_partial,double hi_loud_partial,float minamp,dataptr dz)
+{
+	int n, m, k, maximi_less_one = MAXIMUM_PARTIAL - 1, endd = 0;
+	double whole_number_ratio, comparison_frq;
+	for(n=1;n<maximi_less_one;n++) {
+		for(m=n+1;m<MAXIMUM_PARTIAL;m++) {	/* NOV 7 */
+			whole_number_ratio = (double)m/(double)n;
+			comparison_frq     = lo_loud_partial * whole_number_ratio;
+			if(equivalent_pitches(comparison_frq,hi_loud_partial,dz))
+				endd = (MAXIMUM_PARTIAL/m) * n;		/* explanation at foot of file */
+			else if(comparison_frq > hi_loud_partial)
+				break;
+
+
+			for(k=n;k<=endd;k+=n) {
+				dz->param[PICH_PICH] = lo_loud_partial/(double)k;
+				if(dz->param[PICH_PICH]>dz->param[PICH_HILM])
+					continue;
+				if(dz->param[PICH_PICH]<dz->param[PICH_LOLM])
+					break;
+				if(is_peak_at(dz->param[PICH_PICH],0,minamp,dz)){
+					if(dz->iparam[PICH_MATCH] <= 2)
+						return TRUE;
+					else if(enough_partials_are_harmonics(partials,dz))
+						return TRUE;
+				}
+			}
+		}
+	}
+	return(FALSE);
+}
+
+
+/********************** FIND_PITCH_2 *****************************/
+
+int found_pitch_2(chvptr *partials,dataptr dz)
+{
+	int m, n, k, good_match;
+	int top_of_test = MAXIMI - dz->iparam[PICH_MATCH] + 1;
+	double resolved_pitch, prevpitch,pitchdiff = 0.0;
+	int diffcount = 0;
+	for(n=0;n<top_of_test;n++) {
+		for(m=1;m<=MAXHARM;m++) {
+			dz->param[PICH_PICH] = (partials[n]->val)/(double)m;
+			if(dz->param[PICH_PICH] > dz->param[PICH_HILM])
+				continue;	
+			if(dz->param[PICH_PICH] < dz->param[PICH_LOLM])
+				break;
+			good_match = 1;
+			prevpitch = dz->param[PICH_PICH];
+
+			if(dz->iparam[PICH_MATCH] > 1) {
+				for(k=n+1;k<MAXIMI;k++) {
+					if(is_a_harmonic((double)(partials[k]->val),dz->param[PICH_PICH],dz)) {
+						pitchdiff += (double)(partials[k]->val - prevpitch);
+						prevpitch = (double)(partials[k]->val);
+						diffcount++;
+						if(++good_match >= dz->iparam[PICH_MATCH]) {
+							resolved_pitch = pitchdiff / (double)diffcount;
+							if(equivalent_pitches(resolved_pitch,dz->param[PICH_PICH],dz)){
+								partials[0]->val = (float) resolved_pitch;							
+								dz->param[PICH_PICH] = resolved_pitch;
+							}
+							return TRUE;
+						}
+					}
+				}
+			}
+		}
+	}
+	return(FALSE);
+}
+
+/************************ SMOOTH_SPURIOUS_OCTAVE_LEAPS ***************************/
+
+int smooth_spurious_octave_leaps(int pitchno,float minamp,dataptr dz)
+{
+#define ALMOST_TWO	        (1.75)
+
+	double thispitch = dz->pitches[pitchno];
+	double startpitch, lastpitch;
+	int k = 0;
+	if(pitchno<=0)
+		return(FINISHED);
+	lastpitch = dz->pitches[pitchno-1];
+	if(lastpitch > dz->param[PICH_LOLM] && thispitch > dz->param[PICH_LOLM]) {	/* OCTAVE ADJ HERE */
+		if(thispitch > lastpitch) {		/* OCTAVE ADJ FORWARDS */
+			startpitch = thispitch;
+			while(thispitch/lastpitch > ALMOST_TWO)
+				thispitch /= 2.0;
+			if(thispitch!=startpitch) {
+				if(thispitch < dz->param[PICH_LOLM])
+					return(FINISHED);
+				if(is_peak_at(thispitch,0L,minamp,dz))				
+					dz->pitches[pitchno] = (float)thispitch;
+				else 
+					dz->pitches[pitchno] = (float)startpitch;
+			}
+			return(FINISHED);
+		} else {
+			while(pitchno>=1) {			/* OCTAVE ADJ BCKWARDS */
+				k++;
+				if((thispitch = dz->pitches[pitchno--])<dz->param[PICH_LOLM])
+					return(FINISHED);
+			
+				if((lastpitch = dz->pitches[pitchno])<dz->param[PICH_LOLM])
+					return(FINISHED);
+			
+				startpitch = lastpitch;
+				while(lastpitch/thispitch > ALMOST_TWO)
+					lastpitch /= 2.0;
+			
+				if(lastpitch!=startpitch) {
+					if(lastpitch < dz->param[PICH_LOLM])
+						return(FINISHED);
+					if(is_peak_at(lastpitch,k,minamp,dz))					
+						dz->pitches[pitchno] = (float)lastpitch;
+					else 
+						dz->pitches[pitchno] = (float)startpitch;
+				}
+			}
+		}
+	}
+	return(FINISHED);
+}
+
+/**************************** EQUIVALENT_PITCHES *************************/
+
+int equivalent_pitches(double frq1, double frq2, dataptr dz)
+{
+	double ratio;
+	int   iratio;
+	double intvl;
+
+	ratio = frq1/frq2;
+	iratio = round(ratio);
+
+	if(iratio!=1)
+		return(FALSE);
+
+	if(ratio > iratio)
+		intvl = ratio/(double)iratio;
+	else
+		intvl = (double)iratio/ratio;
+	if(intvl > dz->param[PICH_RNGE])	
+		return FALSE;
+	return TRUE;
+}
+
+/*************************** IS_PEAK_AT ***************************/
+
+#define PEAK_LIMIT (.05)
+
+int is_peak_at(double frq,int window_offset,float minamp,dataptr dz)
+{
+	float *thisbuf;
+	int cc, vc, searchtop, searchbot;
+	if(window_offset) {								/* BAKTRAK ALONG BIGBUF, IF NESS */
+		thisbuf = dz->flbufptr[0] - (window_offset * dz->wanted);
+		if((int)thisbuf < 0 || thisbuf < dz->bigfbuf || thisbuf >= dz->flbufptr[1])
+			return(FALSE);
+	} else
+		thisbuf = dz->flbufptr[0];
+	cc = (int)((frq + dz->halfchwidth)/dz->chwidth);		 /* TRUNCATE */
+	searchtop = min(dz->clength,cc + CHANSCAN + 1);
+	searchbot = max(0,cc - CHANSCAN);
+	for(cc = searchbot ,vc = searchbot*2; cc < searchtop; cc++, vc += 2) {
+		if(!equivalent_pitches((double)thisbuf[vc+1],frq,dz)) {
+			continue;
+		}
+		if(thisbuf[vc] < minamp * PEAK_LIMIT)
+			continue;
+		if(local_peak(cc,frq,thisbuf,dz))		
+			return TRUE;
+	}
+	return FALSE;
+}
+
+/**************************** ENOUGH_PARTIALS_ARE_HARMONICS *************************/
+
+int enough_partials_are_harmonics(chvptr *partials,dataptr dz)
+{
+	int n, good_match = 0;
+	double thisfrq;
+	for(n=0;n<MAXIMI;n++) {
+		if((thisfrq = dz->flbufptr[0][partials[n]->loc]) < dz->param[PICH_PICH])
+			continue;
+		if(is_a_harmonic(thisfrq,dz->param[PICH_PICH],dz)){		
+			if(++good_match >= dz->iparam[PICH_MATCH])
+				return TRUE;
+		}
+	}
+	return FALSE;
+}
+
+/**************************** IS_A_HARMONIC *************************/
+
+int is_a_harmonic(double frq1,double frq2,dataptr dz)
+{
+	double ratio = frq1/frq2;
+	int   iratio = round(ratio);
+	double intvl;
+
+	ratio = frq1/frq2;
+	iratio = round(ratio);
+
+	if(ratio > iratio)
+		intvl = ratio/(double)iratio;
+	else
+		intvl = (double)iratio/ratio;
+	if(intvl > dz->param[PICH_RNGE])
+		return(FALSE);
+	return(TRUE);
+}
+
+/***************************** SPECTRACK *********************************/
+
+int spectrack(dataptr dz)
+{
+	int exit_status;
+	double thisfrq =  dz->param[TRAK_PICH], frqtop, frqbot, maxamp;
+	double outfrq  = 0.0;
+	int n = 0, vc = 0, passed_limit = 0, maxloc;
+	while((thisfrq =  dz->param[TRAK_PICH] * (double)++n) < dz->param[TRAK_HILM]) {
+		frqtop   = thisfrq * dz->param[TRAK_RNGE];
+		frqbot   = thisfrq / dz->param[TRAK_RNGE];
+		if((exit_status = rectify_frqs(dz->flbufptr[0],dz))<0)
+			return(exit_status);
+		while(dz->flbufptr[0][FREQ] < frqbot) {	/* JUMP OVER CHANNELS  */
+			if((vc+=2) >=dz->wanted) {
+				outfrq = -1.0;
+				passed_limit = 1;
+				break;
+			}
+		}
+		if(passed_limit)						/* IF GONE PAST LIMIT  */
+			break;								/* BREAK OUT OF LOOP   */
+		if(dz->flbufptr[0][FREQ]>frqtop) {		/* IF OUTSIDE RANGE    */
+			outfrq = -1.0;						/* BREAK OUT OF LOOP   */
+			break;
+		}
+		maxamp   = dz->flbufptr[0][AMPP];		/* SET MAXAMP TO 1ST IN-RANGE CH */
+		maxloc   = vc;							/* NOTE NO. OF CH THUS MARKED    */
+		while((vc+=2) < dz->wanted) {
+			if(dz->flbufptr[0][FREQ]>frqtop)   	/* IF BEYOND CURRENT RANGE, STOP */
+				break;
+			if(dz->flbufptr[0][AMPP]>maxamp) {	/* IF LOUDER THAN MAX, RESET MAX */
+				maxamp = dz->flbufptr[0][AMPP];	/* AND RESET MAXAMP CHANNEL NO.  */
+				maxloc = vc;
+			}
+		}
+		outfrq = dz->flbufptr[0][maxloc+1];
+	}
+	if(outfrq>MINPITCH)					/* If pitch has been found  */
+		dz->param[TRAK_PICH] = outfrq;	/* reset goal pitch to this */
+	dz->pitches[dz->total_windows] = (float)outfrq;
+	return(FINISHED);
+}
+
+/**************************** OUTER_PICHPICH_LOOP *********************/
+
+int outer_pichpich_loop(dataptr dz)
+{
+	int exit_status, valid_pitch_data = FALSE;
+	int final_length_in_windows = dz->wlength, n;
+	double lastmidi;
+	if(dz->is_transpos) {
+		if((dz->transpos = (float *)malloc(dz->wlength * sizeof(float)))==NULL) {
+			sprintf(errstr,"INSUFFICIENT MEMORY for transpositions array.\n");
+			return(MEMORY_ERROR);
+		}
+		for(n=0;n<dz->wlength;n++)
+			dz->transpos[n] = 1.0f;	/* DEFAULT: no transposition */
+	}
+	for(n=0;n<dz->wlength;n++) {
+		if(dz->pitches[n] > FLTERR) {
+			valid_pitch_data = 1;
+			break;
+		}
+	}
+	if(!valid_pitch_data) {
+		sprintf(errstr,"No valid pitches found in input data.\n");
+		return(DATA_ERROR);
+	}
+	switch(dz->process) {
+	case(P_APPROX):
+		if((exit_status = specpapprox(&final_length_in_windows,&lastmidi,dz))<0)
+			return(exit_status);
+		if((exit_status = trap_junk(final_length_in_windows,dz))<0)
+			return(exit_status);
+		return write_remaining_pitch_or_transpos_data(final_length_in_windows,dz);
+	case(P_CUT):		
+		if((exit_status = specpcut(&final_length_in_windows,dz))<0)
+			return(exit_status);
+		return write_remaining_pitch_or_transpos_data(final_length_in_windows,dz);
+	case(P_EXAG):	
+		if((exit_status = specpexag(dz))<0)
+			return(exit_status);
+		break;
+	case(P_INVERT):		
+		if((exit_status = specpinvert(dz))<0)
+			return(exit_status);
+		break;
+	case(P_QUANTISE):	
+		if((exit_status = specpquantise(dz))<0)
+			return(exit_status);
+		break;
+	case(P_RANDOMISE):	
+		if((exit_status = specprand(dz))<0)
+			return(exit_status);
+		break;
+	case(P_SMOOTH):		
+		if((exit_status = specpsmooth(dz))<0)
+			return(exit_status);
+		break;
+	case(P_TRANSPOSE):	
+		if((exit_status = specptranspose(dz))<0)
+			return(exit_status);
+		break;
+	case(P_VIBRATO):	
+		if((exit_status = specpvib(dz))<0)
+			return(exit_status);
+		break;
+	case(P_SYNTH):	
+		return generate_tone(dz);
+		break;
+	case(P_VOWELS):	
+		return generate_vowels(dz);
+		break;
+	case(P_INSERT):	
+		if((exit_status = pitch_insert(0,dz)) < 0)
+			return(exit_status);	
+		return write_pitch_or_transpos_data(final_length_in_windows,dz);
+		break;
+	case(P_SINSERT):	
+		if((exit_status = pitch_insert(1,dz)) < 0)
+			return(exit_status);	
+		return write_pitch_or_transpos_data(final_length_in_windows,dz);
+		break;
+	case(P_PTOSIL):	
+		if((exit_status = pitch_to_silence(dz)) < 0)
+			return(exit_status);	
+		return write_pitch_or_transpos_data(final_length_in_windows,dz);
+		break;
+	case(P_NTOSIL):	
+		if((exit_status = unpitch_to_silence(dz)) < 0)
+			return(exit_status);	
+		return write_pitch_or_transpos_data(final_length_in_windows,dz);
+		break;
+	case(P_INTERP):	
+		if((exit_status = remove_pitch_zeros(dz)) < 0)
+			return(exit_status);	
+		return write_pitch_or_transpos_data(dz->wlength,dz);
+		break;
+
+	default:
+		sprintf(errstr,"Unknown process in outer_pichpich_loop()\n");
+		return(PROGRAM_ERROR);
+	}
+	if((exit_status = trap_junk(final_length_in_windows,dz))<0)
+		return(exit_status);
+	return write_pitch_or_transpos_data(final_length_in_windows,dz);
+}
+
+/************************** SPECPAPPROX ************************/
+
+int specpapprox(int *newlength_of_data,double *lastmidi,dataptr dz)
+{
+	int exit_status;
+	int    avcnt;
+	int   n = 0, diff;
+	int    is_firstime = TRUE;
+	int	   lastpos = 0;
+	*newlength_of_data = dz->wlength;
+	initrand48();
+	if((exit_status = get_pitchapprox_averages(&avcnt,dz))<0)
+		return(exit_status);
+	if((dz->iparray[PA_CHANGE] = (int *)malloc(avcnt * sizeof(int)))==NULL) {
+		sprintf(errstr,"INSUFFICIENT MEMORY for pitch approximation array.\n");
+		return(MEMORY_ERROR);
+	}
+	if((exit_status = get_statechanges(avcnt,PA_SRANG,PA_AVPICH,PA_CHANGE,SEMITONE_INTERVAL,SEMITONE_DOWN,IS_FRQ,dz))<0)
+		return(exit_status);
+	while(dz->parray[PA_AVPICH][n]<0.0) {
+	    if(++n>=avcnt) {
+			sprintf(errstr,"No valid pitch-average data found.\n");
+			return(DATA_ERROR); /* ??? */
+		}
+	}
+	dz->iparray[PA_CHANGE][n] = 1;
+	for(;n<avcnt;n++) {
+		if(dz->iparray[PA_CHANGE][n]) {
+			if((exit_status = approx_func1(newlength_of_data,&is_firstime,lastmidi,&lastpos,n,dz))<0)
+				return(exit_status);
+			if(exit_status==FINISHED)
+				break;
+		}
+	}
+	if((diff = (dz->wlength-1) - lastpos) > 0 
+	&& (exit_status = approx_func2(newlength_of_data,*lastmidi,lastpos,avcnt,dz))<0)
+		return(exit_status);
+	return(FINISHED);
+}
+
+/***************************** SPECPCUT ***************************/
+
+int specpcut(int *final_length_in_windows,dataptr dz)
+{
+	int m, n;
+	int startcut = 0;
+	int endcut = dz->wlength;
+	if(dz->mode != PCUT_START_ONLY)	    /* is_endtime */
+		endcut   = round(dz->param[PC_END]/dz->frametime);
+	if(dz->mode != PCUT_END_ONLY)	    /* is_starttime */
+		startcut = round(dz->param[PC_STT]/dz->frametime);
+	for(m = 0, n = startcut; n < endcut; n++, m++)
+		dz->pitches[m] = dz->pitches[n];
+	*final_length_in_windows = endcut - startcut;
+	return(FINISHED);
+}
+
+/************************************* SPECPEXAG ******************************/
+
+int specpexag(dataptr dz)
+{
+	int exit_status;
+	int n;
+	double thismidi, maxmidi, minmidi, variance, thispich;
+	double maxpitch = FLTERR, minpitch = dz->nyquist, meanpich, maxint, minint;
+	dz->time = 0.0f;
+	if((exit_status = get_max_and_min_pitches(&maxpitch,&minpitch,dz))<0)
+		return(exit_status);
+	if((exit_status = hztomidi(&maxmidi,maxpitch))<0)
+		return(exit_status);
+	if((exit_status = hztomidi(&minmidi,minpitch))<0)
+		return(exit_status);
+	for(n=0;n<dz->wlength;n++) {
+		if(dz->pitches[n]<MINPITCH)
+			continue;
+		if((exit_status = read_values_from_all_existing_brktables((double)dz->time,dz))<0)
+			return(exit_status);
+		meanpich = miditohz(dz->param[PEX_MEAN]);
+		thispich = dz->pitches[n];
+				   /* contour variable specified */
+		if(dz->mode != RANGE_ONLY_TO_P && dz->mode != RANGE_ONLY_TO_T) {  
+			if((exit_status = hztomidi(&thismidi,thispich))<0)
+				return(exit_status);
+			maxint = maxmidi - dz->param[PEX_MEAN];
+			minint = dz->param[PEX_MEAN] - minmidi;
+			if(thismidi >= dz->param[PEX_MEAN])
+				variance = ((thismidi - dz->param[PEX_MEAN])/12.0)/maxint;
+			else
+				variance = ((dz->param[PEX_MEAN] - thismidi)/12.0)/minint;
+			if(!flteq(variance,0.0))
+			variance = pow(variance,dz->param[PEX_CNTR]);
+			if(thismidi>=dz->param[PEX_MEAN])
+				thispich = (float)(pow(maxpitch,variance) * pow(meanpich,(1.0-variance)));
+			else
+				thispich = (float)(pow(minpitch,variance) * pow(meanpich,(1.0-variance)));
+		}
+
+		if(dz->mode != CONTOUR_ONLY_TO_P && dz->mode != CONTOUR_ONLY_TO_T) {
+			/* range variable specified */
+			if((exit_status = hztomidi(&thismidi,thispich))<0)
+				return(exit_status);
+			thismidi = dz->param[PEX_MEAN] + ((thismidi - dz->param[PEX_MEAN]) 
+				* dz->param[PEX_RANG]);
+			thispich = (float)miditohz(thismidi);
+		}
+		if(dz->is_transpos) {	/* transpos output */
+			dz->transpos[n] = (float)(thispich/dz->pitches[n]);
+			check_transpos(&(dz->transpos[n]),dz);
+		} else {
+			dz->pitches[n] = (float)thispich;
+			check_pitch(&(dz->pitches[n]),dz);
+		}
+		dz->time = (float)(dz->time + dz->frametime);
+	}
+	return(FINISHED);
+}
+
+/****************************** SPECPFIX ********************************/
+ 
+int specpfix(dataptr dz)
+{
+	int exit_status;
+	if(dz->iparam[PF_ISCUT]    && (exit_status = do_pitch_cut(dz))<0)
+		return(exit_status);
+	if(dz->iparam[PF_ISFILTER] && (exit_status = do_pitch_filter(dz))<0)
+		return(exit_status);
+	if(dz->vflag[PF_IS_SMOOTH] && (exit_status = do_pitch_smoothing(dz))<0)
+		return(exit_status);
+	if(dz->vflag[PF_IS_SMARK])
+		dz->pitches[0] = (float)dz->param[PF_SMARK];
+	if(dz->vflag[PF_IS_EMARK])
+		dz->pitches[dz->wlength-1] = (float)dz->param[PF_EMARK];
+	if(dz->vflag[PF_INTERP] && (exit_status = interpolate_pitch(dz->pitches,1,dz))<0)
+		return(exit_status);
+	return write_exact_samps(dz->pitches,dz->wlength,dz);
+}
+
+/************************** SPECPINVERT ************************/
+
+int specpinvert(dataptr dz)
+{	 
+	int exit_status;
+	int n;
+	double midimean = 0.0, thismidi, thisint;
+	dz->time = 0.0f;
+	if(!dz->vflag[PI_IS_MEAN]) {
+		if((exit_status = get_midimean(&midimean,dz))<0)
+			return(exit_status);
+	} else
+		midimean = dz->param[PI_MEAN];
+	for(n=0;n<dz->wlength;n++) {
+		if(dz->pitches[n]<MINPITCH)
+			continue;		
+		if((exit_status = read_values_from_all_existing_brktables((double)dz->time,dz))<0)
+			return(exit_status);
+		if((exit_status = hztomidi(&thismidi,dz->pitches[n]))<0)
+			return(exit_status);
+		if(dz->is_mapping) {
+			if((exit_status = interval_mapping(&thisint,thismidi - midimean,dz))<0)
+				return(exit_status);
+			thismidi = max(dz->param[PI_BOT],min(dz->param[PI_TOP],midimean + thisint));
+		} else
+			thismidi = min(dz->param[PI_TOP],max(dz->param[PI_BOT],((2.0 * midimean) - thismidi)));
+		if(dz->is_transpos) {
+			dz->transpos[n] = (float)(miditohz(thismidi)/dz->pitches[n]);
+			check_transpos(&(dz->transpos[n]),dz);
+		} else  {
+			dz->pitches[n] = (float)miditohz(thismidi);
+			check_pitch(&(dz->pitches[n]),dz);
+		}
+		dz->time = (float)(dz->time + dz->frametime);
+	}
+	return(FINISHED);	
+}
+
+/************************************** SPECPQUANTISE **************************/
+
+int specpquantise(dataptr dz)
+{
+	int exit_status;
+	int n;
+	int got;
+	double *p, thismidi;
+	double *pend = dz->parray[PQ_QSET] + dz->itemcnt;
+	for(n=0;n<dz->wlength;n++) {
+		if(dz->pitches[n]<MINPITCH)
+			continue;
+		got = 0;
+		p = dz->parray[PQ_QSET]; 
+		if((exit_status = hztomidi(&thismidi,dz->pitches[n]))<0)
+			return(exit_status);
+		if(*p >= thismidi) {
+			if((exit_status = set_pval(*p,n,dz))<0)
+				return(exit_status);
+			continue;
+		}
+		while(*p < thismidi) {
+			if(++p >= pend) {
+				p--;
+				if((exit_status = set_pval(*p,n,dz))<0)
+					return(exit_status);
+				got = 1;
+				break;
+			}
+		}
+		if(got)
+			continue;
+		if((*p - thismidi) > (thismidi - *(p-1))) {
+			if((exit_status = set_pval(*(p-1),n,dz))<0)
+				return(exit_status);
+		} else {
+			if((exit_status = set_pval(*p,n,dz))<0)
+				return(exit_status);
+		}
+	}
+	return(FINISHED);	
+}
+
+/***************************************** SPECPRAND *********************/
+
+int specprand(dataptr dz)
+{
+	int exit_status;
+	int n = 0, lastn, m, thiswstep, diff, z;
+	double thisintv, ttime = 0.0, lastmidi, thismidi, mididiff, midistep;
+	initrand48();
+	while(dz->pitches[n]<MINPITCH) {
+		if(++n>=dz->wlength) {
+			sprintf(errstr,"No valid pitchdata found in pitch file.\n");
+			return(DATA_ERROR);
+		}
+	}
+	if((exit_status = hztomidi(&lastmidi,dz->pitches[n]))<0)
+		return(exit_status);
+	ttime = dz->frametime * (double)n;
+	if((exit_status = read_values_from_all_existing_brktables(ttime,dz))<0)
+		return(exit_status);
+	if((exit_status = get_rand_interval(&thisintv,dz))<0)
+		return(exit_status);
+	lastmidi += thisintv;
+	if((exit_status = set_pval(lastmidi,n,dz))<0)
+		return(exit_status);
+	lastn = n;
+	do {
+		thiswstep = round(max(dz->frametime,drand48() * dz->param[PR_TSTEP])/dz->frametime);
+		if((n += thiswstep) >= dz->wlength) {
+		 	sprintf(errstr,"Too much unpitched data in file to proceed this time. But try again.\n");
+			return(DATA_ERROR);
+		}
+		ttime = dz->frametime * (double)n;
+		if(dz->brksize[PR_TSTEP]) {
+			if((exit_status = read_value_from_brktable(ttime,PR_TSTEP,dz))<0)
+				return(exit_status);
+		}
+	} while(dz->pitches[n]<MINPITCH);
+
+	while(n<dz->wlength) {
+		if(dz->brksize[PR_MXINT]) {
+			if((exit_status = read_value_from_brktable(ttime,PR_MXINT,dz))<0)
+				return(exit_status);
+		}
+		if((exit_status = get_rand_interval(&thisintv,dz))<0)
+			return(exit_status);
+		if((exit_status = hztomidi(&thismidi,dz->pitches[n]))<0)
+			return(exit_status);
+		thismidi += thisintv;
+		mididiff  = thismidi - lastmidi;
+		diff	  = n - lastn;
+		midistep  = mididiff/(double)diff; 
+		for(m = lastn+1;m<=n;m++) {			/* Interp pitch between randomised points */
+			if(dz->pitches[m] < MINPITCH)
+				continue;
+			lastmidi  += midistep;
+			if((exit_status = set_pval(lastmidi,m,dz))<0)
+				return(exit_status);
+		}
+		lastmidi  = thismidi;
+		lastn = n;
+		do {
+			if(dz->brksize[PR_TSTEP]) {
+				if((exit_status = read_value_from_brktable(ttime,PR_TSTEP,dz))<0)
+					return(exit_status);
+			}
+			thiswstep = round(max(dz->frametime,drand48() * dz->param[PR_TSTEP])/dz->frametime);
+			if((n+=thiswstep) > dz->wlength)
+				break;
+			ttime = dz->frametime * (double)n;
+		} while(dz->pitches[n]<MINPITCH);
+	}
+	if(lastn < dz->wlength-1) {
+		z = dz->wlength - 1;
+		while(dz->pitches[z]<MINPITCH) {
+			if(--z<=lastn)
+				return(FINISHED);
+		}
+		n = z;
+		thisintv   = ((drand48() * 2.0) - 1.0) * dz->param[PR_MXINT];
+		if((exit_status = hztomidi(&thismidi,dz->pitches[n]))<0)
+			return(exit_status);
+		thismidi  += thisintv;
+		mididiff   = thismidi - lastmidi;
+		if((diff = n - lastn)<2)
+			return(FINISHED);
+		midistep   = mididiff/(double)diff; 
+		for(m = lastn+1;m<=n;m++) {
+			if(dz->pitches[n]<MINPITCH)
+				continue;
+			lastmidi  += midistep;
+			if((exit_status = set_pval(lastmidi,m,dz))<0)
+				return(exit_status);
+		}
+	}
+	return(FINISHED);	
+}
+
+/*************************************** SPECPSMOOTH ***********************************/
+
+int	specpsmooth(dataptr dz)
+{
+	int exit_status;
+	double ttime = 0.0, maxpitch = FLTERR, minpitch = dz->nyquist, 
+		maxmidi, minmidi, lastmidi;
+	double meanpich, maxint, minint, startmidi, endmidi, thismidi, mdiff, step;
+	int lastmaxpos = 0, n=0, m, z, interpfact, lastn;
+	if((exit_status = get_max_and_min_pitches(&maxpitch,&minpitch,dz))<0)
+		return(exit_status);
+	if((exit_status = hztomidi(&maxmidi,maxpitch))<0)
+		return(exit_status);
+	if((exit_status = hztomidi(&minmidi,minpitch))<0)
+		return(exit_status);
+	n = 0;
+	while(dz->pitches[n]<MINPITCH) {
+		if(++n >= dz->wlength) {
+			sprintf(errstr,"No valid data in pitchfile\n");
+			return(DATA_ERROR);
+		}
+	}
+	if(dz->is_transpos)
+		dz->transpos[n] = 1.0f;
+	if((exit_status = hztomidi(&lastmidi,dz->pitches[n]))<0)
+		return(exit_status);
+	ttime    = (double)n * dz->frametime;
+	if((exit_status = read_values_from_all_existing_brktables(ttime,dz))<0)
+		return(exit_status);
+	interpfact = round(dz->param[PS_TFRAME]/dz->frametime);
+	lastn = n;
+	do {
+		if((n += interpfact) >=dz->wlength) {
+			sprintf(errstr,"Too much unpitched data in file: cannot proceed. Try different interpfact(s).\n");
+			return(DATA_ERROR);
+		}
+		ttime = (double)n * dz->frametime;
+		if(dz->brksize[PS_TFRAME]) {
+			if((exit_status = read_value_from_brktable(ttime,PS_TFRAME,dz))<0)
+				return(exit_status);
+			interpfact = round(dz->param[PS_TFRAME]/dz->frametime);
+		}
+	} while(dz->pitches[n]<MINPITCH);
+	if(dz->vflag[PS_MEANP]) {
+		meanpich = miditohz(dz->param[PS_MEAN]);
+		maxint   = maxmidi - dz->param[PS_MEAN];
+		minint   = dz->param[PS_MEAN] - minmidi;
+		while(n<dz->wlength) {
+			if((exit_status = peak_interp(n,lastn,&lastmaxpos,meanpich,minint,maxint,&lastmidi,dz))<0)
+				return(exit_status);
+			if(dz->brksize[PS_TFRAME]) {
+				if((exit_status = read_value_from_brktable(ttime,PS_TFRAME,dz))<0)
+					return(exit_status);
+				interpfact = round(dz->param[PS_TFRAME]/dz->frametime);
+			}
+			if(dz->brksize[PS_MEAN]) {
+				if((exit_status = read_value_from_brktable(ttime,PS_MEAN,dz))<0)
+					return(exit_status);
+				meanpich = miditohz(dz->param[PS_MEAN]);
+				maxint = maxmidi - dz->param[PS_MEAN];
+				minint = dz->param[PS_MEAN] - minmidi;
+			}
+			lastn = n;
+			do{
+				if((n += interpfact) >= dz->wlength)
+					break;
+				ttime = (double)n * dz->frametime;
+				if(dz->brksize[PS_TFRAME]) {
+					if((exit_status = read_value_from_brktable(ttime,PS_TFRAME,dz))<0)
+						return(exit_status);
+					interpfact = round(dz->param[PS_TFRAME]/dz->frametime);
+				}
+			} while(dz->pitches[n]<MINPITCH);
+		}
+		n = lastmaxpos;
+	} else {
+		while(n<dz->wlength) {
+			z = n - lastn;
+			if((exit_status = hztomidi(&startmidi,dz->pitches[lastn]))<0)
+				return(exit_status);
+			if((exit_status = hztomidi(&endmidi,dz->pitches[n]))<0)
+				return(exit_status);
+			mdiff = endmidi - startmidi;
+			step = mdiff/(double)z;
+			for(m=1;m<=z;m++) {
+				if(dz->pitches[m+lastn]<MINPITCH)
+					continue;
+				thismidi = startmidi + (step * (double)m);
+				if((exit_status = set_pval(thismidi,m+lastn,dz))<0)
+					return(exit_status);
+			}
+			lastn = n;
+			do{
+				if((n += interpfact) >=dz->wlength)
+					break;
+				ttime = (float)((double)n * dz->frametime);
+				if(dz->brksize[PS_TFRAME]) {
+					if((exit_status = read_value_from_brktable(ttime,PS_TFRAME,dz))<0)
+						return(exit_status);
+					interpfact = round(dz->param[PS_TFRAME]/dz->frametime);
+				}
+			} while(dz->pitches[n]<MINPITCH);
+		}
+		n = lastn;
+		if((exit_status = hztomidi(&lastmidi,dz->pitches[n]))<0)
+			return(exit_status);
+	}
+	if(n < dz->wlength-1)
+		if((exit_status = do_tail(n,lastmidi,dz))<0)
+			return(exit_status);
+	return(FINISHED);
+}
+
+/***************************** SPECPTRANSPOSE *****************/
+
+int	specptranspose(dataptr dz)
+{	
+	int n;
+	for(n=0;n<dz->wlength;n++) {
+		if(dz->pitches[n]<MINPITCH)
+			continue;
+		dz->pitches[n] = (float)(dz->pitches[n] * dz->param[PT_TVAL]);
+		check_pitch(&(dz->pitches[n]),dz);
+	}
+	return(FINISHED);
+}
+
+/***************************** SPECPVIB *****************/
+
+int specpvib(dataptr dz)
+{
+	int exit_status;
+	double indexf = 0.0, intvl, indexstep;
+	int index = 0;
+	int n;
+	dz->time = 0.0f;
+	if((exit_status = read_values_from_all_existing_brktables((double)dz->time,dz))<0)
+		return(exit_status);
+	indexstep = dz->param[PV_FRQ] * dz->frametime * (double)P_TABSIZE;
+	for(n=0;n<dz->wlength;n++) {
+		if(dz->pitches[n]<MINPITCH)
+			continue;
+		intvl = dz->parray[PV_SIN][index] * dz->param[PV_RANG];
+		intvl = pow(SEMITONE_INTERVAL,intvl);
+		if(dz->is_transpos) {
+			dz->transpos[n] = (float)intvl;
+			check_transpos(&(dz->transpos[n]),dz);
+		} else {
+			dz->pitches[n] = (float)(dz->pitches[n] * intvl);
+			check_pitch(&(dz->pitches[n]),dz);
+		}
+		indexf += indexstep;
+		index   = round(indexf) % P_TABSIZE;
+		dz->time = (float)(dz->time + dz->frametime);
+		if(dz->brksize[PV_FRQ]) {
+			if((exit_status = read_value_from_brktable((double)dz->time,PV_FRQ,dz))<0)
+				return(exit_status);
+			indexstep = dz->param[PV_FRQ] * dz->frametime * (double)P_TABSIZE;
+		}
+		if(dz->brksize[PV_RANG]) {
+			if((exit_status = read_value_from_brktable((double)dz->time,PV_RANG,dz))<0)
+				return(exit_status);
+		}
+	}
+	return(FINISHED);
+}
+
+/*************************** SPECREPITCH ********************/
+
+int specrepitch(dataptr dz)
+{
+	int exit_status;
+	int n, brklen;
+	float frametime;
+	if(dz->wlength == 0) {	/* brkpnt only data entered */
+		dz->wlength = round(dz->duration/DEFAULT_FRAMETIME);
+		frametime   = DEFAULT_FRAMETIME;
+	} else
+		frametime   = dz->frametime;
+	switch(dz->mode) {
+	case(PPT): case(PPT_TO_BRK):	/* PPT */	
+		if((dz->transpos = (float *)malloc(dz->wlength * sizeof(float)))==NULL) {
+			sprintf(errstr,"INSUFFICIENT MEMORY for transpositions array.\n");
+			return(MEMORY_ERROR);
+		}
+		for(n=0;n<dz->wlength;n++) {
+			if(dz->pitches[n]<MINPITCH || dz->pitches2[n]<MINPITCH)
+				dz->transpos[n] = 1.0f;
+			else
+				dz->transpos[n] = (float)(dz->pitches2[n]/dz->pitches[n]);
+			check_transpos(&(dz->transpos[n]),dz);
+		}
+		break;
+	case(PTP): case(PTP_TO_BRK):	/* PTP */
+		for(n=0;n<dz->wlength;n++) {
+			if(dz->pitches[n] < MINPITCH)
+				continue;
+			dz->pitches[n]  = (float)(dz->pitches[n] * dz->transpos[n]);	
+			check_pitch(&(dz->pitches[n]),dz);
+		}
+		break;
+	case(TTT): case(TTT_TO_BRK):	/* TTT */
+		for(n=0;n<dz->wlength;n++) {
+			dz->transpos[n] = (float)(dz->transpos[n] * dz->transpos2[n]);	
+			check_transpos(&(dz->transpos[n]),dz);
+		}
+		break;
+	default:
+		sprintf(errstr,"unknown case in specrepitch()\n");
+		return(PROGRAM_ERROR);
+	}
+	switch(dz->mode) {
+	case(PTP):		  /* out P-bin */
+		if((exit_status = write_samps(dz->pitches,dz->wlength,dz))<0)
+			return(exit_status);
+		break;
+	case(PPT): 
+	case(TTT):		  /* out T-bin */
+		dz->outfiletype = TRANSPOS_OUT; 
+		if((exit_status = write_samps(dz->transpos,dz->wlength,dz))<0)
+			return(exit_status);
+		dz->is_transpos = TRUE;
+		break;
+	case(PTP_TO_BRK): /* P-brk out */ 
+		if((dz->parray[RP_TBRK] 
+			= (double *)malloc(dz->wlength * sizeof(double) * 2))==NULL) {
+			sprintf(errstr,"INSUFFICIENT MEMORY for pitch brkpnt array.\n");
+			return(MEMORY_ERROR);
+		}
+		if((exit_status = interpolate_pitch(dz->pitches,0,dz))<0)
+			return(exit_status);
+		if((exit_status = convert_pch_or_transpos_data_to_brkpnttable(
+			&brklen,dz->pitches,frametime,RP_TBRK,dz))<0)
+			return(exit_status);
+		if((exit_status = write_brkfile(dz->fp,brklen,RP_TBRK,dz))<0)
+			return(exit_status);
+		break;
+	case(PPT_TO_BRK): 
+	case(TTT_TO_BRK): /* T_brk out */
+		if((dz->parray[RP_TBRK] 
+			= (double *)malloc(dz->wlength * sizeof(double) * 2))==NULL) {
+			sprintf(errstr,"INSUFFICIENT MEMORY for transposition brkpnt array.\n");
+			return(MEMORY_ERROR);
+		}
+		if((exit_status = convert_pch_or_transpos_data_to_brkpnttable(&brklen,dz->transpos,frametime,RP_TBRK,dz))<0)
+			return(exit_status);
+		if((exit_status = write_brkfile(dz->fp,brklen,RP_TBRK,dz))<0)
+			return(exit_status);
+		break;
+	}
+	return(FINISHED);
+}
+
+/******************************* DO_PITCH_CUT ******************************/
+
+int do_pitch_cut(dataptr dz)
+{   int n; 
+    for(n=dz->iparam[PF_SCUTW];n<dz->iparam[PF_ECUTW];n++)
+        dz->pitches[n] = (float)NOT_PITCH;
+	return(FINISHED);
+}
+
+/************************* DO_PITCH_SMOOTHING ***************************/
+
+int do_pitch_smoothing(dataptr dz)
+{
+	int exit_status;
+	int z;
+	int first_valid_pitch, n, wlength_less_2 = dz->wlength - 2;
+	double *slopechange;
+	if((slopechange = (double *)malloc(dz->wlength * sizeof(double)))==NULL) {
+		sprintf(errstr,"INSUFFICIENT MEMORY for slopechange array.\n");
+		return(MEMORY_ERROR);
+	}
+	for(z=0;z<dz->iparam[PF_SMOOTH];z++) {
+		if((exit_status = skip_to_first_pitch(&first_valid_pitch,dz))<0)
+			return(exit_status);
+		if((exit_status = calc_slopechanges(first_valid_pitch,slopechange,dz))<0)
+			return(exit_status);
+		for(n=1;n<wlength_less_2;n++) {
+			if(fabs(slopechange[n]) > GLARG) {
+				if(dz->pitches[n+1]<0.0)
+					continue;
+				if((exit_status = is_start_of_glitch(n,slopechange,dz))<0)
+					return(exit_status);
+				if(exit_status==TRUE)
+					continue;   /* WILL BE SMOOTHED OUT AT NEXTSTEP */
+				if(dz->pitches[n-1]<MINPITCH) {		/* ONSET SMOOTH */
+					if((exit_status = do_onset_smooth(n,slopechange,dz))<0)
+						return(exit_status);
+					continue;
+				}
+				if(n>=2 && dz->pitches[n-2]<MINPITCH) {	/* DOUBLE ONSET SMOOTH */
+					if((exit_status = do_double_onset_smooth(n,slopechange,dz))<0)
+						return(exit_status);
+					continue;
+				}					/* NORMAL SMOOTH */
+				if((exit_status = do_smooth(n,slopechange,dz))<0)
+					return(exit_status);
+			}
+		}
+	}
+	free(slopechange);
+	return(FINISHED);
+}
+
+/****************************** DO_SMOOTH **************************
+ *
+ * Including checking for end of a pitched segment.
+ */
+
+int do_smooth(int pitchno,double *slopechange,dataptr dz)
+{
+	double val, val0, val1;
+	if(slopechange[pitchno+1] > GLARG  && pitchno>=1) {
+		if(pitchno+2 < dz->wlength && dz->pitches[pitchno+2] < 0.0) {
+			val0 = log10(dz->pitches[pitchno-1]);		/* TAIL */
+			val1 = log10(dz->pitches[pitchno]);
+			val = val1 - val0;
+			dz->pitches[pitchno+1] = (float)pow((double)10,(val1 + val));
+			slopechange[pitchno]   = 0.0; /* CORRECT SLOPECHANGE APPROPRIATELY */
+			slopechange[pitchno+1] = 0.0; /* AVOID SPURIOUS SMOOTH AT END_OF_TAIL PITCH */
+			return(FINISHED);
+		} else {
+			if(pitchno+3 < dz->wlength && dz->pitches[pitchno+3] < MINPITCH) {
+				val0 = log10(dz->pitches[pitchno-1]);	/* DOUBLE TAIL */
+				val1 = log10(dz->pitches[pitchno]);
+				val  = val1 - val0;
+				dz->pitches[pitchno+1] = (float)pow((double)10,(val1 + val));
+				val += val;
+				dz->pitches[pitchno+2] = (float)pow((double)10,(val1 + val));
+				slopechange[pitchno]   = 0.0;	/* CORRECT SLOPECHANGES APPROPRIATELY */
+				slopechange[pitchno+1] = 0.0;
+				slopechange[pitchno+2] = 0.0;	/* AVOID SPURIOUS SMOOTH AT END_OF_TAIL PITCH */
+				return(FINISHED);
+			}
+		}
+	}							/* NORMAL */
+	val0 = log10(dz->pitches[pitchno-1]);	
+	val1 = log10(dz->pitches[pitchno+1]);
+	val  = (val0 + val1)/2.0;
+	dz->pitches[pitchno] = (float)pow((double)10,val);
+	slopechange[pitchno] = 0.0;		   		/* CORRECT SLOPECHANGE APPROPRIATELY */
+	return(FINISHED);
+}
+
+/************************ SKIP_TO_FIRST_PITCH ***********************/
+
+int skip_to_first_pitch(int *first_pitch,dataptr dz)
+{
+	*first_pitch = 0;
+	while(dz->pitches[*first_pitch] < MINPITCH) {
+		if(++(*first_pitch) >= dz->wlength) {
+			sprintf(errstr,"No pitch data found.\n");
+			return(DATA_ERROR);
+		}
+	}
+	if(++(*first_pitch) >= dz->wlength) {
+		sprintf(errstr,"No pitch data found.\n");
+		return(DATA_ERROR);
+	}
+	return(FINISHED);
+}
+
+/************************* CALC_SLOPECHANGES ***********************/
+
+int calc_slopechanges(int first_valid_pitch,double *slopechange,dataptr dz)
+{
+	int n, k, wlength_less_1 = dz->wlength - 1;
+	int OK = 1;
+	double preslope = 0.0, postslope;
+	for(n=0;n<dz->wlength;n++)
+		slopechange[n] = 0.0;	
+	for(n = first_valid_pitch;n<wlength_less_1;n++) {
+		k = 1;
+		while(dz->pitches[n+k] < 0.0) {
+			k++;
+			if(k+n >= dz->wlength) {
+				OK = 0;
+				break;
+			}
+			if(!OK)
+				break;
+		}
+		if(!OK)
+			break;
+		postslope = (log10(dz->pitches[n+k]) - log10(dz->pitches[n]))/(double)k;
+		slopechange[n] = postslope - preslope;
+		n += k - 1;
+		preslope = postslope;
+	}
+	return(FINISHED);
+}
+
+/********************** IS_START_OF_GLITCH **********************
+ *
+ * WITHOUT THOROUGH CHECK worried that logs may get 0 or -ve vals..
+ */
+
+int is_start_of_glitch(int pitchno,double *slopechange,dataptr dz)
+{
+	double val, val0, val1;
+	if(dz->vflag[PF_TWOW]) {
+		if(pitchno+3 < dz->wlength-1
+		&& fabs(slopechange[pitchno+1]) > GLARG
+		&& fabs(slopechange[pitchno+2]) > GLARG
+		&& fabs(slopechange[pitchno+3]) > GLARG
+		&& ((slopechange[pitchno] > 0.0 
+			&& slopechange[pitchno+1] < 0.0 
+			&& slopechange[pitchno+2] < 0.0 
+			&& slopechange[pitchno+3] > 0.0)  	/* +--+ */
+		||  (slopechange[pitchno] < 0.0 
+			&& slopechange[pitchno+1] > 0.0 
+			&& slopechange[pitchno+2] < 0.0 
+			&& slopechange[pitchno+3] > 0.0)	/* -++- */
+		   )
+		){
+			val0 = log10(dz->pitches[pitchno]);
+			val1 = log10(dz->pitches[pitchno+3]);
+			val  = (val1 - val0)/3.0;	/* 2 WINDOW GLITCH */
+			val0 = log10(dz->pitches[pitchno] + val);
+			dz->pitches[pitchno+1] = (float)pow((double)10,val0);
+			val += val;
+			val1 = log10(dz->pitches[pitchno] + val);
+			dz->pitches[pitchno+2] = (float)pow((double)10,val1);
+			slopechange[pitchno+1] = 0.0;
+			slopechange[pitchno+2] = 0.0;
+			return(TRUE);
+		}
+	}
+	if(fabs(slopechange[pitchno+1]) > GLARG 
+	&& fabs(slopechange[pitchno+2]) > GLARG
+	&& ((slopechange[pitchno] > 0.0 
+		&& slopechange[pitchno+1] < 0.0 
+		&& slopechange[pitchno+2] > 0.0) 	/* +-+ */
+	||  (slopechange[pitchno] < 0.0 
+		&& slopechange[pitchno+1] > 0.0 
+		&& slopechange[pitchno+2] < 0.0)	/* -+- */
+	   )
+	)
+		return(TRUE);
+	return(FALSE);
+}
+
+/*********************** DO_ONSET_SMOOTH ********************/
+
+int do_onset_smooth(int pitchno, double *slopechange,dataptr dz)
+{
+	double val, val0, val1;
+	if(dz->pitches[pitchno+2] < MINPITCH)
+		return(FINISHED);
+	val0 = log10(dz->pitches[pitchno+1]);
+	val1 = log10(dz->pitches[pitchno+2]);
+	val  = (2.0 * val0) - val1;
+	dz->pitches[pitchno] = (float)pow((double)10,val);
+	slopechange[pitchno+1] = 0.0; 	/* CHANGE OF SLOPE HENCE BECOMES ZERO AT NEXT PITCH */
+	return(FINISHED);
+}			      	/* THIS ALSO PREVENTS double_onset BEING CALLED SPURIOUSLY */
+
+/************************ DO_DOUBLE_ONSET_SMOOTH ********************
+ *
+ *    NORMAL DOUBLE ONSET GLITCH	  SITUATION TO BE AVOIDED
+ *						 .
+ *						  .
+ *					           .
+ *	        postslope			    .
+ *	......  X---X---X           X       
+ *	      /					   /  \postslope
+ *	     /					  /    \
+ *	X---X            	 X---X      X---X
+ *      |				     |
+ *      |				     |
+ *  0...|				 0...|
+ *
+ *					     					 X
+ *					     					 |\
+ *  reverse predict from postslope, OK	     | \reverse predict from postslope
+ *	X---X---X---X---X		     			 |	\ gives spurious glitch
+ *	|				     					 |	 X
+ *	|				     					 |	  \
+ *	|				     					 |     \
+ * 	|				     					 |	    \
+ *	|			             				 |       X       
+ *  0...|       			     			 |	      \
+ *	     				     				 |	       \
+ *	                         	     		 |          X---X
+ *       				     				 |
+ *       				     				 |
+ *  					 				 0...|
+ *	                    	           ,X       
+ *	       					          /   \
+ *	      			interp instead  ,X     \
+ *		                   	       /        \
+ *		                   	     X           X---X
+ *       				     	 |
+ *       				      	 |
+ *  	 				 	 0...|
+ *
+ *		and at next pass, there'll probably be a 2nd interp thus..
+ *	                    	                           
+ *	      					    ,X.
+ *		                   	  /    'X.
+ *		                   	 X        ' X---X
+ *       				     |
+ *       				     |
+ *  	 				 0...|
+ *
+ *
+ */
+
+int do_double_onset_smooth(int pitchno,double *slopechange,dataptr dz)
+{
+	double val, val0, val1, preslope, postslope, pn0 ,pn1, pn2;
+	if(dz->pitches[pitchno+2] <  MINPITCH)
+		return(FINISHED);
+	pn0 = log10(dz->pitches[pitchno]);
+	pn1 = log10(dz->pitches[pitchno+1]);
+	pn2 = log10(dz->pitches[pitchno+2]);
+	preslope  = fabs(pn1 - pn0);
+	postslope = fabs(pn2 - pn1);
+	if(postslope > preslope * SLOPE_FUDGE) {	/* 1 */
+		val0 = log10(dz->pitches[pitchno-1]);	/* IF SLOPE AHEAD LOOKS TOO BIG  */
+		val1 = pn1; 		   			/* DON'T RISK USING IT TO GET VALS HERE. */
+		val  = (val0 + val1)/2.0;		/* INTERP INSTEAD */
+		dz->pitches[pitchno] = (float)pow((double)10,val);
+		slopechange[pitchno] = 0.0;		/* CORRECT SLOPECHANGE APPROPRIATELY */
+	} else {
+		val0 = pn1;		   				/* OTHERWISE BASE VALS ON SLOPE AHEAD */
+		val1 = pn2;
+		val  = (2.0 * val0) - val1;
+		dz->pitches[pitchno] = (float)pow((double)10,val);
+		val  = (3.0 * val0) - (2.0 * val1);
+		dz->pitches[pitchno-1] = (float)pow((double)10,val);
+		slopechange[pitchno]   = 0.0;
+		slopechange[pitchno+1] = 0.0;		/* CORRECT SLOPECHANGES APPROPRIATELY */
+	}
+	return(FINISHED);
+}
+
+/********************** GET_MAX_AND_MIN_PITCHES **********************/
+
+int get_max_and_min_pitches(double *maxpitch,double *minpitch,dataptr dz)
+{
+	int n;
+	for(n=0;n<dz->wlength;n++) {
+		if(dz->pitches[n] > MINPITCH) {
+			if(dz->pitches[n] > *maxpitch)
+				*maxpitch = dz->pitches[n];
+			if(dz->pitches[n] < *minpitch)
+				*minpitch = dz->pitches[n];
+		}
+	}
+	return(FINISHED);
+}
+
+/***************************** WRITE_REMAINING_PITCH_OR_TRANSPOS_DATA ******************************/
+
+int write_remaining_pitch_or_transpos_data(int final_length_in_windows,dataptr dz)
+{
+	int exit_status;
+	if(final_length_in_windows > 0) {
+		if(dz->is_transpos) {
+			if((exit_status = write_samps(dz->transpos,final_length_in_windows,dz))<0)
+				return(exit_status);
+		}else {
+			if((exit_status = write_samps(dz->pitches,final_length_in_windows,dz))<0)
+				return(exit_status);
+		}
+	}
+	return(FINISHED);
+}
+
+/***************************** GET_MIDIMEAN ******************************/
+
+int get_midimean(double *midimean,dataptr dz)
+{
+	int exit_status;
+	int n;
+	double  val;
+	*midimean = 0.0;
+	for(n=0;n<dz->wlength;n++) {
+		if(dz->pitches[n]<MINPITCH)
+			continue;
+		if((exit_status = hztomidi(&val,dz->pitches[n]))<0)
+			return(exit_status);
+		*midimean += val;
+	}
+	*midimean /= (double)dz->wlength;	
+	return(FINISHED);
+}
+
+/***************************** SET_PVAL ******************************/
+
+int set_pval(double midivalue,int n,dataptr dz)
+{
+	if(dz->is_transpos) {
+		dz->transpos[n] = (float)(miditohz(midivalue)/dz->pitches[n]);
+		check_transpos(&(dz->transpos[n]),dz);
+	} else {
+		dz->pitches[n] = (float)miditohz(midivalue);
+		check_pitch(&(dz->pitches[n]),dz);
+	}
+	return(FINISHED);
+}
+
+/***************************************** DO_TAIL ************************/
+
+int do_tail(int n,double lastmidi,dataptr dz)
+{
+	int exit_status;
+	double thispich, thismidi, endmidi, mdiff, step;
+	int   diff, m, z;
+	if(dz->vflag[PS_HOLD]) {
+		thispich = dz->pitches[n];
+		n++;
+		while(n < dz->wlength) {
+			if(dz->pitches[n]<MINPITCH) {
+				n++;
+				continue;
+			}
+			if(dz->is_transpos) {
+				dz->transpos[n] = (float)(thispich/dz->pitches[n]);
+				check_transpos(&(dz->transpos[n]),dz);
+			} else {
+				dz->pitches[n] = (float)thispich;
+				check_pitch(&(dz->pitches[n]),dz);
+			}
+			n++;
+		}
+	} else {
+		z = dz->wlength-1;
+		while(dz->pitches[z]<MINPITCH) {
+			if(--z==n)
+				return(FINISHED);
+		}
+		if((exit_status = hztomidi(&endmidi,dz->pitches[z]))<0)
+			return(exit_status);
+		mdiff   = endmidi - lastmidi;
+		if((diff = z - n)<2)
+			return(FINISHED);
+		step = mdiff/(double)diff;
+		n++;
+		for(m=1;n <= z;n++,m++) {
+			if(dz->pitches[n]<MINPITCH)
+				continue;
+			thismidi = lastmidi + (step * (double)m);
+			if((exit_status = set_pval(thismidi,n,dz))<0)
+				return(exit_status);
+		}
+	}
+	return(FINISHED);
+}
+
+/************************** GET_PITCHAPPROX_AVERAGES ************************/
+
+int get_pitchapprox_averages(int *avcnt,dataptr dz)
+{
+	int exit_status;
+	int OK = 1, n = 0, m, cnt;
+	double val;
+	*avcnt = 0;
+	if((dz->parray[PA_AVPICH] = (double *)malloc(dz->wlength * sizeof(double)))==NULL) {
+		sprintf(errstr,"INSUFFICIENT MEMORY for averaging array.\n");
+		return(MEMORY_ERROR);
+	}
+	while(OK) {
+		dz->parray[PA_AVPICH][*avcnt] = 0.0;
+		m = 0;
+		cnt = 0;
+		while(m < BLOKCNT) {
+			if(dz->pitches[n]<MINPITCH) {
+				m++;
+				if(++n >= dz->wlength) {
+					OK = 0;
+					break;
+				}
+				continue;
+			}
+			if((exit_status = hztomidi(&val,dz->pitches[n]))<0)
+				return(exit_status);
+			dz->parray[PA_AVPICH][*avcnt] += val;
+			cnt++;
+			m++;
+			if(++n >= dz->wlength) {
+				OK = 0;
+				break;
+			}
+		}
+		if(cnt==0)
+			dz->parray[PA_AVPICH][*avcnt] = -1.0f;
+		else {
+		    dz->parray[PA_AVPICH][*avcnt] /= (double)cnt;
+		    dz->parray[PA_AVPICH][*avcnt]  = miditohz(dz->parray[PA_AVPICH][*avcnt]);
+		}
+		(*avcnt)++;
+	}
+	return(FINISHED);
+}
+
+/********************************** APPROX_FUNC1 **********************************/
+
+int approx_func1(int *newlength_of_data,int *is_firsttime,
+					double *lastmidi,int *lastpos,int n,dataptr dz)
+{
+	int q, m, thispos, diff;
+	int exit_status = CONTINUE;
+	double ttime, thismidi, wiggle, this_prange, this_trange, mididiff, midistep;
+	int here = min(dz->wlength-1,n * BLOKCNT); /* just being ultra careful !! */
+	for(q=here;q<here+BLOKCNT;q++) {
+		if(q>=dz->wlength)
+			break;
+		if(dz->pitches[q] > MINPITCH)
+			break;
+	}
+	if(q>=here+BLOKCNT || q>=dz->wlength)	   /* No valid pitchdata here !! */
+		return(CONTINUE);
+	here = q;
+	ttime = dz->frametime * (double)here;
+	if((exit_status = hztomidi(&thismidi,dz->pitches[here]))<0)
+		return(exit_status);
+	if(dz->brksize[PA_PRANG])  {	/* RWD need curly */
+		if((exit_status = read_value_from_brktable(ttime,PA_PRANG,dz))<0)
+			return(exit_status);
+	}	
+	wiggle = (drand48() * 2.0) -1.0;	/* random  +-  */
+	this_prange = wiggle * dz->param[PA_PRANG];
+	thismidi += this_prange;
+	if(*is_firsttime) {
+		if((exit_status = set_pval(thismidi,q,dz))<0)
+			return(exit_status);
+		*lastpos  = q;
+		*lastmidi = thismidi;
+		*is_firsttime = FALSE;
+	} else {
+		wiggle = (drand48() * 2.0) -1.0;
+		if(dz->brksize[PA_TRANG])  {	/* RWD need curly */
+			if((exit_status = read_value_from_brktable(ttime,PA_TRANG,dz))<0)
+				return(exit_status);
+		}	
+		this_trange = dz->param[PA_TRANG] * wiggle;
+		ttime  += this_trange;
+		thispos = round(ttime/dz->frametime);
+		thispos = max(0L,thispos);
+		if((diff = thispos - *lastpos)>0) {
+			if(thispos > (*newlength_of_data)-1) {
+				if(dz->is_transpos) {
+					thispos = (*newlength_of_data)-1;
+					exit_status = FINISHED;
+				} else {
+					*newlength_of_data = thispos + 1;
+					if((dz->pitches  = (float *)realloc((char *)dz->pitches,
+						(*newlength_of_data) * sizeof(float)))==NULL) {
+						sprintf(errstr,"INSUFFICIENT MEMORY to reallocate pitch array.\n");
+						return(MEMORY_ERROR);
+					}
+				}
+			}
+			mididiff = thismidi - *lastmidi;
+			midistep = mididiff/(double)diff;
+			for(m=1,q= *lastpos + 1;m<=diff;m++,q++) {
+				if(q < dz->wlength && dz->pitches[q]<MINPITCH)
+					continue;
+				thismidi = *lastmidi + (midistep * (double)m);
+				if((exit_status = set_pval(thismidi,q,dz))<0)
+					return(exit_status);
+			}
+			*lastmidi = thismidi;
+			*lastpos  = thispos;
+		}
+	}
+ 	return(exit_status);
+}
+
+/********************************** APPROX_FUNC2 **********************************/
+
+int approx_func2(int *newlength_of_data,double lastmidi,int lastpos,int avcnt,dataptr dz)
+{
+	int exit_status;
+	int q, n, thispos, diff = 0;
+	double thismidi,ttime, wiggle, this_prange, this_trange;
+	double mididiff, midistep;
+	q = avcnt-1;
+	while(dz->parray[PA_AVPICH][q]<0.0) {
+		if(--q<=lastpos)
+			return(FINISHED);
+	}	
+	if((exit_status = hztomidi(&thismidi,dz->parray[PA_AVPICH][q]))<0)
+		return(exit_status);
+	ttime = (q * BLOKCNT) * dz->frametime;
+	if(dz->brksize[PA_PRANG]) {		//RWD need curly
+		if((exit_status = read_value_from_brktable(ttime,PA_PRANG,dz))<0)
+			return(exit_status);
+	}	
+	wiggle = (drand48() * 2.0) -1.0;	/* random  +-  */
+	this_prange = wiggle * dz->param[PA_PRANG];
+	thismidi += this_prange;
+	if(dz->is_transpos)
+		thispos = dz->wlength-1;
+	else {
+		wiggle = (drand48() * 2.0) -1.0;	/* random  +-  */
+		if(dz->brksize[PA_TRANG]) {		/* RWD need curly */
+			if((exit_status = read_value_from_brktable(ttime,PA_TRANG,dz))<0)
+				return(exit_status);
+		}	
+		this_trange = dz->param[PA_TRANG] * wiggle;
+		ttime  += this_trange;
+		thispos = round(ttime/dz->frametime);
+		thispos = max(0L,thispos);
+		if((diff = thispos - lastpos)>0 && thispos > *newlength_of_data-1) {
+			*newlength_of_data = thispos + 1;
+			if((dz->pitches  = 
+			(float *)realloc((char *)dz->pitches,*newlength_of_data * sizeof(float)))==NULL) {
+				sprintf(errstr,"INSUFFICIENT MEMORY to reallocate pitch array.\n");
+				return(MEMORY_ERROR);
+			}
+		}
+	}
+	if(diff>0) {
+		mididiff = thismidi - lastmidi;
+		midistep = mididiff/(double)diff;
+		for(n=1,q=lastpos+1;n<=diff;n++,q++) {
+			if(q < dz->wlength && dz->pitches[q]<MINPITCH)
+				continue;
+			thismidi = lastmidi + (midistep * (double)n);
+			if((exit_status = set_pval(thismidi,q,dz))<0)
+				return(exit_status);
+		}
+	} else
+		*newlength_of_data = lastpos + 1;
+	return(FINISHED);
+}
+
+/************************** GET_RAND_INTERVAL ************************/
+
+int get_rand_interval(double *thisintv,dataptr dz)
+{
+	double wiggle = ((drand48() * 2.0) - 1.0);
+	if(dz->vflag[PR_IS_SLEW]) {
+		if(wiggle < dz->param[PR_SLEW] 
+			|| (dz->iparam[PR_NEGATIV_SLEW]==TRUE 
+			&& (wiggle > dz->param[PR_SLEW])))
+			wiggle = -wiggle;
+	}
+	*thisintv = dz->param[PR_MXINT] * wiggle;
+	return(FINISHED);
+}
+		
+/************************** INTERVAL_MAPPING ************************
+ *
+ * Approximate input interval to nearest value in LHS column of input map.
+ * Find variance from that value.										    
+ * Return corresponding value in RHS column of map, with the variance correction added.
+ */
+
+int interval_mapping(double *thisint,double thismidi,dataptr dz)
+{
+	double *p    = dz->parray[PI_INTMAP];
+	double *pend = dz->parray[PI_INTMAP] + (dz->itemcnt * 2);
+	double variance, v1, v2;
+	if(thismidi <= *p) {				 /* intvl is below all entries in mapping table */
+		variance = thismidi - *p;
+		*thisint = *(p+1) - variance;	 /* return map of bottom val (-variance) */
+		return(FINISHED); 				
+	}
+	while(thismidi > *p) {
+		p += 2;
+		if(p >= pend) {					 /* intvl is above all entries in mapping table */
+			p -= 2;
+			variance = thismidi - *p;
+			*thisint = *(p+1) - variance;/* return map of top val (-variance) */
+			return(FINISHED);
+		}
+	}
+	v1 = *p - thismidi;					 /* intvl is between 2 entries in mapping table */
+	v2 = thismidi - *(p-2);
+	if(v1 > v2) {						 /* Compare variances, to find which intvl closer */
+		variance = v2;
+		*thisint = *(p-1) - variance;
+	} else {
+		variance = v1;
+		*thisint = *(p+1) + variance;	 /* return appropriate mapped pitch (+/-variance) */
+	}
+	return(FINISHED);			 
+}
+
+/************************************** PEAK_INTERP ****************/
+
+int peak_interp
+(int pitchno,int last_validpitch_no,int *lastmaxpos,double meanpich,
+double minint,double maxint,double *lastmidi,dataptr dz)							
+{
+	int exit_status;
+	double thispitch, thismidi, variance, mdiff,step;
+	int m, k, maxpos = 0, minpos = 0, diff;
+ 	double maxvar = 0.0, minvar = 0.0;
+	k = pitchno - last_validpitch_no;
+	for(m=0;m<k;m++) {
+		if((thispitch = dz->pitches[k+m])<MINPITCH)
+			continue;
+		if(thispitch >= meanpich) {
+			if((variance = thispitch/meanpich)>maxvar) {
+				maxvar = variance;
+				maxpos = k+m;
+			}
+		} else {
+			if((variance = meanpich/thispitch)>minvar) {
+				minvar = variance;
+				minpos = k+m;
+			}
+   		}
+//TW avoid log(0)
+		if(minvar > 0.0)
+			minvar = LOG2(minvar) * 12.0;
+//TW avoid log(0)
+		if(maxvar > 0.0)
+			maxvar = LOG2(maxvar) * 12.0;
+		minvar /= minint;
+		maxvar /= maxint;	 /* NORMALISE */
+		if(maxvar < minvar)
+			maxpos = minpos;
+	}
+	diff = maxpos - *lastmaxpos;
+	if((exit_status = hztomidi(&thismidi,dz->pitches[maxpos]))<0)
+		return(exit_status);
+	mdiff =	thismidi - *lastmidi;
+	step = mdiff/(double)diff;
+	for(m=1;m<=diff;m++) {
+		thismidi = *lastmidi + (step * (double)m);
+		if(dz->pitches[(*lastmaxpos)+m]<MINPITCH)
+			continue;
+		if((exit_status = set_pval(thismidi,(*lastmaxpos)+m,dz))<0)
+			return(exit_status);
+	}
+	*lastmidi = thismidi;
+	*lastmaxpos = maxpos;
+	return(FINISHED);
+}
+
+/*************************** DO_PITCH_FILTER *************************/
+
+int do_pitch_filter(dataptr dz)
+{
+	int n;
+	switch(dz->iparam[PF_ISFILTER]) {
+	case(IS_HIPASS):
+		for(n=0;n<dz->wlength;n++) {	
+			if(dz->pitches[n] < dz->param[PF_LOF])
+			dz->pitches[n] = (float)NOT_PITCH;
+		}
+		break;
+	case(IS_LOPASS):
+		for(n=0;n<dz->wlength;n++) {	
+			if(dz->pitches[n] > dz->param[PF_HIF])
+			dz->pitches[n] = (float)NOT_PITCH;
+		}
+		break;
+	case(IS_BANDPASS):
+		for(n=0;n<dz->wlength;n++) {	
+			if(dz->pitches[n] < dz->param[PF_LOF] || dz->pitches[n] > dz->param[PF_HIF])
+				dz->pitches[n] = (float)NOT_PITCH;
+		}
+		break;
+	}
+	return(FINISHED);
+}
+
+/***************************** TIDY_UP_PITCH_DATA ***********************/
+
+int tidy_up_pitch_data(dataptr dz)
+{
+	int exit_status;
+	if((exit_status = anti_noise_smoothing(dz->wlength,dz->pitches,dz->frametime))<0)
+		return(exit_status);
+	if((exit_status = mark_zeros_in_pitchdata(dz))<0)
+		return(exit_status);
+	if((exit_status = eliminate_blips_in_pitch_data(dz))<0)
+		return(exit_status);
+	if(dz->vflag[KEEP_PITCH_ZEROS]==FALSE)
+		return interpolate_pitch(dz->pitches,1,dz);
+	return pitch_found(dz);
+}
+
+/************************* GENERATE_TONE *************************/
+
+int generate_tone(dataptr dz)
+{
+
+#define VOLUME_PAD	(0.3)
+#define NOISEBASE	(0.2)
+
+	int exit_status;
+	int m, done, cc, vc, partials_in_test_tone;
+	float thisamp;
+	double thisfrq, basefrq;
+	int n = 0, last_partial;
+	double noisrange = 1.0 - NOISEBASE;
+	double level, totamp = 0.0;
+	dz->flbufptr[0] = dz->bigfbuf;
+	thisamp = (float)(VOLUME_PAD/(double)dz->clength);
+	if(dz->process==P_SYNTH) {
+		dz->wanted = dz->clength * 2;
+		partials_in_test_tone = dz->itemcnt;
+	} else
+		partials_in_test_tone = PARTIALS_IN_TEST_TONE;
+
+	while(n < dz->wlength) {
+		done = FALSE;
+		thisfrq = dz->pitches[n];
+		if(thisfrq < 0.0){		/* NO PITCH FOUND : GENERATE NOISE */
+			if(thisfrq > NOT_SOUND) {
+				if(dz->process!=P_SYNTH)
+					thisamp = (float)((dz->parray[PICH_PRETOTAMP][n]/(double)dz->clength) * VOLUME_PAD);
+				basefrq = 0.0;
+				dz->flbufptr[0][1] = (float)(drand48() * dz->halfchwidth);
+				basefrq += dz->halfchwidth;
+				for(cc = 1, vc = 2; cc < dz->clength - 1; cc++, vc += 2) {
+					dz->flbufptr[0][FREQ] = (float)((drand48() * dz->chwidth) + basefrq);
+					dz->flbufptr[0][AMPP] = (float)(thisamp * ((drand48() * noisrange) + NOISEBASE));
+					basefrq += dz->chwidth;
+				}
+				dz->flbufptr[0][FREQ] = (float)(dz->nyquist - (drand48() * dz->halfchwidth));
+				dz->flbufptr[0][AMPP] = (float)(thisamp * ((drand48() * noisrange) + NOISEBASE));
+				done = TRUE;
+			} else {
+				basefrq = 0.0;
+				for(cc = 0, vc = 0; cc < dz->clength-1; cc++, vc += 2) {
+					dz->flbufptr[0][FREQ] = (float)basefrq;
+					dz->flbufptr[0][AMPP] = 0.0f;
+					basefrq += dz->chwidth;
+				}
+				dz->flbufptr[0][FREQ] = (float)dz->nyquist;
+				dz->flbufptr[0][AMPP] = 0.0f;
+				done = TRUE;
+			}
+		} else {			/* GENERATE TESTTONE AT FOUND PITCH */
+			if(dz->process==P_SYNTH) {
+				for(cc = 0, vc = 0; cc < dz->clength; cc++, vc += 2)
+					dz->flbufptr[0][AMPP] = 0.0f;
+				basefrq = thisfrq;
+				totamp = 0.0;
+				for(m=0;m<partials_in_test_tone;m++) {
+					cc = (int)((thisfrq + dz->halfchwidth)/dz->chwidth);
+					vc = cc * 2;
+					if((level = dz->parray[PICH_SPEC][m]) > 0.0) { 
+						dz->flbufptr[0][AMPP] = (float)level;
+						dz->flbufptr[0][FREQ] = (float)thisfrq;
+						totamp += dz->flbufptr[0][AMPP];
+					}
+					if((thisfrq += basefrq) > dz->nyquist) {
+						if((exit_status = normalise(VOLUME_PAD,totamp,dz))<0)
+							return(exit_status);
+						done = TRUE;
+						break;
+					}
+				}
+			} else {
+				for(cc = 0, vc = 0; cc < dz->clength; cc++, vc += 2)
+					dz->flbufptr[0][AMPP] = 0.0f;
+				for(m=0;m<partials_in_test_tone;m++) {
+					cc = (int)((thisfrq + dz->halfchwidth)/dz->chwidth); 	/* TRUNCATE */
+					vc = cc * 2;
+					dz->flbufptr[0][AMPP] = dz->windowbuf[TESTPAMP][m];
+					dz->flbufptr[0][FREQ] = (float)thisfrq;
+					if((thisfrq = thisfrq * 2.0) > dz->nyquist) {
+						if((exit_status = normalise(dz->parray[PICH_PRETOTAMP][n] * VOLUME_PAD,
+										dz->windowbuf[TOTPAMP][m],dz))<0)
+							return(exit_status);
+						done = TRUE;
+						break;
+					}
+				}
+			}
+		}
+
+		if(!done) {
+			last_partial = partials_in_test_tone-1;
+			if(dz->process==P_SYNTH) {
+				if((level = dz->parray[PICH_SPEC][last_partial]) > 0.0) {
+					if((exit_status = normalise(VOLUME_PAD,totamp,dz))<0)
+						return(exit_status);
+				}
+			} else {
+				if((exit_status = normalise(dz->parray[PICH_PRETOTAMP][n],
+				dz->windowbuf[TOTPAMP][last_partial],dz))<0)
+					return(exit_status);
+			}
+		}
+		if((dz->flbufptr[0] += dz->wanted) >= dz->flbufptr[1]) {
+			if((exit_status = write_samps(dz->bigfbuf,dz->big_fsize,dz))<0)
+				return(exit_status);
+			dz->flbufptr[0] = dz->bigfbuf;
+		}
+		n++;
+	}
+	if(dz->flbufptr[0] != dz->bigfbuf) {
+		if((exit_status = write_samps(dz->bigfbuf,dz->flbufptr[0] - dz->bigfbuf,dz))<0)
+			return(exit_status);
+	}
+	return(FINISHED);
+}
+
+/********************** ANTI_NOISE_SMOOTHING *********************/
+/*RWD used in conditional test, so better as a real var:*/
+static const int MIN_SMOOTH_SET = 3;
+/*#define MIN_SMOOTH_SET (3)*/		/* minimum number of adjacent smooth pitches to imply true pitch present */
+#define MAX_GLISRATE   (16.0)	/* Assumptions: pitch can't move faster than 16 octaves per sec: MAX_GLISRATE */ 
+								/* Possible movement from window-to-window = MAX_GLISRATE * dz->frametime */
+
+int anti_noise_smoothing(int wlength,float *pitches,float frametime)
+{
+	char *smooth;
+	double max_pglide;
+	int n;
+	if(MIN_SMOOTH_SET<3) {
+		sprintf(errstr,"Bad constant: MIN_SMOOTH_SET: anti_noise_smoothing()\n");
+		return(PROGRAM_ERROR);
+	}
+	if(wlength < MIN_SMOOTH_SET + 1)
+		return(FINISHED);
+
+	max_pglide = pow(2.0,MAX_GLISRATE * frametime);
+
+	if((smooth = (char *)malloc((size_t)wlength))==NULL) {
+		sprintf(errstr,"aINSUFFICIENT MEMORY for smoothing array.\n");
+		return(MEMORY_ERROR);
+	}
+	for(n=1;n<wlength-1;n++)
+		smooth[n] = (char)is_smooth_from_both_sides(n,max_pglide,pitches);
+	smooth[0]         = (char)is_initialpitch_smooth(smooth,max_pglide,pitches);
+	smooth[wlength-1] = (char)is_finalpitch_smooth(smooth,max_pglide,wlength,pitches);
+	for(n=MIN_SMOOTH_SET-1;n<wlength;n++) {
+		if(!smooth[n])
+			smooth[n] = (char)is_smooth_from_before(n,smooth,max_pglide,pitches);
+	}
+	for(n=0;n<=wlength-MIN_SMOOTH_SET;n++) {
+		if(!smooth[n])
+			smooth[n] = (char)is_smooth_from_after(n,smooth,max_pglide,pitches);
+	}
+	test_glitch_sets(smooth,max_pglide,wlength,pitches);
+	remove_unsmooth_pitches(smooth,wlength,pitches);
+	free(smooth);
+	return(FINISHED);
+}		
+
+/********************** IS_SMOOTH_FROM_BOTH_SIDES *********************
+ *
+ * verify a pitch if it has continuity with the pitches on either side.
+ */
+
+int is_smooth_from_both_sides(int n,double max_pglide,float *pitches)
+{
+	float thispitch, pitch_before, pitch_after;
+	double pre_interval, post_interval;
+	if((thispitch = pitches[n]) < FLTERR)
+		return FALSE;
+	if((pitch_before = pitches[n-1]) < FLTERR)
+		return  FALSE;
+	if((pitch_after = pitches[n+1]) < FLTERR)
+		return  FALSE;
+	pre_interval  = pitch_before/thispitch;
+	if(pre_interval < 1.0)
+		pre_interval = 1.0/pre_interval;
+	post_interval = pitch_after/thispitch;
+	if(post_interval < 1.0)
+		post_interval = 1.0/post_interval;
+	if(pre_interval  > max_pglide
+	|| post_interval > max_pglide)
+		return  FALSE;
+	return  TRUE;
+}
+
+/********************** IS_INITIALPITCH_SMOOTH *********************
+ *
+ * verify first pitch if it has continuity with an ensuing verified pitch.
+ */
+
+int is_initialpitch_smooth(char *smooth,double max_pglide,float *pitches)
+{
+	float thispitch;
+	int n;
+	double post_interval;
+	if((thispitch = pitches[0]) < FLTERR)
+		return FALSE;
+	for(n=1;n < MIN_SMOOTH_SET;n++) {
+		if(smooth[n]) {
+			post_interval = pitches[n]/pitches[0];
+			if(post_interval < 1.0)
+				post_interval = 1.0/post_interval;
+			if(post_interval <= pow(max_pglide,(double)n))
+				return TRUE;
+		}
+	}	
+	return(FALSE);
+}
+			
+/********************** IS_FINALPITCH_SMOOTH *********************
+ *
+ * verify final pitch if it has continuity with a preceding verified pitch.
+ */
+
+int is_finalpitch_smooth(char *smooth,double max_pglide,int wlength,float *pitches)
+{
+	float thispitch;
+	double pre_interval;
+	int n;
+	int last = wlength - 1;
+	if((thispitch = pitches[last]) < FLTERR)
+		return FALSE;
+	for(n=1;n < MIN_SMOOTH_SET;n++) {
+		if(smooth[last-n]) {
+			pre_interval = pitches[last-n]/pitches[last];
+			if(pre_interval < 1.0)
+				pre_interval = 1.0/pre_interval;
+			if(pre_interval <= pow(max_pglide,(double)n))
+				return TRUE;
+		}
+	}
+	return(FALSE);
+}
+			
+/********************** IS_SMOOTH_FROM_BEFORE *********************
+ *
+ * verify a pitch which has continuity with a preceding set of verified pitches.
+ */
+
+int is_smooth_from_before(int n,char *smooth,double max_pglide,float *pitches)
+{
+	float thispitch, pitch_before;
+	double pre_interval;
+	int m;
+	if((thispitch = pitches[n]) < FLTERR)
+		return FALSE;
+	for(m=1;m<MIN_SMOOTH_SET;m++) {		/* If there are (MIN_SMOOTH_SET-1) smooth pitches before */
+		if(!smooth[n-m])
+			return(FALSE);
+	}
+	pitch_before = pitches[n-1];		/* Test the interval with the previous pitch */
+	pre_interval  = pitch_before/thispitch;
+	if(pre_interval < 1.0)
+		pre_interval = 1.0/pre_interval;
+	if(pre_interval  > max_pglide)   
+		return  FALSE;				   	/* And if it's acceptably smooth */
+	return  TRUE;					   	/* mark this pitch as smooth also */
+}
+
+/********************** IS_SMOOTH_FROM_AFTER *********************
+ *
+ * verify a pitch which has continuity with a following set of verified pitches.
+ */
+
+int is_smooth_from_after(int n,char *smooth,double max_pglide,float *pitches)
+{
+	float thispitch, pitch_after;
+	double post_interval;
+	int m;
+	if((thispitch = pitches[n]) < FLTERR)
+		return FALSE;
+	for(m=1;m<MIN_SMOOTH_SET;m++) {	/* If there are (MIN_SMOOTH_SET-1) smooth pitches after */
+		if(!smooth[n+m])
+		return(FALSE);
+	}
+	pitch_after = pitches[n+1];		/* Test the interval with the next pitch */
+	post_interval  = pitch_after/thispitch;
+	if(post_interval < 1.0)
+		post_interval = 1.0/post_interval;
+	if(post_interval  > max_pglide)   
+		return  FALSE;				/* And if it's acceptably smooth */
+	return  TRUE;					/* mark this pitch as smooth also */
+}
+
+/********************** TEST_GLITCH_SETS *********************
+ *
+ * This function looks for any sets of values that appear to be glitches
+ * amongst the real pitch data.
+ * It is possible some items are REAL pitch data isolated BETWEEN short glitches.
+ * This function checks for these cases.
+ */
+
+int test_glitch_sets(char *smooth,double max_pglide,int wlength,float *pitches)
+{
+	int exit_status;
+	int gotglitch = FALSE;
+	int n, gltchend, gltchstart = 0;
+	for(n=0;n<wlength;n++) {
+		if(gotglitch) {			/* if inside a glitch */
+			if(smooth[n]) {		/* if reached its end, mark the end, then process the glitch */
+				gltchend = n;
+				if((exit_status = test_glitch_forwards(gltchstart,gltchend,smooth,max_pglide,pitches))<0)
+					return(exit_status);
+				if((exit_status = test_glitch_backwards(gltchstart,gltchend,smooth,max_pglide,wlength,pitches))<0)
+					return(exit_status);
+				gotglitch = 0;
+			}
+		} else {				/* look for a glitch and mark its start */
+			if(!smooth[n]) {
+				gotglitch = 1;
+				gltchstart = n;
+			}
+		}
+	}
+	if(gotglitch) {				/* if inside a glitch at end of data, process glitch */
+		gltchend = n;
+		test_glitch_forwards(gltchstart,gltchend,smooth,max_pglide,pitches);
+	}
+	return(FINISHED);
+}
+
+/********************* REMOVE_UNSMOOTH_PITCHES ***********************
+ *
+ * delete all pitches which have no verified continuity with surrounding pitches.
+ */
+
+void remove_unsmooth_pitches(char *smooth,int wlength,float *pitches)
+{
+	int n;
+	for(n=0;n<wlength;n++) {
+		if(!smooth[n])		
+			pitches[n] = (float)NOT_PITCH;
+	}
+}
+
+/********************** TEST_GLITCH_FORWARDS *********************
+ *
+ * searching from start of glitch, look for isolated true pitches
+ * amongst glitch data.
+ */
+
+#define LAST_SMOOTH_NOT_SET (-1)
+
+int test_glitch_forwards(int gltchstart,int gltchend,char *smooth,double max_pglide,float *pitches)
+{
+	int n, glcnt;
+	int last_smooth, previous;
+	double pre_interval;
+	if((previous = gltchstart - 1) < 0)
+		return FINISHED;
+	if(pitches[previous] < FLTERR) {
+		sprintf(errstr,"Error in previous smoothing logic: test_glitch_forwards()\n");
+		return(PROGRAM_ERROR);
+	}
+	last_smooth = previous;
+	n = gltchstart+1;								/* setup params for local search of glitch */
+	glcnt = 1;
+	while(n < gltchend) {							/* look through the glitch */
+		if(pitches[n] > FLTERR) {					/* if glitch location holds a true pitch */
+			pre_interval = pitches[n]/pitches[previous]; 
+			if(pre_interval < 1.0)
+				pre_interval = 1.0/pre_interval;	/* compare against previous verified pitch */
+			if(pre_interval <= pow(max_pglide,(double)(n-previous))) {
+				smooth[n] = TRUE;	   				/* if comparable: mark this pitch as verified */
+				last_smooth = n;
+			}
+		}											
+		n++;										/* Once more than a max-glitch-set has been scanned */							  				
+													/* or the end of the entire glitch is reached */
+		if(++glcnt >= MIN_SMOOTH_SET || n >= gltchend) {
+			if(last_smooth == previous)
+				break;								/* If no new verifiable pitch found, give up */
+			previous = last_smooth;
+			n = last_smooth + 1;					/* Otherwise start a new local search from newly verified pitch */
+			glcnt = 1;									
+		}
+	}
+	return(FINISHED);
+}
+
+/********************** TEST_GLITCH_BACKWARDS *********************
+ *
+ * searching from end of glitch, look for isolated true pitches
+ * amongst glitch data.
+ */
+
+int test_glitch_backwards(int gltchstart,int gltchend,char *smooth,double max_pglide,int wlength,float *pitches)
+{
+	int n, glcnt, next, next_smooth;
+	double post_interval;
+	if((next = gltchend) >= wlength)
+		return FINISHED;
+	if(pitches[next] < FLTERR) {
+		sprintf(errstr,"Error in previous smoothing logic: test_glitch_backwards()\n");
+		return(PROGRAM_ERROR);
+	}
+	next_smooth = next;
+	n = gltchend-2;			 						/* setup params for local search of glitch */
+	glcnt = 1;
+	while(n >= gltchstart) {						/* look through the glitch */
+		if(pitches[n] > FLTERR) {					/* if glitch location holds a true pitch */
+			post_interval = pitches[n]/pitches[next]; 
+			if(post_interval < 1.0)
+				post_interval = 1.0/post_interval;	/* compare against previous verified pitch */
+			if(post_interval <= pow(max_pglide,(double)(next - n))) {
+				smooth[n] = TRUE;	   				/* if comparable: mark this pitch as verified */
+				next_smooth = n;
+			}
+		}							  				
+		n--;						  				/* Once more than a max-glitch-set has been scanned */
+													/* or the start of the entire glitch is reached */							  				
+		if(++glcnt >= MIN_SMOOTH_SET || n < gltchstart) {	  				
+			if(next_smooth == next)
+				break;								/* If no new verifiable pitch found, give up */
+			next = next_smooth;
+			n = next_smooth - 1;
+			glcnt = 1;								/* Otherwise start a new local search */
+		}
+	}
+	return(FINISHED);
+}
+
+/*********** WRITE_PITCH_OUTHEADER_FROM_ANALYSIS_INHEADER_TO_SECOND_OUTFILE **************
+ *
+ * Works for specpitch and spectrack: which write to 2nd datafile!!!
+ */
+
+int write_pitch_outheader_from_analysis_inheader_to_second_outfile(int ofd,dataptr dz)
+{
+	int exit_status;
+	int orig_process 	 = dz->process_type;
+	int orig_outfiletype = dz->outfiletype;
+	int orig_chans       = dz->infile->channels;
+	int orig_origchans   = dz->infile->origchans;
+	dz->process_type = ANAL_TO_PITCH;
+	dz->outfiletype  = PITCH_OUT;
+	dz->outfile->origchans = dz->infile->channels;
+	dz->outfile->channels  = 1;
+	if((exit_status = headwrite(ofd,dz))<0)
+		return(exit_status);
+		/* restore orig values */
+	dz->process_type       = orig_process;
+	dz->outfiletype        = orig_outfiletype;
+	dz->outfile->origchans = orig_origchans;
+	dz->outfile->channels  = orig_chans;
+	return(FINISHED);
+}
+
+/***************************** LOCAL_PEAK **************************/
+
+int local_peak(int thiscc,double frq, float *thisbuf, dataptr dz)
+{
+	int thisvc = thiscc * 2;
+	int cc, vc, searchtop, searchbot;
+	double frqtop = frq * SEMITONE_INTERVAL;
+	double frqbot = frq / SEMITONE_INTERVAL;
+	searchtop = (int)((frqtop + dz->halfchwidth)/dz->chwidth);		/* TRUNCATE */
+	searchtop = min(dz->clength,searchtop + PEAKSCAN + 1);
+	searchbot = (int)((frqbot + dz->halfchwidth)/dz->chwidth);		/* TRUNCATE */
+	searchbot = max(0,searchbot - PEAKSCAN);
+	for(cc = searchbot ,vc = searchbot*2; cc < searchtop; cc++, vc += 2) {
+		if(thisbuf[thisvc] < thisbuf[vc])
+			return(FALSE);
+	}
+	return(TRUE);
+}
+
+/**************************** INTERPOLATE_PITCH ***************************/
+
+int interpolate_pitch(float *floatbuf,int skip_silence,dataptr dz)
+{
+	int exit_status;
+	int pitchno;
+	for(pitchno=0;pitchno<dz->wlength;pitchno++) {
+		if(floatbuf[pitchno] < MINPITCH) {
+			if(skip_silence && flteq((double)floatbuf[pitchno],NOT_SOUND))
+				continue;
+			if((exit_status = do_interpolating(&pitchno,floatbuf,skip_silence,dz))<0)
+				return(exit_status);
+		}
+	}
+	return(FINISHED);
+}
+
+/****************************** DO_INTERPOLATING ************************
+ *
+ * WITHOUT THOROUGH CHECK, worried about logs getting <= 0.0.
+ */
+
+int do_interpolating(int *pitchno,float *floatbuf,int skip_silence,dataptr dz)
+{
+#define MID_PITCH   (0)
+#define FIRST_PITCH (1)
+#define END_PITCH   (2)
+#define NO_PITCH    (3)
+
+	int act_type = MID_PITCH;
+	int start = *pitchno, m;
+	double startpitch, endpitch, thispitch, lastpitch, pstep;
+	if(*pitchno==0L)
+		act_type = FIRST_PITCH;
+	while(floatbuf[*pitchno] < MINPITCH) {
+		if(++(*pitchno)>=dz->wlength) {
+			if(act_type == FIRST_PITCH)
+				act_type = NO_PITCH;
+			else
+				act_type = END_PITCH;
+			break;
+		}
+	}
+	if(act_type==MID_PITCH) {
+		m = start-1;		
+		while(floatbuf[m] < MINPITCH) {
+			if(--m <= 0) {
+				act_type = FIRST_PITCH;
+				break;
+			}
+		}
+		start = m;
+	}
+	switch(act_type) {
+	case(MID_PITCH):
+		startpitch = hz_to_pitchheight((double)floatbuf[start-1]);
+		endpitch   = hz_to_pitchheight((double)floatbuf[*pitchno]);
+		pstep = (endpitch - startpitch)/(double)((*pitchno) - (start - 1));
+		lastpitch = startpitch;
+		for(m=start;m<*pitchno;m++) {   /* INTERP PITCH ACROSS UNPITCHED SEG */
+			thispitch  = lastpitch + pstep;
+			if(!(skip_silence && flteq(floatbuf[m],NOT_SOUND)))
+				floatbuf[m] = (float)pitchheight_to_hz(thispitch);
+			lastpitch = thispitch;
+		}
+		break;
+	case(FIRST_PITCH):
+		for(m=0;m<*pitchno;m++) {	/* EXTEND FIRST CLEAR PITCH BACK TO START */
+			if(!(skip_silence && flteq(floatbuf[m],NOT_SOUND)))
+				floatbuf[m] = floatbuf[*pitchno];
+		}
+		break;
+	case(END_PITCH):			/* EXTEND LAST CLEAR PITCH ON TO END */
+		for(m=start;m<*pitchno;m++) {
+			if(!(skip_silence && flteq(floatbuf[m],NOT_SOUND)))
+				floatbuf[m] = floatbuf[start-1];
+		}
+		break;
+	case(NO_PITCH): 
+		sprintf(errstr,"No valid pitch found.\n");
+		return(GOAL_FAILED);				 
+	}
+	(*pitchno)--;
+	return(FINISHED);
+}
+
+/***************************** HZ_TO_PITCHHEIGHT *******************************
+ *
+ * Real pitch is 12 * log2(frq/basis_frq).
+ * 
+ * BUT (with a little help from the Feynman lectures!!)
+ * (1) 	The basis_frq is arbitrary, and cancels out, so let it be 1.0.
+ 		i.e. pitch1 = 12 * log2(frq1/basis_frq) = 12 * (log2(frq1) - log2(basis_frq));
+ 			 pitch2 = 12 * log2(frq2/basis_frq) = 12 * (log2(frq2) - log2(basis_frq));
+			 pitch1 - pitch2 = 12 * (log2(frq1) - log2(frq2)) = 12 * log2(frq1/frq2);
+ * (2) 	Finding the difference of 2 log2() numbers, interpolating and
+ *     	reconverting to pow(2.0,...) is no different to doing same
+ *		calculation to base e.
+ * (3)	The (12 *) is also a cancellable factor in all this.
+ * 		So pitch_height serves the same function as pitch in these calculations!!
+ */
+
+double hz_to_pitchheight(double frqq)
+{   
+	return log(frqq);
+}
+
+/***************************** PITCHHEIGHT_TO_HZ *******************************/
+
+double pitchheight_to_hz(double pitch_height)
+{
+	return exp(pitch_height);
+}
+
+/************************** ELIMINATE_BLIPS_IN_PITCH_DATA ****************************
+ *
+ * (1) 	Eliminate any group of 'dz->param[PICH_VALID]' pitched windows, bracketed by
+ *	unpitched windows, as unreliable data.
+ */
+
+int eliminate_blips_in_pitch_data(dataptr dz)
+{
+	int q;
+	int n, m, k, wlength_less_bliplen;
+	int OK = 1;
+	switch(dz->process) {
+	case(PITCH): q = PICH_VALID;	break;
+	case(TRACK): q = TRAK_VALID;	break;
+	default:
+		sprintf(errstr,"unknown case in eliminate_blips_in_pitch_data()\n");
+		return(PROGRAM_ERROR);
+	}
+	if(dz->iparam[q]<=0)
+		return(FINISHED);
+	wlength_less_bliplen = dz->wlength - dz->iparam[q];
+	for(n=1;n<wlength_less_bliplen;n++) {
+		if(dz->pitches[n] > 0.0) {
+			if(dz->pitches[n-1] < 0.0) {
+				for(k = 1; k <= dz->iparam[q]; k++) {
+					if(dz->pitches[n+k] < 0.0) {
+						for(m=0;m<k;m++)
+							dz->pitches[n+m] = (float)NOT_PITCH;
+						n += k;
+						continue;
+					}
+				}
+			}
+		}
+	}
+	n = wlength_less_bliplen;
+	if((dz->pitches[n] > 0.0) && (dz->pitches[n-1] < 0.0)) {
+/* UNREACHABLE at level4 ??? */
+		for(k = 1; k < dz->iparam[q]; k++) {
+			if(dz->pitches[n+k] < 0.0)
+				OK = 0;
+			break;
+		}
+	}
+	if(!OK)  {
+		for(n=wlength_less_bliplen;n<dz->wlength;n++)
+			dz->pitches[n] = (float)NOT_PITCH;
+	}
+	return(FINISHED);
+}
+
+/********************************** MARK_ZEROS_IN_PITCHDATA ************************
+ *
+ * Disregard data on windows which are SILENCE_RATIO below maximum level.
+ */
+
+int mark_zeros_in_pitchdata(dataptr dz)
+{
+	int k;
+	int n;
+	double maxlevel = 0.0, minlevel;
+	switch(dz->process) {
+	case(PITCH): k = PICH_SRATIO;	break;
+	case(TRACK): k = TRAK_SRATIO;	break;
+	default:
+		sprintf(errstr,"unknown case in mark_zeros_in_pitchdata()\n");
+		return(PROGRAM_ERROR);
+	}
+	for(n=0;n<dz->wlength;n++) {
+		if(dz->parray[PICH_PRETOTAMP][n] > maxlevel)
+			maxlevel = dz->parray[PICH_PRETOTAMP][n];
+	}
+	minlevel = maxlevel * dz->param[k];
+	for(n=0;n<dz->wlength;n++) {
+		if(dz->parray[PICH_PRETOTAMP][n] < minlevel)
+			dz->pitches[n] = (float)NOT_SOUND;
+	}
+	return(FINISHED);
+}
+
+/**************************** PITCH_FOUND ****************************/
+
+int pitch_found(dataptr dz)
+{
+	int n;
+    for(n=0;n<dz->wlength;n++) {
+		if(dz->pitches[n] > NOT_PITCH)
+			return(FINISHED);
+	}
+	sprintf(errstr,"No valid pitch found.\n");
+	return(GOAL_FAILED);
+}
+ 
+/**************************** CHECK_TRANSPOS ****************************/
+
+void check_transpos(float *t,dataptr dz)
+{
+	if(*t <= MIN_TRANSPOS) {
+		if(!dz->fzeroset) {
+			fprintf(stdout,"WARNING: Transposition(s) by > max permitted: adjusted.\n");
+			fflush(stdout);
+			dz->fzeroset = TRUE;
+		}
+		*t = (float)(MIN_TRANSPOS + FLTERR);
+	}
+	if(*t >= MAX_TRANSPOS) {
+		if(!dz->fzeroset) {
+			fprintf(stdout,"WARNING: Transposition(s) by > max permitted: adjusted.\n");
+			fflush(stdout);
+			dz->fzeroset = TRUE;
+		}
+		*t = (float)(MAX_TRANSPOS - 1.0);
+	}
+}
+
+/**************************** CHECK_PITCH ****************************/
+
+void check_pitch(float *t,dataptr dz)
+{
+	if(*t <= SPEC_MINFRQ) {
+		if(!dz->fzeroset) {
+			fprintf(stdout,"WARNING: Pitch(es) out of permitted range: adjusted.\n");
+			fflush(stdout);
+			dz->fzeroset = TRUE;
+		}
+		*t = (float)(SPEC_MINFRQ + FLTERR);
+	}
+	if(*t >= DEFAULT_NYQUIST) {
+		if(!dz->fzeroset) {
+			fprintf(stdout,"WARNING: Pitch(es) out of permitted range: adjusted.\n");
+			fflush(stdout);
+			dz->fzeroset = TRUE;
+		}
+		*t = (float)(DEFAULT_NYQUIST-1.0);
+	}
+}
+
+/***************************** WRITE_PITCH_OR_TRANSPOS_DATA ******************************/
+
+int write_pitch_or_transpos_data(int final_length_in_windows,dataptr dz)
+{
+	int exit_status;
+	if(final_length_in_windows > 0) {
+		if(dz->is_transpos) {
+			if((exit_status = write_exact_samps(dz->transpos,final_length_in_windows,dz))<0)
+				return(exit_status);
+		} else {
+			if((exit_status = write_exact_samps(dz->pitches,final_length_in_windows,dz))<0)
+				return(exit_status);
+		}
+	}
+	return(FINISHED);
+}
+
+/***************************** TRAP_JUNK ******************************/
+
+int trap_junk(int final_length_in_windows,dataptr dz)
+{
+	int n;
+	int caught_zero = 0, caught_skrch = 0;
+	double mintrans, maxtrans;
+	if((dz->process==P_EXAG && ODD(dz->mode)) || dz->mode==TRANSP_OUT) {	
+		/* Transposition file output */
+		maxtrans = dz->nyquist/MINPITCH;
+		mintrans = 1.0/maxtrans;
+		for(n=0;n<final_length_in_windows;n++) {
+			//if(!caught_zero && (dz->pitches[n] < mintrans && !flteq((double)dz->pitches[n],NOT_PITCH)))
+			//	caught_zero = 1;
+			/*RWD 6:2001 */
+			if(!caught_zero && (dz->transpos[n] < mintrans && !
+				    (flteq((double)dz->transpos[n],NOT_PITCH)  || flteq((double)dz->transpos[n],NOT_SOUND))))
+				caught_zero = 1;
+			if(!caught_skrch && (dz->transpos[n] > maxtrans))
+				caught_skrch = 1;
+			if(caught_zero && caught_skrch)
+				break;
+		}
+		if(caught_zero || caught_skrch) {
+			if(caught_zero)
+				sprintf(errstr,"You have generated transposition data < the minimum possible.\n");
+			if(caught_skrch)
+				sprintf(errstr,"You have generated transposition data > the maximum possible.\n");
+			return(GOAL_FAILED);
+		}
+	} else { /* Pitch file output */
+		for(n=0;n<final_length_in_windows;n++) {
+			//if(!caught_zero && (dz->pitches[n] < MINPITCH && !flteq((double)dz->pitches[n],NOT_PITCH)))
+			//	caught_zero = 1;
+			/* RWD 6:2001 trap zero windows too? */
+			if(!caught_zero && (dz->pitches[n] < MINPITCH && !
+				(flteq((double)dz->pitches[n],NOT_PITCH)  || flteq((double)dz->pitches[n],NOT_SOUND))))
+				caught_zero = 1;
+			if(!caught_skrch && (dz->pitches[n] > dz->nyquist))
+				caught_skrch = 1;
+			if(caught_zero && caught_skrch)
+				break;
+		}
+
+		if(caught_zero || caught_skrch) {
+			if(caught_zero)
+				sprintf(errstr,"You have generated pitch data below %.0lfHz.\n",MINPITCH);
+			if(caught_skrch)
+				sprintf(errstr,"You have generated pitch data above the nyquist frq.\n");
+			return(GOAL_FAILED);
+		}
+
+	}
+	return(FINISHED);
+}
+
+int pitch_insert(int is_sil,dataptr dz)
+{
+	int n, m, start, end;
+	int last_window = dz->wlength - 1;
+	int cnt = 0;
+	for(n=0;n<dz->itemcnt;n++) {
+		start = dz->lparray[0][n];		
+		end  =  dz->lparray[1][n];
+		if(start > last_window)
+			break;
+		end = min(end,last_window);
+		if(is_sil) {
+			for(m=start;m<=end;m++) {
+				dz->pitches[m] = (float)NOT_SOUND;		
+				cnt++;
+			}
+		} else {
+			for(m=start;m<=end;m++) {
+				dz->pitches[m] = (float)NOT_PITCH;		
+				cnt++;
+			}
+		}
+	}
+	if(cnt==0) {
+		sprintf(errstr,"No insertions made.\n");
+		return(GOAL_FAILED);
+	}
+	return(FINISHED);
+}
+
+int pitch_to_silence(dataptr dz)
+{
+	int n, cnt = 0;
+
+	for(n=0;n < dz->wlength;n++) {
+		if(!flteq((double)dz->pitches[n],NOT_PITCH)) {
+			dz->pitches[n] = (float)NOT_SOUND;			
+			cnt++;
+		}
+	}
+	if(cnt==0) {
+		sprintf(errstr,"No silence inserted.\n");
+		return(GOAL_FAILED);
+	}
+	return(FINISHED);
+}
+
+int unpitch_to_silence(dataptr dz)
+{
+	int n, cnt = 0;
+
+	for(n=0;n<dz->wlength;n++) {
+		if(flteq((double)dz->pitches[n],NOT_PITCH)) {
+			dz->pitches[n] = (float)NOT_SOUND;			
+			cnt++;
+		}
+	}
+	if(cnt==0) {
+		sprintf(errstr,"No silence inserted.\n");
+		return(GOAL_FAILED);
+	}
+	return(FINISHED);
+}
+
+/***************************** GET_ANAL_ENVELOPE ***********************/
+
+int get_anal_envelope(dataptr dz)
+{
+	int exit_status;
+	int samps_read, wc, windows_in_buf, samps_left;
+	double totalamp;
+	dz->flbufptr[1] = dz->flbufptr[2];
+	while((samps_read = fgetfbufEx(dz->bigfbuf,dz->big_fsize,dz->ifd[0],0)) > 0) {
+		dz->flbufptr[0] = dz->bigfbuf;
+		windows_in_buf = samps_read/dz->wanted;
+		for(wc=0; wc<windows_in_buf; wc++) {
+			if((exit_status = get_totalamp(&totalamp,dz->flbufptr[0],dz->wanted))<0)
+				return(exit_status);
+			*(dz->flbufptr[1]) = (float)totalamp;
+			if(++dz->flbufptr[1] >= dz->flbufptr[3]) {
+				dz->flbufptr[1] = dz->flbufptr[2];
+				if((exit_status = write_samps(dz->flbufptr[2],dz->big_fsize,dz))<0)
+					return(exit_status);
+			}
+			dz->flbufptr[0] += dz->wanted;
+		}
+	}  
+	if((samps_left = dz->flbufptr[1] - dz->flbufptr[2]) > 0) {
+		if((exit_status = write_samps(dz->flbufptr[2],samps_left,dz))<0)
+			return(exit_status);
+	}
+	dz->outfile->window_size = (float)(dz->frametime * SECS_TO_MS);
+	return(FINISHED);
+}
+
+/************************************ GENERATE_VOWELS ************************************/
+
+int generate_vowels(dataptr dz)
+{
+	int *vowels = dz->iparray[0];
+	double *times = dz->parray[0];
+	double startformant1, startformant2, startformant3, endformant1, endformant2, endformant3;
+	double formant1, formant2, formant3;
+	double form1step, form2step, form3step;
+	double starttime, endtime, time, timefrac, timestep, *sensitivity;
+	double thisfrq, basefrq;
+	double f3startatten, f3endatten, f3attenstep, f3atten;
+	double f2startatten, f2endatten, f2attenstep, f2atten;
+	float thisamp = (float)(VOLUME_PAD/(double)dz->clength);
+	double noisrange = 1.0 - NOISEBASE;
+	int cc, vc, exit_status, senslen, is_offset = 0;
+	int n = 0, t = 0;
+
+	if((exit_status = define_sensitivity_curve(&sensitivity,&senslen))<0)
+		return(exit_status);
+
+	if(dz->param[PV_OFFSET] > 0.0)
+		is_offset = 1;
+	dz->flbufptr[0] = dz->bigfbuf;
+	dz->wanted = dz->infile->origchans;
+
+	if((exit_status = get_formant_frqs
+	(vowels[t],&startformant1,&startformant2,&startformant3,&f2startatten,&f3startatten))<0)
+		return(exit_status);
+	starttime = times[t++];
+	if((exit_status = get_formant_frqs(vowels[t],&endformant1,&endformant2,&endformant3,&f2endatten,&f3endatten))<0)
+		return(exit_status);
+	endtime = times[t++];
+	form1step = endformant1 - startformant1;
+	form2step = endformant2 - startformant2;
+	form3step = endformant3 - startformant3;
+	f2attenstep = f2endatten - f2startatten; 
+	f3attenstep = f3endatten - f3startatten; 
+	timestep  = endtime-starttime;
+	formant1 = startformant1;	/* works if only one vowel is entered (for time zero) */
+	formant2 = startformant2;
+	formant3 = startformant3;
+	f2atten  = f2startatten;
+	f3atten  = f3startatten;
+	while(n < dz->wlength) {
+		thisfrq = dz->pitches[n];
+		if(thisfrq < 0.0){		/* NO PITCH FOUND : GENERATE NOISE */
+			if(thisfrq > NOT_SOUND) {
+				basefrq = 0.0;
+				dz->flbufptr[0][1] = (float)(drand48() * dz->halfchwidth);
+				basefrq += dz->halfchwidth;
+				for(cc = 1, vc = 2; cc < dz->clength - 1; cc++, vc += 2) {
+					dz->flbufptr[0][FREQ] = (float)((drand48() * dz->chwidth) + basefrq);
+					dz->flbufptr[0][AMPP] = (float)(thisamp * ((drand48() * noisrange) + NOISEBASE));
+					basefrq += dz->chwidth;
+				}
+				dz->flbufptr[0][FREQ] = (float)(dz->nyquist - (drand48() * dz->halfchwidth));
+				dz->flbufptr[0][AMPP] = (float)(thisamp * ((drand48() * noisrange) + NOISEBASE));
+			} else {			/* NO SOUND FOUND, GENERATE SILENCE */
+				basefrq = 0.0;
+				for(cc = 0, vc = 0; cc < dz->clength-1; cc++, vc += 2) {
+					dz->flbufptr[0][FREQ] = (float)basefrq;
+					dz->flbufptr[0][AMPP] = 0.0f;
+					basefrq += dz->chwidth;
+				}
+				dz->flbufptr[0][FREQ] = (float)dz->nyquist;
+				dz->flbufptr[0][AMPP] = 0.0f;
+			}
+		} else {				/* GENERATE VOWEL */
+			basefrq = 0.0;
+			for(cc = 0, vc = 0; cc < dz->clength-1; cc++, vc += 2) {
+				dz->flbufptr[0][AMPP] = 0.0f;
+				dz->flbufptr[0][FREQ] = (float)basefrq;	 /* default frq, overwritten by vowel partials */
+				basefrq += dz->chwidth;
+			}
+			dz->flbufptr[0][AMPP] = 0.0f;
+			dz->flbufptr[0][FREQ] = (float)dz->nyquist;
+			if(dz->itemcnt) {
+				time = n * dz->frametime;
+				while(time >= endtime) {	  	/* advance along vowels */
+					startformant1 = endformant1;
+					startformant2 = endformant2;
+					startformant3 = endformant3;
+					f2startatten  = f2endatten;
+					f3startatten  = f3endatten;
+					starttime = endtime;
+					if(t < dz->itemcnt) {
+						if((exit_status = get_formant_frqs(vowels[t],&endformant1,&endformant2,&endformant3,&f2endatten,&f3endatten))<0)
+							return(exit_status);
+						endtime = times[t++];
+					} else
+						break;
+					form1step = endformant1 - startformant1;
+					form2step = endformant2 - startformant2;
+					form3step = endformant3 - startformant3;
+					f2attenstep = f2endatten - f2startatten; 
+					f3attenstep = f3endatten - f3startatten; 
+					timestep  = endtime-starttime;
+				}
+				if(!flteq(starttime,endtime)) {			   		/* interpolate between vowels : or retain last vowel */
+					timefrac = (time - starttime)/timestep;
+					formant1 = startformant1 + (form1step * timefrac);
+					formant2 = startformant2 + (form2step * timefrac);
+					formant3 = startformant3 + (form3step * timefrac);
+					f2atten  = f2startatten  + (f2attenstep * timefrac);
+					f3atten  = f3startatten  + (f3attenstep * timefrac);
+				}
+			}
+			if((exit_status = generate_vowel_spectrum
+			(thisfrq,formant1,formant2,formant3,f2atten,f3atten,sensitivity,senslen,is_offset,dz)) <0)
+				return(exit_status);
+		}
+		if((dz->flbufptr[0] += dz->wanted) >= dz->flbufptr[1]) {
+			if((exit_status = write_samps(dz->bigfbuf,dz->big_fsize,dz))<0)
+				return(exit_status);
+			dz->flbufptr[0] = dz->bigfbuf;
+		}
+		n++;
+	}
+	if(dz->flbufptr[0] != dz->bigfbuf) {
+		if((exit_status = write_samps(dz->bigfbuf,dz->flbufptr[0] - dz->bigfbuf,dz))<0)
+			return(exit_status);
+	}
+	return(FINISHED);
+}
+		
+/************************************ DEFINE_SENSITIVITY_CURVE ************************************
+ *
+ * approximate compensation for aural sensitivity 
+ */
+
+#define	LOFRQ_BOOST		(2.511)		/* 8dB  */
+#define	HIFRQ_LOSS		(0.4)		/* -8dB */
+
+#define	LOFRQ_FOOT		(250.0)
+#define	MIDFRQSHELF_BOT	(2000.0)
+#define	MIDFRQSHELF_TOP	(3000.0)
+#define	HIFRQ_FOOT		(4000.0)
+#define	TOP_OF_SPECTRUM	(96000.0)	/* double maximum nyquist (i.e. >nyquist: for safety margin)  */
+
+int define_sensitivity_curve(double **sensitivity,int *senslen)
+{
+	int arraysize = BIGARRAY;
+	double *p;
+	int n = 0;
+
+	if((*sensitivity = (double *)malloc(arraysize * sizeof(double)))==NULL) {
+		sprintf(errstr,"INSUFFICIENT MEMORY for time data.\n");
+		return(MEMORY_ERROR);
+	}
+	p = *sensitivity;
+	*p++ = 0.0;				*p++ = 1.0;						n+= 2;	/* everything must be in 0-1 range */
+	*p++ = LOFRQ_FOOT;		*p++ = 1.0;						n+= 2;	/* for pow() calculations to work, later */
+	*p++ = MIDFRQSHELF_BOT;	*p++ = 1.0/LOFRQ_BOOST;			n+= 2;
+	*p++ = MIDFRQSHELF_TOP;	*p++ = 1.0/LOFRQ_BOOST;			n+= 2;
+	*p++ = HIFRQ_FOOT;		*p++ = HIFRQ_LOSS/LOFRQ_BOOST;	n+= 2;
+	*p++ = TOP_OF_SPECTRUM;	*p++ = HIFRQ_LOSS/LOFRQ_BOOST;	n+= 2;
+
+	if((*sensitivity = (double *)realloc((char *)(*sensitivity),n * sizeof(double)))==NULL) {
+		sprintf(errstr,"INSUFFICIENT MEMORY for sensitivity curve.\n");
+		return(MEMORY_ERROR);
+	}
+	*senslen = n;
+	return(FINISHED);
+}
+
+/************************************ GET_FORMANT_FRQS ************************************/
+
+int get_formant_frqs
+(int vowel,double *formant1, double *formant2, double *formant3, double *f2atten, double *f3atten)
+{
+	switch(vowel) {
+	case(VOWEL_EE):	*formant1= EE_FORMANT1;	*formant2= EE_FORMANT2;	*formant3= EE_FORMANT3;	
+	/* heed  */								*f2atten = EE_F2ATTEN;	*f3atten = EE_F3ATTEN;
+					break;
+	case(VOWEL_I):	*formant1= I_FORMANT1;	*formant2= I_FORMANT2;	*formant3= I_FORMANT3;
+	/* hid  */								*f2atten = I_F2ATTEN;	*f3atten = I_F3ATTEN;
+					break;
+	case(VOWEL_AI):	*formant1= AI_FORMANT1;	*formant2= AI_FORMANT2;	*formant3= AI_FORMANT3;	
+	/* maid  */								*f2atten = AI_F2ATTEN;	*f3atten = AI_F3ATTEN;
+					break;
+	case(VOWEL_AII): *formant1= AII_FORMANT1;	*formant2= AII_FORMANT2;	*formant3= AII_FORMANT3;	
+	/* scottish educAted  */				*f2atten = AII_F2ATTEN;	*f3atten = AII_F3ATTEN;
+					break;
+	case(VOWEL_E):	*formant1= E_FORMANT1;	*formant2= E_FORMANT2;	*formant3= E_FORMANT3;	
+	/* head  */								*f2atten = E_F2ATTEN;	*f3atten = E_F3ATTEN;
+					break;
+	case(VOWEL_A):	*formant1= A_FORMANT1;	*formant2= A_FORMANT2;	*formant3= A_FORMANT3;	
+	/* had  */								*f2atten = A_F2ATTEN;	*f3atten = A_F3ATTEN;
+					break;
+	case(VOWEL_AR):	*formant1= AR_FORMANT1;	*formant2= AR_FORMANT2;	*formant3= AR_FORMANT3;	
+	/* hard  */								*f2atten = AR_F2ATTEN;	*f3atten = AR_F3ATTEN;
+					break;
+	case(VOWEL_O):	*formant1= O_FORMANT1;	*formant2= O_FORMANT2;	*formant3= O_FORMANT3;	
+	/* hod  */								*f2atten = O_F2ATTEN;	*f3atten = O_F3ATTEN;
+					break;
+	case(VOWEL_OR):	*formant1= OR_FORMANT1;	*formant2= OR_FORMANT2;	*formant3= OR_FORMANT3;	
+	/* hoard  */							*f2atten = OR_F2ATTEN;	*f3atten = OR_F3ATTEN;
+					break;
+	case(VOWEL_OA):	*formant1= OA_FORMANT1;	*formant2= OA_FORMANT2;	*formant3= OA_FORMANT3;	
+	/* load (North of England)  */			*f2atten = OA_F2ATTEN;	*f3atten = OA_F3ATTEN;
+					break;
+	case(VOWEL_U):	*formant1= U_FORMANT1;	*formant2= U_FORMANT2;	*formant3= U_FORMANT3;	
+	/* hood, mud (Norht of England)  */		*f2atten = U_F2ATTEN;	*f3atten = U_F3ATTEN;
+					break;
+	case(VOWEL_UU):	*formant1= UU_FORMANT1;	*formant2= UU_FORMANT2;	*formant3= UU_FORMANT3;	
+	/* Scottish edUcated  */				*f2atten = UU_F2ATTEN;	*f3atten = UU_F3ATTEN;
+					break;
+	case(VOWEL_UI):	*formant1= UI_FORMANT1;	*formant2= UI_FORMANT2;	*formant3= UI_FORMANT3;	
+	/* Scottish 'could'  */					*f2atten = UI_F2ATTEN;	*f3atten = UI_F3ATTEN;
+					break;
+	case(VOWEL_OO):	*formant1= OO_FORMANT1;	*formant2= OO_FORMANT2;	*formant3= OO_FORMANT3;	
+	/* mood  */								*f2atten = OO_F2ATTEN;	*f3atten = OO_F3ATTEN;
+					break;
+	case(VOWEL_XX):	*formant1= XX_FORMANT1;	*formant2= XX_FORMANT2;	*formant3= XX_FORMANT3;	
+	/* mud (South of England)  */			*f2atten = XX_F2ATTEN;	*f3atten = XX_F3ATTEN;
+					break;
+	case(VOWEL_X):	*formant1= X_FORMANT1;	*formant2= X_FORMANT2;	*formant3 = X_FORMANT3;	
+	/* the, herd  */						*f2atten = X_F2ATTEN;	*f3atten = X_F3ATTEN;
+					break;
+	case(VOWEL_N):	*formant1= N_FORMANT1;	*formant2= N_FORMANT2;	*formant3 = N_FORMANT3;	
+	/* 'n'  */								*f2atten = N_F2ATTEN;	*f3atten = N_F3ATTEN;
+					break;
+	case(VOWEL_M):	*formant1= M_FORMANT1;	*formant2= M_FORMANT2;	*formant3 = M_FORMANT3;	
+	/* 'm' */								*f2atten = M_F2ATTEN;	*f3atten = M_F3ATTEN;
+					break;
+	case(VOWEL_R):	*formant1= R_FORMANT1;	*formant2= R_FORMANT2;	*formant3 = R_FORMANT3;	
+	/* dRaws  */							*f2atten = R_F2ATTEN;	*f3atten = R_F3ATTEN;
+					break;
+	case(VOWEL_TH):	*formant1= TH_FORMANT1;	*formant2= TH_FORMANT2;	*formant3 = TH_FORMANT3;	
+	/* dRaws  */							*f2atten = TH_F2ATTEN;	*f3atten = TH_F3ATTEN;
+					break;
+	default:
+		sprintf(errstr,"Unknown vowel\n");
+		return(PROGRAM_ERROR);
+	}
+	return(FINISHED);
+}
+
+/************************************ GENERATE_VOWEL_SPECTRUM ************************************
+ *
+ * "sensitivity" compensates for frq sensitivity of ear at low end, and attenuates
+ * formant bamds above c3500.
+ */
+
+int generate_vowel_spectrum(double frq,double formant1,double formant2,double formant3,double f2atten,double f3atten,
+							double *sensitivity,int senslen,int is_offset,dataptr dz)
+
+{	
+	double hfwidth1, hfwidth2, hfwidth3 = 0.0, lolim1, lolim2, lolim3 = 0.0, hilim1, hilim2, hilim3 = 0.0;
+	double basefrq = frq, harmfrq = basefrq, thisfrq = basefrq, frq_offset;
+	double amp, amp2 = 0.0, amp3 = 0.0, totamp = 0.0;
+	int exit_status, cc, vc;
+	int overlapped_formants12 = 0, overlapped_formants23 = 0, overlapped_formants13 = 0;
+	int is_overlap12, is_overlap23, is_overlap13;
+	double toplim;
+	int is_third_formant = 0;
+	double signal_base = 1.0 - dz->param[PV_PKRANG];
+
+	if(formant3 > 0.0)
+		is_third_formant = 1;
+	hfwidth1 = formant1 * dz->param[PV_HWIDTH];	/* set limits of formant bands */
+	lolim1  = formant1 - hfwidth1;
+	hilim1  = formant1 + hfwidth1;
+	hfwidth2 = formant2 * dz->param[PV_HWIDTH];
+	lolim2  = formant2 - hfwidth2;
+	hilim2  = formant2 + hfwidth2;
+	if(is_third_formant) {
+		hfwidth3 = formant3 * dz->param[PV_HWIDTH];
+		lolim3  = formant3 - hfwidth3;
+		hilim3  = formant3 + hfwidth3;
+	}
+
+ 	if(hilim1 > lolim2)		/* deal with overlapping formants */
+		overlapped_formants12 = 1;
+	if(is_third_formant) {	
+		if(hilim2 > lolim3)
+			overlapped_formants23 = 1;
+		if(hilim1 > lolim3)
+			overlapped_formants13 = 1;
+	}
+	if(is_third_formant)
+		toplim =  hilim3;
+	else
+		toplim =  hilim2;
+	while(thisfrq < toplim) {
+		amp = 0.0;					/* amplitude will get signal_base * sensitivity */
+		is_overlap12 = 0;
+		is_overlap23 = 0;
+		is_overlap13 = 0;
+		if(thisfrq < lolim1) {
+			if(flteq(thisfrq,basefrq))
+				amp = dz->param[PV_FUNBAS];
+		} else if((thisfrq > lolim1) && (thisfrq < hilim1)) {
+ 			if(overlapped_formants12 && (thisfrq > lolim2)) {
+				is_overlap12 = 1;
+				if(thisfrq >= formant2)
+					amp2 = (hilim2 - thisfrq)/hfwidth2;
+				else
+					amp2 = (thisfrq - lolim2)/hfwidth2;
+				amp2 *= f2atten;
+			}
+			if(is_third_formant) {
+				if(overlapped_formants13 && (thisfrq > lolim3)) {
+					is_overlap13 = 1;
+					if(thisfrq >= formant3)
+						amp3 = (hilim3 - thisfrq)/hfwidth3;
+					else
+						amp3 = (thisfrq - lolim3)/hfwidth3;
+					amp3 *= f3atten;
+				}
+			}
+			if(thisfrq >= formant1)
+				amp = (hilim1 - thisfrq)/hfwidth1;
+			else
+				amp = (thisfrq - lolim1)/hfwidth1;
+			if(is_overlap12)
+				amp = max(amp,amp2);
+			if(is_third_formant && is_overlap13)
+				amp = max(amp,amp3);
+		} else if((thisfrq > lolim2) && (thisfrq < hilim2)) {
+			if(is_third_formant && overlapped_formants23 && (thisfrq > lolim3)) {
+				is_overlap23 = 1;
+				if(thisfrq >= formant3)
+					amp3 = (hilim3 - thisfrq)/hfwidth3;
+				else
+					amp3 = (thisfrq - lolim3)/hfwidth3;
+				amp3 *= f3atten;
+			}
+			if(thisfrq >= formant2)
+				amp = (hilim2 - thisfrq)/hfwidth2;
+			else
+				amp = (thisfrq - lolim2)/hfwidth2;
+			amp *= f2atten;
+
+			if(is_third_formant && is_overlap23)
+				amp = max(amp,amp3);
+		} else if(is_third_formant && (thisfrq > lolim3)) {
+			if(thisfrq >= formant3)
+				amp = (hilim3 - thisfrq)/hfwidth3;
+			else
+				amp = (thisfrq - lolim3)/hfwidth3;
+			amp *= f3atten;
+		}
+		amp = pow(amp,dz->param[PV_CURVIT]);
+		amp *= dz->param[PV_PKRANG];
+		amp += signal_base;
+		if((exit_status = adjust_for_sensitivity(&amp,(double)thisfrq,sensitivity,senslen))<0)
+			return(exit_status);
+		cc = (int)((thisfrq + dz->halfchwidth)/dz->chwidth);
+		vc = cc * 2;
+		dz->flbufptr[0][AMPP] = (float)amp;
+		dz->flbufptr[0][FREQ] = (float)thisfrq;
+		totamp += amp;
+		if(is_offset) {
+			harmfrq += basefrq; 
+			frq_offset = (drand48() - .5) * dz->param[PV_OFFSET] * basefrq;
+			if(harmfrq + frq_offset > dz->nyquist)
+				thisfrq = harmfrq - frq_offset;
+			else
+				thisfrq = harmfrq + frq_offset;
+		} else
+			thisfrq += basefrq;
+		if(thisfrq > dz->nyquist) {
+			sprintf(errstr,"Error in setting formant: overran nyquist\n");
+			return(PROGRAM_ERROR);
+		}
+	}
+	if((exit_status = normalise(VOLUME_PAD,totamp,dz))<0)
+		return(exit_status);
+	return(FINISHED);
+}
+
+/************************************ ADJUST_FOR_SENSITIVITY ************************************/
+
+int adjust_for_sensitivity(double *amp,double frq,double *sensitivity,int senslen)
+{
+	int n = 0;
+	double multiplier, losensfrq, hisensfrq, losens, hisens, frqfrac, sensstep;
+
+	while(frq > sensitivity[n]) {
+		n += 2;
+		if(n > senslen) {
+			sprintf(errstr,"Failed to find sensitivity value (1)\n");
+			return(PROGRAM_ERROR);
+		}
+	}
+	hisensfrq = sensitivity[n]; 
+	n -= 2;
+	if(n < 0) {
+		sprintf(errstr,"Failed to find sensitivity value (2)\n");
+		return(PROGRAM_ERROR);
+	}
+	losensfrq = sensitivity[n]; 
+	frqfrac = (frq - losensfrq)/(hisensfrq - losensfrq);
+	n++;
+	losens = sensitivity[n];
+	n += 2;
+	if(n >= senslen) {
+		sprintf(errstr,"Failed to find sensitivity value (3)\n");
+		return(PROGRAM_ERROR);
+	}
+	hisens = sensitivity[n];
+	sensstep = hisens - losens;
+
+	multiplier = losens + (sensstep * frqfrac);
+	* amp *= multiplier;
+	return(FINISHED);
+}
+
+/************************************ GENERATE_PITCH ************************************/
+
+int generate_pitch(dataptr dz)
+{
+	double *times = dz->parray[0];
+	double *pitch = dz->parray[1];
+	double startpitch, endpitch, pitchstep, thispitch;
+	double starttime, endtime, time, timefrac, timestep;
+	int n = 0, m = 0, samps_written;
+
+	if((dz->pitches = (float *)malloc(dz->wlength * sizeof(float)))==NULL) {
+		sprintf(errstr,"Insufficient memory to store pitch data\n");
+		return(MEMORY_ERROR);
+	}
+	starttime  = times[m];
+	startpitch = pitch[m];
+	m++;
+	endtime  = times[m];
+	endpitch = pitch[m];
+	m++;
+	pitchstep = endpitch - startpitch;
+	timestep  = endtime - starttime;
+	while(n < dz->wlength) {
+		time = n * dz->frametime;
+		while(time >= endtime) {	  	/* advance along (MIDI) pitches */
+			startpitch = endpitch;
+			starttime  = endtime;
+			if(m < dz->itemcnt) {
+				endtime  = times[m];
+				endpitch = pitch[m];
+				m++;
+			} else
+				break;
+		}
+		if(!flteq(starttime,endtime)) {			   		/* interpolate between pitches : or retain last pitches */
+			pitchstep = endpitch - startpitch;
+			timestep  = endtime - starttime;
+			timefrac  = (time - starttime)/timestep;
+			thispitch = (pitchstep * timefrac) + startpitch;
+		} else
+			thispitch = startpitch;
+		dz->pitches[n++] = (float)miditohz(thispitch);
+	}
+	dz->is_transpos = 0;	
+	return write_samps_no_report(dz->pitches,dz->wlength,&samps_written,dz);
+}
+
+/********************** REMOVE_PITCH_ZEROS *********************
+ *
+ * This function removes pitch zeroes (and si;ences) by interpolation.
+ */
+
+int remove_pitch_zeros(dataptr dz)
+{
+	int gotglitch = FALSE, gstart = -1;
+	double pstep, pstartval = 0.0;
+	int n, m;
+	for(n=0;n<dz->wlength;n++) {
+		if(gotglitch) {
+			if(dz->pitches[n] < MINPITCH)
+				continue;
+			if(gstart<0) {
+				for(m=0; m < n; m++)				   /* Interp to start if ness */
+					dz->pitches[m] = dz->pitches[n];
+			} else {								   /* Interp between good vals */
+				switch(dz->mode) {
+				case(PI_GLIDE):
+					pstep = (dz->pitches[n] - pstartval)/(double)(n - gstart);
+					for(m=gstart+1; m < n; m++) {
+						pstartval += pstep;
+						dz->pitches[m] = (float)pstartval;
+					}						
+					break;
+				case(PI_SUSTAIN):
+					for(m=gstart+1; m < n; m++)
+						dz->pitches[m] = (float)pstartval;
+					break;
+				}
+			}
+			gotglitch = 0;
+		} else {
+			if(dz->pitches[n] >= MINPITCH)
+				continue;
+			gstart = n-1;							
+			if(gstart >= 0)
+				pstartval = (double)dz->pitches[gstart];
+			gotglitch = 1;
+		}					
+	}
+	if(gotglitch) {
+		if(gstart < 0) {
+			sprintf(errstr,"No pitched data found.");
+			return(GOAL_FAILED);
+		}
+		for(m=gstart+1; m < n; m++)					   /* Interp to end if ness */
+			dz->pitches[m] = (float)pstartval;
+	}
+	return(FINISHED);
+}
+
+/*************************** CONVERT_PITCH_FROM_BINARY_TO_TEXT **************************/
+
+int convert_pitch_from_binary_to_text(dataptr dz)
+{
+	int exit_status;
+	int brklen, n, m;
+
+	if((dz->parray[0] = malloc(((dz->wlength + 1) * 2) * sizeof(double)))==NULL) {
+		sprintf(errstr,"INSUFFICIENT MEMORY FOR TEXT DATA\n");
+		return MEMORY_ERROR;
+	}
+	if((exit_status = interpolate_pitch(dz->pitches,0,dz))<0)
+		return(exit_status);
+	if(dz->wlength == 1) {
+		if((exit_status = convert_single_window_pch_or_transpos_data_to_brkpnttable(&brklen,dz->pitches,dz->frametime,0,dz))<0)
+			return(exit_status);
+	} else {
+		if((exit_status = convert_pch_or_transpos_data_to_brkpnttable(&brklen,dz->pitches,dz->frametime,0,dz))<0)
+			return(exit_status);
+	}
+	for(n=0,m=0;n<brklen;n++,m+=2)
+		fprintf(dz->fp,"%lf\t%lf\n",dz->parray[0][m],dz->parray[0][m+1]);
+	return(FINISHED);
+}
+
+/***************** CONVERT_SINGLE_WINDOW_PCH_OR_TRANSPOS_DATA_TO_BRKPNTTABLE ***********************/
+
+int convert_single_window_pch_or_transpos_data_to_brkpnttable(int *brksize,float *floatbuf,float frametime,int array_no,dataptr dz)
+{
+	double *q;
+	float *p = floatbuf;
+	int bsize;
+
+	q = dz->parray[array_no];
+	*q++ = 0.0;
+	*q++ = (double)*p++;
+	bsize = q - dz->parray[array_no];
+
+	if((dz->parray[array_no] = (double *)realloc((char *)dz->parray[array_no],bsize*sizeof(double)))==NULL) {
+		sprintf(errstr,"convert_single_window_pch_or_transpos_data_to_brkpnttable()\n");
+		return(MEMORY_ERROR);
+	}
+	*brksize = bsize/2;
+	return(FINISHED);
+}
+