Browse Source

initial commit

richarddobson 3 years ago
parent
commit
d35aa6c47b

+ 20 - 0
dev/strange/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(strange main.c ap_strange.c strange.c)
+
+target_link_libraries(strange cdp2k sfsys ${EXTRA_LIBRARIES})
+
+my_install(strange)
+

+ 829 - 0
dev/strange/ap_strange.c

@@ -0,0 +1,829 @@
+/*
+ * 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 <strange.h>
+#include <processno.h>
+#include <modeno.h>
+#include <globcon.h>
+#include <logic.h>
+#include <filetype.h>
+#include <mixxcon.h>
+#include <speccon.h>
+#include <flags.h>
+#include <arrays.h>
+#include <formants.h>
+#include <sfsys.h>
+#include <osbind.h>
+#include <string.h>
+#include <math.h>
+#include <srates.h>
+
+/********************************************************************************************/
+/********************************** FORMERLY IN buffers.c ***********************************/
+/********************************************************************************************/
+
+static int 	allocate_warp_buffer(dataptr dz);
+
+/********************************************************************************************/
+/********************************** FORMERLY IN preprocess.c ********************************/
+/********************************************************************************************/
+
+#define	ROLL_OFF	(500.0)
+static int  setup_internal_arrays_for_specshift(dataptr dz);
+static int  establish_internal_params_for_glis(dataptr dz);
+static int  setup_internal_arrays_for_waver(dataptr dz);
+static int  setup_array_of_botfrq_of_each_channel(int *botchan,dataptr dz);
+static int  warp_preprocess(dataptr dz);
+static int  convert_params_for_warp(dataptr dz);
+static int  setup_internal_arrays_and_params_for_specwarp(dataptr dz);
+static int  convert_pitchdata_to_midi_for_warp(dataptr dz);
+static int  invert_preprocess(dataptr dz);
+static int  setup_internal_arrays_for_invert(dataptr dz);
+static int  extract_normalising_criteria_by_reading_infile(dataptr dz);
+
+/***************************************************************************************/
+/****************************** FORMERLY IN aplinit.c **********************************/
+/***************************************************************************************/
+
+/***************************** ESTABLISH_BUFPTRS_AND_EXTRA_BUFFERS **************************/
+
+int establish_bufptrs_and_extra_buffers(dataptr dz)
+{
+	int exit_status;
+	int is_spec = FALSE;
+	dz->extra_bufcnt = -1;	/* ENSURE EVERY CASE HAS A PAIR OF ENTRIES !! */
+	dz->bptrcnt = 0;
+	dz->bufcnt  = 0;
+	switch(dz->process) {
+	case(SHIFT):      		dz->extra_bufcnt =  0; dz->bptrcnt = 1; 	is_spec = TRUE;		break;
+	case(GLIS):       		dz->extra_bufcnt =  0; dz->bptrcnt = 1; 	is_spec = TRUE;		break;
+	case(WAVER):      		dz->extra_bufcnt =  0; dz->bptrcnt = 1; 	is_spec = TRUE;		break;
+	case(WARP):	      		dz->extra_bufcnt =  1; dz->bptrcnt = 7; 	is_spec = TRUE;		break;
+	case(INVERT):     		dz->extra_bufcnt =  0; dz->bptrcnt = 1; 	is_spec = TRUE;		break;	
+	default:
+		sprintf(errstr,"Unknown program type [%d] in establish_bufptrs_and_extra_buffers()\n",dz->process);
+		return(PROGRAM_ERROR);
+	}
+
+	if(dz->extra_bufcnt < 0) {
+		sprintf(errstr,"bufcnts have not been set: establish_bufptrs_and_extra_buffers()\n");
+		return(PROGRAM_ERROR);
+	}
+	if(is_spec)
+		return establish_spec_bufptrs_and_extra_buffers(dz);
+	else if((dz->process==HOUSE_SPEC && dz->mode==HOUSE_CONVERT) || dz->process==INFO_DIFF) {
+		if((exit_status = establish_spec_bufptrs_and_extra_buffers(dz))<0)
+			return(exit_status);
+	}
+	return establish_groucho_bufptrs_and_extra_buffers(dz);
+}
+
+/***************************** SETUP_INTERNAL_ARRAYS_AND_ARRAY_POINTERS **************************/
+
+int setup_internal_arrays_and_array_pointers(dataptr dz)
+{
+	int n;		 
+	dz->ptr_cnt    = -1;		/* base constructor...process */
+	dz->array_cnt  = -1;
+	dz->iarray_cnt = -1;
+	dz->larray_cnt = -1;
+	switch(dz->process) {
+	case(SHIFT):  	dz->array_cnt =2;  dz->iarray_cnt =2;  dz->larray_cnt = 0; dz->ptr_cnt = 0; dz->fptr_cnt = 0;	break;
+	case(GLIS):   	dz->array_cnt = 0; dz->iarray_cnt = 0; dz->larray_cnt = 0; dz->ptr_cnt = 0; dz->fptr_cnt = 0;	break;
+	case(WAVER):  	dz->array_cnt =1;  dz->iarray_cnt = 0; dz->larray_cnt = 0; dz->ptr_cnt = 0; dz->fptr_cnt = 0;	break;
+	case(WARP):   	dz->array_cnt =2;  dz->iarray_cnt =1;  dz->larray_cnt = 0; dz->ptr_cnt = 0; dz->fptr_cnt = 0;	break; 	
+	case(INVERT): 	dz->array_cnt =1;  dz->iarray_cnt = 0; dz->larray_cnt = 0; dz->ptr_cnt = 0; dz->fptr_cnt = 0;	break;
+	}
+
+/*** WARNING ***
+ANY APPLICATION DEALING WITH A NUMLIST INPUT: MUST establish AT LEAST 1 double array: i.e. dz->array_cnt = at least 1
+**** WARNING ***/
+
+
+	if(dz->array_cnt < 0 || dz->iarray_cnt < 0 || dz->larray_cnt < 0 || dz->ptr_cnt < 0 || dz->fptr_cnt < 0) {
+		sprintf(errstr,"array_cnt not set in setup_internal_arrays_and_array_pointers()\n");	   
+		return(PROGRAM_ERROR);
+	}
+
+	if(dz->array_cnt > 0) {  
+		if((dz->parray  = (double **)malloc(dz->array_cnt * sizeof(double *)))==NULL) {
+			sprintf(errstr,"INSUFFICIENT MEMORY for internal double arrays.\n");
+			return(MEMORY_ERROR);
+		}
+		for(n=0;n<dz->array_cnt;n++)
+			dz->parray[n] = NULL;
+	}
+	if(dz->iarray_cnt > 0) {
+		if((dz->iparray = (int     **)malloc(dz->iarray_cnt * sizeof(int *)))==NULL) {
+			sprintf(errstr,"INSUFFICIENT MEMORY for internal int arrays.\n");
+			return(MEMORY_ERROR);
+		}
+		for(n=0;n<dz->iarray_cnt;n++)
+			dz->iparray[n] = NULL;
+	}
+	if(dz->larray_cnt > 0) {	  
+		if((dz->lparray = (int    **)malloc(dz->larray_cnt * sizeof(int *)))==NULL) {
+			sprintf(errstr,"INSUFFICIENT MEMORY for internal long arrays.\n");
+			return(MEMORY_ERROR);
+		}
+		for(n=0;n<dz->larray_cnt;n++)
+			dz->lparray[n] = NULL;
+	}
+	if(dz->ptr_cnt > 0)   {  	  
+		if((dz->ptr    	= (double  **)malloc(dz->ptr_cnt  * sizeof(double *)))==NULL) {
+			sprintf(errstr,"INSUFFICIENT MEMORY for internal pointer arrays.\n");
+			return(MEMORY_ERROR);
+		}
+		for(n=0;n<dz->ptr_cnt;n++)
+			dz->ptr[n] = NULL;
+	}
+	if(dz->fptr_cnt > 0)   {  	  
+		if((dz->fptr = (float  **)malloc(dz->fptr_cnt * sizeof(float *)))==NULL) {
+			sprintf(errstr,"INSUFFICIENT MEMORY for internal float-pointer arrays.\n");
+			return(MEMORY_ERROR);
+		}
+		for(n=0;n<dz->fptr_cnt;n++)
+			dz->fptr[n] = NULL;
+	}
+	return(FINISHED);
+}
+
+/****************************** ASSIGN_PROCESS_LOGIC *********************************/
+
+int assign_process_logic(dataptr dz)
+{						 
+	switch(dz->process) {
+	case(SHIFT):		setup_process_logic(ANALFILE_ONLY,		  	EQUAL_ANALFILE,		ANALFILE_OUT,	dz);	break;
+	case(GLIS):			setup_process_logic(ANALFILE_ONLY,		  	EQUAL_ANALFILE,		ANALFILE_OUT,	dz);	break;
+	case(WAVER):		setup_process_logic(ANALFILE_ONLY,		  	EQUAL_ANALFILE,		ANALFILE_OUT,	dz);	break;
+	case(WARP):		  	setup_process_logic(ANAL_WITH_PITCHDATA,  	BIG_ANALFILE,		ANALFILE_OUT,	dz);	break;
+	case(INVERT):		setup_process_logic(ANALFILE_ONLY,		  	EQUAL_ANALFILE,		ANALFILE_OUT,	dz);	break;
+	default:
+		sprintf(errstr,"Unknown process: assign_process_logic()\n");
+		return(PROGRAM_ERROR);
+		break;
+	}
+	if(dz->has_otherfile) {
+		switch(dz->input_data_type) {
+		case(ALL_FILES):
+		case(TWO_SNDFILES):
+		case(SNDFILE_AND_ENVFILE):
+		case(SNDFILE_AND_BRKFILE):
+		case(SNDFILE_AND_UNRANGED_BRKFILE):
+		case(SNDFILE_AND_DB_BRKFILE):
+			break;
+		case(MANY_SNDFILES):
+			if(dz->process==INFO_TIMELIST)
+				break;
+			/* fall thro */
+		default:
+			sprintf(errstr,"Most processes accepting files with different properties\n"
+						   "can only take 2 sound infiles.\n");
+			return(PROGRAM_ERROR);
+		}
+	}
+	return(FINISHED);
+}
+
+/***************************** SET_LEGAL_INFILE_STRUCTURE **************************
+ *
+ * Allows 2nd infile to have different props to first infile.
+ */
+
+void set_legal_infile_structure(dataptr dz)
+{
+	switch(dz->process) {
+	default:
+		dz->has_otherfile = FALSE;
+		break;
+	}
+}
+
+/***************************************************************************************/
+/****************************** FORMERLY IN internal.c *********************************/
+/***************************************************************************************/
+
+/****************************** SET_LEGAL_INTERNALPARAM_STRUCTURE *********************************/
+
+int set_legal_internalparam_structure(int process,int mode,aplptr ap)
+{
+	int exit_status = FINISHED;
+	switch(process) {
+	case(SHIFT):	  	return(FINISHED);
+	case(GLIS):		  	exit_status = set_internalparam_data("ddddddd",ap);				break;
+	case(WAVER):      	exit_status = set_internalparam_data("ii",ap);					break;
+	case(WARP):		  	exit_status = set_internalparam_data("iii",ap);					break;
+	case(INVERT):	  	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)	   
+{
+	aplptr ap = dz->application;
+	switch(ap->special_data) {
+	default:
+		sprintf(errstr,"Unknown special_data type: read_special_data()\n");
+		return(PROGRAM_ERROR);
+	}
+	return(FINISHED);	/* NOTREACHED */
+}
+
+/********************************************************************************************/
+/********************************** FORMERLY IN preprocess.c ********************************/
+/********************************************************************************************/
+
+/****************************** PARAM_PREPROCESS *********************************/
+
+int param_preprocess(dataptr dz)	
+{
+	switch(dz->process) {
+	case(SHIFT):		return setup_internal_arrays_for_specshift(dz);
+	case(GLIS):			return establish_internal_params_for_glis(dz);
+	case(WAVER):		return setup_internal_arrays_for_waver(dz);
+	case(WARP):			return warp_preprocess(dz);	
+	case(INVERT):		return invert_preprocess(dz);
+	default:
+		sprintf(errstr,"PROGRAMMING PROBLEM: Unknown process in param_preprocess()\n");
+		return(PROGRAM_ERROR);
+	}
+	return(FINISHED);	/* NOTREACHED */
+}
+
+/************ SETUP_INTERNAL_ARRAYS_FOR_SPECSHIFT *************/
+
+int setup_internal_arrays_for_specshift(dataptr dz)
+{
+	int n;
+	if((dz->iparray[SHIFT_OVER]  = (int *)malloc(dz->clength * sizeof(int)))==NULL) {
+		sprintf(errstr,"INSUFFICIENT MEMORY for shift over array.\n");
+		return(MEMORY_ERROR);
+	}
+	if((dz->iparray[SHIFT_DONE]  = (int *)malloc(dz->clength * sizeof(int)))==NULL) {
+		sprintf(errstr,"INSUFFICIENT MEMORY for shift done array.\n");
+		return(MEMORY_ERROR);
+	}
+	if((dz->parray[SHIFT_CHTOP]  
+		= (double *)malloc(dz->clength * sizeof(double)))==NULL) {
+		sprintf(errstr,"INSUFFICIENT MEMORY for shift channel top array.\n");
+		return(MEMORY_ERROR);
+	}
+	if((dz->parray[SHIFT_CHMID]  
+		= (double *)malloc(dz->clength * sizeof(double)))==NULL) {
+		sprintf(errstr,"INSUFFICIENT MEMORY for shift channel mid array.\n");
+		return(MEMORY_ERROR);
+	}
+	dz->parray[SHIFT_CHTOP][0] = dz->halfchwidth;
+	dz->parray[SHIFT_CHMID][0] = 0.0;
+	for(n = 1;n < dz->clength; n++) {
+		dz->parray[SHIFT_CHTOP][n] = dz->parray[SHIFT_CHTOP][n-1] + dz->chwidth;
+		dz->parray[SHIFT_CHMID][n] = dz->parray[SHIFT_CHMID][n-1] + dz->chwidth;
+	}
+	dz->parray[SHIFT_CHMID][0] = 1.0;	 /* arbitrary, but NOT zero!! */
+	return(FINISHED);
+}
+
+/********************** ESTABLISH_INTERNAL_PARAMS_FOR_GLIS **********************/
+
+int establish_internal_params_for_glis(dataptr dz)
+{
+	dz->param[GLIS_CONVERTOR] = dz->frametime/SEMITONES_PER_OCTAVE;
+	if(dz->brksize[GLIS_RATE]==0)
+		dz->param[GLIS_RATE] *= dz->param[GLIS_CONVERTOR];
+	dz->param[GLIS_HALF_SHIFT]   = dz->param[GLIS_SHIFT]/2.0;
+	dz->param[GLIS_REFPITCH]      = log(GLIS_REFERENCE_FRQ);
+	dz->param[GLIS_HALF_REFPITCH] = log(GLIS_REFERENCE_FRQ/2.0);
+	if(dz->vflag[GLIS_FTOP]) {
+		dz->param[GLIS_FRQTOP_TOP] = min(dz->nyquist,dz->param[GLIS_HIFRQ] + ROLL_OFF);
+		dz->param[GLIS_ROLL_OFF]   = 
+			min(dz->param[GLIS_FRQTOP_TOP] - dz->param[GLIS_HIFRQ], ROLL_OFF);
+	}
+	dz->param[GLIS_BASEFRQ] = GLIS_REFERENCE_FRQ;
+	return(FINISHED);
+}
+
+/************ SETUP_INTERNAL_ARRAYS_FOR_WAVER *************/
+
+int setup_internal_arrays_for_waver(dataptr dz)
+{
+	int exit_status;
+   	if((dz->parray[WAVER_CHFBOT] = (double *)malloc((dz->clength + 1) * sizeof(double)))==NULL) {
+		sprintf(errstr,"INSUFFICIENT MEMORY for waver channel bottom array.\n");
+		return(MEMORY_ERROR);
+	}
+	if((exit_status = setup_array_of_botfrq_of_each_channel(&(dz->iparam[WAVER_BOTCHAN]),dz))<0)
+		return(exit_status);
+   	dz->iparam[WAVER_STRCHANS] = dz->clength - dz->iparam[WAVER_BOTCHAN];
+	/* No of chans to be stretched */
+
+	return(FINISHED);
+}
+
+/*********************** SETUP_ARRAY_OF_BOTFRQ_OF_EACH_CHANNEL *********************/
+
+int setup_array_of_botfrq_of_each_channel(int *botchan,dataptr dz)
+{
+	int n = 1;
+	double boundary; 
+	*botchan = 0;
+	dz->parray[WAVER_CHFBOT][0] = 0.0;
+	boundary  = dz->chwidth/2.0;
+	while(boundary < dz->nyquist && n < dz->clength) {
+		dz->parray[WAVER_CHFBOT][n] = boundary;
+		if(*botchan==0 && (dz->param[WAVER_LOFRQ] < boundary)) 	/* IF botchan not set */
+			*botchan = n;		/* AND if botfrq BELOW this chan */
+					     		/* set botchan to THIS chan */
+		boundary += dz->chwidth;
+		n++;
+	}
+	(*botchan)--;			   /* RESET botchan to its true location */
+	if(n!=dz->clength) {
+		sprintf(errstr,"arithmetic error in setup_array_of_botfrq_of_each_channel()\n");
+		return(PROGRAM_ERROR);
+	}
+	dz->parray[WAVER_CHFBOT][dz->clength] = dz->nyquist; 
+	/* upper boundary channel clength-1 */
+	return(FINISHED);
+}
+
+/************************** WARP_PREPROCESS ******************************/
+
+int warp_preprocess(dataptr dz)
+{
+	int exit_status;
+	if((exit_status = convert_params_for_warp(dz))<0)
+		return(exit_status);
+	if((exit_status = setup_internal_arrays_and_params_for_specwarp(dz))<0)
+		return(exit_status);
+	return convert_pitchdata_to_midi_for_warp(dz);
+}
+
+/************ CONVERT_PARAMS_FOR_WARP *************/
+
+int convert_params_for_warp(dataptr dz)
+{
+	int exit_status;
+	if((exit_status = convert_msecs_to_secs(WARP_TRNG,dz))<0)
+		return(exit_status);
+	return convert_msecs_to_secs(WARP_SRNG,dz);
+}
+
+/************ SETUP_INTERNAL_ARRAYS_AND_PARAMS_FOR_SPECWARP *************/
+
+int setup_internal_arrays_and_params_for_specwarp(dataptr dz)
+{
+	double d;
+	int cc;
+	if((dz->parray[WARP_P2]	     
+		= (double *)malloc(dz->wlength * sizeof(double)))==NULL) {
+		sprintf(errstr,"INSUFFICIENT MEMORY for warp array.\n");
+		return(MEMORY_ERROR);
+	}
+	if((dz->parray[WARP_AVP]     = (double *)malloc(((dz->wlength/BLOKCNT) + 2) * sizeof(double)))==NULL) {
+		sprintf(errstr,"INSUFFICIENT MEMORY for warp average array.\n");
+		return(MEMORY_ERROR);
+	}
+	if((dz->iparray[WARP_CHANGE] = (int    *)malloc(((dz->wlength/BLOKCNT) + 2) * sizeof(int)))==NULL) {
+		sprintf(errstr,"INSUFFICIENT MEMORY for warp change array.\n");
+		return(MEMORY_ERROR);
+	}
+	dz->flbufptr[WCHTOP] = dz->windowbuf[0];	   /* use existing windowbuf for chtop and chbot store */
+	dz->flbufptr[WCHBOT] = dz->windowbuf[0] + dz->clength;
+	d = 0.0;
+	for(cc=0; cc < dz->clength;cc++)	{
+		dz->flbufptr[WCHTOP][cc] = (float)min(dz->nyquist,d + (dz->chwidth * (double)CHANSPAN));
+		dz->flbufptr[WCHBOT][cc] = (float)max(0.0,d - (dz->chwidth * (double)CHANSPAN));
+ 		d += dz->chwidth;
+	}
+	dz->iparam[WARP_PART_INBUF] = 0;
+	dz->iparam[WARP_ATEND] = 0;
+	return(FINISHED);
+}
+
+/************ CONVERT_PITCHDATA_TO_MIDI_FOR_WARP *************/
+
+int convert_pitchdata_to_midi_for_warp(dataptr dz)
+{
+	int exit_status;
+	int n;
+	double val;
+	for(n=0;n<dz->wlength;n++)	{
+		if(dz->pitches[n]<MINPITCH)
+			dz->pitches[n] = -1.0f;
+		else {
+			if((exit_status = hztomidi(&val,dz->pitches[n]))<0)
+				return(exit_status);
+			dz->pitches[n] = (float)val;
+		}
+	}
+	return(FINISHED);
+}
+
+/************************** INVERT_PREPROCESS ******************************/
+
+int invert_preprocess(dataptr dz)
+{
+	int exit_status;
+	if((exit_status = setup_internal_arrays_for_invert(dz))<0)
+		return(exit_status);
+	return extract_normalising_criteria_by_reading_infile(dz);
+}
+
+/************ SETUP_INTERNAL_ARRAYS_FOR_INVERT *************/
+
+int setup_internal_arrays_for_invert(dataptr dz)
+{
+	int cc, vc; 
+   	if((dz->parray[INV_AMPRATIO] = (double *)malloc(dz->clength * sizeof(double)))==NULL) {
+		sprintf(errstr,"INSUFFICIENT MEMORY for invert amplitude ratio array.\n");
+		return(MEMORY_ERROR);
+	}
+	for(cc = 0, vc = 0; cc < dz->clength; cc++, vc += 2) {
+		dz->amp[cc] 		 = (float)(-BIGAMP);
+		dz->parray[INV_AMPRATIO][cc] = -BIGAMP;
+	}
+	return(FINISHED);
+}
+
+/*************** EXTRACT_NORMALISING_CRITERIA_BY_READING_INFILE ********************/
+
+int extract_normalising_criteria_by_reading_infile(dataptr dz)
+{
+	int exit_status;
+	int samps_read, w_to_buf, wc;
+	double pre_totalamp;
+	int cc, vc;
+	fprintf(stdout,"INFO: Extracting normalisation criteria.\n");
+	fflush(stdout);
+	while((samps_read = fgetfbufEx(dz->bigfbuf,dz->big_fsize,dz->ifd[0],0)) > 0) {
+		dz->flbufptr[0] = dz->bigfbuf;     
+		w_to_buf    = samps_read/dz->wanted;
+		for(wc=0; wc<w_to_buf; wc++) {
+			switch(dz->mode) {
+			case(INV_NORMAL):
+				for(cc = 0, vc = 0; cc < dz->clength; cc++, vc += 2)
+					dz->amp[cc] = max(dz->amp[cc],dz->flbufptr[0][vc]);
+				break;
+			case(INV_KEEPAMP):
+				if((exit_status = get_totalamp(&pre_totalamp,dz->flbufptr[0],dz->wanted))<0)
+					return(exit_status);
+				if(pre_totalamp > MINAMP) {
+					for(cc = 0, vc = 0; cc < dz->clength; cc++, vc += 2)
+						dz->parray[INV_AMPRATIO][cc] = 
+						max(dz->parray[INV_AMPRATIO][cc],dz->flbufptr[0][vc]/pre_totalamp);
+				}
+				break;
+			default:
+				sprintf(errstr,"Unknown progmode in extract_normalising_criteria_by_reading_infile()\n"); 
+				return(PROGRAM_ERROR);
+			}
+			dz->flbufptr[0] += dz->wanted; 
+		}
+	}
+	if(samps_read < 0) {
+		sprintf(errstr,"Sound read error.\n");
+		return(SYSTEM_ERROR);
+	}
+	if(sndseekEx(dz->ifd[0],0,0)<0) {
+		sprintf(errstr,"seek failed in extract_normalising_criteria_by_reading_infile()\n");
+		return(SYSTEM_ERROR);
+	}
+	fprintf(stdout,"INFO: Processing the file.\n");
+	fflush(stdout);
+	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(SHIFT):	return specshift(dz);
+	case(GLIS):		return outer_loop(dz);
+	case(INVERT):	return outer_loop(dz);
+
+	case(WAVER): 	return specwaver(dz);
+	case(WARP): 	return specwarp(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(GLIS):		exit_status = specglis(dz);	  						break;
+		case(INVERT):	exit_status = specinvert(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 exit_status = FINISHED;
+	switch(dz->process) {
+	case(INVERT): 	case(GLIS): 	
+		switch(dz->process) {
+		case(GLIS):
+			if((exit_status = initialise_window_frqs(dz))<0)
+				return(exit_status);
+			break;
+		}
+		return(TRUE);
+	}
+	return(FALSE);
+}
+
+/********************************************************************************************/
+/********************************** FORMERLY IN pconsistency.c ******************************/
+/********************************************************************************************/
+
+/****************************** CHECK_PARAM_VALIDITY_AND_CONSISTENCY *********************************/
+
+int check_param_validity_and_consistency(dataptr dz)
+{
+	handle_pitch_zeros(dz);
+	return(FINISHED);
+}
+
+/********************************************************************************************/
+/********************************** FORMERLY IN buffers.c ***********************************/
+/********************************************************************************************/
+
+/**************************** ALLOCATE_LARGE_BUFFERS ******************************/
+
+int allocate_large_buffers(dataptr dz)
+{
+	switch(dz->process) {
+	case(SHIFT):	case(GLIS):		case(WAVER):	
+	case(INVERT):	
+		return allocate_single_buffer(dz);
+
+	case(WARP):		
+		return allocate_warp_buffer(dz);
+	default:
+		sprintf(errstr,"Unknown program no. in allocate_large_buffers()\n");
+		return(PROGRAM_ERROR);
+	}
+	return(FINISHED);	/* NOTREACHED */
+}
+
+/*************************** ALLOCATE_WARP_BUFFER ****************************
+ *
+ *	2 equal large buffs and an overflow of dz->wanted floats.
+ */
+
+int allocate_warp_buffer(dataptr dz)
+{
+	unsigned int buffersize;
+	if(dz->bptrcnt < 7) {
+		sprintf(errstr,"Insufficient bufptrs established in allocate_warp_buffer()\n");
+		return(PROGRAM_ERROR);
+	}
+//TW REVISED, secsize mult of bufs not needed
+	buffersize = dz->wanted * BUF_MULTIPLIER;
+	dz->buflen = buffersize;
+	buffersize *= 2;
+	buffersize += dz->wanted;
+	if((dz->bigfbuf	= (float*)malloc((size_t)buffersize * sizeof(float)))==NULL) {
+		sprintf(errstr,"INSUFFICIENT MEMORY for sound buffers.\n");
+		return(MEMORY_ERROR);
+	}
+
+	dz->big_fsize   = dz->buflen;
+	dz->flbufptr[0] = dz->bigfbuf;
+	dz->flbufptr[2] = dz->flbufptr[0] + dz->big_fsize;
+	dz->flbufptr[1] = dz->flbufptr[2];
+	dz->flbufptr[3] = dz->flbufptr[2] + dz->big_fsize;
+	return(FINISHED);
+}
+
+/********************************************************************************************/
+/********************************** FORMERLY IN cmdline.c ***********************************/
+/********************************************************************************************/
+
+int get_process_no(char *prog_identifier_from_cmdline,dataptr dz)
+{
+	if     (!strcmp(prog_identifier_from_cmdline,"shift"))	   		dz->process = SHIFT;
+	else if(!strcmp(prog_identifier_from_cmdline,"glis"))	   		dz->process = GLIS;
+	else if(!strcmp(prog_identifier_from_cmdline,"waver"))	   		dz->process = WAVER;
+	else if(!strcmp(prog_identifier_from_cmdline,"warp"))  	   		dz->process = WARP;
+	else if(!strcmp(prog_identifier_from_cmdline,"invert"))    		dz->process = INVERT;
+	else {
+		sprintf(errstr,"Unknown program identification string '%s'\n",prog_identifier_from_cmdline);
+		return(USAGE_ONLY);
+	}
+//TW UPDATE
+	return(FINISHED);
+}
+
+/********************************************************************************************/
+/********************************** FORMERLY IN usage.c *************************************/
+/********************************************************************************************/
+
+/******************************** USAGE1 ********************************/
+
+int usage1(void)
+{
+	sprintf(errstr,
+	"\nSTRANGE OPERATIONS ON A SPECTRAL FILE\n\n"
+	"USAGE: strange NAME (mode) infile outfile parameters: \n"
+	"\n"
+	"where NAME can be any one of\n"
+	"\n"
+	"shift    glis    waver    invert\n\n"
+	"Type 'strange shift' for more info on strange shift..ETC.\n");
+	return(USAGE_ONLY);
+}
+
+/******************************** USAGE2 ********************************/
+
+int usage2(char *str)
+{
+	if(!strcmp(str,"shift")) {
+		fprintf(stdout,
+		"strange shift 1   infile outfile frqshift               [-l]\n"
+		"strange shift 2-3 infile outfile frqshift frq_divide    [-l]\n"
+		"strange shift 4-5 infile outfile frqshift frqlo   frqhi [-l]\n"
+		"\n"
+		"LINEAR FREQUENCY SHIFT OF (PART OF) THE SPECTRUM\n"
+		"\n"
+		"MODES :-\n"
+		"1   Shift the whole spectrum.\n"
+		"2   Shift the spectrum above frq_divide.\n"
+		"3   Shift the spectrum below frq_divide.\n"
+		"4   Shift the spectrum only in the range frqlo and frqhi.\n"
+		"5   Shift the spectrum outside the range  frqlo to frqhi.\n"
+		"\n"
+		"frqshift      linear shift of spectral frequencies (same for all).\n"
+		"frq_divide    frq at which shifting starts or stops.\n"
+		"frqlo & frqhi define a range inside or outside of which shifting takes place.\n"
+		"-l            log interpolation between varying frq vals (Default: linear).\n"
+		"              (Useful only if any of above input parameters are time-varying,\n"
+	   	"               AND frqshift vals must be all +ve, or all -ve for this to work).\n"
+		"\n"
+		"frqshift,frq_divide,frqlo & frqhi may vary over time.\n");
+	} else if(!strcmp(str,"glis")) {
+		fprintf(stdout,
+		"strange glis 1 infile outfile -fN|-pN [-i] glisrate        [-ttopfrq] \n"
+		"strange glis 2 infile outfile -fN|-pN [-i] glisrate hzstep [-ttopfrq] \n"
+		"strange glis 3 infile outfile -fN|-pN [-i] glisrate        [-ttopfrq] \n"
+		"\n"
+		"CREATE GLISSANDI INSIDE THE (CHANGING) SPECTRAL ENVELOPE OF ORIGINAL SOUND\n"
+		"\n"
+		"MODES :-\n"
+		"1   shepard tones.\n"
+		"2   inharmonic glide.\n"
+		"3   self-glissando.\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"
+		"glisrate rate of glissing in semitones per second (-ve val for downward gliss).\n"
+		"hzstep   partials-spacing in inharmonic glide.\n"
+	    "         Range: FROM channel-frq-width TO nyquist/2.\n"
+		"topfrq   top of spectrum: must be > 2*chanwidth of analysis (default:nyquist)\n"
+		"\n"
+		"glisrate may vary over time.\n");
+	} else if(!strcmp(str,"waver")) {
+		fprintf(stdout,
+		"strange waver 1 infile outfile vibfrq stretch botfrq\n"
+		"strange waver 2 infile outfile vibfrq stretch botfrq expon\n"
+		"\n"
+		"OSCILLATE BETWEEN HARMONIC AND INHARMONIC STATE\n"
+		"\n"
+		"MODES :-\n"
+		"1   Standard spectral stretching for inharmonic state.\n"
+		"2   Specify spectral stretching for inharmonic state.\n"
+		"\n"
+		"vibfrq    is frq of oscillation. \n"
+		"stretch   is maximum spectral stretch in inharmonic state. \n"
+		"botfrq    is frq above which spectral stretching happens.\n"
+		"expon     defines type of stretch (must be > 0.0).\n"
+		"\n"
+		"vibfrq and stretch may vary over time.\n");
+/***
+	} else if(!strcmp(str,"warp")) {
+		fprintf(stdout,
+		"strange warp infile pitchfile outfile [-pprange] [-ttrange] [-ssrange]\n\n"
+		"PRODUCE AN APPROXIMATE COPY OF SPECTRUM.\n\n"
+		"PITCHFILE must be derived from infile.\n"
+		"PRANGE    Interval (semitones) over which pitch varies\n"
+		"          +- randomly from orig. Range > 0.0.\n"
+		"TRANGE    Time-interval (msecs) by which pitch can stray from orig time.\n"
+		"          Range: duration of 1 analysis window to dur of entire file.\n"
+		"SRANGE    Time-interval (msecs) over which pitch contour scanned.\n"
+		"          Pitchshift by %.2lf semitones within scanrange, indicates\n"
+		"          pitch rise or fall.\n"
+		"          Range: from dur of %d anal windows to (approx) dur of entire file.\n\n"
+		"prange, trange and srange may vary over time.\n",WARP_MININT,2*BLOKCNT);
+***/
+	} else if(!strcmp(str,"invert")) {
+		fprintf(stdout,
+		"strange invert mode infile outfile\n"
+		"\n"
+		"INVERT THE SPECTRUM\n"
+		"\n"
+		"MODES :-\n"
+		"1	Normal inversion.\n"
+		"2	Output sound retains amplitude envelope of source sound.\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);
+}
+

+ 235 - 0
dev/strange/main.c

@@ -0,0 +1,235 @@
+/*
+ * 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 <strange.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((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);
+}
+

+ 1504 - 0
dev/strange/strange.c

@@ -0,0 +1,1504 @@
+/*
+ * 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 <pnames.h>
+#include <globcon.h>
+#include <modeno.h>
+#include <arrays.h>
+#include <flags.h>
+#include <strange.h>
+#include <cdpmain.h>
+#include <formants.h>
+#include <speccon.h>
+#include <sfsys.h>
+#include <osbind.h>
+#include <string.h>
+#include <strange.h>
+
+#ifdef unix
+#define round(x) lround((x))
+#endif
+
+#define	RATIO_LIMIT 			 (20.0)	   /* Max ratio actual chanamp allowed to exceed
+											  formant derived amp for frq */
+#define SMOOTHER				  (0.5)
+#define	VERY_SMALL (0.0000000000000001)
+
+static int  zero_sampbuf(dataptr dz);
+static int  establish_frq_params(double *scalefact,dataptr dz);
+static int  write_partials_moving_down(double scalefact,dataptr dz);
+static int  write_partials_moving_up(double scalefact,dataptr dz);
+static int  cut_or_rolloff_high_frq(dataptr dz);
+static int  selfglis_down_within_spectral_envelope(int vc,double transpos,dataptr dz);
+static int  glis_down_within_spectral_envelope(double fundamental,double *thisfrq,double scalefact,int *n,dataptr dz);
+static int  selfglis_up_within_spectral_envelope(int vc,double transpos,dataptr dz);
+static int  glis_up_within_spectral_envelope(double fundamental,double *thisfrq,double scalefact,int *n,dataptr dz);
+static int  do_waver(int *wc,int *w_to_buf,int *samps_read,int wcnt,int upwcnt,int dnwcnt,dataptr dz);
+static int  spectrally_stretch_window(double thisstr,dataptr dz);
+static int  advance_along_windows(int *wc,int *w_to_buf,int *samps_read,dataptr dz);
+static int  warp_pitch(int *avcnt,dataptr dz);
+static int  warp_time(int avcnt,dataptr dz);
+static int  get_pitch_averages(int *avcnt,dataptr dz);
+static int  setup_and_do_pitchwarp(int start,int avg_no,int *lastpos,double *lastmidi,dataptr dz);
+static int  do_pitch_wiggle(double *thismidi,double ttime, dataptr dz);
+static int  warp_pitches(int thispos,int diff,int *lastpos,double thismidi,double *lastmidi,dataptr dz);
+static int  setup_and_do_timewarp(float **thisbuf,float **nextbuf,int n,int *lastoutpos,
+				int *lastinpos,int *last_total_wndws,dataptr dz);
+static int  adjust_input_buffers(float **thisbuf,float **nextbuf,int thisindex,
+				int *last_total_wndws,int do_next,dataptr dz);
+static int  transpos_initial_windows(float **thisbuf,float **nextbuf,int cnt,int *last_total_wndws,dataptr dz);
+static int	do_time_wiggle(double *ttime,dataptr dz);
+static int  do_timewarp(float **thisbuf,float **nextbuf,int thisinpos,int outdiff,
+				int *lastinpos,int *last_total_wndws,dataptr dz);
+static int  find_currentbuf_index(int *currentbuf_index,int *last_total_wndws,float **thisbuf,dataptr dz);
+static int  find_currentbuf_nextindex(int *currentbuf_nextindex,int last_total_wndws,dataptr dz);
+static int  setup_thisbuf_and_nextbuf(int last_total_wndws,float **thisbuf,float **nextbuf,dataptr dz);
+static int  interp_between_vals_in_two_bufs(float *thisbuf,float *nextbuf,double interpval,dataptr dz);
+static int  interp_between_pitch_vals(double *thismidi,float *pitch,int thisindex,double interpval,dataptr dz);
+static int  interp_between_pitch_vals2(double *thismidi,double *pitch,int thisindex,double interpval,dataptr dz);
+static int  transpose_outbuf(double transp,dataptr dz);
+static int  put_transposed_data_in_appropriate_chans(double transp,dataptr dz);
+static int  put_thisdata_in_appropriate_chan(int cc,int vc, dataptr dz);
+static int	do_specshift(int windows_in_buf,dataptr dz);
+static int  do_the_specshift(dataptr dz);
+static int  logread_shift(double timenow,int btktable_no,dataptr dz);
+static int  read_value_from_brktable_using_log_interpolation(double thistime,int paramno,dataptr dz);
+static int  reassign_frqs_to_appropriate_chans(dataptr dz);
+static int  do_chan_shifting(int cc,int vc,dataptr dz);
+static int  assign_new_frqs_to_appropriate_channels(dataptr dz);
+
+/**************************** SPECSHIFT ****************************/
+
+int specshift(dataptr dz)
+{
+	int exit_status;
+	int samps_read, windows_in_buf;
+	dz->time = 0.0f;
+	if(dz->bptrcnt <= 0) {
+		sprintf(errstr,"flbufptr[0] not established by outer_shift_loop()\n");
+		return(PROGRAM_ERROR);
+	}
+	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;
+		if((exit_status = do_specshift(windows_in_buf,dz))<0)
+			return(exit_status);
+		if((exit_status = write_exact_samps(dz->bigfbuf,samps_read,dz))<0)
+			return(exit_status);
+	}  
+	if(samps_read<0) {
+		sprintf(errstr,"Sound read error.\n");
+		return(SYSTEM_ERROR);
+	}
+	return(FINISHED);
+}
+
+/**************************** DO_SPECSHIFT ****************************/
+
+int	do_specshift(int windows_in_buf,dataptr dz)
+{
+	int exit_status;
+	int wc;
+   	for(wc=0; wc<windows_in_buf; wc++) {
+		if(dz->vflag[SHIFT_LOG]) {
+			if(dz->brksize[SHIFT_SHIF]) {
+				if((exit_status = logread_shift(dz->time,SHIFT_SHIF,dz))<0)
+					return(exit_status);
+			}
+			if(dz->brksize[SHIFT_FRQ1]) {
+				if((exit_status = 
+					read_value_from_brktable_using_log_interpolation((double)dz->time,SHIFT_FRQ1,dz))<0)
+					return(exit_status);
+			}
+			if(dz->brksize[SHIFT_FRQ2]) {
+				if((exit_status = 
+					read_value_from_brktable_using_log_interpolation((double)dz->time,SHIFT_FRQ2,dz))<0)
+					return(exit_status);
+			}
+		} else {
+			if((exit_status = read_values_from_all_existing_brktables((double)dz->time,dz))<0)
+				return(exit_status);
+		}
+		if((exit_status = do_the_specshift(dz))<0)
+			return(exit_status);
+		dz->flbufptr[0] += dz->wanted;
+		dz->time = (float)(dz->time + dz->frametime);
+	}
+	return(FINISHED);
+}
+
+/**************************** DO_THE_SPECSHIFT ***************************
+ *
+ * linear frequency shift of spectrum.
+ */
+
+int do_the_specshift(dataptr dz)
+{
+	int cc, vc;
+	switch(dz->mode) {
+	case(SHIFT_ALL):
+		for(cc=0,vc=0;cc< dz->clength; cc++, vc+=2)
+			dz->flbufptr[0][FREQ] = (float)(dz->flbufptr[0][FREQ] + dz->param[SHIFT_SHIF]);
+		break;
+	case(SHIFT_ABOVE):
+		for(cc=0,vc=0;cc< dz->clength; cc++, vc+=2) {
+			if(dz->flbufptr[0][FREQ] > dz->param[SHIFT_FRQ1])
+				dz->flbufptr[0][FREQ] = (float)(dz->flbufptr[0][FREQ] + dz->param[SHIFT_SHIF]);
+		}
+		break;
+	case(SHIFT_BELOW):
+		for(cc=0,vc=0;cc< dz->clength; cc++, vc+=2) {
+			if(dz->flbufptr[0][FREQ] < dz->param[SHIFT_FRQ1])
+				dz->flbufptr[0][FREQ] = (float)(dz->flbufptr[0][FREQ] + dz->param[SHIFT_SHIF]);
+		}
+		break;
+	case(SHIFT_BETWEEN):
+		for(cc=0,vc=0;cc< dz->clength; cc++, vc+=2) {
+			if(dz->flbufptr[0][FREQ] > dz->param[SHIFT_FRQ1] && dz->flbufptr[0][FREQ] < dz->param[SHIFT_FRQ2])
+				dz->flbufptr[0][FREQ] = (float)(dz->flbufptr[0][FREQ] + dz->param[SHIFT_SHIF]);
+		}
+		break;
+	case(SHIFT_OUTSIDE):
+		for(cc=0,vc=0;cc< dz->clength; cc++, vc+=2) {
+			if(dz->flbufptr[0][FREQ] < dz->param[SHIFT_FRQ1] || dz->flbufptr[0][FREQ] > dz->param[SHIFT_FRQ2])
+				dz->flbufptr[0][FREQ] = (float)(dz->flbufptr[0][FREQ] + dz->param[SHIFT_SHIF]);
+		}
+		break;
+	default:
+		sprintf(errstr,"Unkonwn mode in do_specshift()\n");
+		return(PROGRAM_ERROR);
+	}
+	return reassign_frqs_to_appropriate_chans(dz);
+ }
+
+/*************************** REASSIGN_FRQS_TO_APPROPRIATE_CHANS ***************************/
+
+int reassign_frqs_to_appropriate_chans(dataptr dz)
+{
+	int exit_status;
+	int cc, vc;
+ 	for(cc=0,vc=0;cc< dz->clength; cc++, vc+=2) {
+		dz->iparray[SHIFT_OVER][cc] = 0;
+		dz->iparray[SHIFT_DONE][cc] = 0;
+	}
+	if(dz->param[SHIFT_SHIF] > 0.0) {
+		for(cc=0,vc=0;cc< dz->clength; cc++, vc+=2) {
+			if(dz->flbufptr[0][FREQ] > (float)dz->parray[SHIFT_CHTOP][cc]) 
+				dz->iparray[SHIFT_OVER][cc] = 1;
+		}					    /* Work down from top, shifting up */
+		for(cc=dz->clength-1,vc=(dz->clength-1)*2;cc>=0; cc--, vc-=2) {
+			if(dz->iparray[SHIFT_OVER][cc]) {
+				if((exit_status = do_chan_shifting(cc,vc,dz))<0)
+					return(exit_status);
+			}
+		}
+	}					      	/* Work up from bottom shifting down */
+	if(dz->param[SHIFT_SHIF] < 0.0) {
+		for(cc=1,vc=2;cc< dz->clength; cc++, vc+=2) {		
+			if(dz->flbufptr[0][FREQ] <= (float)dz->parray[SHIFT_CHTOP][cc-1]) {
+				if((exit_status = do_chan_shifting(cc,vc,dz))<0)
+					return(exit_status);
+			}
+		}
+	}				
+	return(FINISHED);
+}		
+
+/*************************** DO_CHAN_SHIFTING ***************************/
+
+int do_chan_shifting(int cc,int vc,dataptr dz)
+{
+	int k = (int)((dz->flbufptr[0][FREQ] + dz->halfchwidth)/dz->chwidth);  /* TRUNCATE */
+	int newvc = k * 2;
+	if(k >=0 && k < dz->clength) {
+		if(!dz->iparray[SHIFT_DONE][k]
+		|| (dz->iparray[SHIFT_DONE][k] && (dz->flbufptr[0][AMPP] > dz->flbufptr[0][newvc]))) {
+			dz->flbufptr[0][newvc++]    = dz->flbufptr[0][AMPP];
+			dz->flbufptr[0][newvc]      = dz->flbufptr[0][FREQ];
+			dz->iparray[SHIFT_DONE][k] = 1;
+		}
+	}
+	dz->flbufptr[0][AMPP] = 0.0f;
+	dz->flbufptr[0][FREQ] = (float)dz->parray[SHIFT_CHMID][cc];
+	return(FINISHED);
+}
+
+/*********************** SPECGLIS ***************************/
+
+int specglis(dataptr dz)
+{
+	int exit_status;
+	double pre_totalamp, post_totalamp;
+	double scalefact;
+	if(dz->brksize[GLIS_RATE])
+		dz->param[GLIS_RATE] *= dz->param[GLIS_CONVERTOR];
+	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);
+	if(dz->mode != SELFGLIS) {
+		if((exit_status = zero_sampbuf(dz))<0)
+			return(exit_status);
+	}
+	if((exit_status = establish_frq_params(&scalefact,dz))<0)
+		return(exit_status);
+	if(dz->param[GLIS_RATE] <= 0.0) {
+		if((exit_status = write_partials_moving_down(scalefact,dz))<0)
+			return(exit_status);
+	} else {
+		if((exit_status = write_partials_moving_up(scalefact,dz))<0)
+			return(exit_status);
+	}
+	if(dz->vflag[GLIS_FTOP]) {
+		if((exit_status = cut_or_rolloff_high_frq(dz))<0)
+			return(exit_status);
+	}
+	if((exit_status = get_totalamp(&post_totalamp,dz->flbufptr[0],dz->wanted))<0)
+		return(exit_status);
+	return normalise(pre_totalamp,post_totalamp,dz);
+}
+
+
+/*********************** ZERO_SAMPBUF **********************/
+
+int zero_sampbuf(dataptr dz)
+{
+	int vc;
+	for(vc = 0; vc < dz->wanted; vc += 2) 
+		dz->flbufptr[0][AMPP] = 0.0f;
+	return(FINISHED);
+}
+
+/*********************** ESTABLISH_FRQ_PARAMS **********************/
+
+int establish_frq_params(double *scalefact,dataptr dz)
+{
+	double thispitch;
+	dz->param[GLIS_BASEFRQ] *= pow(2.0,dz->param[GLIS_RATE]);
+	if(dz->param[GLIS_RATE] >= 0.0) {		 /* GOING UP */
+		while(dz->param[GLIS_BASEFRQ] > GLIS_REFERENCE_FRQ * 2.0)
+			dz->param[GLIS_BASEFRQ] /= 2.0;
+		thispitch  = log(dz->param[GLIS_BASEFRQ]);
+		*scalefact = thispitch - dz->param[GLIS_REFPITCH];
+	} else {								/* GOING DOWN */
+		while(dz->param[GLIS_BASEFRQ] < GLIS_REFERENCE_FRQ/2.0)
+			dz->param[GLIS_BASEFRQ] *= 2.0;
+		thispitch  = log(dz->param[GLIS_BASEFRQ]);
+		*scalefact = thispitch - dz->param[GLIS_HALF_REFPITCH];
+	}
+ 	return(FINISHED);
+}
+
+/********************* WRITE_PARTIALS_MOVING_DOWN *********************
+ *
+ * (0)	Assume we start at fundamental.
+ * (1)	Calculate partials from where we are.
+ * (2)  Fade out odd partials.
+ * (3)	Move up by equal frq steps, or by multiples of current fundamental.
+ */
+
+int write_partials_moving_down(double scalefact,dataptr dz)
+{
+	int exit_status;
+	int n, cc, vc;									/* 0 */
+	double fundamental, thisfrq, transpos;
+	switch(dz->mode) {
+	case(SELFGLIS):
+		rectify_window(dz->flbufptr[0],dz);
+		transpos = dz->param[GLIS_BASEFRQ]/GLIS_REFERENCE_FRQ;
+		for(cc=0,vc=0;cc < dz->clength;cc++,vc+=2) {
+			dz->amp[cc]  = 0.0f;
+			dz->freq[cc] = dz->flbufptr[0][FREQ];
+		}
+		for(vc=0;vc < dz->wanted; vc+=2) {
+			if((exit_status = selfglis_down_within_spectral_envelope(vc,transpos,dz))<0)
+				return(exit_status);
+		}
+		if((exit_status = put_amp_and_frq(dz->flbufptr[0],dz))<0)
+			return(exit_status);
+		break;
+	case(INHARMONIC):
+	case(SHEPARD):
+		fundamental = dz->param[GLIS_BASEFRQ];				/* 1 */
+		thisfrq 	= dz->param[GLIS_BASEFRQ];
+		n = 1;
+		while(thisfrq < dz->nyquist) {
+			if((exit_status = glis_down_within_spectral_envelope(fundamental,&thisfrq,scalefact,&n,dz))<0)
+				return(exit_status);
+		}
+		break;
+	default:
+		sprintf(errstr,"Unknown mode in write_partials_moving_down()\n");
+		return(PROGRAM_ERROR);
+	}
+	return(FINISHED);
+}
+
+/************************ WRITE_PARTIALS_MOVING_UP ***********************
+ *
+ * (0)	Assume we start at 2nd harmonic.
+ * (1)	Calculate partials from a fundamental an 8va below ref pitch.
+ * (2)  Fade in lowest component, and odd partials.
+ * (3)	Move up by equal frq steps, or by multiples of current fundamental.
+ */
+
+int write_partials_moving_up(double scalefact,dataptr dz)
+{
+	int exit_status;
+	int n = 2, cc, vc;						/* 0 */
+	double fundamental = dz->param[GLIS_BASEFRQ]/2.0;			/* 1 */
+	double thisfrq 	   = dz->param[GLIS_BASEFRQ];
+	double transpos;
+	switch(dz->mode) {
+	case(SELFGLIS) :
+		transpos = dz->param[GLIS_BASEFRQ]/ GLIS_REFERENCE_FRQ;
+		for(cc=0,vc=0;cc < dz->clength;cc++,vc+=2) {
+			dz->amp[cc]  = 0.0f;
+			dz->freq[cc] = dz->flbufptr[0][FREQ];
+		}
+		for(vc=0;vc < dz->wanted;vc+=2) {
+			if((exit_status = selfglis_up_within_spectral_envelope(vc,transpos,dz))<0)
+				return(exit_status);		
+		}
+		if((exit_status = put_amp_and_frq(dz->flbufptr[0],dz))<0)
+			return(exit_status);		
+		break;
+    case(SHEPARD):
+    case(INHARMONIC):
+		while(thisfrq < dz->nyquist) {
+			if((exit_status = glis_up_within_spectral_envelope(fundamental,&thisfrq,scalefact,&n,dz))<0)
+				return(exit_status);
+		}
+		break;
+	default:
+		sprintf(errstr,"Unknown mode in write_partials_moving_up()\n");
+		return(PROGRAM_ERROR);
+	}
+	return(FINISHED);
+}
+
+/****************************** CUT_OR_ROLLOFF_HIGH_FRQ *****************************/
+
+int cut_or_rolloff_high_frq(dataptr dz)
+{
+	int vc;
+	for(vc = 0; vc < dz->wanted;vc += 2) {
+		if(dz->flbufptr[0][FREQ] > dz->param[GLIS_HIFRQ]) {
+			if(dz->flbufptr[0][FREQ] >= dz->param[GLIS_FRQTOP_TOP])
+				dz->flbufptr[0][AMPP] = 0.0f;
+			else
+				dz->flbufptr[0][AMPP] =
+			(float)(dz->flbufptr[0][AMPP] * (dz->param[GLIS_FRQTOP_TOP] - dz->flbufptr[0][FREQ])/dz->param[GLIS_ROLL_OFF]);
+		}
+	}
+	return(FINISHED);
+}
+
+/******************* SELFGLIS_DOWN_WITHIN_SPECTRAL_ENVELOPE ********************/
+
+int selfglis_down_within_spectral_envelope(int vc,double transpos,dataptr dz)
+{
+	int exit_status;
+	double ampratio, amphere, thisfrq, thisamp, frqhi, amphi;
+	int n;
+	if((exit_status = getspecenvamp(&amphere,dz->flbufptr[0][FREQ],0,dz))<0)
+		return(exit_status);
+	if(amphere <= VERY_SMALL)
+		ampratio = 0.0;
+	else {
+		if((ampratio = fabs(dz->flbufptr[0][AMPP]/amphere)) > RATIO_LIMIT)
+			ampratio = RATIO_LIMIT;
+	}
+	if((thisfrq  = fabs(dz->flbufptr[0][FREQ]) * transpos) < dz->nyquist) {
+		if((exit_status = getspecenvamp(&thisamp,thisfrq,0,dz))<0)
+			return(exit_status);
+		thisamp *= ampratio;
+		thisamp *= pow(max(0.0,(transpos * 2.0) - 1.0),SMOOTHER);
+		if((exit_status = get_channel_corresponding_to_frq(&n,thisfrq,dz))<0)
+			return(exit_status);
+		if(n >=0 && n < dz->clength && thisamp > dz->amp[n]) {
+			dz->amp[n++] = (float)thisamp;
+			dz->freq[n]  = (float)thisfrq;
+		}
+	}	
+	if((frqhi = thisfrq * 2.0) < dz->nyquist) {
+		if((exit_status = getspecenvamp(&amphi,frqhi,0,dz))<0)
+			return(exit_status);
+		amphi   *= ampratio;
+		amphi   *= pow(max(0.0,2.0 - (transpos * 2.0)),SMOOTHER);
+		if((exit_status = get_channel_corresponding_to_frq(&n,thisfrq,dz))<0)
+			return(exit_status);
+		if(n >=0 && n < dz->clength && amphi > dz->amp[n]) {
+			dz->amp[n++] = (float)amphi;
+			dz->freq[n]  = (float)frqhi;
+		}
+	}
+	return(FINISHED);
+}
+
+/******************* GLIS_DOWN_WITHIN_SPECTRAL_ENVELOPE ********************/
+
+int glis_down_within_spectral_envelope(double fundamental,double *thisfrq,double scalefact,int *n,dataptr dz)
+{
+	int exit_status;
+	int cc, vc;
+	double thisamp;
+	if((exit_status = get_channel_corresponding_to_frq(&cc,*thisfrq,dz))<0)
+		return(exit_status);
+	vc = cc * 2;
+	dz->flbufptr[0][FREQ] = (float)(*thisfrq);
+	if((exit_status = getspecenvamp(&thisamp,*thisfrq,0,dz))<0)
+		return(exit_status);
+	dz->flbufptr[0][AMPP] = (float)thisamp;
+	if(ODD(*n))
+		dz->flbufptr[0][AMPP] = (float)(dz->flbufptr[0][AMPP] * scalefact);	/* 2 */
+	(*n)++;
+	switch(dz->mode) {
+	case(INHARMONIC): *thisfrq += dz->param[GLIS_SHIFT];		break;
+	case(SHEPARD):    *thisfrq  = fundamental * (double)(*n);	break;	
+	}							/* 3 */
+	return(FINISHED);
+}
+
+/******************* SELFGLIS_UP_WITHIN_SPECTRAL_ENVELOPE ********************/
+
+int selfglis_up_within_spectral_envelope(int vc,double transpos,dataptr dz)
+{
+	int exit_status;
+	double amphere, ampratio;
+	double thisfrq, thisamp, frqlo, amplo;
+	int n;
+	if((exit_status = getspecenvamp(&amphere,dz->flbufptr[0][FREQ],0,dz))<0)
+		return(exit_status);
+	if(amphere <= VERY_SMALL)
+		ampratio = 0.0;
+	else {
+		if((ampratio = fabs(dz->flbufptr[0][AMPP]/amphere)) > RATIO_LIMIT)
+			ampratio = RATIO_LIMIT;
+	}
+	if((thisfrq  = fabs(dz->flbufptr[0][FREQ]) * transpos) < dz->nyquist) {
+		if((exit_status = getspecenvamp(&thisamp,thisfrq,0,dz))<0)
+			return(exit_status);
+		thisamp *= ampratio;
+		thisamp *= pow(2.0 - transpos,SMOOTHER);
+		if((exit_status = get_channel_corresponding_to_frq(&n,thisfrq,dz))<0)
+			return(exit_status);
+		if(n >=0 && n < dz->clength && thisamp > dz->amp[n]) {
+			dz->amp[n]  = (float)thisamp;
+			dz->freq[n] = (float)thisfrq;
+		}
+	}
+	if((frqlo = thisfrq/2.0) < dz->nyquist) {
+		if((exit_status = getspecenvamp(&amplo,frqlo,0,dz))<0)
+			return(exit_status);
+		amplo   *= ampratio;
+		amplo   *= pow(transpos - 1.0,SMOOTHER);
+		exit_status = get_channel_corresponding_to_frq(&n,thisfrq,dz);
+		if(n < dz->clength && amplo > dz->amp[n]) {
+			dz->amp[n]  = (float)amplo;
+			dz->freq[n] = (float)frqlo;
+		}
+	}
+	return(FINISHED);
+}
+
+/******************* GLIS_UP_WITHIN_SPECTRAL_ENVELOPE ********************/
+
+int glis_up_within_spectral_envelope(double fundamental,double *thisfrq,double scalefact,int *n,dataptr dz)
+{
+	int exit_status;
+	int cc, vc;
+	double thisamp;
+	if((exit_status = get_channel_corresponding_to_frq(&cc,*thisfrq,dz))<0)
+		return(exit_status);
+	vc = cc * 2;
+	dz->flbufptr[0][FREQ] = (float)(*thisfrq);
+	if((exit_status = getspecenvamp(&thisamp,*thisfrq,0,dz))<0)
+		return(exit_status);
+	dz->flbufptr[0][AMPP] = (float)thisamp;
+	if(ODD(*n) || *n==2)
+		dz->flbufptr[0][AMPP] = (float)(dz->flbufptr[0][AMPP] * scalefact);	/* 2 */
+	(*n)++;
+	switch(dz->mode) {
+	case(INHARMONIC):*thisfrq += dz->param[GLIS_HALF_SHIFT];	break;
+	case(SHEPARD):   *thisfrq  = fundamental * (double)(*n); 	break;
+	}						/* 3 */
+	return(FINISHED);
+}
+
+/*************************** SPECINVERT *********************/
+
+int specinvert(dataptr dz)
+{
+	int exit_status;
+	double zort, pre_totalamp;
+	int cc, vc;
+	switch(dz->mode) {
+	case(INV_NORMAL):
+		for(cc = 0, vc = 0; cc < dz->clength; cc++, vc += 2)
+			dz->flbufptr[0][AMPP] = dz->amp[cc] - dz->flbufptr[0][AMPP];
+		break;
+	case(INV_KEEPAMP):
+		if((exit_status = get_totalamp(&pre_totalamp,dz->flbufptr[0],dz->wanted))<0)
+			return(exit_status);
+		if(pre_totalamp > MINAMP) {
+			for(cc = 0, vc = 0; cc < dz->clength; cc++, vc += 2) {
+				zort = dz->parray[INV_AMPRATIO][cc] - (dz->flbufptr[0][vc]/pre_totalamp);
+				dz->flbufptr[0][vc] = (float)(zort * pre_totalamp);
+			}
+		}
+		break;
+	}
+	return(FINISHED);
+}
+
+/******************************* SPECWAVER ********************************/
+
+int specwaver(dataptr dz)
+{
+	int exit_status = FINISHED;
+	double duration = dz->wlength * dz->frametime;
+	int   wcnt, upwcnt, dnwcnt, wc, samps_read, w_to_buf;
+	if(duration <= 0.0) {	
+		sprintf(errstr,"Zero length analysis file: cannot proceed.\n");
+		return(DATA_ERROR);
+	}
+	if((samps_read = fgetfbufEx(dz->bigfbuf, dz->big_fsize,dz->ifd[0],0)) > 0) {
+		dz->flbufptr[0] = dz->bigfbuf;
+		w_to_buf       = samps_read/dz->wanted;    
+		wc             = 0;
+	}
+	else {
+		if(samps_read<0) {
+			sprintf(errstr,"Sound read error.\n");
+			return(SYSTEM_ERROR);
+		}
+		sprintf(errstr,"No windows found. specwaver()\n");
+		return(PROGRAM_ERROR);
+    }
+	while(dz->time < duration) {
+		if((exit_status = read_values_from_all_existing_brktables((double)dz->time,dz))<0)
+			return(exit_status);
+		wcnt = round(1.0/(dz->param[WAVER_VIB] * dz->frametime));
+		dnwcnt = upwcnt = wcnt/2;
+		if(ODD(wcnt))
+			upwcnt++;
+		if((exit_status = do_waver(&wc,&w_to_buf,&samps_read,wcnt,upwcnt,dnwcnt,dz))!=CONTINUE)
+			break;
+	}
+	return(exit_status);
+}
+
+/******************************** DO_WAVER *******************************/
+
+int do_waver(int *wc,int *w_to_buf,int *samps_read,int wcnt,int upwcnt,int dnwcnt,dataptr dz)
+{
+	int exit_status;
+	int n;
+	double strstep = dz->param[WAVER_STR]/(double)upwcnt;
+	double thisstr = dz->param[WAVER_STR];
+	for(n=0;n<upwcnt;n++) {
+		if((exit_status = spectrally_stretch_window(thisstr,dz))<0)
+			return(exit_status);
+		if((exit_status = advance_along_windows(wc,w_to_buf,samps_read,dz))!=CONTINUE)
+			return(exit_status);
+		thisstr += strstep;
+	}
+	if(ODD(wcnt))
+		thisstr -= strstep;
+	for(n=0;n<dnwcnt;n++) {
+		if((exit_status = spectrally_stretch_window(thisstr,dz))<0)
+			return(exit_status);
+		if((exit_status = advance_along_windows(wc,w_to_buf,samps_read,dz))!=CONTINUE)
+			return(exit_status);
+		thisstr -= strstep;
+	}
+	return(CONTINUE);
+}
+    
+/*********************** SPECTRALLY_STRETCH_WINDOW *****************************/
+
+int spectrally_stretch_window(double thisstr,dataptr dz)
+{
+	int dd;
+	int cc, vc;
+	double herestr, thislocation, strdiff = thisstr - 1.0;
+	for(dd=0,cc=dz->iparam[WAVER_BOTCHAN],vc=dz->iparam[WAVER_BOTCHAN]*2; cc < dz->clength; dd++,cc++,vc+=2) {
+		thislocation = (double)dd/(double)dz->iparam[WAVER_STRCHANS];
+		if(dz->mode==WAVER_SPECIFIED)
+			thislocation = pow(thislocation,dz->param[WAVER_EXP]);
+		herestr  = (thislocation * strdiff) + 1.0;
+		dz->amp[cc]  = dz->flbufptr[0][AMPP];
+		dz->freq[cc] = (float)fabs(dz->flbufptr[0][FREQ] * herestr);
+	}
+	return assign_new_frqs_to_appropriate_channels(dz);
+}
+
+/***************************** ADVANCE_ALONG_WINDOWS *************************/
+
+int advance_along_windows(int *wc,int *w_to_buf,int *samps_read,dataptr dz)
+{
+	int exit_status;
+	dz->flbufptr[0] += dz->wanted;
+	if(++(*wc) >= *w_to_buf) {
+		if(*samps_read > 0) {
+			if((exit_status = write_exact_samps(dz->bigfbuf,*samps_read,dz))<0)
+				return(exit_status);
+		}
+		if((*samps_read = fgetfbufEx(dz->bigfbuf, dz->big_fsize,dz->ifd[0],0)) > 0) {
+			dz->flbufptr[0] = dz->bigfbuf;
+			*w_to_buf      = *samps_read/dz->wanted;    
+			*wc            = 0;
+		} else {
+//TW CORRECTED indirection error : Dec 2002
+			if(*samps_read<0) {
+				sprintf(errstr,"Sound read error.\n");
+				return(SYSTEM_ERROR);
+			}
+			return(FINISHED);
+		}
+	}  
+	dz->time = (float)(dz->time + dz->frametime);
+	return(CONTINUE);
+}
+
+/****************************** SPECWARP ***************************/
+
+int	specwarp(dataptr dz)
+{
+	int exit_status;
+	int avcnt;
+	if(sloom) {
+		fprintf(stdout,"INFO: Warping pitch.\n");
+		fflush(stdout);
+	}
+	if((exit_status = warp_pitch(&avcnt,dz))<0)
+		return(exit_status);
+	if(sloom) {
+		fprintf(stdout,"INFO: Warping time.\n");
+		fflush(stdout);
+	}
+	return warp_time(avcnt,dz);
+}
+
+/************************** WARP_PITCH ************************/
+
+int warp_pitch(int *avcnt,dataptr dz)
+{
+	int exit_status;
+	int   n = 0, lastpos = 0, thispos, diff, q, start;
+	double lastmidi;
+	double ttime, thismidi;
+	initrand48();
+	if((exit_status = get_pitch_averages(avcnt,dz))<0)
+		return(exit_status);
+	if((exit_status = get_statechanges(*avcnt,WARP_SRNG,WARP_AVP,WARP_CHANGE,WARP_MININT,-WARP_MININT,IS_PITCH,dz))<0)
+		return(exit_status);
+	while(dz->parray[WARP_AVP][n] < MIDIMIN) {
+	    if(++n >= *avcnt) {
+			sprintf(errstr,"No valid pitch-average data found: warp_pitch()\n");
+			return(PROGRAM_ERROR);
+		}
+	}
+	dz->iparray[WARP_CHANGE][n] = 1;
+	start = n;
+	for(;n < *avcnt;n++) {
+		if(dz->iparray[WARP_CHANGE][n])	{
+			if((exit_status = setup_and_do_pitchwarp(start,n,&lastpos,&lastmidi,dz))<0)
+				return(exit_status);
+		}
+	}
+	thispos = (dz->wlength - 1);
+	if((diff = thispos - lastpos) > 0) {
+		q = (*avcnt) - 1;
+		while(dz->parray[WARP_AVP][q]<MIDIMIN) {
+			if(--q<=lastpos)
+				return(FINISHED);
+		}	
+		thismidi = dz->parray[WARP_AVP][q];
+		ttime = (q * BLOKCNT) * dz->frametime;
+		if((exit_status = do_pitch_wiggle(&thismidi,ttime,dz))<0)
+			return(exit_status);
+		if((exit_status = warp_pitches(thispos,diff,&lastpos,thismidi,&lastmidi,dz))<0)
+			return(exit_status);
+	}
+	return(FINISHED);
+}
+
+/************************** WARP_TIME ************************/
+
+int warp_time(int avcnt,dataptr dz)
+{
+	int exit_status = CONTINUE;
+	int   lastoutpos = 0, lastinpos  = 0,  indiff, remain;
+	int   n, ip, samps_read;
+	int last_total_wndws = 0;
+	float *nextbuf = dz->flbufptr[0] + dz->wanted, *thisbuf = dz->flbufptr[0];
+	if(sloom)
+		dz->total_samps_read = 0;
+	if((samps_read = fgetfbufEx(dz->bigfbuf,dz->big_fsize,dz->ifd[0],0)) <= 0) {
+		if(samps_read<0) {
+			sprintf(errstr,"Sound read error.\n");
+			return(SYSTEM_ERROR);
+		} else {
+			sprintf(errstr,"Cannot read data from input analysis file.\n");
+			return(DATA_ERROR);
+		}
+	}
+	if(sloom)
+		dz->total_samps_read += samps_read;
+	dz->iparam[WARP_WREAD] = samps_read/dz->wanted;
+	if((dz->flbufptr[6] = dz->bigfbuf + samps_read)!=dz->flbufptr[2]) {
+		dz->iparam[WARP_PART_INBUF] = 1;
+		dz->iparam[WARP_ATEND] = 1;
+	}
+	for(n=0;n<avcnt;n++) {
+		if(dz->iparray[WARP_CHANGE][n]) {
+			if((exit_status = setup_and_do_timewarp(&thisbuf,&nextbuf,n,&lastoutpos,&lastinpos,&last_total_wndws,dz))<0)
+				return(exit_status);
+		}
+		if(exit_status!=CONTINUE)
+			break;
+	}
+	if((indiff = (dz->wlength - 1) - lastinpos) > 0) {
+		ip = lastinpos + 1;
+		while(lastinpos < dz->wlength) {
+			if((exit_status = adjust_input_buffers(&thisbuf,&nextbuf,ip,&last_total_wndws,0,dz))<0)
+				return(exit_status);
+			if(dz->flbufptr[1]!=thisbuf)
+				memmove((char *)dz->flbufptr[1],(char *)thisbuf,(size_t)(dz->wanted * sizeof(float)));
+			if((dz->flbufptr[1] += dz->wanted) >= dz->flbufptr[3]) {
+				if((exit_status = write_exact_samps(dz->flbufptr[2],dz->big_fsize,dz))<0)
+					return(exit_status);
+				dz->flbufptr[1] = dz->flbufptr[2];
+			}
+ 			lastinpos++;	/* MAY 1997 ??? */
+			ip = lastinpos;	/* MAY 1997 ??? */
+		}
+	}
+	if((remain = (dz->flbufptr[1]  - dz->flbufptr[2]))>0) {
+		if((exit_status = write_samps(dz->flbufptr[2],remain,dz))<0)
+			return(exit_status);
+	}
+	return(FINISHED);
+}
+
+/************************** GET_PITCH_AVERAGES ************************/
+
+int get_pitch_averages(int *avcnt,dataptr dz)
+{
+	int k = 0, OK = 1, n = 0, m, cnt;
+	while(OK) {
+		dz->parray[WARP_AVP][k] = 0.0;
+		m = 0;
+		cnt = 0;
+		while(m < BLOKCNT) {
+			if(dz->pitches[n]<MIDIMIN) {
+				m++;
+				if(++n >= dz->wlength) {
+					OK = 0;
+					break;
+				}
+				continue;
+			}
+			dz->parray[WARP_AVP][k] += dz->pitches[n];
+			cnt++;
+			m++;
+			if(++n >= dz->wlength) {
+				OK = 0;
+				break;
+			}
+		}
+		if(cnt==0)
+			dz->parray[WARP_AVP][k] = -1.0;
+		else
+		    dz->parray[WARP_AVP][k] /= (double)cnt;
+		k++;
+	}
+	if((dz->parray[WARP_AVP] = (double *)realloc((char *)dz->parray[WARP_AVP],k * sizeof(double)))==NULL) {
+		sprintf(errstr,"INSUFFICIENT MEMORY for warp averages array.\n");
+		return(MEMORY_ERROR);
+	}
+	*avcnt = k;
+	return(FINISHED);
+}
+
+/************************** SETUP_AND_DO_PITCHWARP ************************/
+
+int setup_and_do_pitchwarp(int start,int avg_no,int *lastpos,double *lastmidi,dataptr dz)
+{
+	int exit_status;
+	int here, q, z, diff;
+	double thismidi, ttime;
+	here = min((dz->wlength - 1),avg_no * BLOKCNT); /* just being ultra careful !! */
+	for(q = here; q < here+BLOKCNT; q++) {
+		if(q>=dz->wlength)
+			break;
+		if(dz->pitches[q] >= MIDIMIN)
+			break;
+	}
+	if(q >= here+BLOKCNT || q>=dz->wlength) {	   /* No valid pitchdata here !! */
+		for(z=here; z<q; z++)
+			dz->parray[WARP_P2][z] = -1.0;
+		dz->iparray[WARP_CHANGE][avg_no] = 0;
+		return(FINISHED);
+	} else		/* [WARP_CHANGE] remembers position of approp wndw to work on */
+		dz->iparray[WARP_CHANGE][avg_no] = q;	
+	here     = q;
+	ttime    = dz->frametime * (double)here;
+	thismidi = dz->pitches[here];
+	if((exit_status = do_pitch_wiggle(&thismidi,ttime,dz))<0)
+			return(exit_status);
+	if(avg_no==start) {
+		dz->parray[WARP_P2][q] = thismidi;
+		*lastpos  = q;
+		*lastmidi = thismidi;
+		return(FINISHED);
+	}
+	diff  = q - *lastpos;
+	return warp_pitches(q,diff,lastpos,thismidi,lastmidi,dz);
+}
+
+/***************** DO_PITCH_WIGGLE *******************/
+
+int do_pitch_wiggle(double *thismidi,double ttime, dataptr dz)
+{
+	int exit_status;
+	double wiggle, this_prange;
+	if(dz->brksize[WARP_PRNG]) {
+		if((exit_status  = read_value_from_brktable(ttime,WARP_PRNG,dz))<0)
+			return(exit_status);
+	}
+	wiggle = (drand48() * 2.0) -1.0;	/* random  +-  */
+	this_prange = wiggle * dz->param[WARP_PRNG];
+	*thismidi += this_prange;
+	return(FINISHED);
+}
+
+/***************** WARP_PITCHES *******************/
+
+int warp_pitches(int thispos,int diff,int *lastpos,double thismidi,double *lastmidi,dataptr dz)
+{
+	int   n, m;
+	double mididiff = thismidi - *lastmidi;
+	double midistep = mididiff/(double)diff;
+	for(m=1, n=(*lastpos)+1; m <= diff; m++, n++) {
+		if(n < dz->wlength && dz->pitches[n]<MIDIMIN) {
+			dz->parray[WARP_P2][n] = -1.0;
+			continue;
+		}
+		thismidi = *lastmidi + (midistep * (double)m);
+		dz->parray[WARP_P2][n] = thismidi;
+	}
+	*lastmidi = thismidi;
+	*lastpos  = thispos;
+	return(FINISHED);
+}
+
+/************************** SETUP_AND_DO_TIMEWARP ************************/
+
+int setup_and_do_timewarp
+(float **thisbuf,float **nextbuf,int n,int *lastoutpos,int *lastinpos,int *last_total_wndws,dataptr dz)
+{
+	int exit_status;
+	int thisoutpos, outdiff;
+	int thisinpos  = dz->iparray[WARP_CHANGE][n];
+	double ttime = dz->frametime * (double)thisinpos;
+	if(n==0) {
+		if((exit_status = transpos_initial_windows(thisbuf,nextbuf,thisinpos,last_total_wndws,dz))!=CONTINUE)
+			return(exit_status);
+		*lastinpos   = thisinpos;			 
+		*lastoutpos  = thisinpos;
+	} else {
+		if((exit_status = do_time_wiggle(&ttime,dz))<0)
+			return(exit_status);
+		thisoutpos = round(ttime/dz->frametime);
+		thisoutpos = max(0L,thisoutpos);
+		if((outdiff = thisoutpos - *lastoutpos)>0) {/* number of windows to scan in output data */
+			if((exit_status = do_timewarp(thisbuf,nextbuf,thisinpos,outdiff,lastinpos,last_total_wndws,dz))!=CONTINUE)
+				return(exit_status);
+		}
+		*lastinpos  = thisinpos; 	/* ??? */
+		*lastoutpos = thisoutpos;	/* ??? */
+	}
+	return(CONTINUE);
+}
+
+/***************** ADJUST_INPUT_BUFFERS *******************/
+
+int adjust_input_buffers(float **thisbuf,float **nextbuf,int thisindex,int *last_total_wndws,int do_next,dataptr dz)
+{
+	int exit_status;
+	int currentbuf_index, currentbuf_nextindex;
+	currentbuf_index = thisindex - *last_total_wndws;
+
+	if(currentbuf_index >= dz->iparam[WARP_WREAD]) {
+		if((exit_status = find_currentbuf_index(&currentbuf_index,last_total_wndws,thisbuf,dz))!=CONTINUE)
+			return(exit_status);
+	}
+	if(do_next) {
+		currentbuf_nextindex = currentbuf_index + 1;
+		if(currentbuf_nextindex >= dz->iparam[WARP_WREAD]) {
+			if(dz->flbufptr[3]!=*thisbuf)
+				memmove((char *)dz->flbufptr[3],(char *)(*thisbuf),(size_t)(dz->wanted * sizeof(float)));
+			*thisbuf   = dz->flbufptr[3];
+			if((exit_status = find_currentbuf_nextindex(&currentbuf_nextindex,*last_total_wndws,dz))<0)
+				return(exit_status);
+			*nextbuf  = dz->bigfbuf + (currentbuf_nextindex * dz->wanted);
+		}
+	}
+	return(FINISHED);
+}
+
+/***************** TRANSPOS_INITIAL_WINDOWS   ******************/
+
+int transpos_initial_windows(float **thisbuf,float **nextbuf,int cnt,int *last_total_wndws,dataptr dz)
+{
+	int exit_status;
+	int cc, vc;
+	int n = 0, samps_to_write, samps_read;
+	double transp;
+	while(n <= cnt) {
+		rectify_window(dz->flbufptr[0],dz);
+		if(dz->pitches[n] > MIDIMIN) {
+			transp = SEMITONES_AS_RATIO(dz->parray[WARP_P2][n] - dz->pitches[n]);
+			for(cc=0,vc=0;cc<dz->clength;cc++,vc+=2) {
+				dz->flbufptr[1][AMPP] = dz->flbufptr[0][AMPP];	
+				dz->flbufptr[1][FREQ] = (float)(dz->flbufptr[0][FREQ] * transp);
+			}
+			if((exit_status = put_transposed_data_in_appropriate_chans(transp,dz))<0)
+				return(exit_status);
+		} else {
+			for(vc=0;vc<dz->wanted;vc+=2)
+				dz->flbufptr[1][vc] = dz->flbufptr[0][vc];	  /* Copy unpitched windows */
+		}
+		dz->flbufptr[1] += dz->wanted;
+		if((dz->flbufptr[0] += dz->wanted) >= dz->flbufptr[6]) {
+ 			if(dz->iparam[WARP_PART_INBUF]) {
+				if((samps_to_write = dz->flbufptr[1] - dz->flbufptr[2])>0)
+					return write_samps(dz->flbufptr[2],samps_to_write,dz);
+				return FINISHED;
+			} else {
+				if((exit_status = write_exact_samps(dz->flbufptr[2],dz->big_fsize,dz))<0)
+					return(exit_status);
+			} 
+			if((samps_read = fgetfbufEx(dz->bigfbuf,dz->big_fsize,dz->ifd[0],0)) <= 0) {
+				if(samps_read<0) {
+					sprintf(errstr,"Sound read error.\n");
+					return(SYSTEM_ERROR);
+				}
+    			return(FINISHED);
+			}
+			if(sloom)
+				dz->total_samps_read += samps_read;
+			*last_total_wndws += dz->iparam[WARP_WREAD];
+			dz->iparam[WARP_WREAD] = samps_read/dz->wanted;
+			if(samps_read < dz->big_fsize) {
+				dz->iparam[WARP_PART_INBUF] = 1;
+				dz->flbufptr[6] = dz->bigfbuf + samps_read;
+			}
+			dz->flbufptr[1] = dz->flbufptr[2];
+			dz->flbufptr[0] = dz->bigfbuf;
+		}
+		n++;
+	}
+	if((exit_status = setup_thisbuf_and_nextbuf(*last_total_wndws,thisbuf,nextbuf,dz))<0)
+		return(exit_status);
+	return(CONTINUE);
+}
+
+/************************** DO_TIME_WIGGLE ************************/
+
+int	do_time_wiggle(double *ttime,dataptr dz)
+{	
+	int exit_status;
+	double this_trange;
+	double wiggle = (drand48() * 2.0) -1.0;
+	if(dz->brksize[WARP_TRNG])	 {		/* RWD need curly */
+		if((exit_status = read_value_from_brktable(*ttime,WARP_TRNG,dz))<0)
+			return(exit_status);
+	}
+	this_trange = dz->param[WARP_TRNG] * wiggle;
+	*ttime  += this_trange;
+	return(FINISHED);
+}
+
+/************************** DO_TIMEWARP ************************/
+
+int do_timewarp
+(float **thisbuf,float **nextbuf,int thisinpos,int outdiff,int *lastinpos,int *last_total_wndws,dataptr dz)
+{
+	int exit_status;
+	int   indiff = thisinpos - *lastinpos;						/* number of windows to scan in  input data */
+	double step = (double)indiff/(double)outdiff;	       		/* fractional step in input data */
+	int   move;
+	int   n, ip, lastip = *lastinpos;
+	double thisfrac, thisindex = (double)(*lastinpos) + step;  	/* fractional position in input data */
+	double oldmidi, newmidi, transp; 
+
+	for(n=1; n <= outdiff; n++, thisindex+=step) {
+		ip = (int)thisindex; /* TRUNCATE */
+		thisfrac = thisindex - (double)ip;
+		move     = ip - lastip;
+		lastip   = ip;
+		if(move) {
+			if((exit_status = adjust_input_buffers(thisbuf,nextbuf,ip,last_total_wndws,1,dz))!=CONTINUE)
+				return(exit_status);
+		}
+		if((exit_status = interp_between_vals_in_two_bufs(*thisbuf,*nextbuf,thisfrac,dz))<0)
+			return(exit_status);
+		if((exit_status = interp_between_pitch_vals(&oldmidi,dz->pitches,ip,thisfrac,dz))<0)
+			return(exit_status);
+		if((exit_status = interp_between_pitch_vals2(&newmidi,dz->parray[WARP_P2],ip,thisfrac,dz))<0)
+			return(exit_status);
+		transp  = SEMITONES_AS_RATIO(newmidi - oldmidi);
+		if((exit_status = transpose_outbuf(transp,dz))<0)
+			return(exit_status);
+		if((dz->flbufptr[1] += dz->wanted) >= dz->flbufptr[3]) {
+			if((exit_status = write_exact_samps(dz->flbufptr[2],dz->big_fsize,dz))<0)
+				return(exit_status);
+			dz->flbufptr[1] = dz->flbufptr[2];
+		}
+	}
+	return(CONTINUE);
+}
+
+/***************** FIND_CURRENTBUF_INDEX *******************/	
+
+int find_currentbuf_index(int *currentbuf_index,int *last_total_wndws,float **thisbuf,dataptr dz)
+{
+	int samps_read = 0;
+	int finalbuf_index;
+	if(dz->iparam[WARP_ATEND]) {
+		*currentbuf_index = max((dz->wlength - 2) - (*last_total_wndws),0);
+		return(CONTINUE);
+	}
+	while(*currentbuf_index >= dz->iparam[WARP_WREAD]) {
+		if((samps_read = fgetfbufEx(dz->bigfbuf,dz->big_fsize,dz->ifd[0],0)) <= 0) {
+			if(samps_read<0) {
+				sprintf(errstr,"Sound read error.\n");
+				return(SYSTEM_ERROR);
+			}
+			return(FINISHED);
+		}
+		if(sloom)
+			dz->total_samps_read += samps_read;
+		if(samps_read <= dz->big_fsize)
+			dz->iparam[WARP_ATEND] = 1;
+		*currentbuf_index -= dz->iparam[WARP_WREAD];
+		*last_total_wndws += dz->iparam[WARP_WREAD];
+		if(dz->iparam[WARP_ATEND]) {
+			finalbuf_index = max((dz->wlength - 2) - (*last_total_wndws),0);
+			*currentbuf_index = min(*currentbuf_index,finalbuf_index);
+		}
+	}
+	dz->iparam[WARP_WREAD] = samps_read/dz->wanted;
+	if(dz->iparam[WARP_ATEND])
+		dz->flbufptr[6] = dz->bigfbuf + samps_read;
+
+	*thisbuf = dz->bigfbuf + (*currentbuf_index * dz->wanted);
+	return(CONTINUE);
+}
+
+/***************** FIND_CURRENTBUF_NEXTINDEX *******************/
+
+int find_currentbuf_nextindex(int *currentbuf_nextindex,int last_total_wndws,dataptr dz)
+{
+	int samps_read;
+	int lastindex = (dz->wlength - 1) - last_total_wndws;
+	*currentbuf_nextindex = lastindex;
+	if(dz->iparam[WARP_ATEND])
+		return(FINISHED);
+	if((samps_read = fgetfbufEx(dz->bigfbuf, dz->big_fsize,dz->ifd[0],0)) <= 0) {
+		if(samps_read<0) {
+			sprintf(errstr,"Sound read error.\n");
+			return(SYSTEM_ERROR);
+		}
+		dz->iparam[WARP_ATEND] = 1;
+		return(FINISHED);
+	}
+	if(sloom)
+		dz->total_samps_read += samps_read;
+	dz->iparam[WARP_WREAD] = samps_read/dz->wanted;
+	if(samps_read < dz->big_fsize) {
+		dz->iparam[WARP_ATEND] = 1;
+		dz->flbufptr[6] = dz->bigfbuf + samps_read;
+	}
+	*currentbuf_nextindex = 0L;
+	return(FINISHED);
+}
+
+/***************** SETUP_THISBUF_AND_NEXTBUF *******************/
+
+int setup_thisbuf_and_nextbuf(int last_total_wndws,float **thisbuf,float **nextbuf,dataptr dz)
+{
+	int  exit_status;
+	int currentbuf_nextindex;
+	if(dz->flbufptr[0] + dz->wanted >= dz->flbufptr[2]) {
+		memmove((char *)dz->flbufptr[3],(char *)dz->flbufptr[0],(size_t)dz->wanted * sizeof(float));
+		*thisbuf   = dz->flbufptr[3];
+		if((exit_status = find_currentbuf_nextindex(&currentbuf_nextindex,last_total_wndws,dz))<0)
+			return(exit_status);
+		*nextbuf   = dz->bigfbuf + (currentbuf_nextindex * dz->wanted);
+	}
+	return(FINISHED);
+}
+
+/***************** INTERP_BETWEEN_VALS_IN_TWO_BUFS *******************/
+
+int interp_between_vals_in_two_bufs(float *thisbuf,float *nextbuf,double interpval,dataptr dz)
+{
+	int vc;
+	double thismidi, nextmidi, mididiff, ampdiff;
+	rectify_window(thisbuf,dz);
+	if(interpval<FLTERR) {
+		rectify_window(thisbuf,dz);
+		if(dz->flbufptr[1]!=thisbuf)
+			memmove((char *)dz->flbufptr[1],(char *)thisbuf,(size_t)(dz->wanted * sizeof(float)));
+		return(FINISHED);
+	}
+	if(interpval > (1.0 - FLTERR)) {
+		rectify_window(nextbuf,dz);
+		if(dz->flbufptr[1]!=nextbuf)
+			memmove((char *)dz->flbufptr[1],(char *)nextbuf,(size_t)(dz->wanted * sizeof(float)));
+		return(FINISHED);
+	}
+	rectify_window(thisbuf,dz);
+	rectify_window(nextbuf,dz);
+	for(vc = 0; vc<dz->wanted; vc+=2) {
+		thismidi = log(max(SPEC_MINFRQ,(double)thisbuf[FREQ]));	/* quick calc using logs, without hztimidi() */
+		nextmidi = log(max(SPEC_MINFRQ,(double)nextbuf[FREQ]));	/* works because logs to different bases are simply */
+		mididiff = nextmidi - thismidi;	 						/* scaled versions of one another. See Feynmann book. */
+		ampdiff  = nextbuf[AMPP] - thisbuf[AMPP];
+		dz->flbufptr[1][FREQ] = (float)exp(thismidi + (mididiff * interpval));	/* exp() = antilog of log() */
+		dz->flbufptr[1][AMPP] = (float)(thisbuf[AMPP] + (ampdiff * interpval));
+	}
+	return(FINISHED);
+}
+
+/***************** INTERP_BETWEEN_PITCH_VALS *******************/
+
+int interp_between_pitch_vals(double *thismidi,float *pitch,int thisindex,double interpval,dataptr dz)
+{
+	double mididiff;
+	if(thisindex<0) {
+		sprintf(errstr,"Pitch_interpolation val < 0 in interp_between_pitch_vals()\n");
+		return(PROGRAM_ERROR);
+	}
+	if(thisindex >= (dz->wlength - 2)) {
+		*thismidi = (double)pitch[(dz->wlength - 1)];
+		return(FINISHED);
+	}
+	if(interpval < FLTERR) {
+		*thismidi = (double)pitch[thisindex];
+		return(FINISHED);
+	}
+	if(interpval > (1.0 - FLTERR)) {
+		*thismidi = (double)pitch[thisindex+1];
+		return(FINISHED);
+	}
+	mididiff  = pitch[thisindex+1] - pitch[thisindex];
+	*thismidi = pitch[thisindex] + (mididiff * interpval);
+	return(FINISHED);
+}
+
+/***************** INTERP_BETWEEN_PITCH_VALS2 *******************/
+
+int interp_between_pitch_vals2(double *thismidi,double *pitch,int thisindex,double interpval,dataptr dz)
+{
+	double mididiff;
+	if(thisindex<0) {
+		sprintf(errstr,"Interpolation val < 0 in interp_between_pitch_vals2()\n");
+		return(PROGRAM_ERROR);
+	}
+	if(thisindex >= (dz->wlength - 2)) {
+		*thismidi = pitch[(dz->wlength - 1)];
+		return(FINISHED);
+	}
+	if(interpval < FLTERR) {
+		*thismidi = pitch[thisindex];
+		return(FINISHED);
+	}
+	if(interpval > (1.0 - FLTERR)) {
+		*thismidi = pitch[thisindex+1];
+		return(FINISHED);
+	}
+	mididiff = pitch[thisindex+1] - pitch[thisindex];
+	*thismidi = pitch[thisindex] + (mididiff * interpval);
+	return(FINISHED);
+}
+
+/***************** TRANSPOSE_OUTBUF *******************/
+
+int transpose_outbuf(double transp,dataptr dz)
+{
+	int vc;
+	for(vc=0;vc<dz->wanted;vc+=2)
+		dz->flbufptr[1][FREQ] = (float)(dz->flbufptr[1][FREQ] * transp);
+	return put_transposed_data_in_appropriate_chans(transp,dz);
+}
+
+/***************** PUT_TRANSPOSED_DATA_IN_APPROPRIATE_CHANS *******************/	
+
+int put_transposed_data_in_appropriate_chans(double transp,dataptr dz)
+{
+	int exit_status;
+	int cc,vc;
+	if((exit_status = rectify_frqs(dz->flbufptr[1],dz))<0)
+		return(exit_status);
+	if(transp < 1.0) {	  			  /* If transposition is downwards, go up the channels */
+		for(cc=0,vc=0; cc < dz->clength; cc++,vc+=2) {
+			if((exit_status = put_thisdata_in_appropriate_chan(cc,vc,dz))<0)
+				return(exit_status);
+		}
+	} else {						  /* If transposition is upwards, go down the channels */
+		for(cc=dz->clength-1,vc = dz->wanted-2; cc >=0 ;cc--,vc-=2) {
+			if((exit_status = put_thisdata_in_appropriate_chan(cc,vc,dz))<0)
+				return(exit_status);
+		}
+	}
+	return(FINISHED);
+}
+
+/***************** PUT_THISDATA_IN_APPROPRIATE_CHAN *******************/	
+
+int put_thisdata_in_appropriate_chan(int cc,int vc, dataptr dz)
+{
+	int exit_status;
+	int truecc, truevc, trutop;
+	if(dz->flbufptr[1][FREQ] > dz->nyquist) {			/* zero out frqs above nyquist */
+		dz->flbufptr[1][AMPP] = 0.0f;
+		dz->flbufptr[1][FREQ] = (float)dz->nyquist;
+		return(FINISHED);
+	}									    /* if new frq outside acceptable frq limits for channel */
+	if(dz->flbufptr[1][FREQ] < dz->flbufptr[WCHBOT][cc] || dz->flbufptr[1][FREQ] > dz->flbufptr[WCHTOP][cc]) { 
+		if((exit_status = get_channel_corresponding_to_frq(&truecc,(double)dz->flbufptr[1][FREQ],dz))<0)
+			return(exit_status);
+		trutop = min(dz->clength-1,truecc + CHANSPAN);
+		truecc = max(truecc - CHANSPAN,0); /* find bottom and top chans that could receive this frq */
+		truevc = truecc * 2;				
+		while(dz->flbufptr[1][FREQ] > dz->flbufptr[1][truevc+1]) {
+			truevc += 2;		/* find position of new freq amongst freq ordering of existing data */
+			if(truevc >= trutop)
+				break;
+		}
+		truevc -= 2;
+		do {
+			if(dz->flbufptr[1][AMPP] > dz->flbufptr[1][truevc]) { /* If transpd data stronger than existing data  */
+				dz->flbufptr[1][truevc]   = dz->flbufptr[1][AMPP];/* replace existing data by transposed data     */
+				dz->flbufptr[1][truevc+1] = dz->flbufptr[1][FREQ];
+				break;
+		 	}
+		 	truevc += 2;
+		}  while(truevc < trutop);
+		dz->flbufptr[1][AMPP] = 0.0f;			/* Zero out channel from which data has been moved  */
+		if(cc>0 && cc < dz->clength-1)			/* Interp frq of that chan, betwn preexisting chans */
+			dz->flbufptr[1][FREQ] = (float)((dz->flbufptr[1][FREQ+2]  + dz->flbufptr[1][FREQ-2])/2.0);
+		else {					            	
+			if(cc==0) dz->flbufptr[1][FREQ] = 0.0f;
+			else	  dz->flbufptr[1][FREQ] = (float)dz->nyquist;
+		}										/* This chan may later be filld by other moved data */
+	}
+	return(FINISHED);
+}
+
+/**************************** LOGREAD_SHIFT *****************************/
+
+int logread_shift(double timenow,int btktable_no,dataptr dz)
+{
+	double *endpair, *p;
+	double hival, loval, hiind, loind, lopshift, interval, newpshift;
+    if(!dz->brkinit[btktable_no]) {
+		dz->firstval[btktable_no] = *(dz->brk[btktable_no]+1);
+		endpair                   = dz->brk[btktable_no] 
+									+ ((dz->brksize[btktable_no]-1)*2);
+		dz->lastind[btktable_no]  = *endpair;
+		dz->lastval[btktable_no]  = *(endpair+1);
+ 		dz->brkinit[btktable_no]  = 1;
+    }
+	p = dz->brkptr[btktable_no];
+	if(timenow <= *(dz->brk[btktable_no])) {
+		dz->param[btktable_no] = dz->firstval[btktable_no];
+		return(FINISHED);
+	} else if(timenow >= dz->lastind[btktable_no]) {
+		dz->param[btktable_no] = dz->lastval[btktable_no];
+		return(FINISHED);
+	} 
+	if(timenow > *(p)) {
+		while(*(p)<timenow)
+			p += 2;
+	} else {
+		while(*(p)>=timenow)
+			p -= 2;
+		p += 2;
+	}
+	hival = *(p+1);
+	hiind  = *p;
+	loval = *(p-1);
+	loind  = *(p-2);
+	if(flteq(loval,hival))
+		dz->param[btktable_no]  = loval;
+	else if(loval < 0.0 && hival < 0.0) {
+		lopshift  = log(-loval);
+		interval  = log(-hival/-loval);
+		interval *= (timenow - loind)/(hiind - loind);
+		newpshift = lopshift + interval;
+		dz->param[btktable_no] = -exp(newpshift);
+	} else if (loval > 0.0 && hival > 0.0){
+		lopshift  = log(loval);
+		interval  = log(hival/loval);
+		interval *= (timenow - loind)/(hiind - loind);
+		newpshift = lopshift + interval;
+		dz->param[btktable_no] = exp(newpshift);
+	} else {
+/*  if shift changes from +ve (or 0) to -ve (or 0) or v.v., do linear shift */
+		interval  = hival - loval;
+		interval *= (timenow - loind)/(hiind - loind);
+		dz->param[btktable_no] = loval + interval;
+	}	
+ 	dz->brkptr[btktable_no] = p;
+	return(FINISHED);
+}
+
+/**************************** READ_VALUE_FROM_BRKTABLE_USING_LOG_INTERPOLATION *****************************
+ *
+ * Slightly weird function that fudges problem of log(0) and log(-ve).
+ */
+
+int read_value_from_brktable_using_log_interpolation(double thistime,int paramno,dataptr dz)
+{
+	double *endpair, *p;
+	double hival, loval, hiind, loind, lopitch, interval, newpitch;
+
+    if(!dz->brkinit[paramno]) {
+		dz->brkptr[paramno]   = dz->brk[paramno];
+		dz->firstval[paramno] = *(dz->brk[paramno]+1);
+		endpair             = dz->brk[paramno] + ((dz->brksize[paramno]-1)*2);
+		dz->lastind[paramno]  = *endpair;
+		dz->lastval[paramno]  = *(endpair+1);
+ 		dz->brkinit[paramno] = 1;
+    }
+	p = dz->brkptr[paramno];
+	if(thistime <= *(dz->brk[paramno])) {
+		dz->param[paramno] = dz->firstval[paramno];
+		return(FINISHED);
+	} else if(thistime >= dz->lastind[paramno]) {
+		dz->param[paramno] = dz->lastval[paramno];
+		return(FINISHED);
+	} 
+	if(thistime > *(p)) {
+		while(*(p)<thistime)
+			p += 2;
+	} else {
+		while(*(p)>=thistime)
+			p -= 2;
+		p += 2;
+	}
+	hival = *(p+1);
+	hiind = *p;
+	loval = *(p-1);
+	loind = *(p-2);
+	if(flteq(loval,hival))
+		dz->param[paramno]  = loval;
+	else if(loval < 0.0 && hival < 0.0) {
+		lopitch   = log(-loval);
+		interval  = log(-hival/-loval);
+		interval *= (thistime - loind)/(hiind - loind);
+		newpitch  = lopitch + interval;
+		dz->param[paramno] = -exp(newpitch);
+	} else if (loval > 0.0 && hival > 0.0){
+		lopitch   = log(loval);
+		interval  = log(hival/loval);
+		interval *= (thistime - loind)/(hiind - loind);
+		newpitch  = lopitch + interval;
+		dz->param[paramno] = exp(newpitch);
+	} else {
+		/*  if val changes from +ve (or 0) to -ve (or 0) or v.v., do linear shift */
+		interval  = hival - loval;
+		interval *= (thistime - loind)/(hiind - loind);
+		dz->param[paramno] = loval + interval;
+	}	
+ 	dz->brkptr[paramno] = p;
+	return(FINISHED);
+}
+
+/**************************** ASSIGN_NEW_FRQS_TO_APPROPRIATE_CHANNELS ****************************
+ *
+ * (0)	Find the lowest channel for which we have generated a new freq value.
+ * (0a) If no frqs lie below nyquist, zero all chan amps above botchan!!
+ * (1)	Set initial amplitude for each transformed channel to zero.
+ * (2)	Look through the set of stretched channels for any frequency
+ *		values which lie below the top frq boundary of the current channel,
+ * (3)	IF they are also above the bottom freq boundary of this channel,
+ *		(i.e. they should be in THIS channel), if their amplitude
+ *		is greater than any amp already assigned to this channel,
+ *		substitute this frq/amp pair as the true value for this channel.
+ * (4)	If we run out of values among the transformed freq values,
+ *		break, and set OK=0 to break from outer loop too.
+ * (5)	If we've broken from inner loop, break from outer loop too.
+ * (6)	If we've broken from inner loop, zero amplitude of any channels
+ *		which have not been assigned a new frequency.
+ */
+
+int assign_new_frqs_to_appropriate_channels(dataptr dz)
+{
+	int dd = dz->iparam[WAVER_BOTCHAN];								/* 0 */
+	int  OK = 1, cc = 0, vc;
+	while(dz->freq[dd] >= (float)(dz->parray[WAVER_CHFBOT][cc+1])) {
+		if(++cc >= dz->clength) {					/* 0a */
+			for(vc = dz->iparam[WAVER_BOTCHAN] * 2; vc < dz->wanted; vc += 2)
+				dz->flbufptr[0][AMPP] = 0.0F;
+			return(FINISHED);
+		}
+	}
+	for(vc=cc*2; cc<dz->clength; cc++,vc+=2) {
+		dz->flbufptr[0][AMPP] = 0.0F;					/* 1 */
+		while(dz->freq[dd] < (float)(dz->parray[WAVER_CHFBOT][cc+1])) {	/* 2 */
+			if((dz->freq[dd] >= dz->parray[WAVER_CHFBOT][cc]) && (dz->amp[dd] > dz->flbufptr[0][AMPP])) {
+				dz->flbufptr[0][AMPP] = dz->amp[dd];		/* 3 */
+				dz->flbufptr[0][FREQ] = dz->freq[dd];
+			}
+			if(++dd>=dz->clength) {					/* 4 */
+				OK = 0;
+				break;
+			}
+		}
+		if(!OK)										/* 5 */
+			break;
+	}
+	if(!OK) {
+		while(vc<dz->wanted) {						/* 6 */
+			dz->flbufptr[0][AMPP] = 0.0F;
+			vc += 2;
+		}
+	}
+	return(FINISHED);
+}

+ 20 - 0
dev/stretch/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(stretch main.c ap_stretch.c stretch.c)
+
+target_link_libraries(stretch cdp2k sfsys ${EXTRA_LIBRARIES})
+
+my_install(stretch)
+

+ 594 - 0
dev/stretch/ap_stretch.c

@@ -0,0 +1,594 @@
+/*
+ * Copyright (c) 1983-2020 Trevor Wishart and Composers Desktop Project Ltd
+ * http://www.trevorwishart.co.uk
+ * http://www.composersdesktop.com
+ *
+ This file is part of the CDP System.
+
+    The CDP System is free software; you can redistribute it
+    and/or modify it under the terms of the GNU Lesser General Public
+    License as published by the Free Software Foundation; either
+    version 2.1 of the License, or (at your option) any later version.
+
+    The CDP System is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public
+    License along with the CDP System; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+    02111-1307 USA
+ *
+ */
+
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <structures.h>
+#include <cdpmain.h>
+#include <tkglobals.h>
+#include <pnames.h>
+#include <stretch.h>
+#include <processno.h>
+#include <modeno.h>
+#include <globcon.h>
+#include <logic.h>
+#include <filetype.h>
+#include <mixxcon.h>
+#include <speccon.h>
+#include <flags.h>
+#include <arrays.h>
+#include <formants.h>
+#include <sfsys.h>
+#include <osbind.h>
+#include <string.h>
+#include <math.h>
+#include <srates.h>
+
+/********************************************************************************************/
+/********************************** FORMERLY IN buffers.c ***********************************/
+/********************************************************************************************/
+
+static int  allocate_tstretch_buffer(dataptr dz);
+
+/********************************************************************************************/
+/********************************** FORMERLY IN pconsistency.c ******************************/
+/********************************************************************************************/
+
+static int  check_viability_and_compatibility_of_stretch_params(dataptr dz);
+static int  check_for_enough_tstretch_brkpnt_vals(dataptr dz);
+
+/********************************************************************************************/
+/********************************** FORMERLY IN preprocess.c ********************************/
+/********************************************************************************************/
+
+#define POSMIN      (200)   /* Minimum size for positions array in spec tstretch */
+static int  set_internal_stretch_params(dataptr dz);
+static int  setup_internal_params_for_tstretch(dataptr dz);
+
+/***************************************************************************************/
+/****************************** FORMERLY IN aplinit.c **********************************/
+/***************************************************************************************/
+
+/***************************** ESTABLISH_BUFPTRS_AND_EXTRA_BUFFERS **************************/
+
+int establish_bufptrs_and_extra_buffers(dataptr dz)
+{
+    int exit_status;
+    int is_spec = FALSE;
+    dz->extra_bufcnt = -1;  /* ENSURE EVERY CASE HAS A PAIR OF ENTRIES !! */
+    dz->bptrcnt = 0;
+    dz->bufcnt  = 0;
+    switch(dz->process) {
+    case(STRETCH):          dz->extra_bufcnt =  0; dz->bptrcnt = 1;     is_spec = TRUE;     break;
+    case(TSTRETCH):         dz->extra_bufcnt =  0; dz->bptrcnt = 6;     is_spec = TRUE;     break;
+    default:
+        sprintf(errstr,"Unknown program type [%d] in establish_bufptrs_and_extra_buffers()\n",dz->process);
+        return(PROGRAM_ERROR);
+    }
+
+    if(dz->extra_bufcnt < 0) {
+        sprintf(errstr,"bufcnts have not been set: establish_bufptrs_and_extra_buffers()\n");
+        return(PROGRAM_ERROR);
+    }
+    if(is_spec)
+        return establish_spec_bufptrs_and_extra_buffers(dz);
+    else if((dz->process==HOUSE_SPEC && dz->mode==HOUSE_CONVERT) || dz->process==INFO_DIFF) {
+        if((exit_status = establish_spec_bufptrs_and_extra_buffers(dz))<0)
+            return(exit_status);
+    }
+    return establish_groucho_bufptrs_and_extra_buffers(dz);
+}
+
+/***************************** SETUP_INTERNAL_ARRAYS_AND_ARRAY_POINTERS **************************/
+
+int setup_internal_arrays_and_array_pointers(dataptr dz)
+{
+    int n;       
+    dz->ptr_cnt    = -1;        /* base constructor...process */
+    dz->array_cnt  = -1;
+    dz->iarray_cnt = -1;
+    dz->larray_cnt = -1;
+    switch(dz->process) {
+    case(STRETCH):  dz->array_cnt = 0; dz->iarray_cnt = 0; dz->larray_cnt = 0; dz->ptr_cnt = 0; dz->fptr_cnt = 0;   break;
+    case(TSTRETCH): dz->array_cnt =2;  dz->iarray_cnt = 0; dz->larray_cnt = 0; dz->ptr_cnt =4;  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(STRETCH):      setup_process_logic(ANALFILE_ONLY,          EQUAL_ANALFILE,     ANALFILE_OUT,   dz);    break;
+    case(TSTRETCH):
+        switch(dz->mode) {
+        case(TSTR_NORMAL):setup_process_logic(ANALFILE_ONLY,        BIG_ANALFILE,       ANALFILE_OUT,   dz);    break;
+        case(TSTR_LENGTH):setup_process_logic(ANALFILE_ONLY,        SCREEN_MESSAGE,     NO_OUTPUTFILE,  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(STRETCH):      exit_status = set_internalparam_data("idd",ap);                 break;
+    case(TSTRETCH):     exit_status = set_internalparam_data("di",ap);                  break;
+    default:
+        sprintf(errstr,"Unknown process in set_legal_internalparam_structure()\n");
+        return(PROGRAM_ERROR);
+    }
+    return(exit_status);        
+}
+
+/********************************************************************************************/
+/********************************** FORMERLY IN specialin.c *********************************/
+/********************************************************************************************/
+
+/********************** READ_SPECIAL_DATA ************************/
+
+int read_special_data(char *str,dataptr dz)
+{
+    aplptr ap = dz->application;
+    switch(ap->special_data) {
+    default:
+        sprintf(errstr,"Unknown special_data type: read_special_data()\n");
+        return(PROGRAM_ERROR);
+    }
+    return(FINISHED);   /* NOTREACHED */
+}
+
+/********************************************************************************************/
+/********************************** FORMERLY IN preprocess.c ********************************/
+/********************************************************************************************/
+
+/****************************** PARAM_PREPROCESS *********************************/
+
+int param_preprocess(dataptr dz)
+{
+    switch(dz->process) {
+    case(STRETCH):      return set_internal_stretch_params(dz);
+    case(TSTRETCH):     return setup_internal_params_for_tstretch(dz);
+    default:
+        sprintf(errstr,"PROGRAMMING PROBLEM: Unknown process in param_preprocess()\n");
+        return(PROGRAM_ERROR);
+    }
+    return(FINISHED);   /* NOTREACHED */
+}
+
+/************ SET_INTERNAL_STRETCH_PARAMS *************/
+
+int set_internal_stretch_params(dataptr dz)
+{
+    dz->param[STR_FFRQ]  += dz->chwidth/2.0;    /* set up FDCNO */
+    dz->iparam[STR_FDCNO] = (int)floor(dz->param[STR_FFRQ]/dz->chwidth);
+    if(dz->vflag[STR_IS_DEPTH]) {
+        dz->param[STR_SL1] = dz->param[STR_SHIFT] - 1.0;
+        if(dz->brksize[STR_DEPTH]==0)
+            dz->param[STR_NSHIFT] = (dz->param[STR_SL1] * dz->param[STR_DEPTH]) + 1.0;
+    } else
+        dz->param[STR_NSHIFT] = dz->param[STR_SHIFT];
+    return(FINISHED);
+}
+
+/************ SETUP_INTERNAL_PARAMS_FOR_TSTRETCH *************/
+
+int setup_internal_params_for_tstretch(dataptr dz)
+{
+    int exit_status;
+    if(dz->brksize[TSTR_STRETCH] && (exit_status = force_value_at_zero_time(TSTR_STRETCH,dz))<0)
+        return(exit_status);
+    dz->param[TSTR_TOTIME] = (double)dz->wlength * dz->frametime;
+    /* dur of orig sound source */
+
+    dz->iparam[TSTR_ARRAYSIZE]  = POSMIN;
+    if((dz->parray[TSTR_PBUF]
+        = (double *)malloc(dz->iparam[TSTR_ARRAYSIZE] * sizeof(double)))==NULL) {
+        sprintf(errstr,"INSUFFICIENT MEMORY for timestretch array.\n");
+        return(MEMORY_ERROR);
+    }
+    dz->ptr[TSTR_PEND]  = dz->parray[TSTR_PBUF] + dz->iparam[TSTR_ARRAYSIZE];
+    if((dz->parray[TSTR_QBUF]  
+        = (double *)malloc(dz->iparam[TSTR_ARRAYSIZE] * sizeof(double)))==NULL) {
+        sprintf(errstr,"INSUFFICIENT MEMORY for 2nd timestretch array.\n");
+        return(MEMORY_ERROR);
+    }
+    return(FINISHED);
+}
+
+/********************************************************************************************/
+/********************************** FORMERLY IN procspec.c **********************************/
+/********************************************************************************************/
+
+/**************************** SPEC_PROCESS_FILE ****************************/
+
+int spec_process_file(dataptr dz)
+{   
+    dz->total_windows = 0;
+
+    if(!(dz->process==TSTRETCH && dz->mode==TSTR_LENGTH))
+        display_virtual_time(0L,dz);
+
+    switch(dz->process) {
+    case(STRETCH):  return outer_loop(dz);
+    case(TSTRETCH): return spectstretch(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(STRETCH):  exit_status = specstretch(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)
+{
+    return(FALSE);
+}
+
+/********************************************************************************************/
+/********************************** FORMERLY IN pconsistency.c ******************************/
+/********************************************************************************************/
+
+/****************************** CHECK_PARAM_VALIDITY_AND_CONSISTENCY *********************************/
+
+int check_param_validity_and_consistency(dataptr dz)
+{
+    handle_pitch_zeros(dz);
+    switch(dz->process) {
+    case(STRETCH):     return check_viability_and_compatibility_of_stretch_params(dz);
+    case(TSTRETCH):    return check_for_enough_tstretch_brkpnt_vals(dz);
+    }
+    return(FINISHED);
+}
+
+/*************** CHECK_VIABILITY_AND_COMPATIBILITY_OF_STRETCH_PARAMS **********/
+
+int check_viability_and_compatibility_of_stretch_params(dataptr dz)
+{
+    int exit_status;
+    /* set up FDCNO for tests */
+    double  frq = dz->param[STR_FFRQ] + dz->chwidth/2.0;
+    int fdcno = (int)floor(frq/dz->chwidth);
+    if(flteq(dz->param[STR_SHIFT],1.0)) {
+        sprintf(errstr,"Shift = 1. No change. Use your original source.\n");
+        return(DATA_ERROR);
+    }
+    if(dz->vflag[STR_IS_DEPTH]) {
+        if((exit_status = check_depth_vals(STR_DEPTH,dz)) <0)
+            return(exit_status);
+    }
+    switch(dz->mode) {
+    case(STRETCH_ABOVE):
+        if(dz->param[STR_SHIFT] > 1.0
+        && round((double)(dz->clength-1)/dz->param[STR_SHIFT]) < fdcno) {
+            sprintf(errstr,"Maxstretch incompatible with frq_split.\n");
+            return(DATA_ERROR);
+        }
+        if(dz->param[STR_SHIFT] <= 1.0
+        && round((double)(dz->clength-1)*dz->param[STR_SHIFT]) < fdcno) {
+            sprintf(errstr,"Maxstretch incompatible with frq_split.\n");
+            return(DATA_ERROR);
+        }
+        break;
+    case(STRETCH_BELOW):
+        if(dz->param[STR_SHIFT] >= (double)fdcno) {
+            sprintf(errstr,"Maxstretch incompatible with frq_split.\n");
+            return(DATA_ERROR);
+        }
+        if(dz->param[STR_SHIFT] <= 1.0
+        && 1.0/dz->param[STR_SHIFT] >= (double)fdcno) {
+            sprintf(errstr,"Maxstretch incompatible with frq_split.\n");
+            return(DATA_ERROR);
+        }
+        break;
+    default:
+        sprintf(errstr,"Unknown spec stretch mode in check_stretch_params()\n");
+        return(PROGRAM_ERROR);
+    }
+    return(FINISHED);
+}
+
+/********************* CHECK_FOR_ENOUGH_TSTRETCH_BRKPNT_VALS **********************/
+
+int check_for_enough_tstretch_brkpnt_vals(dataptr dz)
+{
+    if(dz->brksize[TSTR_STRETCH] && dz->brksize[TSTR_STRETCH] < 2) {
+        sprintf(errstr,"Not enough data in tsretch data file.\n");
+        return(DATA_ERROR);
+    }
+    return(FINISHED);
+}
+
+/********************************************************************************************/
+/********************************** FORMERLY IN buffers.c ***********************************/
+/********************************************************************************************/
+
+/**************************** ALLOCATE_LARGE_BUFFERS ******************************/
+
+int allocate_large_buffers(dataptr dz)
+{
+    switch(dz->process) {
+    case(STRETCH):
+        return allocate_single_buffer(dz);
+    case(TSTRETCH):
+        if(dz->mode==TSTR_NORMAL)
+            return allocate_tstretch_buffer(dz);
+        return(FINISHED);
+    default:
+        sprintf(errstr,"Unknown program no. in allocate_large_buffers()\n");
+        return(PROGRAM_ERROR);
+    }
+    return(FINISHED);   /* NOTREACHED */
+}
+
+/*************************** ALLOCATE_TSTRETCH_BUFFER ****************************/
+
+int allocate_tstretch_buffer(dataptr dz)
+{
+    unsigned int buffersize;
+    if(dz->bptrcnt < 6) {
+        sprintf(errstr,"Insufficient bufptrs established in allocate_tstretch_buffer()\n");
+        return(PROGRAM_ERROR);
+    }
+//TW REVISED: multiplle of LCM no longer required
+    buffersize = dz->wanted * BUF_MULTIPLIER;
+    dz->buflen = buffersize;
+    buffersize *= 2;
+    buffersize += dz->wanted;
+    if((dz->bigfbuf = (float *)malloc((size_t)(buffersize * sizeof(float))))==NULL) {
+        sprintf(errstr,"INSUFFICIENT MEMORY for sound buffers.\n");
+        return(MEMORY_ERROR);
+    }
+    dz->big_fsize = dz->buflen;
+    dz->flbufptr[0] = dz->bigfbuf + dz->wanted;         /* inbuf */
+    dz->flbufptr[1] = dz->flbufptr[0] + dz->big_fsize;  /* outbuf & inbufend */
+    dz->flbufptr[2] = dz->flbufptr[1] + dz->big_fsize;  /* outbufend */
+
+    dz->flbufptr[3] = dz->flbufptr[0];                  /* 1st inbuf pointer */
+    dz->flbufptr[4] = dz->flbufptr[0] + dz->wanted;     /* 2nd inbuf pointer */
+    dz->flbufptr[5] = dz->flbufptr[1];                  /* outbuf ptr */
+    return(FINISHED);
+}
+
+/********************************************************************************************/
+/********************************** FORMERLY IN cmdline.c ***********************************/
+/********************************************************************************************/
+
+int get_process_no(char *prog_identifier_from_cmdline,dataptr dz)
+{
+    if     (!strcmp(prog_identifier_from_cmdline,"spectrum"))       dz->process = STRETCH;
+    else if(!strcmp(prog_identifier_from_cmdline,"time"))           dz->process = TSTRETCH;
+    else {
+        sprintf(errstr,"Unknown program identification string '%s'\n",prog_identifier_from_cmdline);
+        return(USAGE_ONLY);
+    }
+//TW UPDATE
+    return(FINISHED);
+}
+
+/********************************************************************************************/
+/********************************** FORMERLY IN usage.c *************************************/
+/********************************************************************************************/
+
+/******************************** USAGE1 ********************************/
+
+int usage1(void)
+{
+    sprintf(errstr,
+    "\nSTRETCHING A SPECTRAL FILE\n\n"
+    "USAGE: stretch NAME (mode) infile outfile parameters: \n"
+    "\n"
+    "where NAME can be any one of\n"
+    "spectrum      time\n\n"
+    "Type 'stretch spectrum' for more info on stretch spectrum..ETC.\n");
+    return(USAGE_ONLY);
+}
+
+/******************************** USAGE2 ********************************/
+
+int usage2(char *str)
+{
+    if(!strcmp(str,"spectrum")) {     /* STRETCH */
+        fprintf(stdout,
+        "stretch spectrum mode infile outfile frq_divide maxstretch exponent [-ddepth]\n"
+        "\n"
+        "STRETCH THE FREQUENCIES IN THE SPECTRUM\n"
+        "\n"
+        "MODES:-\n"
+        "1     Stretch above the frq_divide.\n"
+        "2     Stretch below the frq_divide.\n"
+        "\n"
+        "frq_divide is the frq above or below which spectral stretching takes place.\n"
+        "maxstretch is the transposition ratio of the topmost spectral components.\n"
+        "exponent   specifies the type of stretching required.  (> 0)\n"
+        "depth      stretch effect on source (from 0 (no effect) to 1 (full effect))\n\n"
+        "depth can vary over time.\n");
+    } else if(!strcmp(str,"time")) {    /* TSTRETCH */
+        sprintf(errstr,
+        "stretch time 1 infile outfile timestretch\n"
+        "stretch time 2 infile timestretch\n"
+        "\n"
+        "TIME-STRETCHING OF INFILE.\n"
+        "In mode 2, program calculates length of output, only."
+        "\n"
+        "Timestretch may itself vary over time.\n");
+    } else
+        sprintf(errstr,"Unknown option '%s'\n",str);
+    return(USAGE_ONLY);
+}
+
+/******************************** USAGE3 ********************************/
+
+int usage3(char *str1,char *str2)
+{
+//TW AVOID WARNINGS
+//    str1 = str1;
+//    str2 = str2;
+
+    sprintf(errstr,"Insufficient parameters on command line.\n");
+    return(USAGE_ONLY);
+}
+

+ 234 - 0
dev/stretch/main.c

@@ -0,0 +1,234 @@
+/*
+ * 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 <stretch.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((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);
+}
+

+ 695 - 0
dev/stretch/stretch.c

@@ -0,0 +1,695 @@
+/*
+ * Copyright (c) 1983-2013 Trevor Wishart and Composers Desktop Project Ltd
+ * http://www.trevorwishart.co.uk
+ * http://www.composersdesktop.com
+ *
+ This file is part of the CDP System.
+
+    The CDP System is free software; you can redistribute it
+    and/or modify it under the terms of the GNU Lesser General Public
+    License as published by the Free Software Foundation; either
+    version 2.1 of the License, or (at your option) any later version.
+
+    The CDP System is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public
+    License along with the CDP System; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+    02111-1307 USA
+ *
+ */
+
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <structures.h>
+#include <tkglobals.h>
+#include <pnames.h>
+#include <globcon.h>
+#include <modeno.h>
+#include <arrays.h>
+#include <stretch.h>
+#include <cdpmain.h>
+#include <formants.h>
+#include <speccon.h>
+#include <sfsys.h>
+#include <string.h>
+#include <stretch.h>
+
+static int  	do_constant_timestretch(int *thatwindow,dataptr dz);
+static int  	do_timevariable_timestretch(int *thatwindow,dataptr dz);
+static int  	do_timestretching(int *thatwindow,int count,dataptr dz);
+static int  	do_timevariable_count(int *outcnt,dataptr dz);
+static int  	divide_time_into_equal_increments(int *thatwindow,int startwindow,
+					double dur,int count,dataptr dz);
+static int  	get_both_vals_from_brktable(double *thistime,double *thisstretch,int brktab_no,dataptr dz);
+static int  	timestretch_this_segment(int *thatwindow,int startwindow,
+					double thiswdur,double nextwdur,int totaldur,dataptr dz);
+static int  	advance_along_input_windows(int wdw_to_advance,int atend,dataptr dz);
+static double  	calculate_number_of_output_windows(double startwdur,double endwdur,int totaldur);
+static int  	calc_position_output_wdws_relative_to_input_wdws_for_decreasing_stretch
+					(int *thatwindow,int startwindow,int count,int totaldur,
+					double param0,double param1,double param2,dataptr dz);
+static int  	calc_position_output_wdws_relative_to_input_wdws_for_increasing_stretch
+					(int *thatwindow,int startwindow,int count,
+					double param0,double param1,double param2,dataptr dz);
+static double  	calculate_position(int x,double param0,double param1,double param2);
+static int  	retrograde_sequence_of_time_intervals(int endtime,int count,double *startptr,dataptr dz);
+static int 		stretch_spectrum(double shift,dataptr dz);
+
+/********************************** SPECTSTRETCH **********************************
+ *
+ * Timestretch spectrum.
+ */
+ 
+int spectstretch(dataptr dz)
+{
+	int exit_status;
+	int thatwindow, outcnt = 0;
+	int samps_read;
+
+	switch(dz->mode) {
+	case(TSTR_NORMAL):
+		if((samps_read = fgetfbufEx(dz->flbufptr[0], dz->big_fsize,dz->ifd[0],0)) < 0) {
+			sprintf(errstr,"No data found in input soundfile.\n");
+			return(DATA_ERROR);
+		}
+		if(sloom)
+			dz->total_samps_read = samps_read;
+		dz->flbufptr[3] = dz->flbufptr[0];
+		dz->flbufptr[4] = dz->flbufptr[0] + dz->wanted;
+		thatwindow = 0;
+		if(dz->brksize[TSTR_STRETCH]==0)
+			exit_status = do_constant_timestretch(&thatwindow,dz);
+		else
+			exit_status = do_timevariable_timestretch(&thatwindow,dz);
+		if(exit_status<0)
+			return(exit_status);
+		if((exit_status = do_timestretching(&thatwindow,dz->ptr[TSTR_PBUF] - dz->parray[TSTR_PBUF],dz))<0)
+			return(exit_status);
+		if(dz->flbufptr[5] - dz->flbufptr[1] > 0)
+			return write_samps(dz->flbufptr[1],dz->flbufptr[5] - dz->flbufptr[1],dz);
+		return FINISHED;
+	case(TSTR_LENGTH):
+		if(dz->brksize[TSTR_STRETCH]==0)
+			outcnt = round(fabs((double)dz->wlength * dz->param[TSTR_STRETCH]));
+		else if((exit_status = do_timevariable_count(&outcnt,dz))<0)
+			return(exit_status);
+		fprintf(stdout,"INFO: Length of output file will be %.3lf secs.\n",outcnt * dz->frametime);
+		fflush(stdout);
+		break;
+	default:
+		sprintf(errstr,"Unknown mode in specstretch()\n");
+		return(PROGRAM_ERROR);
+	}
+	return(FINISHED);
+}
+
+/******************************* DO_CONSTANT_TIMESTRETCH ****************************
+ *
+ * Set up array of indices for reading source window values into new
+ * windows.
+ *
+ * (0)	Initialise position-buffer pointer and start window.
+ * (1)	Get first breakpoint pair from brkpoint table.
+ * (2)	Calculate initial time as whole number of WINDOWS.
+ * (3)	If time is stretched, output window is SHRUNK relative to input
+ *	window. Hence val = 1/stretch.
+ * (4)	Proceed in a loop of all input breakpoint values.
+ * (5)	Returns if premature end of file encountered.
+ */
+
+int do_constant_timestretch(int *thatwindow,dataptr dz)
+{
+	double thiswdur, dcount, dur;
+	int count;
+	int startwindow = 0;
+	dz->ptr[TSTR_PBUF] = dz->parray[TSTR_PBUF];
+	thiswdur  = 1.0/dz->param[TSTR_STRETCH];					/* 3 */
+	dcount = (double)dz->wlength/thiswdur;
+	count = round(fabs(dcount));
+	dur = (double)dz->wlength/(double)count;
+	return divide_time_into_equal_increments(thatwindow,startwindow,dur,count,dz);
+}
+
+/******************************* DO_TIMEVARIABLE_TIMESTRETCH ****************************
+ *
+ * Set up array of indices for reading source window values into new
+ * windows.
+ *
+ * (0)	Initialise position-buffer pointer and start window.
+ * (1)	Get first breakpoint pair from brkpoint table.
+ * (2)	Calculate initial time as whole number of WINDOWS.
+ * (3)	If time is stretched, output window is SHRUNK relative to input
+ *		window. Hence val = 1/stretch.
+ * (4)	Proceed in a loop of all input breakpoint values.
+ * (5)	Returns if brkpnt times ran off end of source soundfile.
+ */
+
+int do_timevariable_timestretch(int *thatwindow,dataptr dz)
+{
+	int exit_status;
+	int time0, time1, time2, totaldur;
+	double stretch0, stretch1, thiswdur, nextwdur, valdiff, dtime0, dtime1;
+	int atend = FALSE;
+	int startwindow = 0;												  /* 0 */
+	int timestretch_called = FALSE;
+	dz->ptr[TSTR_PBUF] = dz->parray[TSTR_PBUF];										
+	if((exit_status = get_both_vals_from_brktable(&dtime0,&stretch0,TSTR_STRETCH,dz))<0)	/* 1 */
+		return(exit_status);
+	if(exit_status == FINISHED) {
+		sprintf(errstr,"Not enough data in brkfile & not trapped earlier: do_timevariable_timestretch()\n");
+		return(PROGRAM_ERROR); 
+	}
+	time0 = round(dtime0/dz->frametime);								  /* 2 */
+	thiswdur  = 1.0/stretch0;												  /* 3 */
+	while((exit_status = get_both_vals_from_brktable(&dtime1,&stretch1,TSTR_STRETCH,dz))==CONTINUE) {/* 4 */
+		nextwdur  = 1.0/stretch1;
+		if((time1 = round(dtime1/dz->frametime)) > dz->wlength) {
+			time2  = time1;												  /* 5 */
+			time1 = round(dz->param[TSTR_TOTIME]/dz->frametime);
+			valdiff  = nextwdur - thiswdur;
+			valdiff *= (double)(time1 - time0)/(double)(time2 - time0);
+			nextwdur = thiswdur + valdiff;
+			atend = TRUE;
+		}
+		totaldur = time1 - time0;
+		timestretch_called = TRUE;
+		if((exit_status = timestretch_this_segment(thatwindow,startwindow,thiswdur,nextwdur,totaldur,dz))<0)
+			return(exit_status);
+		startwindow += totaldur;
+		thiswdur  = nextwdur;
+		time0 = time1;
+		if(atend)
+			break;
+	}
+	if(timestretch_called == FALSE) {
+		sprintf(errstr,"Not enough data in brkfile & not trapped earlier: do_timevariable_timestretch()\n");
+		return(PROGRAM_ERROR);
+	} 
+	return(FINISHED);
+}
+
+/*************************** DO_TIMESTRETCHING ********************************
+ *
+ * Read/interpolate source analysis windows.
+ *
+ * (1)	initialise the position-buffer pointer. NB we don't use pbufptr as
+ *		this is (?) still marking the current position in the output buffer.
+ * (2)	For each entry in the position-array.
+ * (3)	get the absolute position.
+ * (4)	The window to intepolate FROM is this truncated
+ *		e.g. position 3.2 translates to window 3.
+ * (5)	Is this is a move on from the current window position? How far?
+ * (6)	If we're in the final window, set the 'atend' flag.
+ * (7)	If we need to move on, call advance-windows and set up a new PAIR of
+ *		input windows.
+ * (8)	Get Interpolation time-fraction.
+ * (9)	Get output values by interpolation between input values.
+ * (10) Write a complete out-windowbuf to output file.
+ * (11)	Give on-screen user information.
+ */
+
+int do_timestretching(int *thatwindow,int count,dataptr dz)
+{
+	int exit_status;
+	double amp0, amp1, phas0, phas1;
+	int	 vc;
+	int n, thiswindow, step;
+	int atend = FALSE;						
+	double here, frac;
+	double *p = dz->parray[TSTR_PBUF];				/* 1 */   
+	for(n=0;n<count;n++) {							/* 2 */
+		here = *p++;								/* 3 */
+		thiswindow = (int)here; /* TRUNCATE */		/* 4 */
+		step = thiswindow - *thatwindow;			/* 5 */
+		if(thiswindow == dz->wlength-1)				/* 6 */
+			atend = TRUE;
+		if(step) {
+			if((exit_status = advance_along_input_windows(step,atend,dz))<0)   /* 7 */
+				return(exit_status);
+		}
+		frac = here - (double)thiswindow;			/* 8 */
+		for(vc = 0; vc < dz->wanted; vc += 2) {
+			amp0  = dz->flbufptr[3][AMPP];			/* 9 */
+			phas0 = dz->flbufptr[3][FREQ];
+			amp1  = dz->flbufptr[4][AMPP];
+			phas1 = dz->flbufptr[4][FREQ];
+			dz->flbufptr[5][AMPP]  = (float)(amp0  + ((amp1  - amp0)  * frac));
+			dz->flbufptr[5][FREQ]  = (float)(phas0 +	((phas1 - phas0) * frac));
+		}
+		if((dz->flbufptr[5] += dz->wanted) >= dz->flbufptr[2]) {
+			if((exit_status = write_exact_samps(dz->flbufptr[1],dz->big_fsize,dz))<0)
+				return(exit_status);
+			dz->flbufptr[5] = dz->flbufptr[1];
+		}
+		*thatwindow = thiswindow;
+	}
+	return(FINISHED);
+}
+
+/******************************* DO_TIMEVARIABLE_COUNT *****************************/
+
+int do_timevariable_count(int *outcnt,dataptr dz)
+{
+	int exit_status;
+	int time0, time1, time2, totaldur;
+	double stretch0, stretch1, thiswdur, nextwdur, valdiff, dtime0, dtime1;
+	int atend = FALSE;
+	int timestretch_called = FALSE;
+	if((exit_status = get_both_vals_from_brktable(&dtime0,&stretch0,TSTR_STRETCH,dz))==FINISHED) {
+		sprintf(errstr,"Not enough data in brkfile & not trapped earlier: do_timevariable_count()\n");
+		return(PROGRAM_ERROR);
+	}
+	time0 = round(dtime0/dz->frametime);								  /* 2 */
+	thiswdur  = 1.0/stretch0;												  /* 3 */
+	while((exit_status = get_both_vals_from_brktable(&dtime1,&stretch1,TSTR_STRETCH,dz))==CONTINUE) {/* 4 */
+		nextwdur  = 1.0/stretch1;
+		if((time1 = round(dtime1/dz->frametime)) > dz->wlength) {
+			time2  = time1;												  /* 5 */
+			time1 = round(dz->param[TSTR_TOTIME]/dz->frametime);
+			valdiff  = nextwdur - thiswdur;
+			valdiff *= (double)(time1 - time0)/(double)(time2 - time0);
+			nextwdur = thiswdur + valdiff;
+			atend = TRUE;
+		}
+		totaldur = time1 - time0;
+		timestretch_called = TRUE;
+
+
+		*outcnt += round(fabs(calculate_number_of_output_windows(thiswdur,nextwdur,totaldur)));
+		thiswdur  = nextwdur;
+		time0 = time1;
+		if(atend)
+			break;
+	}
+	if(timestretch_called == FALSE) {
+		sprintf(errstr,"Not enough data in brkfile & not trapped earlier: do_timevariable_count()\n");
+		return(PROGRAM_ERROR);
+	} 
+	return(FINISHED);
+}
+
+/**************************** DIVIDE_TIME_INTO_EQUAL_INCREMENTS *****************************
+ *
+ * all time intervals are equal. Divide up total time thus.
+ */
+
+int divide_time_into_equal_increments(int *thatwindow,int startwindow,double dur,int count,dataptr dz)
+{
+	int exit_status;
+	int n, remnant;
+	int end   = dz->ptr[TSTR_PEND] - dz->ptr[TSTR_PBUF];
+	int start = 0;
+	while(count >= end) {
+		for(n = start; n < end; n++)
+			*(dz->ptr[TSTR_PBUF])++ = (dur * (double)n) + (double)startwindow;
+		if((exit_status = do_timestretching(thatwindow,dz->iparam[TSTR_ARRAYSIZE],dz))<0)	  
+			return(exit_status);
+		dz->ptr[TSTR_PBUF] = dz->parray[TSTR_PBUF];
+		start = end;
+		end  += dz->iparam[TSTR_ARRAYSIZE];
+	}
+	if((remnant = count - start)>0) {
+		for(n=start;n<count;n++)
+			*(dz->ptr[TSTR_PBUF])++ = (dur * (double)n) + (double)startwindow;
+	}
+	return(FINISHED);
+}
+
+/**************************** GET_BOTH_VALS_FROM_BRKTABLE ****************************/
+
+int get_both_vals_from_brktable(double *thistime,double *thisstretch,int brktab_no,dataptr dz)
+{
+	double *brkend = dz->brk[brktab_no] + (dz->brksize[brktab_no] * 2);
+	if(dz->brkptr[brktab_no]>=brkend)
+		return(FINISHED);
+	*thistime = *(dz->brkptr[brktab_no])++;
+	if(dz->brkptr[brktab_no]>=brkend) {
+		sprintf(errstr,"Anomaly in get_both_vals_from_brktable().\n");
+		return(PROGRAM_ERROR);
+	}
+	*thisstretch = *(dz->brkptr[brktab_no])++;
+	return(CONTINUE);
+}
+
+/************************** TIMESTRETCH_THIS_SEGMENT *****************************
+ *
+ * Takes a group of input windows, counts number of output windows
+ * corresponding to this buffer, and sets up, in pbuff, array(s) of values
+ * which are the positions in the input array corresponding to the output
+ * array positions.
+ * (1)  If there is (almost) no change in duration of segments, calculates
+ *       times on simple additive basis.
+ * (2)  Otherwise, uses exponential formula.
+ * (3)  If NOT passed a negative number (i.e. flagged), the sequence of time
+ *      intervals is reversed.
+ */
+
+int timestretch_this_segment(int *thatwindow,int startwindow,double thiswdur,double nextwdur,int totaldur,dataptr dz)
+{
+	int    stretch_decreasing = TRUE;
+	int   count;
+	double dur, dcount = calculate_number_of_output_windows(thiswdur,nextwdur,totaldur);
+	double param0, param1, param2;
+	if(dcount < 0.0)
+		stretch_decreasing = FALSE; 
+	count = round(fabs(dcount));
+	if(fabs(nextwdur - thiswdur)<=FLTERR) {            	/* 1 */
+		dur = (double)totaldur/(double)count;
+		return divide_time_into_equal_increments(thatwindow,startwindow,dur,count,dz);
+	}    
+	param0  = nextwdur - thiswdur;                      /* 2 */
+	param1  = param0/(double)totaldur;
+	param2  = thiswdur * (double)totaldur;
+	if(stretch_decreasing==TRUE)							 	/* 3 */
+		return calc_position_output_wdws_relative_to_input_wdws_for_decreasing_stretch
+		(thatwindow,startwindow,count,totaldur,param0,param1,param2,dz);
+	else
+		return calc_position_output_wdws_relative_to_input_wdws_for_increasing_stretch
+		(thatwindow,startwindow,count,param0,param1,param2,dz);
+}
+
+/*************************** ADVANCE_ALONG_INPUT_WINDOWS ****************************
+ *
+ * Advance window frame in input.
+ * (1)	If got to end of data... Advanve ONE LESS than the distance
+ * 	(wdw_to_advance) from last window-pair.
+ * (2)	Else, advance by cnt windows.
+ * (3)	If at end of buffer, copy THIS window to start of whole buffer,
+ * (4)	And read more data in AFTER that (dz->wanted samps from start).
+ * (6)	If this is the last window in the source file, there is no other
+ *  	window to interpolate to, so set last window to same as this.
+ */
+
+int advance_along_input_windows(int wdw_to_advance,int atend,dataptr dz)			  
+{
+	int n, count;
+	int samps_read;
+	if(atend)						/* 1 */
+		count = wdw_to_advance-1;
+	else							/* 2 */
+		count = wdw_to_advance;
+	for(n=0;n<count;n++) {
+		dz->flbufptr[3] = dz->flbufptr[4];			   	 /* ADVANCE LASTWINDOW TO THISWINDOW */
+		if((dz->flbufptr[4] += dz->wanted) > dz->flbufptr[1]) {  /* ADVANCE THISWINDOW TO NEXT */
+			memmove((char *)dz->bigfbuf,(char *)dz->flbufptr[3],dz->wanted * sizeof(float));
+			dz->flbufptr[3] = dz->bigfbuf;				    /* 3 */
+			dz->flbufptr[4] = dz->flbufptr[0];				/* 4 */
+			if((samps_read = fgetfbufEx(dz->flbufptr[4],dz->big_fsize,dz->ifd[0],0)) < dz->wanted) {
+				if(n <= count-2) {
+					sprintf(errstr,"Program miscounted windows: anomaly 1 at EOF? : advance_along_input_windows()\n");
+					return(PROGRAM_ERROR);
+				}
+				if(samps_read < 0) {
+					sprintf(errstr,"Program miscounted windows: anomaly 2 at EOF? : advance_along_input_windows()\n");
+					return(PROGRAM_ERROR);
+				}
+				return(FINISHED);
+			}
+			if(sloom)
+				dz->total_samps_read += samps_read;
+		}
+	}
+	if(atend)							/* 6 */
+		dz->flbufptr[4] = dz->flbufptr[3];
+	return(CONTINUE);
+}
+
+/*************************** CALCULATE_NUMBER_OF_OUTPUT_WINDOWS ***************************
+ *
+ * Given a sequence of events of varying duration, where initial and 
+ * final durations are known, together with start and end times of the
+ * total sequence, this function calculates the total number of events.
+ *
+ *	NB
+ * (1)	Where the segment duration is increading, log(startwdur/edndur) is -ve,
+ *		so the returned count is -ve.
+ * (2)	Where segment duration is NOT changing, log(startwdur/endwdur), and hence dcount, would be zero.
+ *		This situation is trapped by first checking for (approx) equality of startwdur and endwdur
+ *		and calculating the count in simpler manner.
+ */
+
+double calculate_number_of_output_windows(double startwdur,double endwdur,int totaldur)
+{
+	double durdiff, dcount;
+	if(flteq((durdiff = endwdur - startwdur),0.0)) {
+		dcount = (double)totaldur/endwdur;
+		return(dcount);
+	}
+	dcount  = startwdur/endwdur;
+	dcount  = log(dcount);
+	dcount *= (double)totaldur/durdiff;
+	return(dcount);
+}
+
+/********* CALC_POSITION_OUTPUT_WDWS_RELATIVE_TO_INPUT_WDWS_FOR_DECREASING_STRETCH ************
+ *
+ * THE ARRAY OF positions has to be retrograded, but if we have more than
+ * a single output-arrayfull of position values, we must start calculating
+ * the output position array from the last input position, then invert those
+ * positions so they are first positions, and so on!!!
+ * (0)	As the array is to be filled backwards, start calculating positions
+ *		from end of input. So end of first pass = end of input (= count).
+ * (1)	Find how many locations remain in output-position buffer.
+ * (2)	Start of first pass is this no of positions before end.
+ * (3)	If start is < 0 this means that all the positions in the current input
+ *		pass will fit in the output buffer in its current state, so we skip the
+ *		loop and go to (10), Otherwise...
+ * (4)	Mark the address in the output buffer where writing-values begins.
+ * (5)	Store in output buffer, the positions RELATIVE to start of this segment
+ *		of input values (i.e. relative to ZERO).
+ * (6)	Retrograde this time-interval set.
+ * (7)	Increment these relative values by startwindow, to give absolute
+ *		position values.
+ * (8)	Do the output, and reinitialise the output buffer pointer to start
+ *		of buffer. Reset new input-block end to START of previous block
+ *		(we're working backwards).
+ * (9)	Decrement start of block by size of output array.
+ * (10)	If either we did not enter the loop OR we have some input values
+ *		left on leaving the principle loop, calcuate output positions of
+ *		these items, and store in the output buffer (which will be flushed
+ *		either by next call to timestretch_this_segment() or, at end, by flushbuf()).
+ */
+
+int calc_position_output_wdws_relative_to_input_wdws_for_decreasing_stretch
+(int *thatwindow,int startwindow,int count,int totaldur,double param0,double param1,double param2,dataptr dz)
+{
+	int exit_status;
+	int n, start, end = count;								/* 0 */
+	double *p, *startptr;
+	int tofill = dz->ptr[TSTR_PEND] - dz->ptr[TSTR_PBUF];	/* 1 */
+	start = count - tofill;									/* 2 */
+	while(start>=0) {										/* 3 */
+		startptr = dz->ptr[TSTR_PBUF];						/* 4 */
+		for(n=start;n<end;n++)			 					/* 5 */
+			*(dz->ptr[TSTR_PBUF])++ = calculate_position(n,param0,param1,param2);
+															/* 6 */
+		if((exit_status = retrograde_sequence_of_time_intervals(totaldur - start,end - start,startptr,dz))<0)
+			return(exit_status);
+		for(p = startptr;p<dz->ptr[TSTR_PEND];p++)
+			*p += (double)startwindow;						/* 7 */
+		if((exit_status = do_timestretching(thatwindow,dz->iparam[TSTR_ARRAYSIZE],dz))<0)	
+			return(exit_status);
+		dz->ptr[TSTR_PBUF] = dz->parray[TSTR_PBUF];			/* 8 */
+		end    = start;
+		start -= dz->iparam[TSTR_ARRAYSIZE];				/* 9 */
+	}
+	if(end) {												/* 10 */
+		startptr = dz->ptr[TSTR_PBUF];
+		for(n=0;n<end;n++)
+			*(dz->ptr[TSTR_PBUF])++ = calculate_position(n,param0,param1,param2);
+		if((exit_status = retrograde_sequence_of_time_intervals(totaldur,end,startptr,dz))<0)
+			return(exit_status);
+		for(p = startptr;p<dz->ptr[TSTR_PBUF];p++)
+			*p += (double)startwindow;
+	}
+	return(FINISHED);
+}
+
+/********* CALC_POSITION_OUTPUT_WDWS_RELATIVE_TO_INPUT_WDWS_FOR_INCREASING_STRETCH ************
+ *
+ * Find positions of output samples relative to input samples, buffer 
+ * by buffer.
+ */
+   
+int calc_position_output_wdws_relative_to_input_wdws_for_increasing_stretch
+(int *thatwindow,int startwindow,int count,double param0,double param1,double param2,dataptr dz)
+{
+	int exit_status;
+	int n;
+	int start = 0;
+	int end  = dz->ptr[TSTR_PEND] - dz->ptr[TSTR_PBUF];
+	while(count>=end) {
+		for(n=start;n<end;n++)
+			*(dz->ptr[TSTR_PBUF])++ = calculate_position(n,param0,param1,param2) + (double)startwindow;
+		if((exit_status = do_timestretching(thatwindow,dz->iparam[TSTR_ARRAYSIZE],dz))<0)
+			return(exit_status);
+		dz->ptr[TSTR_PBUF] = dz->parray[TSTR_PBUF];				   
+		start = end;
+		end  += dz->iparam[TSTR_ARRAYSIZE];
+	}
+	if(count-start) {
+		for(n=start;n<count;n++)
+			*(dz->ptr[TSTR_PBUF])++ = calculate_position(n,param0,param1,param2) + (double)startwindow;
+	}
+	return(FINISHED);
+}
+
+/*************************** CALCULATE_POSITION ****************************
+ *
+ * Do the position calculation using the exponential formula.
+ */
+
+double calculate_position(int x,double param0,double param1,double param2)
+{
+	double k;
+	k  = param1;
+	k *= (double)x;
+	k  = exp(k);
+	k *= param2;
+	k -= param2;
+	return(k/(param0));
+}
+
+/*************************** RETROGRADE_SEQUENCE_OF_TIME_INTERVALS **************************
+ *
+ * Accepts a sequence of times, starting in address startptr, 
+ * and retrogrades the sequence of time-intervals, storing the
+ * results back in startptr onwards.
+ */
+
+int retrograde_sequence_of_time_intervals(int endtime,int count,double *startptr,dataptr dz)
+{
+	double newtime, lasttime, tsize;
+	int n;
+	double *p  = startptr;
+	dz->ptr[TSTR_QBUF] = dz->parray[TSTR_QBUF] + (count-1);
+	newtime = endtime;
+	for(n=0;n<(count-1);n++) {
+		lasttime   = *p++;
+		tsize      = *p - lasttime;
+		newtime   -= tsize;
+		*dz->ptr[TSTR_QBUF]-- = newtime; 
+	}
+	if(dz->ptr[TSTR_QBUF]!=dz->parray[TSTR_QBUF]) {
+		sprintf(errstr,"counting problem: retrograde_sequence_of_time_intervals()\n");
+		return(PROGRAM_ERROR);
+	}
+	*dz->ptr[TSTR_QBUF] = *p; /* put starttime at start of intervals inverted array */
+	p  = startptr;
+	for(n=0;n<count;n++)
+		*p++ = *dz->ptr[TSTR_QBUF]++;
+	return(FINISHED);
+}
+
+/**************************** SPECSTRETCH ***************************
+ *
+ * stretch the frq values in spectrum (e.g. harmonic -> inharmonic).
+ */
+
+int specstretch(dataptr dz)
+{
+	int exit_status;
+	if(dz->brksize[STR_DEPTH] && flteq(dz->param[STR_DEPTH],0.0))
+		return(FINISHED);
+	if((exit_status = get_amp_and_frq(dz->flbufptr[0],dz))<0)
+		return(exit_status);		
+	if(dz->brksize[STR_DEPTH])
+		dz->param[STR_NSHIFT] = (dz->param[STR_SL1] * dz->param[STR_DEPTH]) + 1.0;
+	if((exit_status = stretch_spectrum(dz->param[STR_NSHIFT],dz))<0)
+		return(exit_status);
+	if((exit_status = put_amp_and_frq(dz->flbufptr[0],dz))<0)
+		return(exit_status);
+	return(FINISHED);
+}
+
+/************************** STRETCH_SPECTRUM *****************************/
+
+int stretch_spectrum(double shift,dataptr dz)
+{
+	int    j, k, spectop ,specbot;
+	double chshift, ratio, str_part;
+	double slone, onels, flone;
+	switch(dz->mode) {
+	case(STRETCH_ABOVE): 		/* STRETCH SPECTRUM, above fdcno, BY SHIFT */
+		if( shift >= 1.0) {  
+			slone    = shift - 1.0;
+			j        = dz->clength - 1;
+			str_part = (double)((dz->clength - 1) - dz->iparam[STR_FDCNO]);
+			chshift  = shift;
+			k              = round((double)j/chshift);
+			while( k >= dz->iparam[STR_FDCNO]) {
+				dz->amp[j]  = dz->amp[k];
+				dz->freq[j] = (float)chshift*dz->freq[k];
+				if(--j <= dz->iparam[STR_FDCNO])
+					break;
+				ratio   = (double)(j - dz->iparam[STR_FDCNO])/str_part;
+				ratio   = pow(ratio,dz->param[STR_EXP]);
+				chshift = (ratio * (slone)) + 1.0;
+				k       = round((double)j/chshift);
+			}
+		} else {
+			onels = 1.0 - shift;
+			spectop  = round((double)(dz->clength-1) * shift);
+			str_part = (float)(spectop - dz->iparam[STR_FDCNO]);
+			chshift  = 1.0;
+			k        = dz->iparam[STR_FDCNO];
+			j        = k;
+			while( (k <= (dz->clength-1)) && (j <=spectop)) {
+				dz->amp[j]  = dz->amp[k];
+				dz->freq[j] = (float)chshift * dz->freq[k];
+				j++;
+				ratio   = (double)(j - dz->iparam[STR_FDCNO])/str_part;
+				ratio   = pow(ratio,dz->param[STR_EXP]);
+				chshift = 1.0 - (ratio * onels);
+				k       = round((double)j/chshift);
+			}
+		}
+		break;
+	case(STRETCH_BELOW):		/* STRETCH SPECTRUM, below fdcno, DOWN BY SHIFT */
+		flone = dz->iparam[STR_FDCNO] - 1;
+		if(shift <= 1.0) {
+			onels   = 1.0 - shift;
+			j       = 1;
+			k       = round((double)j/shift);
+			chshift = shift;
+			while( k < dz->iparam[STR_FDCNO]) {
+				dz->amp[j]  = dz->amp[k];
+				dz->freq[j] = (float)chshift*dz->freq[k];
+				j++ ;
+				ratio   = (double)j/flone;
+				ratio   = pow(ratio,dz->param[STR_EXP]);
+				chshift = shift + (ratio * onels);
+				k       = round((double)j/chshift);
+			}
+		} else {
+			slone    = shift - 1.0;
+			j        = dz->iparam[STR_FDCNO] - 1;
+			k        = j;
+			specbot  = round(shift);
+			str_part = flone - (double)specbot;
+			chshift  = 1.0;
+
+			while( (k > 0) && (j >= specbot)) {
+				dz->amp[j]  = dz->amp[k];
+				dz->freq[j] = (float)chshift * dz->freq[k];
+				j-- ;
+				ratio   = (flone - (double)j)/str_part;
+				ratio   = pow(ratio,dz->param[STR_EXP]);
+				chshift = (ratio * slone) + 1.0;
+				k       = round((double)j/chshift);
+			}
+		}
+		break;
+	default:
+		sprintf(errstr,"Unknown mode in stretch_spectrum()\n");
+		return(PROGRAM_ERROR);
+	}
+	return(FINISHED);
+}
+